1452 lines
48 KiB
TypeScript
1452 lines
48 KiB
TypeScript
import type { XOTemplate } from "@xo-cash/types";
|
|
import { generateTemplateIdentifier } from "@xo-cash/engine";
|
|
|
|
export const p2pkhTemplate: XOTemplate = {
|
|
$schema: "https://libauth.org/schemas/wallet-template-v0.schema.json",
|
|
|
|
// Name for this template.
|
|
name: "Wallet (P2PKH)",
|
|
|
|
// Description for this template.
|
|
description:
|
|
"A standard single-factor wallet template that uses Pay-to-Public-Key-Hash (P2PKH) locking scripts.",
|
|
|
|
// Icon for this template.
|
|
icon: "wallet",
|
|
|
|
// Version number for this template.
|
|
version: 0,
|
|
|
|
// List of VM versions that can be used to run this template.
|
|
supported: ["BCH_2023_05", "BCH_2024_05", "BCH_2025_05", "BCH_2026_05"],
|
|
|
|
// Describe a list of roles that are used in this template.
|
|
roles: {
|
|
owner: {
|
|
name: "Wallet Owner",
|
|
description: "The party who can spend from this wallet.",
|
|
icon: "owner",
|
|
},
|
|
receiver: {
|
|
name: "Receiver",
|
|
description: "A party that is receiving value.",
|
|
icon: "receiver",
|
|
},
|
|
sender: {
|
|
name: "Sender",
|
|
description: "A party that is sending value.",
|
|
icon: "sender",
|
|
},
|
|
},
|
|
|
|
// Define a list of entrypoints supported by this template.
|
|
start: [
|
|
{
|
|
action: "receive",
|
|
role: "receiver",
|
|
},
|
|
{
|
|
action: "requestSatoshis",
|
|
role: "receiver",
|
|
},
|
|
{
|
|
action: "requestFungibleTokens",
|
|
role: "receiver",
|
|
},
|
|
{
|
|
action: "requestNonfungibleTokens",
|
|
role: "receiver",
|
|
},
|
|
],
|
|
|
|
// Define a list of actions that can be taken by this template.
|
|
// NOTE: There is no action to generate an address, but a wallet can create an invitation to a receive action and
|
|
// extract the generated lockscript as needed as the engine will track all lockscripts it generates.
|
|
actions: {
|
|
receive: {
|
|
// TODO: Consider rewriting to be generic/role-less.
|
|
name: "Receive",
|
|
description:
|
|
"Receive an unspecified amount of cash and/or tokens from one or more senders.",
|
|
icon: "receive",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Receive",
|
|
description:
|
|
"Receive an unspecified amount of cash and/or tokens from one or more senders.",
|
|
icon: "receive",
|
|
|
|
requirements: {
|
|
generate: ["ownerKey"],
|
|
},
|
|
},
|
|
sender: {
|
|
name: "Send",
|
|
description:
|
|
"Send an unspecified amount of cash and/or tokens to the provided receiver.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "receiver",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: undefined },
|
|
},
|
|
],
|
|
variables: ["requestedSatoshis"],
|
|
},
|
|
|
|
transaction: "receiveTransaction",
|
|
},
|
|
requestSatoshis: {
|
|
// TODO: Consider rewriting to be generic/role-less.
|
|
name: "Request Satoshis",
|
|
description:
|
|
"Requests a specific amount of Bitcoin Cash from one or more senders.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Request Satoshis",
|
|
description:
|
|
"Requests a specific amount of Bitcoin Cash from one or more senders.",
|
|
icon: "request",
|
|
|
|
requirements: {
|
|
generate: ["ownerKey"],
|
|
variables: ["requestedSatoshis"],
|
|
},
|
|
},
|
|
sender: {
|
|
name: "Send",
|
|
description:
|
|
"Send a specific amount of Bitcoin Cash to the provided receiver.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "receiver",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: undefined },
|
|
},
|
|
],
|
|
},
|
|
|
|
transaction: "requestSatoshisTransaction",
|
|
},
|
|
requestFungibleTokens: {
|
|
// TODO: Consider rewriting to be generic/role-less.
|
|
name: "Request Fungible Tokens",
|
|
description:
|
|
"Requests a specific amount of a fungible tokens from one or more senders.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Request Fungible Tokens",
|
|
description:
|
|
"Requests a specific amount of a fungible tokens from one or more senders.",
|
|
icon: "request",
|
|
|
|
requirements: {
|
|
generate: ["ownerKey"],
|
|
variables: ["requestedTokenCategory", "requestedTokenAmount"],
|
|
},
|
|
},
|
|
sender: {
|
|
name: "Send",
|
|
description:
|
|
"Send a specific amount of fungible tokens to the provided receiver.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "receiver",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: undefined },
|
|
},
|
|
],
|
|
},
|
|
|
|
transaction: "requestFungibleTokensTransaction",
|
|
},
|
|
requestNonfungibleTokens: {
|
|
// TODO: Consider rewriting to be generic/role-less.
|
|
name: "Request a Non-fungible Token",
|
|
description: "Requests a non-fungible token from one or more senders.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Request a Non-fungible Token",
|
|
description:
|
|
"Requests a non-fungible token from one or more senders.",
|
|
icon: "request",
|
|
|
|
requirements: {
|
|
generate: ["ownerKey"],
|
|
variables: [
|
|
"requestedTokenCategory",
|
|
"requestedTokenCapability",
|
|
"requestedTokenCommitment",
|
|
],
|
|
},
|
|
},
|
|
sender: {
|
|
name: "Send",
|
|
description: "Send a non-fungible token to the provided receiver.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "receiver",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: undefined },
|
|
},
|
|
],
|
|
},
|
|
|
|
transaction: "requestNonfungibleTokensTransaction",
|
|
},
|
|
|
|
// NOTE: Sending value can be done without explicit template support.
|
|
// NOTE: This feature is explicitly defined in this template to demonstrate how versatile templates can be, and
|
|
// to ensure the feature is discoverable by the user from outputs that hold value.
|
|
sendSatoshis: {
|
|
name: "Send Satoshis",
|
|
description:
|
|
"Sends a specific amount of Bitcoin Cash to a given recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
sender: {
|
|
requirements: {
|
|
variables: ["transferredSatoshis", "recipientLockingscript"],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Sending is only available for outputs that have sufficient satoshis on them.
|
|
// NOTE: Dust is enforced here according to standardness rules.
|
|
condition: "$(OP_INPUTINDEX OP_UTXOVALUE <dustLimit> OP_GREATERTHAN)",
|
|
|
|
transaction: "transferSatoshisTransaction",
|
|
},
|
|
sendFungibleTokens: {
|
|
name: "Send Fungible Tokens",
|
|
description:
|
|
"Send a specific amount of a fungible token to a given recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
sender: {
|
|
requirements: {
|
|
variables: [
|
|
"transferredTokenCategory",
|
|
"transferredTokenAmount",
|
|
"recipientLockingscript",
|
|
],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Sending is only available for outputs that have fungible tokens on them.
|
|
condition: "$(OP_INPUTINDEX OP_UTXOTOKENAMOUNT <0> OP_GREATERTHAN)",
|
|
|
|
transaction: "transferFungibleTokensTransaction",
|
|
},
|
|
sendNonfungibleTokens: {
|
|
name: "Send a Non-fungible Token",
|
|
description: "Send a non-fungible token to a given recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
sender: {
|
|
requirements: {
|
|
variables: [
|
|
"transferredTokenCategory",
|
|
"transferredTokenCapability",
|
|
"transferredTokenCommitment",
|
|
"recipientLockingscript",
|
|
],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "sender",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Sending is only available for outputs that have a non-fungible token on them.
|
|
condition:
|
|
"$(OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_SIZE OP_NIP <32> OP_GREATERTHAN)",
|
|
|
|
transaction: "transferNonfungibleTokensTransaction",
|
|
},
|
|
|
|
// NOTE: Burning tokens can be done without explicit template support.
|
|
// NOTE: This feature is explicitly defined in this template to demonstrate how versatile templates can be, and
|
|
// to ensure the feature is discoverable by the user from outputs that hold tokens.
|
|
burnFungibleTokens: {
|
|
name: "Delete Fungible Tokens",
|
|
description:
|
|
"Permanently and irreversibly deletes one or more fungible tokens.",
|
|
icon: "burn",
|
|
|
|
roles: {
|
|
owner: {
|
|
requirements: {
|
|
variables: ["burnedTokenCategory", "burnedTokenAmount"],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "owner",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Burning is only available for outputs that have fungible tokens on them.
|
|
condition: "$(OP_INPUTINDEX OP_UTXOTOKENAMOUNT <0> OP_GREATERTHAN)",
|
|
|
|
transaction: "burnFungibleTokensTransaction",
|
|
},
|
|
burnNonfungibleTokens: {
|
|
name: "Delete a Non-fungible Token",
|
|
description:
|
|
"Permanently and irreversibly deletes one non-fungible token.",
|
|
icon: "burn",
|
|
|
|
roles: {
|
|
owner: {
|
|
requirements: {
|
|
variables: [
|
|
"burnedTokenCategory",
|
|
"burnedTokenCapability",
|
|
"burnedTokenCommitment",
|
|
],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "owner",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
// Burning is only available for outputs that have non-fungible tokens on them.
|
|
condition:
|
|
"$(OP_INPUTINDEX OP_UTXOTOKENCATEGORY OP_SIZE OP_NIP <32> OP_GREATERTHAN)",
|
|
|
|
transaction: "burnNonfungibleTokenTransaction",
|
|
},
|
|
|
|
sign: {
|
|
name: "Sign Message",
|
|
description:
|
|
"Signs a provided message using the Bitcoin message signing protocol.",
|
|
icon: "sign",
|
|
|
|
roles: {
|
|
owner: {
|
|
requirements: {
|
|
variables: ["messageToSign"],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "owner",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
data: ["messageSignature"],
|
|
},
|
|
verify: {
|
|
name: "Verify Message Signature",
|
|
description:
|
|
"Verifies a provided message signature according to the Bitcoin message signing protocol.",
|
|
icon: "verify",
|
|
|
|
roles: {
|
|
owner: {
|
|
requirements: {
|
|
variables: ["messageSignature", "messageToVerify"],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
roles: [
|
|
{
|
|
role: "owner",
|
|
slots: { min: 1, max: 1 },
|
|
},
|
|
],
|
|
},
|
|
|
|
data: ["messageSignatureValidity"],
|
|
},
|
|
},
|
|
|
|
// Define a set of data that can be used in this template.
|
|
data: {
|
|
messageSignature: {
|
|
// Evaluate CashASM expression to get the signature needed.
|
|
// NOTE: Pushes the prefix and message, then concatenates them together to form the data to sign.
|
|
// NOTE: In libauth today, it seems that this is done by defining the signature as a variable, and tying it to the key and message,
|
|
// and so this is different
|
|
// TODO: Check with Jason and see if there is any reason why this cannot be done like this.
|
|
value:
|
|
"$(<messagePrefix> <message> OP_CAT <ownerKey.data_signature.top_stack_element>)",
|
|
type: "bytes",
|
|
hint: "signature",
|
|
},
|
|
messageSignatureValidity: {
|
|
// Evaluate the validity of the message with the owners public key.
|
|
value:
|
|
"$(<messageSignature> <messagePrefix> <message> OP_CAT <ownerKey.public_key> OP_CHECKDATASIG)",
|
|
type: "integer",
|
|
hint: "script_boolean",
|
|
},
|
|
},
|
|
|
|
// Define a set of transactions that can be used in this template.
|
|
transactions: {
|
|
receiveTransaction: {
|
|
name: "Transfer request",
|
|
description:
|
|
"Transfer request for an unspecified amount of cash and/or tokens.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received an unspecified amount of cash and/or tokens.",
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent an unspecified amount of cash and/or tokens.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no inputs required, but the engine should detect that there is not sufficient input value to
|
|
// match the output and thus generate an invitation to participate in this action.
|
|
// When the invitation is shared, the other parties can add as many inputs and change outputs as needed.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "receiveOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
requestSatoshisTransaction: {
|
|
name: "Transfer request",
|
|
description: "Transfer request for $(<requestedSatoshis>) satoshis.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received $(<requestedSatoshis>) satoshis.",
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent $(<requestedSatoshis>) satoshis.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no inputs required, but the engine should detect that there is not sufficient input value to
|
|
// match the output and thus generate an invitation to participate in this action.
|
|
// When the invitation is shared, the other party can add as many inputs and outputs as needed since this transaction is composable.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "requestSatoshisOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
requestFungibleTokensTransaction: {
|
|
name: "Transfer request",
|
|
description:
|
|
"Transfer request for $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
"Received $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens.",
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
"Sent $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no inputs required, but the engine should detect that there is not sufficient input value to
|
|
// match the output and thus generate an invitation to participate in this action.
|
|
// When the invitation is shared, the other party can add as many inputs and outputs as needed since this transaction is composable.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "requestFungibleTokensOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
requestNonfungibleTokensTransaction: {
|
|
name: "Transfer request",
|
|
description:
|
|
'Transfer request for one non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<requestedTokenCategory.symbol>) token, with $(<requestedTokenCommitment>) commitment.',
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
'Received one non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<requestedTokenCategory.symbol>) token, with $(<requestedTokenCommitment>) commitment.',
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
'Sent the requested non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<requestedTokenCategory.symbol>) token, with $(<requestedTokenCommitment>) commitment.',
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no inputs required, but the engine should detect that there is not sufficient input value to
|
|
// match the output and thus generate an invitation to participate in this action.
|
|
// When the invitation is shared, the other party can add as many inputs and outputs as needed since this transaction is composable.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "requestNonfungibleTokensOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
|
|
transferSatoshisTransaction: {
|
|
name: "Satoshis Transferred",
|
|
description:
|
|
"$(<transferredSatoshis>) satoshis were transferred to a recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received $(<transferredSatoshis>) satoshis.",
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent $(<transferredSatoshis>) satoshis.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Enforce the inputs and outputs required by the transaction.
|
|
// NOTE: The input is provided from the action since it is only available on outputs with satoshis.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "transferSatoshisOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
transferFungibleTokensTransaction: {
|
|
name: "Fungible Tokens Transferred",
|
|
description:
|
|
"$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens were transferred to a recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
"Received $(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens.",
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
"Sent $(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Enforce the inputs and outputs required by the transaction.
|
|
// NOTE: The input is provided from the action since it is only available on outputs with fungible tokens.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "transferFungibleTokensOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
transferNonfungibleTokensTransaction: {
|
|
name: "Non-fungible Token Transferred",
|
|
description:
|
|
'One non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<transferredTokenCategory.symbol>) token was transferred to a recipient, with $(<transferredTokenCommitment>) commitment.',
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
'Received one non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<transferredTokenCategory.symbol>) token, with $(<transferredTokenCommitment>) commitment.',
|
|
icon: "receive",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
'Sent one non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<transferredTokenCategory.symbol>) token, with $(<transferredTokenCommitment>) commitment.',
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
// Enforce the inputs and outputs required by the transaction.
|
|
// NOTE: The input is provided from the action since it is only available on outputs with a non-fungible token.
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
output: "transferNonfungibleTokenOutput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
|
|
burnFungibleTokensTransaction: {
|
|
name: "Deleted fungible tokens",
|
|
description:
|
|
"Permanently and irreversibly deleted $(<burnedTokenAmount> <burnedTokenCategory.decimalsFactor> OP_DIV).$(<burnedTokenAmount> <burnedTokenCategory.decimalsFactor> OP_MOD) $(<burnedTokenCategory.symbol>) tokens.",
|
|
icon: "burn",
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no defined outputs as any non-burned value is automatically returned as change.
|
|
inputs: [
|
|
{
|
|
input: "burnFungibleTokensInput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
|
|
outputs: [],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
burnNonfungibleTokenTransaction: {
|
|
name: "Deleted non fungible token",
|
|
description:
|
|
'Permanently and irreversibly deleted a non-fungible $(<burnedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <burnedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) (<burnedTokenCategory.symbol>) token, with $(<burnedTokenCommitment>) commitment.',
|
|
icon: "burn",
|
|
|
|
// Inputs and outputs that must exist in the transaction.
|
|
// NOTE: There is no defined outputs as any non-burned value is automatically returned as change.
|
|
inputs: [
|
|
{
|
|
input: "burnNonfungibleTokenInput",
|
|
index: undefined,
|
|
},
|
|
],
|
|
outputs: [],
|
|
|
|
// Standard transaction without a locktime.
|
|
version: 2,
|
|
locktime: 0,
|
|
|
|
// ...
|
|
composable: true,
|
|
},
|
|
},
|
|
|
|
// Define a set of outputs that can be used within transactions in this template.
|
|
outputs: {
|
|
receiveOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
"Transferred an unspecified amount of cash and/or tokens to a recipient.",
|
|
icon: "receive",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received an unspecified amount of cash and/or tokens.",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent an unspecified amount of cash and/or tokens.",
|
|
},
|
|
},
|
|
|
|
// Defines how the requested funds should be locked.
|
|
lockscript: "receivingLockingScript",
|
|
},
|
|
requestSatoshisOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
"Transferred $(<requestedSatoshis>) satoshis to a recipient.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received $(<requestedSatoshis>) satoshis.",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent $(<requestedSatoshis>) satoshis.",
|
|
},
|
|
},
|
|
|
|
// Defines how the requested funds should be locked.
|
|
lockscript: "receivingLockingScript",
|
|
|
|
// Require the specified number of satoshis and no tokens.
|
|
valueSatoshis: "$(<requestedSatoshis>)",
|
|
token: null,
|
|
},
|
|
requestFungibleTokensOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
"Transferred $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens to a recipient.",
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
"Received $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens.",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
"Sent $(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_DIV).$(<requestedTokenAmount> <requestedTokenCategory.decimalsFactor> OP_MOD) $(<requestedTokenCategory.symbol>) tokens.",
|
|
},
|
|
},
|
|
|
|
// Defines how the requested funds should be locked.
|
|
lockscript: "receivingLockingScript",
|
|
|
|
// Require a flat 1000 satoshis to ensure the fungible tokens remains transferrable.
|
|
valueSatoshis: "1000",
|
|
|
|
// Require only the specified amount and type of fungible tokens.
|
|
// NOTE: This can be composed with a request for a non-fungible token, but will always result in two separate outputs.
|
|
token: {
|
|
category: "$(<requestedTokenCategory>)",
|
|
amount: "$(<requestedTokenAmount>)",
|
|
nft: null,
|
|
},
|
|
},
|
|
requestNonfungibleTokensOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
'Transferred one non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<requestedTokenCategory.symbol>) token to a recipient, with $(<requestedTokenCommitment>) commitment.',
|
|
icon: "request",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
'Received one non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<requestedTokenCategory.symbol>) token, with $(<requestedTokenCommitment>) commitment.',
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
'Sent the requested non-fungible $(<requestedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <requestedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<requestedTokenCategory.symbol>) token, with $(<requestedTokenCommitment>) commitment.',
|
|
},
|
|
},
|
|
|
|
// Defines how the requested funds should be locked.
|
|
lockscript: "receivingLockingScript",
|
|
|
|
// Require a flat 1000 satoshis to ensure the non-fungible token remains transferrable.
|
|
valueSatoshis: "1000",
|
|
|
|
// Require only an NFT with specified category, capability and commitment.
|
|
// NOTE: This can be composed with a request for fungible token amounts, but will always result in two separate outputs.
|
|
token: {
|
|
category: "$(<requestedTokenCategory>)",
|
|
amount: null,
|
|
nft: {
|
|
capability: "$(<requestedTokenCapability>)",
|
|
commitment: "$(<requestedTokenCommitment>)",
|
|
},
|
|
},
|
|
},
|
|
|
|
transferSatoshisOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
"Transferred $(<transferredSatoshis>) satoshis to a recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description: "Received $(<transferredSatoshis>) satoshis.",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description: "Sent $(<transferredSatoshis>) satoshis.",
|
|
},
|
|
},
|
|
|
|
// Use the recipients lockscript.
|
|
lockscript: "sendingLockingscript",
|
|
|
|
// Set the amount of satoshis to transfer.
|
|
valueSatoshis: "$(<transferredSatoshis>)",
|
|
},
|
|
transferFungibleTokensOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
"Transferred $(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens to a recipient.",
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
"Received $(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens.",
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
"Sent $(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_DIV).$(<transferredTokenAmount> <transferredTokenCategory.decimalsFactor> OP_MOD) $(<transferredTokenCategory.symbol>) tokens.",
|
|
},
|
|
},
|
|
|
|
// Use the recipients lockscript.
|
|
lockscript: "sendingLockingscript",
|
|
|
|
// Set the amount of fungible tokens to transfer.
|
|
token: {
|
|
category: "$(<transferredTokenCategory>)",
|
|
amount: "$(<transferredTokenAmount>)",
|
|
},
|
|
},
|
|
transferNonfungibleTokenOutput: {
|
|
name: "Recipient output",
|
|
description:
|
|
'Transferred one non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<transferredTokenCategory.symbol>) token to a recipient, with $(<transferredTokenCommitment>) commitment.',
|
|
icon: "send",
|
|
|
|
roles: {
|
|
receiver: {
|
|
name: "Received",
|
|
description:
|
|
'Received one non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<transferredTokenCategory.symbol>) token, with $(<transferredTokenCommitment>) commitment.',
|
|
},
|
|
sender: {
|
|
name: "Sent",
|
|
description:
|
|
'Sent one non-fungible $(<transferredTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <transferredTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) $(<transferredTokenCategory.symbol>) token, with $(<transferredTokenCommitment>) commitment.',
|
|
},
|
|
},
|
|
|
|
// Use the recipients lockscript.
|
|
lockscript: "sendingLockingscript",
|
|
|
|
// Set the non-fungible token to transfer.
|
|
token: {
|
|
category: "$(<transferredTokenCategory>)",
|
|
nft: {
|
|
capability: "$(<transferredTokenCapability>)",
|
|
commitment: "$(<transferredTokenCommitment>)",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
inputs: {
|
|
burnFungibleTokensInput: {
|
|
name: "Deleted fungible tokens",
|
|
description:
|
|
"Permanently and irreversibly deleted $(<burnedTokenAmount>) $(<burnedTokenCategory>).",
|
|
icon: "burn",
|
|
|
|
// Define which unlocking script unlocks this input.
|
|
unlockingScript: "unlockP2PKH",
|
|
|
|
// Require a fungible token of the requested token category, with an amount larger than or equal to the requested amount to burn.
|
|
token: {
|
|
category: "$(<burnedTokenCategory>)",
|
|
amount:
|
|
"$(<this.fungibleTokenAmount> <burnedTokenAmount> OP_GREATERTHANOREQUAL OP_IF <this.fungibleTokens> OP_ENDIF)",
|
|
},
|
|
|
|
// Ignore the burned token amount when determining change for this output.
|
|
// NOTE: The engine must check that this does not exceed the input value.
|
|
omitChangeAmounts: {
|
|
fungibleTokens: "${<burnedTokenAmount>}",
|
|
},
|
|
},
|
|
burnNonfungibleTokenInput: {
|
|
name: "Deleted non-fungible token",
|
|
description:
|
|
'Permanently and irreversibly burned one non-fungible $(<burnedTokenCapability> <0x02> OP_EQUAL OP_IF <"minting"> OP_ELSE <burnedTokenCapability> <0x01> OP_EQUAL OP_IF <"mutable"> OP_ELSE <"immutable"> OP_ENDIF OP_ENDIF) token of category $(<burnedTokenCategory>), with a $(<burnedTokenCommitment>) commitment.',
|
|
icon: "burn",
|
|
|
|
// Define which unlocking script unlocks this input.
|
|
unlockingScript: "unlockP2PKH",
|
|
|
|
// Require a non-fungible token of the specified category, capability and commitment to burn.
|
|
token: {
|
|
category: "$(<burnedTokenCategory>)",
|
|
nft: {
|
|
capability: "$(<burnedTokenCapability>)",
|
|
commitment: "$(<burnedTokenCommitment>)",
|
|
},
|
|
},
|
|
|
|
// Ignore the burned token when determining change for this output.
|
|
// NOTE: The engine must check that this does not exceed the input value.
|
|
omitChangeAmounts: {
|
|
nonfungibleTokens: 1,
|
|
},
|
|
},
|
|
},
|
|
|
|
// Define locking scripts used by this template.
|
|
// NOTE: Template supported wallets should automatically track all generated lockscripts for on-chain events.
|
|
lockingScripts: {
|
|
sendingLockingscript: {
|
|
// TODO: This currently describes outputs locked to this script, but all actions creating such outputs already have descriptions.
|
|
// This can either be dropped, or maybe more importantly, should be disambiguated so that lockscripts can provide separate
|
|
// descriptions for their script and the outputs that are locked to them. Leaving as a TODO for now and will address later.
|
|
name: "Sent",
|
|
description: "Funds sent to an external recipient",
|
|
icon: "address",
|
|
|
|
// ...
|
|
lockingType: "standard",
|
|
lockingScript: "lockToRecipient",
|
|
|
|
// Indicate that the sent output does not belong to the initiating user.
|
|
// NOTE: These values default to false/empty, but added here for additional clarity.
|
|
actions: [],
|
|
state: [],
|
|
secrets: [],
|
|
balance: false,
|
|
selectable: false,
|
|
privacy: false,
|
|
},
|
|
receivingLockingScript: {
|
|
// NOTE: Outputs to this lockscript by external actors defaults to this description when detected on-chain.
|
|
name: "Received",
|
|
description: "Funds received without wallet coordination.",
|
|
icon: "address",
|
|
|
|
// Defines how spending future received funds should be locked.
|
|
lockingType: "standard",
|
|
lockingScript: "lockP2PKH",
|
|
|
|
// Define a default unlocking script to be used when no action provided script is present.
|
|
unlockingScript: "unlockP2PKH",
|
|
|
|
roles: {
|
|
receiver: {
|
|
// The only state that is required to be persisted when receiving funds is the owners private key.
|
|
// NOTE: This is defined as a secret to not leak when creating invitations for others to participate in request or send actions.
|
|
state: {
|
|
variables: [],
|
|
secrets: ["ownerKey"],
|
|
},
|
|
|
|
// List actions that can be taken with the ownerKey for each address/lockscript.
|
|
actions: [
|
|
{
|
|
action: "sign",
|
|
role: "owner",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "verify",
|
|
role: "owner",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "sendSatoshis",
|
|
role: "sender",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "sendFungibleTokens",
|
|
role: "sender",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "sendNonfungibleTokens",
|
|
role: "sender",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "burnFungibleTokens",
|
|
role: "sender",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
{
|
|
action: "burnNonfungibleTokens",
|
|
role: "sender",
|
|
secrets: ["ownerKey"],
|
|
},
|
|
],
|
|
|
|
// Indicates how much of received funds should be part of a wallets total balance.
|
|
// NOTE: Evaluates in the context of the source transaction, with the current outputs technical data available under this.output.*
|
|
// NOTE: This can either evaluate to a boolean or a number. If evaluated to a boolean, then true means 100% of the output.
|
|
// NOTE: Since we know that the owner controls all assets, we short-cut the evaluations by setting true directly.
|
|
balance: {
|
|
satoshis: true,
|
|
fungibleTokens: true,
|
|
// nonFungibleToken: true,
|
|
},
|
|
|
|
// Indicate when received funds should be considered in automatic coin selection to meet input requirements of other transactions.
|
|
// NOTE: Evaluates in the context of the source transaction, with the current outputs technical data available under this.output.*
|
|
// NOTE: This evaluates to a boolean. If non-true, the output should not be considered for automatic coin selection.
|
|
// NOTE: Since we know that the secret key exist for the owner, this template short-cuts the evaluation by setting true directly.
|
|
selectable: true,
|
|
|
|
// Indicate that received funds are not considered good privacy.
|
|
// NOTE: This information allows wallets to make better privacy decisions, like avoid mixing private and non-private outputs.
|
|
privacy: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
// Define a set of scripts that can be used in this template.
|
|
scripts: {
|
|
lockP2PKH:
|
|
"OP_DUP OP_HASH160 <$(<ownerKey.public_key> OP_HASH160)> OP_EQUALVERIFY OP_CHECKSIG",
|
|
unlockP2PKH:
|
|
"<ownerKey.schnorr_signature.all_outputs> <ownerKey.public_key>",
|
|
lockToRecipient: "<recipientLockingscript>",
|
|
},
|
|
|
|
// TODO: Add icons
|
|
constants: {
|
|
dustLimit: {
|
|
name: "Dust Limit",
|
|
description:
|
|
"Standard required minimum satoshis for Pay to Public Key Hash outputs.",
|
|
type: "integer",
|
|
value: 546,
|
|
},
|
|
|
|
// Define a message prefix for use in arbitrary message signing.
|
|
messagePrefix: {
|
|
name: "Message Prefix",
|
|
description:
|
|
"Standard message prefix used in the bitcoin signed message protocol.",
|
|
type: "bytes",
|
|
|
|
// Value is enforced to the bitcoin signing magic string:
|
|
// "\x18Bitcoin Signed Message:\n"
|
|
value: "0x18426974636f696e205369676e6564204d6573736167653a0a",
|
|
},
|
|
},
|
|
|
|
// TODO: Add icons
|
|
variables: {
|
|
// Describe the secret private key.
|
|
ownerKey: {
|
|
name: "Owners Private Key",
|
|
description:
|
|
"The private key used to authorize spending of received funds.",
|
|
type: "bytes",
|
|
hint: "private_key",
|
|
},
|
|
|
|
messageToSign: {
|
|
name: "Message",
|
|
description: "The text message to sign.",
|
|
type: "string",
|
|
},
|
|
messageToVerify: {
|
|
name: "Message",
|
|
description: "The text message to verify.",
|
|
type: "string",
|
|
},
|
|
messageSignature: {
|
|
name: "Message Signature",
|
|
description: "The signature for the message.",
|
|
type: "bytes",
|
|
hint: "signature",
|
|
},
|
|
|
|
// Describe the parameters used when requesting value.
|
|
requestedSatoshis: {
|
|
name: "Requested Amount",
|
|
description: "The Bitcoin Cash amount requested",
|
|
type: "integer",
|
|
hint: "satoshis",
|
|
},
|
|
requestedTokenCategory: {
|
|
name: "Requested Token Category",
|
|
description: "The token category requested",
|
|
type: "bytes",
|
|
hint: "token_category",
|
|
},
|
|
requestedTokenAmount: {
|
|
name: "Requested Token Amount",
|
|
description: "The fungible token amount requested",
|
|
type: "integer",
|
|
hint: "token_amount",
|
|
},
|
|
requestedTokenCapability: {
|
|
name: "Requested Token Capability",
|
|
description: "The non-fungible token capability requested",
|
|
type: "bytes",
|
|
hint: "token_capability",
|
|
},
|
|
requestedTokenCommitment: {
|
|
name: "Requested Token Commitment",
|
|
description: "The non-fungible token commitment requested",
|
|
type: "bytes",
|
|
hint: "token_commitment",
|
|
},
|
|
transferredTokenCategory: {
|
|
name: "Sending Token Category",
|
|
description: "The token category of the token(s) to send",
|
|
type: "bytes",
|
|
hint: "token_category",
|
|
},
|
|
transferredTokenAmount: {
|
|
name: "Sending Token Amount",
|
|
description: "The fungible token amount to send",
|
|
type: "integer",
|
|
hint: "token_amount",
|
|
},
|
|
transferredTokenCapability: {
|
|
name: "Sending Token Capability",
|
|
description: "The token capability for the non-fungible token to send",
|
|
type: "bytes",
|
|
hint: "token_capability",
|
|
},
|
|
transferredTokenCommitment: {
|
|
name: "Sending Token Commitment",
|
|
description: "The token commitment for the non-fungible token to send",
|
|
type: "bytes",
|
|
hint: "token_commitment",
|
|
},
|
|
burnedTokenCategory: {
|
|
name: "Deleted Token Category",
|
|
description: "The token category of the token(s) to delete",
|
|
type: "bytes",
|
|
hint: "token_category",
|
|
},
|
|
burnedTokenAmount: {
|
|
name: "Deleted Token Amount",
|
|
description: "The fungible token amount to delete",
|
|
type: "integer",
|
|
hint: "token_amount",
|
|
},
|
|
burnedTokenCapability: {
|
|
name: "Deleted Token Capability",
|
|
description: "The token capability for the non-fungible token to delete",
|
|
type: "bytes",
|
|
hint: "token_capability",
|
|
},
|
|
burnedTokenCommitment: {
|
|
name: "Deleted Token Commitment",
|
|
description: "The token commitment for the non-fungible token to delete",
|
|
type: "bytes",
|
|
hint: "token_commitment",
|
|
},
|
|
},
|
|
|
|
// Define a list of re-usable icons that can be used as part of metadata.
|
|
// NOTE: the actual icons are not embedded in the template but only referenced by hashes here,
|
|
// and can be distributed either as an asset pack or looked up through something like IPFS.
|
|
icons: [
|
|
{
|
|
name: "wallet",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "owner",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "sender",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "address",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "receive",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "request",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "send",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "burn",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "sign",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
{
|
|
name: "verify",
|
|
hash: "0000000000000000000000",
|
|
},
|
|
],
|
|
|
|
scenarios: [
|
|
{
|
|
name: "requesting satoshis",
|
|
description: "happy-path evaluation for requesting satoshis.",
|
|
|
|
// The action being run in the scenario.
|
|
action: "requestSatoshis",
|
|
|
|
// List of roles taken in this scenario, and the resources they provided.
|
|
roles: [
|
|
{
|
|
role: "receiver",
|
|
values: {
|
|
generated: {
|
|
ownerKey: "KyRQa5pEXuzVcDwnXRLpYAascjchQW5DoxVRMbj4DTxS83573mz8",
|
|
},
|
|
variables: {
|
|
requestedSatoshis: 2000,
|
|
},
|
|
secrets: {
|
|
// This scenario does not carry any secrets.
|
|
},
|
|
inputs: [],
|
|
outputs: [
|
|
{
|
|
lockingBytecode:
|
|
"76a91475c715ecb74178fe87933e57e947e5e92d904b8188ac",
|
|
valueSatoshis: 2000,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
{
|
|
role: "sender",
|
|
values: {
|
|
// The sender provides no raw data to the action.
|
|
generated: {},
|
|
variables: {},
|
|
secrets: {},
|
|
|
|
// The sender does provide input and change.
|
|
inputs: [
|
|
{
|
|
outpointTransactionHash:
|
|
"4ef28553a31a266719e66ba97fee3aeecd6d1788f7ff6ab12f8ebceda49660c0",
|
|
outpointIndex: 0,
|
|
sequenceNumber: 0,
|
|
unlockingBytecode:
|
|
"41226b2be7c2890c8bbde2f79e79640e56d866843f2e822ec51c469019d13db04a422c9ee49f5eefd26fee24e91910edbbb032b90cc54c34da80a61e69b0ee3d22412103e7ab26c36a7c7f45b2c26f33c08b0fa43a633268700f47216646d4cb37ae5696",
|
|
},
|
|
],
|
|
outputs: [
|
|
{
|
|
lockingBytecode:
|
|
"76a91475c715ecb74178fe87933e57e947e5e92d904b8188ac",
|
|
valueSatoshis: 2000,
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
|
|
// List of resources provided outside the context of a role.
|
|
values: {
|
|
generated: {
|
|
// This scenario does not have any non-role generated values.
|
|
},
|
|
variables: {
|
|
// This scenario does not have any non-role variables.
|
|
},
|
|
secrets: {
|
|
// This scenario does not have any non-role secrets.
|
|
},
|
|
},
|
|
|
|
// Outcomes provides the set of resulting values created from the action.
|
|
outcome: {
|
|
roles: {
|
|
receiver: {
|
|
name: "Request",
|
|
description:
|
|
"Requested a specific amount of satoshis from one or more senders.",
|
|
icon: "request",
|
|
},
|
|
sender: {
|
|
name: "Send",
|
|
description:
|
|
"Sent a specific amount of satoshis to the provided receiver.",
|
|
icon: "send",
|
|
},
|
|
},
|
|
|
|
transactions: [
|
|
{
|
|
transaction:
|
|
"0200000001c06096a4edbc8e2fb16afff788176dcdee3aee7fa96be61967261aa35385f24e000000006441226b2be7c2890c8bbde2f79e79640e56d866843f2e822ec51c469019d13db04a422c9ee49f5eefd26fee24e91910edbbb032b90cc54c34da80a61e69b0ee3d22412103e7ab26c36a7c7f45b2c26f33c08b0fa43a633268700f47216646d4cb37ae5696000000000267530300000000001976a91475c715ecb74178fe87933e57e947e5e92d904b8188acd0070000000000001976a91475c715ecb74178fe87933e57e947e5e92d904b8188ac00000000",
|
|
value: "",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
export const p2pkhTemplateIdentifier =
|
|
generateTemplateIdentifier(p2pkhTemplate);
|