Skip to content

Commit ea9014d

Browse files
committed
feat(sdk-coin-stx): modified explain transaction to accomodate token transfer transactions
Ticket: COIN-3291
1 parent a73603e commit ea9014d

File tree

5 files changed

+109
-21
lines changed

5 files changed

+109
-21
lines changed

modules/sdk-coin-stx/src/lib/transaction.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import {
22
addressToString,
33
BufferReader,
4+
ContractCallPayload,
45
createStacksPrivateKey,
56
createStacksPublicKey,
67
createTransactionAuthField,
8+
cvToString,
9+
cvToValue,
710
deserializeTransaction,
811
isSingleSig,
912
MultiSigSpendingCondition,
@@ -13,7 +16,9 @@ import {
1316
StacksTransaction,
1417
TransactionSigner,
1518
} from '@stacks/transactions';
19+
1620
import { BaseCoin as CoinConfig, StacksNetwork } from '@bitgo/statics';
21+
1722
import {
1823
BaseKey,
1924
BaseTransaction,
@@ -23,11 +28,13 @@ import {
2328
SigningError,
2429
TransactionType,
2530
} from '@bitgo/sdk-core';
31+
32+
import BigNum from 'bn.js';
33+
2634
import { SignatureData, StacksContractPayload, StacksTransactionPayload, TxData } from './iface';
2735
import { functionArgsToSendParams, getTxSenderAddress, removeHexPrefix, stringifyCv, unpadMemo } from './utils';
2836
import { KeyPair } from './keyPair';
29-
import { ContractCallPayload } from '@stacks/transactions/dist/payload';
30-
import BigNum from 'bn.js';
37+
import { FUNCTION_NAME_TRANSFER } from './constants';
3138

3239
export class Transaction extends BaseTransaction {
3340
private _stxTransaction: StacksTransaction;
@@ -237,6 +244,21 @@ export class Transaction extends BaseTransaction {
237244
const sum: BigNum = sendParams.reduce((current, next) => current.add(new BigNum(next.amount)), new BigNum(0));
238245
this._outputs = sendParams.map((sendParam) => ({ address: sendParam.address, value: sendParam.amount, coin }));
239246
this._inputs = [{ address: txJson.from, value: sum.toString(), coin }];
247+
} else if (txJson.payload.functionName === FUNCTION_NAME_TRANSFER && txJson.payload.functionArgs.length >= 3) {
248+
this._outputs = [
249+
{
250+
address: cvToString(txJson.payload.functionArgs[1]),
251+
value: cvToValue(txJson.payload.functionArgs[2]).toString(),
252+
coin: this._coinConfig.name,
253+
},
254+
];
255+
this._inputs = [
256+
{
257+
address: cvToString(txJson.payload.functionArgs[0]),
258+
value: cvToValue(txJson.payload.functionArgs[2]).toString(),
259+
coin: this._coinConfig.name,
260+
},
261+
];
240262
} else {
241263
this._outputs = [
242264
{

modules/sdk-coin-stx/src/stx.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
VerifyTransactionOptions,
1010
} from '@bitgo/sdk-core';
1111
import { BaseCoin as StaticsBaseCoin, CoinFamily, coins } from '@bitgo/statics';
12+
import { cvToString, cvToValue } from '@stacks/transactions';
1213
import { ExplainTransactionOptions, StxSignTransactionOptions, StxTransactionExplanation } from './types';
1314
import { StxLib } from '.';
1415

@@ -182,24 +183,41 @@ export class Stx extends BaseCoin {
182183
const txJson = tx.toJson();
183184

184185
if (tx.type === TransactionType.Send) {
185-
const outputs: TransactionRecipient[] = [
186-
{
186+
// check if it is a token transaction or native coin transaction
187+
let transactionRecipient: TransactionRecipient;
188+
let outputAmount: string;
189+
let memo: string | undefined;
190+
if (txJson.payload.contractAddress && txJson.payload.functionArgs.length >= 3) {
191+
outputAmount = cvToValue(txJson.payload.functionArgs[2]).toString();
192+
transactionRecipient = {
193+
address: cvToString(txJson.payload.functionArgs[1]),
194+
amount: outputAmount,
195+
};
196+
if (txJson.payload.functionArgs.length === 4) {
197+
memo = txJson.payload.functionArgs[3].buffer.toString('ascii');
198+
transactionRecipient['memo'] = memo;
199+
}
200+
} else {
201+
outputAmount = txJson.payload.amount;
202+
memo = txJson.payload.memo;
203+
transactionRecipient = {
187204
address: txJson.payload.to,
188-
amount: txJson.payload.amount,
189-
memo: txJson.payload.memo,
190-
},
191-
];
205+
amount: outputAmount,
206+
memo: memo,
207+
};
208+
}
209+
const outputs: TransactionRecipient[] = [transactionRecipient];
192210

193211
const displayOrder = ['id', 'outputAmount', 'changeAmount', 'outputs', 'changeOutputs', 'fee', 'memo', 'type'];
194212
return {
195213
displayOrder,
196214
id: txJson.id,
197-
outputAmount: txJson.payload.amount.toString(),
215+
outputAmount: outputAmount.toString(),
198216
changeAmount: '0',
199217
outputs,
200218
changeOutputs: [],
201219
fee: txJson.fee,
202-
memo: txJson.payload.memo,
220+
memo: memo,
203221
type: tx.type,
204222
};
205223
}

modules/sdk-coin-stx/test/fixtures.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,34 @@ export const unsignedTxExplainedTransfer = {
3030
recipient: 'STDE7Y8HV3RX8VBM2TZVWJTS7ZA1XB0SSC3NEVH0',
3131
sender: 'STB44HYPYAT2BB2QE513NSP81HTMYWBJP02HPGK6',
3232
};
33+
34+
export const txForExplainFungibleTokenTransfer =
35+
'808000000004012fe507c09dbb23c3b7e5d166c81fc4b87692510b000000000000000000000000000000b4000000030200ffa41419c088011baffa87d0113257dbf2033e19ffd5098e9c3e1d8bc606f5e97519688630d57154fcad34967ea04246fe5127203c9971e0b1426cdbd6c132d502004fed6b5699e3211629ad182bf53392374a72e692eb4afe770ffa1fd715661c5706ec16854d14028c49d54806b34b89f108f76d39f2a7675589a94a179bba0ed100038e3c4529395611be9abf6fa3b6987e81d402385e3d605a073f42f407565a4a3d0002030200000000021a1500a1c42f0c11bfe3893f479af18904677685be0d747369703664702d746f6b656e087472616e7366657200000004051a1500a1c42f0c11bfe3893f479af18904677685be0515ab50cac953ac55edc14e2b236854b1ead863fece0100000000000000000000000000002710020000000131';
36+
37+
export const fungibleTokenTransferTx = {
38+
id: 'f2ea2261c3d66b87ffe67dedbf36e8ab00762bd6fa8d8fafdf6299c56deb1ebf',
39+
fee: '180',
40+
contractAddress: 'STAG18E45W613FZ3H4ZMF6QHH426EXM5QTSAVWYH',
41+
contractName: 'tsip6dp-token',
42+
functionName: 'transfer',
43+
functionArgs: [
44+
{
45+
type: 5,
46+
address: {
47+
type: 0,
48+
version: 26,
49+
hash160: '1500a1c42f0c11bfe3893f479af18904677685be',
50+
},
51+
},
52+
{
53+
type: 5,
54+
address: {
55+
type: 0,
56+
version: 21,
57+
hash160: 'ab50cac953ac55edc14e2b236854b1ead863fece',
58+
},
59+
},
60+
{ type: 1, value: '10000' },
61+
{ type: 2 },
62+
],
63+
};

modules/sdk-coin-stx/test/unit/stx.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1-
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
1+
import assert from 'assert';
2+
23
import { BitGoAPI } from '@bitgo/sdk-api';
4+
import { Wallet } from '@bitgo/sdk-core';
5+
import { TestBitGo, TestBitGoAPI } from '@bitgo/sdk-test';
36
import { coins } from '@bitgo/statics';
7+
import { cvToString } from '@stacks/transactions';
8+
49
import * as testData from '../fixtures';
510
import { Stx, Tstx, StxLib } from '../../src';
6-
import assert from 'assert';
7-
import { Wallet } from '@bitgo/sdk-core';
811

912
const { KeyPair } = StxLib;
1013

@@ -190,6 +193,20 @@ describe('STX:', function () {
190193
explain.contractFunctionArgs[0].value.toString().should.equal(testData.txExplainedContract.functionArgs[0].value);
191194
});
192195

196+
it('should explain a fungible token transfer transaction', async function () {
197+
const explain = await basecoin.explainTransaction({
198+
txHex: testData.txForExplainFungibleTokenTransfer,
199+
feeInfo: { fee: '' },
200+
});
201+
explain.id.should.equal(testData.fungibleTokenTransferTx.id);
202+
explain.fee.should.equal(testData.fungibleTokenTransferTx.fee);
203+
explain.memo.should.equal('1');
204+
explain.outputAmount.should.equal(testData.fungibleTokenTransferTx.functionArgs[2].value);
205+
explain.outputs[0].amount.should.equal(testData.fungibleTokenTransferTx.functionArgs[2].value);
206+
explain.outputs[0].address.should.equal(cvToString(testData.fungibleTokenTransferTx.functionArgs[1]));
207+
explain.outputs[0].memo.should.equal('1');
208+
});
209+
193210
describe('Keypairs:', () => {
194211
it('should generate a keypair from random seed', function () {
195212
const keyPair = basecoin.generateKeyPair();

modules/sdk-coin-stx/test/unit/transactionBuilder/fungibleTokenTransferBuilder.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ describe('Stacks: Fungible Token Transfer Builder', () => {
7474

7575
tx.type.should.equal(TransactionType.Send);
7676
tx.outputs.length.should.equal(1);
77-
tx.outputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.CONTRACT_ADDRESS);
78-
tx.outputs[0].value.should.equal('0');
77+
tx.outputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.RECEIVER_ADDRESS);
78+
tx.outputs[0].value.should.equal('10000');
7979
tx.inputs.length.should.equal(1);
80-
tx.inputs[0].address.should.equal(testData.TX_SENDER.address);
81-
tx.inputs[0].value.should.equal('0');
80+
tx.inputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.SENDER_ADDRESS);
81+
tx.inputs[0].value.should.equal('10000');
8282
});
8383

8484
it('an unsigned fungible token transfer transaction without memo', async () => {
@@ -105,11 +105,11 @@ describe('Stacks: Fungible Token Transfer Builder', () => {
105105

106106
tx.type.should.equal(TransactionType.Send);
107107
tx.outputs.length.should.equal(1);
108-
tx.outputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.CONTRACT_ADDRESS);
109-
tx.outputs[0].value.should.equal('0');
108+
tx.outputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.RECEIVER_ADDRESS);
109+
tx.outputs[0].value.should.equal('10000');
110110
tx.inputs.length.should.equal(1);
111-
tx.inputs[0].address.should.equal(testData.TX_SENDER.address);
112-
tx.inputs[0].value.should.equal('0');
111+
tx.inputs[0].address.should.equal(testData.FUNGIBLE_TOKEN_TRANSFER_CONSTANTS.SENDER_ADDRESS);
112+
tx.inputs[0].value.should.equal('10000');
113113
});
114114

115115
it('a multisig fungible token transfer transaction', async () => {

0 commit comments

Comments
 (0)