Skip to content

Commit

Permalink
feat(sdk-coin-stx): add support to nakamoto updgrade stack-stx tx
Browse files Browse the repository at this point in the history
  • Loading branch information
rliberal-simtlix committed Apr 10, 2024
1 parent c8d69d0 commit f9cab3a
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 18 deletions.
6 changes: 5 additions & 1 deletion modules/sdk-coin-stx/src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
export const FUNCTION_NAME_SENDMANY = 'send-many';
export const CONTRACT_NAME_SENDMANY = 'send-many-memo';
export const CONTRACT_NAME_STAKING = 'pox-3';
export const CONTRACT_NAME_STAKING = 'pox-4';

// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
export const BACKWARD_COMPATIBILITY_CONTRACT_NAME_STAKING = 'pox-3';

export const VALID_CONTRACT_FUNCTION_NAMES = [
'stack-stx',
Expand Down
16 changes: 13 additions & 3 deletions modules/sdk-coin-stx/src/lib/contractBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ import { Transaction } from './transaction';
import { isValidAddress } from './utils';
import { ClarityValueJson } from './iface';
import { Utils } from '.';
import { CONTRACT_NAME_SENDMANY, CONTRACT_NAME_STAKING } from './constants';
import {
BACKWARD_COMPATIBILITY_CONTRACT_NAME_STAKING,
CONTRACT_NAME_SENDMANY,
CONTRACT_NAME_STAKING,
} from './constants';
import { AbstractContractBuilder } from './abstractContractBuilder';

export class ContractBuilder extends AbstractContractBuilder {
Expand Down Expand Up @@ -60,8 +64,14 @@ export class ContractBuilder extends AbstractContractBuilder {
if (name.length === 0) {
throw new InvalidParameterValueError('Invalid name');
}
if (name !== CONTRACT_NAME_STAKING && name !== CONTRACT_NAME_SENDMANY) {
throw new InvalidParameterValueError('Only pox-3 and send-many-memo contracts supported');
if (
// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
name !== BACKWARD_COMPATIBILITY_CONTRACT_NAME_STAKING &&
name !== CONTRACT_NAME_STAKING &&
name !== CONTRACT_NAME_SENDMANY
) {
throw new InvalidParameterValueError('Only pox-3, pox-4 and send-many-memo contracts supported');
}
this._contractName = name;
return this;
Expand Down
6 changes: 3 additions & 3 deletions modules/sdk-coin-stx/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ export const txExplainedTransfer = {
};

export const txForExplainContract =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000037980c4fe5607724d9d6cbd320d38cea5931cc940ac23b6e36316cf5f077a0ec260e7c5d3916d0e375d4c68e94e4779ad8b7226c34c71fd453b818066a5a30ac030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c090a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40000dba4d775d6894746f0b8ff3cbc1b0f2696890d0669ffbb8eb8df51098741115e28af448a59583e3d34e344c34879c5c7a82d223833c1214d13cd9813165d8e1e030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c090a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';

export const txExplainedContract = {
id: '686864ede927cc05a16a842951d96e6e4a201432f33ab01d58e952ef0e958832',
id: '14e44db3f77b527d7a9a0fb2d09c079a7a50c03e06e6a4508a4be417346d810d',
fee: '180',
contractAddress: 'ST000000000000000000002AMW42H',
contractName: 'pox-3',
contractName: 'pox-4',
functionName: 'stack-stx',
functionArgs: [{ type: 1, value: '400000000' }],
};
Expand Down
19 changes: 12 additions & 7 deletions modules/sdk-coin-stx/test/unit/resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,20 +125,25 @@ export const MULTI_SIG_SIGNED_TRANSACTION =

// contract call
export const CONTRACT_ADDRESS = 'ST000000000000000000002AMW42H';
export const CONTRACT_NAME = 'pox-3';
export const CONTRACT_NAME = 'pox-4';
export const CONTRACT_FUNCTION_NAME = 'stack-stx';
export const UNSIGNED_SELF_STACK_CONTRACT_CALL =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000040100000000000000000000000017d784000c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101010000000000000000000000000000ce400100000000000000000000000000000002';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000080100000000000000000000000017d784000c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101010000000000000000000000000000ce4001000000000000000000000000000000020a0200000009736f6d652d686173680200000009736f6d652d6861736801ffffffffffffffffffffffffffffffff010000000000000000000000000001e240';
export const SIGNED_SELF_STACK_CONTRACT_CALL =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40001710f7ede3c8a199c5303fe42f3b2e984db28b60fd288257773287f595c8142ba43a2dc3c60cf332c9f123ceffd24a26e0fe8d08a1fd36bc3cba118a4c436f397030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000040100000000000000000000000017d784000c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101010000000000000000000000000000ce400100000000000000000000000000000002';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40001833db79cd9c39c7262b808b6ea80a001a9bd290648cf3a19da95f10d1814d69437a00075e8325ef564ed9d6690c575583bcbb29c4e33c8ce80c34e7efd1f5457030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000080100000000000000000000000017d784000c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101010000000000000000000000000000ce4001000000000000000000000000000000020a0200000009736f6d652d686173680200000009736f6d652d6861736801ffffffffffffffffffffffffffffffff010000000000000000000000000001e240';

// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
export const POX_3_SIGNED_SELF_STACK_CONTRACT_CALL =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b400002a0f4802bba8d6c1e6311b55a47500046e59be18dc9dc0166fb358d05a20f0cd20f970859601f9f7a558483cc2cf22abd7dab2f5bc05df60093e7ad04a04c6d8030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000040100000000000000000000000017d784000c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101010000000000000000000000000000ce400100000000000000000000000000000002';
export const UNSIGNED_CONTRACT_CALL =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c0a01000000000000000000000000000000c80a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c0a01000000000000000000000000000000c80a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';
export const SIGNED_CONTRACT_WITH_ARGS =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b4000037980c4fe5607724d9d6cbd320d38cea5931cc940ac23b6e36316cf5f077a0ec260e7c5d3916d0e375d4c68e94e4779ad8b7226c34c71fd453b818066a5a30ac030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c090a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40000dba4d775d6894746f0b8ff3cbc1b0f2696890d0669ffbb8eb8df51098741115e28af448a59583e3d34e344c34879c5c7a82d223833c1214d13cd9813165d8e1e030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000040100000000000000000000000017d7840005163248e7aa6879968d241f3e5152d9f2796994d96c090a0c00000002096861736862797465730200000009736f6d652d686173680776657273696f6e020000000101';
export const SIGNED_CONTRACT_CALL =
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40001d140984651d7b3339c85df78cc59c176237579421112da4eb45ce75803d87176155d48c63afd595a3469b0b2b2a9f81e4806d7ce9b9acdc59d4af23356d37b84030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000010a000000000000000000000000000000007b';
'80800000000400164247d6f2b425ac5771423ae6c80c754f7172b0000000000000000000000000000000b40001b693bdf014c1ac78e307fed49bc1df8fed2a5e42d4b79993f5df626d7b1b2516741495198a3dbf079deebc46ecdd535fe66f518c0a695c533f1667455a05036a030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000010a000000000000000000000000000000007b';
export const MULTI_SIG_CONTRACT_CALL =
'808000000004012fe507c09dbb23c3b7e5d166c81fc4b87692510b000000000000000000000000000000b400000003020037aed42ad2597983a6803c8122d9bca4c6f3566fc078fe2bbfdcf0d5f7eae68121e575eb94704c0c6cb40a5b1e7a8458bba45ffd1a54408c8efa4bcf0c0a818f02011478d5f323ea1da203fc2661aeb363f66e5b19e4e9d1ed80de99054372d573cd0942fad4e9f5cfba3e8086bb75f5def6c2220afb1feae11f249f334304831f7b00038e3c4529395611be9abf6fa3b6987e81d402385e3d605a073f42f407565a4a3d0002030200000000021a000000000000000000000000000000000000000005706f782d3309737461636b2d737478000000010a000000000000000000000000000000007b';
'808000000004012fe507c09dbb23c3b7e5d166c81fc4b87692510b000000000000000000000000000000b400000003020169a032112373b481c48ecb12b8847519f89720d4297a7bf5cac43b9daa8d4ad23dd53657089dad55c94e8be5762e97052683f49e1f457b2e9252f27e975603230200128d0ba2b9584339359ff42c1d6f35ce79a7073152b3c90879bc5162eb8df73b02eada3ee322873a5fa736479e6c536109681482d9f22f1e1a89608090b8666800038e3c4529395611be9abf6fa3b6987e81d402385e3d605a073f42f407565a4a3d0002030200000000021a000000000000000000000000000000000000000005706f782d3409737461636b2d737478000000010a000000000000000000000000000000007b';

// contract call with memo nonce 45n,
export const SEND_MANY_CONTRACT_ADDRESS_WITH_MEMO = 'ST3F1X4QGV2SM8XD96X45M6RTQXKA1PZJZZCQAB4B';
Expand Down
100 changes: 98 additions & 2 deletions modules/sdk-coin-stx/test/unit/transactionBuilder/contractBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ describe('Stacks: Contract Builder', function () {

it('an unsigned self stacking contract call transaction', async () => {
const builder = initTxBuilder();
/* Contract call in clarity POX-4
(define-public (stack-stx (amount-ustx uint)
(pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
(start-burn-ht uint)
(lock-period uint)
(signer-sig (optional (buff 65)))
(signer-key (buff 33))
(max-amount uint)
(auth-id uint))
*/
builder.functionArgs([
{ type: 'uint128', val: '400000000' },
{
Expand All @@ -106,6 +116,12 @@ describe('Stacks: Contract Builder', function () {
},
{ type: 'uint128', val: '52800' },
{ type: 'uint128', val: '2' },
// Nakamoto upgrade new 4 parameters
// https://docs.stacks.co/nakamoto-upgrade/signing-and-stacking/stacking-flow#solo-stacker-flow
{ type: 'optional', val: { type: 'buffer', val: Buffer.from('some-hash') } },
{ type: 'buffer', val: Buffer.from('some-hash') },
{ type: 'uint128', val: '340282366920938463463374607431768211455' },
{ type: 'uint128', val: '123456' },
]);
builder.fromPubKey(testData.TX_SENDER.pub);
builder.numberSignatures(1);
Expand Down Expand Up @@ -167,6 +183,16 @@ describe('Stacks: Contract Builder', function () {

it('a signed self stacking contract call', async () => {
const builder = initTxBuilder();
/* Contract call in clarity POX-4
(define-public (stack-stx (amount-ustx uint)
(pox-addr (tuple (version (buff 1)) (hashbytes (buff 32))))
(start-burn-ht uint)
(lock-period uint)
(signer-sig (optional (buff 65)))
(signer-key (buff 33))
(max-amount uint)
(auth-id uint))
*/
builder.functionArgs([
{ type: 'uint128', val: '400000000' },
{
Expand All @@ -178,6 +204,12 @@ describe('Stacks: Contract Builder', function () {
},
{ type: 'uint128', val: '52800' },
{ type: 'uint128', val: '2' },
// Nakamoto upgrade new 4 parameters
// https://docs.stacks.co/nakamoto-upgrade/signing-and-stacking/stacking-flow#solo-stacker-flow
{ type: 'optional', val: { type: 'buffer', val: Buffer.from('some-hash') } },
{ type: 'buffer', val: Buffer.from('some-hash') },
{ type: 'uint128', val: '340282366920938463463374607431768211455' },
{ type: 'uint128', val: '123456' },
]);
builder.sign({ key: testData.TX_SENDER.prv });
const tx = await builder.build();
Expand All @@ -199,6 +231,42 @@ describe('Stacks: Contract Builder', function () {
tx.inputs[0].value.should.equal('0');
});

// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
it('a signed pox-3 backward support pre-fork self stacking contract call', async () => {
const builder = initTxBuilder();
builder.functionArgs([
{ type: 'uint128', val: '400000000' },
{
type: 'tuple',
val: [
{ key: 'hashbytes', type: 'buffer', val: Buffer.from('some-hash') },
{ key: 'version', type: 'buffer', val: new BigNum(1).toBuffer() },
],
},
{ type: 'uint128', val: '52800' },
{ type: 'uint128', val: '2' },
]);
builder.sign({ key: testData.TX_SENDER.prv });
const tx = await builder.build();

const txJson = tx.toJson();
should.deepEqual(txJson.payload.contractAddress, testData.CONTRACT_ADDRESS);
should.deepEqual(txJson.payload.contractName, testData.CONTRACT_NAME);
should.deepEqual(txJson.payload.functionName, testData.CONTRACT_FUNCTION_NAME);
should.deepEqual(txJson.nonce, 0);
should.deepEqual(txJson.fee.toString(), '180');
should.deepEqual(tx.toBroadcastFormat(), testData.POX_3_SIGNED_SELF_STACK_CONTRACT_CALL);

tx.type.should.equal(TransactionType.ContractCall);
tx.outputs.length.should.equal(1);
tx.outputs[0].address.should.equal(testData.CONTRACT_ADDRESS);
tx.outputs[0].value.should.equal('0');
tx.inputs.length.should.equal(1);
tx.inputs[0].address.should.equal(testData.TX_SENDER.address);
tx.inputs[0].value.should.equal('0');
});

it('a signed contract call transaction', async () => {
const amount = 123;
const builder = initTxBuilder();
Expand Down Expand Up @@ -246,7 +314,9 @@ describe('Stacks: Contract Builder', function () {
should.deepEqual(txJson.payload.functionName, testData.CONTRACT_FUNCTION_NAME);
should.deepEqual(txJson.nonce, 0);
should.deepEqual(txJson.fee.toString(), '180');
should.deepEqual(txJson.payload.functionArgs.length, 4);
// Now stacks-stx self-stacking supports 8 parameters
// https://docs.stacks.co/nakamoto-upgrade/signing-and-stacking/stacking-flow#solo-stacker-flow
should.deepEqual(txJson.payload.functionArgs.length, 8);
should.deepEqual(tx.toBroadcastFormat(), testData.SIGNED_SELF_STACK_CONTRACT_CALL);
tx.type.should.equal(TransactionType.ContractCall);
tx.outputs.length.should.equal(1);
Expand All @@ -257,6 +327,29 @@ describe('Stacks: Contract Builder', function () {
tx.inputs[0].value.should.equal('0');
});

// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
it('a signed serialized pox-3 backward support pre-fork self stacking contract call transaction', async () => {
const builder = factory.from(testData.POX_3_SIGNED_SELF_STACK_CONTRACT_CALL);
const tx = await builder.build();
const txJson = tx.toJson();
should.deepEqual(txJson.payload.contractAddress, testData.CONTRACT_ADDRESS);
should.deepEqual(txJson.payload.contractName, testData.CONTRACT_NAME);
should.deepEqual(txJson.payload.functionName, testData.CONTRACT_FUNCTION_NAME);
should.deepEqual(txJson.nonce, 0);
should.deepEqual(txJson.fee.toString(), '180');
// POX-3 stacks-stx self-stacking supports 4 parameters
should.deepEqual(txJson.payload.functionArgs.length, 4);
should.deepEqual(tx.toBroadcastFormat(), testData.POX_3_SIGNED_SELF_STACK_CONTRACT_CALL);
tx.type.should.equal(TransactionType.ContractCall);
tx.outputs.length.should.equal(1);
tx.outputs[0].address.should.equal(testData.CONTRACT_ADDRESS);
tx.outputs[0].value.should.equal('0');
tx.inputs.length.should.equal(1);
tx.inputs[0].address.should.equal(testData.TX_SENDER.address);
tx.inputs[0].value.should.equal('0');
});

it('a multisig transfer transaction', async () => {
const builder = initTxBuilder();
builder.functionArgs([{ type: 'optional', val: { type: 'int128', val: '123' } }]);
Expand Down Expand Up @@ -374,7 +467,10 @@ describe('Stacks: Contract Builder', function () {
});
it('a contract call with an invalid contract name', () => {
const builder = initTxBuilder();
assert.throws(() => builder.contractName('pox-2'), /Only pox-3 and send-many-memo contracts supported/);
assert.throws(
() => builder.contractName('pox-2'),
/Only pox-3, pox-4 and send-many-memo contracts supported/
);
});
it('a contract call with an invalid contract function name', () => {
const builder = initTxBuilder();
Expand Down
28 changes: 26 additions & 2 deletions modules/sdk-core/src/bitgo/staking/iStakingWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,13 @@ export interface DelegationRequest {
* @property {string} [duration] - delegation duration: a numeric string, in days or cycles
* @property {string} [subType] - coin sepcific staking subtype
* @property {string} [btcRewardAddress] - btc reward address
* @property {string} [signerPub] - stx signer public key
* @property {string} [signerSignature] - stx signer signature
* @property {DelegationRequest[]} [delegationRequests] - The delegation requests
* TODO: remove support to this contract version after STX fork
* https://bitgoinc.atlassian.net/browse/EA-3482
* @property {string} [contractName] - stx contract name: valid names are pox-3 and pox-4 only, used only for backward compatibility during nakamoto fork
*/
export interface StakeOptions {
amount?: string;
Expand All @@ -51,14 +57,32 @@ export interface StakeOptions {
*/
blsSignature?: string;
/**
* coin sepcific staking subtype
* coin specific staking subtype
*/
subType?: string;
/**
* btc reward address
* stx btc reward address
*/
btcRewardAddress?: string;

/**
* stx signer pub
*/
signerPub?: string;

/**
* stx signer signature
*/
signerSignature?: string;

delegationRequests?: DelegationRequest[];

// TODO: remove support to this contract version after STX fork
// https://bitgoinc.atlassian.net/browse/EA-3482
/**
* pox-contract name (valid values are pox-3 and pox-4)
*/
contractName?: 'pox-3' | 'pox-4';
}

export interface UnstakeOptions {
Expand Down

0 comments on commit f9cab3a

Please sign in to comment.