Skip to content

Commit 3249a6f

Browse files
authored
Merge pull request #6562 from BitGo/COIN-4916-sdk-add-ylds-token-support
test: add token transfer tests for hash
2 parents 164ddf6 + 7c614fb commit 3249a6f

File tree

5 files changed

+372
-2
lines changed

5 files changed

+372
-2
lines changed

modules/sdk-coin-hash/src/lib/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const validDenoms = ['nhash', 'uhash', 'mhash', 'hash'];
1+
export const validDenoms = ['nhash', 'uhash', 'mhash', 'hash', 'uylds.fcc'];
22
export const mainnetAccountAddressRegex = /^(pb)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
33
export const mainnetValidatorAddressRegex = /^(pbvaloper)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38})$/;
44
export const mainnetContractAddressRegex = /^(pb)1(['qpzry9x8gf2tvdw0s3jn54khce6mua7l]+)$/;

modules/sdk-coin-hash/test/resources/hash.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,39 @@ export const TEST_SEND_TX = {
4747
},
4848
};
4949

50+
export const TEST_SEND_TOKEN_TX = {
51+
hash: 'A5EFED6B56EACCF531C9A7FC13731A9E0AF6F7101876995035D9AD6DA40C3B2D',
52+
signature: 'JI7RpMouIn5VAoYpLH171tGogINLbQjDsyJ33lsWDPkYVF3kc39YDBo0sRq9fXEeZedP/pEh1f7fXPxaZisIFw==',
53+
pubKey: 'Asujzd7qXNDrdmH8ZbeVDtZbunQiYhlZNt5Qw7J3E0Me',
54+
privateKey: 'qp/Z1b0NeHgROzRAOqSxpBLZydY89cHSgWquf5/0nOs=',
55+
signedTxBase64:
56+
'CokBCoYBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmYKKXRwMWxmbXp4bG5wZjhrNXJxOThqeGV0ajUyZW5mMGFoenF6MDY5c3kzEil0cDEzZmE3amE4ZnhyejV3aDJka3dmZjlwbGNxZ2NqYTNycHkzeXFwORoOCgl1eWxkcy5mY2MSATESbQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAsujzd7qXNDrdmH8ZbeVDtZbunQiYhlZNt5Qw7J3E0MeEgQKAggBGBISGQoTCgVuaGFzaBIKMzgxMDAwMDAwMBDAmgwaQCSO0aTKLiJ+VQKGKSx9e9bRqICDS20Iw7Mid95bFgz5GFRd5HN/WAwaNLEavX1xHmXnT/6RIdX+31z8WmYrCBc=',
57+
sender: 'tp1lfmzxlnpf8k5rq98jxetj52enf0ahzqz069sy3',
58+
recipient: 'tp13fa7ja8fxrz5wh2dkwff9plcqgcja3rpy3yqp9',
59+
chainId: 'pio-testnet-1',
60+
accountNumber: 235524,
61+
sequence: 18,
62+
sendAmount: '1',
63+
feeAmount: '3810000000',
64+
sendMessage: {
65+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
66+
value: {
67+
amount: [
68+
{
69+
denom: 'uylds.fcc',
70+
amount: '1',
71+
},
72+
],
73+
toAddress: 'tp13fa7ja8fxrz5wh2dkwff9plcqgcja3rpy3yqp9',
74+
fromAddress: 'tp1lfmzxlnpf8k5rq98jxetj52enf0ahzqz069sy3',
75+
},
76+
},
77+
gasBudget: {
78+
amount: [{ denom: 'nhash', amount: '3810000000' }],
79+
gasLimit: 200000,
80+
},
81+
};
82+
5083
export const TEST_DELEGATE_TX = {
5184
hash: 'BD887ADE5E10C378B4B3DB3E4E0D5D77F0C2F3DFEE1A352BF186B22A8F022967',
5285
signature: 'FMZqHoNhxzJRvhhZbiLLybgAHdkszEstxow2oj1T1It8OyEGLJ8o2jnUo9OuCfeCKBfcWrKAi4w9dwsC8rBChQ==',
@@ -194,6 +227,45 @@ export const TEST_TX_WITH_MEMO = {
194227
},
195228
};
196229

230+
export const TEST_TOKEN_TX_WITH_MEMO = {
231+
hash: 'F4B979ECBF56EA203EA24ECE1F44AD621C5BC97955722C16AFBFC902E0001E5D',
232+
signature: 'HkE/roZVKf3rj4RH07fPPLeSJzxSGmz+7FQJ6nom1e9pD/3QMLXVHLpswFJCNDwoS9kfeSifBFKgPc6dpOr+7w==',
233+
pubKey: 'Asujzd7qXNDrdmH8ZbeVDtZbunQiYhlZNt5Qw7J3E0Me',
234+
privateKey: 'qp/Z1b0NeHgROzRAOqSxpBLZydY89cHSgWquf5/0nOs=',
235+
signedTxBase64:
236+
'CowBCoYBChwvY29zbW9zLmJhbmsudjFiZXRhMS5Nc2dTZW5kEmYKKXRwMWxmbXp4bG5wZjhrNXJxOThqeGV0ajUyZW5mMGFoenF6MDY5c3kzEil0cDEzZmE3amE4ZnhyejV3aDJka3dmZjlwbGNxZ2NqYTNycHkzeXFwORoOCgl1eWxkcy5mY2MSATESATcSbQpQCkYKHy9jb3Ntb3MuY3J5cHRvLnNlY3AyNTZrMS5QdWJLZXkSIwohAsujzd7qXNDrdmH8ZbeVDtZbunQiYhlZNt5Qw7J3E0MeEgQKAggBGBESGQoTCgVuaGFzaBIKMzgxMDAwMDAwMBDAmgwaQB5BP66GVSn964+ER9O3zzy3kic8Uhps/uxUCep6JtXvaQ/90DC11Ry6bMBSQjQ8KEvZH3konwRSoD3OnaTq/u8=',
237+
from: 'tp1lfmzxlnpf8k5rq98jxetj52enf0ahzqz069sy3',
238+
to: 'tp13fa7ja8fxrz5wh2dkwff9plcqgcja3rpy3yqp9',
239+
chainId: 'pio-testnet-1',
240+
accountNumber: 235524,
241+
sequence: 17,
242+
sendAmount: '1',
243+
feeAmount: '3810000000',
244+
sendMessage: {
245+
typeUrl: '/cosmos.bank.v1beta1.MsgSend',
246+
value: {
247+
amount: [
248+
{
249+
denom: 'uylds.fcc',
250+
amount: '1',
251+
},
252+
],
253+
toAddress: 'tp13fa7ja8fxrz5wh2dkwff9plcqgcja3rpy3yqp9',
254+
fromAddress: 'tp1lfmzxlnpf8k5rq98jxetj52enf0ahzqz069sy3',
255+
},
256+
},
257+
memo: '7',
258+
gasBudget: {
259+
amount: [
260+
{
261+
denom: 'nhash',
262+
amount: '3810000000',
263+
},
264+
],
265+
gasLimit: 200000,
266+
},
267+
};
268+
197269
export const mainnetAddress = {
198270
address1: 'pb1fmxzuzx5c4ja50vu94nt0aessnuedzmppde8qr',
199271
address2: 'pb16vmp7sz28pnvgz6f3zm6q93y39jsd33aazwg4u',
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { toHex, TransactionType } from '@bitgo/sdk-core';
2+
import { coins } from '@bitgo/statics';
3+
import { fromBase64 } from '@cosmjs/encoding';
4+
import should from 'should';
5+
6+
import { CosmosTransaction, SendMessage } from '@bitgo/abstract-cosmos';
7+
import { HashUtils } from '../../src/lib/utils';
8+
import * as testData from '../resources/hash';
9+
10+
describe('Hash Token Transaction', () => {
11+
let tx: CosmosTransaction;
12+
const tokenName = 'thash:ylds';
13+
const config = coins.get(tokenName);
14+
const utils = new HashUtils(config.network.type);
15+
16+
beforeEach(() => {
17+
tx = new CosmosTransaction(config, utils);
18+
});
19+
20+
describe('Empty transaction', () => {
21+
it('should throw empty transaction', function () {
22+
should.throws(() => tx.toBroadcastFormat(), 'Empty transaction');
23+
});
24+
});
25+
26+
describe('From raw transaction', () => {
27+
it('should build a transfer from raw signed base64', function () {
28+
tx.enrichTransactionDetailsFromRawTransaction(testData.TEST_SEND_TX.signedTxBase64);
29+
const json = tx.toJson();
30+
should.equal(json.sequence, testData.TEST_SEND_TX.sequence);
31+
should.deepEqual(json.gasBudget, testData.TEST_SEND_TX.gasBudget);
32+
should.equal(json.publicKey, toHex(fromBase64(testData.TEST_SEND_TX.pubKey)));
33+
should.equal(
34+
(json.sendMessages[0].value as SendMessage).toAddress,
35+
testData.TEST_SEND_TX.sendMessage.value.toAddress
36+
);
37+
should.deepEqual(
38+
(json.sendMessages[0].value as SendMessage).amount,
39+
testData.TEST_SEND_TX.sendMessage.value.amount
40+
);
41+
should.equal(Buffer.from(json.signature as any).toString('base64'), testData.TEST_SEND_TX.signature);
42+
should.equal(tx.type, TransactionType.Send);
43+
tx.loadInputsAndOutputs();
44+
should.deepEqual(tx.inputs, [
45+
{
46+
address: testData.TEST_SEND_TX.sender,
47+
value: testData.TEST_SEND_TX.sendMessage.value.amount[0].amount,
48+
coin: tokenName,
49+
},
50+
]);
51+
should.deepEqual(tx.outputs, [
52+
{
53+
address: testData.TEST_SEND_TX.sendMessage.value.toAddress,
54+
value: testData.TEST_SEND_TX.sendMessage.value.amount[0].amount,
55+
coin: tokenName,
56+
},
57+
]);
58+
});
59+
60+
it('should build a transfer from raw signed hex', function () {
61+
tx.enrichTransactionDetailsFromRawTransaction(toHex(fromBase64(testData.TEST_SEND_TX.signedTxBase64)));
62+
const json = tx.toJson();
63+
should.equal(json.sequence, testData.TEST_SEND_TX.sequence);
64+
should.deepEqual(json.gasBudget, testData.TEST_SEND_TX.gasBudget);
65+
should.equal(json.publicKey, toHex(fromBase64(testData.TEST_SEND_TX.pubKey)));
66+
should.equal(
67+
(json.sendMessages[0].value as SendMessage).toAddress,
68+
testData.TEST_SEND_TX.sendMessage.value.toAddress
69+
);
70+
should.deepEqual(
71+
(json.sendMessages[0].value as SendMessage).amount,
72+
testData.TEST_SEND_TX.sendMessage.value.amount
73+
);
74+
should.equal(Buffer.from(json.signature as any).toString('base64'), testData.TEST_SEND_TX.signature);
75+
should.equal(tx.type, TransactionType.Send);
76+
tx.loadInputsAndOutputs();
77+
should.deepEqual(tx.inputs, [
78+
{
79+
address: testData.TEST_SEND_TX.sender,
80+
value: testData.TEST_SEND_TX.sendMessage.value.amount[0].amount,
81+
coin: tokenName,
82+
},
83+
]);
84+
should.deepEqual(tx.outputs, [
85+
{
86+
address: testData.TEST_SEND_TX.sendMessage.value.toAddress,
87+
value: testData.TEST_SEND_TX.sendMessage.value.amount[0].amount,
88+
coin: tokenName,
89+
},
90+
]);
91+
});
92+
93+
it('should fail to build a transfer from incorrect raw hex', function () {
94+
should.throws(
95+
() => tx.enrichTransactionDetailsFromRawTransaction('random' + testData.TEST_SEND_TX.signedTxBase64),
96+
'incorrect raw data'
97+
);
98+
});
99+
100+
it('should fail to explain transaction with invalid raw hex', function () {
101+
should.throws(() => tx.enrichTransactionDetailsFromRawTransaction('randomString'), 'Invalid transaction');
102+
});
103+
});
104+
105+
describe('Explain transaction', () => {
106+
it('should explain a transfer pay transaction', function () {
107+
tx.enrichTransactionDetailsFromRawTransaction(testData.TEST_SEND_TX.signedTxBase64);
108+
const explainedTransaction = tx.explainTransaction();
109+
explainedTransaction.should.deepEqual({
110+
displayOrder: ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'type'],
111+
id: testData.TEST_SEND_TX.hash,
112+
outputs: [
113+
{
114+
address: testData.TEST_SEND_TX.recipient,
115+
amount: testData.TEST_SEND_TX.sendAmount,
116+
},
117+
],
118+
outputAmount: testData.TEST_SEND_TX.sendAmount,
119+
changeOutputs: [],
120+
changeAmount: '0',
121+
fee: { fee: testData.TEST_SEND_TX.feeAmount },
122+
type: 0,
123+
});
124+
});
125+
126+
it('should fail to explain transaction with invalid raw base64 string', function () {
127+
should.throws(() => tx.enrichTransactionDetailsFromRawTransaction('randomString'), 'Invalid transaction');
128+
});
129+
});
130+
});

modules/sdk-coin-hash/test/unit/transactionBuilder/transactionBuilder.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ describe('Hash Transaction Builder', async () => {
2020
});
2121

2222
const testTxData = testData.TEST_SEND_TX;
23+
const tokenTestTxData = testData.TEST_SEND_TOKEN_TX;
2324
let data;
2425

2526
beforeEach(() => {
2627
data = [
2728
{
2829
type: TransactionType.Send,
29-
testTx: testData.TEST_SEND_TX,
30+
testTx: testTxData,
31+
builder: factory.getTransferBuilder(),
32+
},
33+
{
34+
type: TransactionType.Send,
35+
testTx: tokenTestTxData,
3036
builder: factory.getTransferBuilder(),
3137
},
3238
{
@@ -56,6 +62,15 @@ describe('Hash Transaction Builder', async () => {
5662
should.equal(rawTx, testTxData.signedTxBase64);
5763
});
5864

65+
it('should build a signed token tx from signed token tx data', async function () {
66+
const txBuilder = factory.from(tokenTestTxData.signedTxBase64);
67+
const tx = await txBuilder.build();
68+
should.equal(tx.type, TransactionType.Send);
69+
// Should recreate the same raw tx data when re-build and turned to broadcast format
70+
const rawTx = tx.toBroadcastFormat();
71+
should.equal(rawTx, tokenTestTxData.signedTxBase64);
72+
});
73+
5974
describe('gasBudget tests', async () => {
6075
it('should succeed for valid gasBudget', function () {
6176
for (const { builder } of data) {

0 commit comments

Comments
 (0)