267 lines
6.1 KiB
TypeScript
267 lines
6.1 KiB
TypeScript
import type { XOTemplate } from '@xo-cash/types';
|
|
|
|
export const wrapBCHTemplate: XOTemplate = {
|
|
$schema: 'https://libauth.org/schemas/wallet-template-v0.schema.json',
|
|
|
|
name: 'Wrapped BCH',
|
|
description: 'Convert between BCH and wBCH tokens.',
|
|
icon: 'wrap',
|
|
|
|
version: '1',
|
|
supported: ['BCH_2023_05', 'BCH_2024_05', 'BCH_2025_05', 'BCH_2026_05'],
|
|
|
|
roles: {
|
|
user: {
|
|
name: 'User',
|
|
description: 'The person wrapping or unwrapping BCH.',
|
|
icon: 'user',
|
|
},
|
|
},
|
|
|
|
start: [
|
|
{
|
|
action: 'wrap',
|
|
role: 'user',
|
|
},
|
|
{
|
|
action: 'unwrap',
|
|
role: 'user',
|
|
},
|
|
],
|
|
|
|
actions: {
|
|
wrap: {
|
|
name: 'Wrap BCH',
|
|
description: 'Convert BCH into wBCH tokens.',
|
|
icon: 'wrap',
|
|
|
|
roles: {
|
|
user: {
|
|
requirements: {
|
|
variables: ['amountToWrap', 'recipientLockingScript'],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
participants: [{ role: 'user', slots: { min: 1, max: 1 } }],
|
|
},
|
|
|
|
transaction: 'wrapTransaction',
|
|
},
|
|
|
|
unwrap: {
|
|
name: 'Unwrap wBCH',
|
|
description: 'Convert wBCH tokens back into BCH.',
|
|
icon: 'unwrap',
|
|
|
|
roles: {
|
|
user: {
|
|
requirements: {
|
|
variables: ['amountToUnwrap', 'recipientLockingScript'],
|
|
},
|
|
},
|
|
},
|
|
|
|
requirements: {
|
|
participants: [{ role: 'user', slots: { min: 1, max: 1 } }],
|
|
},
|
|
|
|
transaction: 'unwrapTransaction',
|
|
},
|
|
},
|
|
|
|
transactions: {
|
|
wrapTransaction: {
|
|
name: 'Wrapped BCH',
|
|
description: 'Wrapped $(<amountToWrap> <satoshisPerBCH> OP_DIV).$(<amountToWrap> <satoshisPerBCH> OP_MOD) BCH into wBCH tokens.',
|
|
icon: 'wrap',
|
|
|
|
inputs: [
|
|
{ input: 'covenantInput', inputIndex: 0 },
|
|
],
|
|
outputs: [
|
|
{ output: 'covenantOutput', outputIndex: 0 },
|
|
{ output: 'wrappedTokensOutput', outputIndex: undefined },
|
|
],
|
|
|
|
version: 2,
|
|
locktime: 0,
|
|
composable: true,
|
|
},
|
|
|
|
unwrapTransaction: {
|
|
name: 'Unwrapped wBCH',
|
|
description: 'Unwrapped $(<amountToUnwrap> <satoshisPerBCH> OP_DIV).$(<amountToUnwrap> <satoshisPerBCH> OP_MOD) wBCH tokens back into BCH.',
|
|
icon: 'unwrap',
|
|
|
|
inputs: [
|
|
{ input: 'covenantInput', inputIndex: 0 },
|
|
],
|
|
outputs: [
|
|
{ output: 'covenantOutput', outputIndex: 0 },
|
|
{ output: 'unwrappedSatoshisOutput', outputIndex: undefined },
|
|
],
|
|
|
|
version: 2,
|
|
locktime: 0,
|
|
composable: true,
|
|
},
|
|
},
|
|
|
|
outputs: {
|
|
covenantOutput: {
|
|
name: 'wBCH Covenant',
|
|
description: 'Holds BCH and wBCH tokens that can be freely converted.',
|
|
icon: 'contract',
|
|
|
|
lockingScript: 'wrapBCHLockingScript',
|
|
},
|
|
|
|
wrappedTokensOutput: {
|
|
name: 'Wrapped wBCH',
|
|
description: 'Wrapped $(<amountToWrap> <satoshisPerBCH> OP_DIV).$(<amountToWrap> <satoshisPerBCH> OP_MOD) wBCH tokens.',
|
|
icon: 'receive',
|
|
|
|
valueSatoshis: '$(<amountToWrap>)',
|
|
token: {
|
|
category: '$(<wbchTokenCategory>)',
|
|
amount: '$(<amountToWrap>)',
|
|
nft: null,
|
|
},
|
|
|
|
roles: {
|
|
user: {
|
|
balance: {
|
|
satoshis: true,
|
|
fungibleTokens: true,
|
|
nonfungibleTokens: true,
|
|
},
|
|
selectable: true,
|
|
},
|
|
},
|
|
|
|
lockingScript: '$(<recipientLockingScript>)',
|
|
},
|
|
|
|
unwrappedSatoshisOutput: {
|
|
name: 'Unwrapped BCH',
|
|
description: 'Unwrapped $(<amountToUnwrap> <satoshisPerBCH> OP_DIV).$(<amountToUnwrap> <satoshisPerBCH> OP_MOD) BCH.',
|
|
icon: 'receive',
|
|
|
|
valueSatoshis: '$(<amountToUnwrap>)',
|
|
token: null,
|
|
|
|
roles: {
|
|
user: {
|
|
balance: {
|
|
satoshis: true,
|
|
fungibleTokens: true,
|
|
nonfungibleTokens: true,
|
|
},
|
|
selectable: true,
|
|
},
|
|
},
|
|
|
|
lockingScript: '$(<recipientLockingScript>)',
|
|
},
|
|
},
|
|
|
|
inputs: {
|
|
covenantInput: {
|
|
name: 'wBCH Covenant',
|
|
description: 'The covenant being updated.',
|
|
icon: 'contract',
|
|
|
|
unlockingScript: 'unlockCovenant',
|
|
},
|
|
},
|
|
|
|
lockingScripts: {
|
|
wrapBCHLockingScript: {
|
|
name: 'wBCH Covenant',
|
|
description: 'Holds BCH and wBCH tokens that can be freely converted.',
|
|
icon: 'contract',
|
|
|
|
lockingType: 'p2sh',
|
|
lockingBytecode: 'wrapBCHLockingBytecode',
|
|
|
|
actions: [
|
|
{ action: 'wrap', role: 'user' },
|
|
{ action: 'unwrap', role: 'user' },
|
|
],
|
|
|
|
state: {
|
|
variables: [],
|
|
secrets: [],
|
|
},
|
|
balance: {
|
|
satoshis: 0n,
|
|
fungibleTokens: 0n,
|
|
},
|
|
selectable: false,
|
|
},
|
|
},
|
|
|
|
scripts: {
|
|
enforceCovenantPersists: 'OP_INPUTINDEX OP_DUP OP_OUTPUTBYTECODE OP_SWAP OP_UTXOBYTECODE OP_EQUAL OP_VERIFY',
|
|
enforceTokenCategoryPreserved: 'OP_INPUTINDEX OP_DUP OP_OUTPUTTOKENCATEGORY OP_SWAP OP_UTXOTOKENCATEGORY OP_EQUAL OP_VERIFY',
|
|
enforceValueTokenSumConserved: 'OP_INPUTINDEX OP_UTXOVALUE OP_INPUTINDEX OP_UTXOTOKENAMOUNT OP_ADD OP_INPUTINDEX OP_OUTPUTVALUE OP_INPUTINDEX OP_OUTPUTTOKENAMOUNT OP_ADD OP_EQUAL OP_VERIFY',
|
|
|
|
// Direct script references — introspection opcodes must not use $(...) evaluations
|
|
// because those are evaluated at compile time without transaction context.
|
|
wrapBCHLockingBytecode: 'enforceCovenantPersists enforceTokenCategoryPreserved enforceValueTokenSumConserved',
|
|
unlockCovenant: '',
|
|
},
|
|
|
|
constants: {
|
|
wbchTokenCategory: {
|
|
name: 'wBCH Token Category',
|
|
description: 'The official token category for Wrapped BCH.',
|
|
type: 'bytes',
|
|
value: 'ff4d6e4b90aa8158d39c5dc874fd9411af1ac3b5ed6f354755e8362a0d02c6b3',
|
|
},
|
|
satoshisPerBCH: {
|
|
name: 'Satoshis per BCH',
|
|
description: 'Used to display amounts in BCH with decimals.',
|
|
type: 'integer',
|
|
value: 100000000,
|
|
},
|
|
tokenDust: {
|
|
name: 'Token Dust Limit',
|
|
description: 'Minimal satoshis required for a token-bearing output.',
|
|
type: 'integer',
|
|
value: 1000,
|
|
},
|
|
},
|
|
|
|
variables: {
|
|
amountToWrap: {
|
|
name: 'Amount to Wrap',
|
|
description: 'How much BCH to convert to wBCH (in satoshis).',
|
|
type: 'integer',
|
|
hint: 'satoshis',
|
|
},
|
|
amountToUnwrap: {
|
|
name: 'Amount to Unwrap',
|
|
description: 'How much wBCH to convert back to BCH (in satoshis).',
|
|
type: 'integer',
|
|
hint: 'satoshis',
|
|
},
|
|
recipientLockingScript: {
|
|
name: 'Destination',
|
|
description: 'Where to receive your BCH or wBCH tokens.',
|
|
type: 'bytes',
|
|
hint: 'lockingScript',
|
|
},
|
|
},
|
|
|
|
icons: [
|
|
{ name: 'wrap', hash: '0000000000000000000000' },
|
|
{ name: 'unwrap', hash: '0000000000000000000000' },
|
|
{ name: 'user', hash: '0000000000000000000000' },
|
|
{ name: 'contract', hash: '0000000000000000000000' },
|
|
{ name: 'receive', hash: '0000000000000000000000' },
|
|
],
|
|
};
|