1- import 'should' ;
2-
1+ import Tonweb from 'tonweb' ;
2+ import should from 'should' ;
3+ import * as sinon from 'sinon' ;
4+ import { TransactionExplanation } from '@bitgo/sdk-core' ;
35import { TestBitGo , TestBitGoAPI } from '@bitgo/sdk-test' ;
46import { BitGoAPI } from '@bitgo/sdk-api' ;
5- import { JettonToken } from '../../src' ;
7+ import { JettonToken , Ton , TonParseTransactionOptions } from '../../src' ;
8+ import * as testData from '../resources/ton' ;
69
710describe ( 'Jetton Tokens' , function ( ) {
811 let bitgo : TestBitGoAPI ;
@@ -11,6 +14,31 @@ describe('Jetton Tokens', function () {
1114 const testnetTokenName = 'tton:ukwny-us' ;
1215 const mainnetTokenName = 'ton:usdt' ;
1316
17+ const txPrebuildList = [
18+ {
19+ txHex : Buffer . from ( testData . signedTokenSendTransaction . tx , 'base64' ) . toString ( 'hex' ) ,
20+ txInfo : { } ,
21+ } ,
22+ ] ;
23+ const txPrebuildBounceableList = [
24+ {
25+ txHex : Buffer . from ( testData . signedTokenSendTransaction . txBounceable , 'base64' ) . toString ( 'hex' ) ,
26+ txInfo : { } ,
27+ } ,
28+ ] ;
29+
30+ const txParamsList = [
31+ {
32+ recipients : [ testData . signedTokenSendTransaction . recipient ] ,
33+ } ,
34+ ] ;
35+
36+ const txParamsBounceableList = [
37+ {
38+ recipients : [ testData . signedTokenSendTransaction . recipientBounceable ] ,
39+ } ,
40+ ] ;
41+
1442 before ( function ( ) {
1543 bitgo = TestBitGo . decorate ( BitGoAPI , { env : 'test' } ) ;
1644 JettonToken . createTokenConstructors ( ) . forEach ( ( { name, coinConstructor } ) => {
@@ -46,4 +74,261 @@ describe('Jetton Tokens', function () {
4674 mainnetJettonToken . contractAddress . should . equal ( 'EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs' ) ;
4775 mainnetJettonToken . decimalPlaces . should . equal ( 6 ) ;
4876 } ) ;
77+
78+ describe ( 'Verify Jetton transaction: ' , ( ) => {
79+ txParamsList . forEach ( ( _ , index ) => {
80+ const txParams = txParamsList [ index ] ;
81+ const txPrebuild = txPrebuildList [ index ] ;
82+ const txParamsBounceable = txParamsBounceableList [ index ] ;
83+ const txPrebuildBounceable = txPrebuildBounceableList [ index ] ;
84+
85+ it ( 'should succeed to verify transaction' , async function ( ) {
86+ const verification = { } ;
87+ const isTransactionVerified = await testnetJettonToken . verifyTransaction ( {
88+ txParams,
89+ txPrebuild,
90+ verification,
91+ } as any ) ;
92+ isTransactionVerified . should . equal ( true ) ;
93+
94+ const isBounceableTransactionVerified = await testnetJettonToken . verifyTransaction ( {
95+ txParams : txParamsBounceable ,
96+ txPrebuild : txPrebuildBounceable ,
97+ verification : { } ,
98+ } as any ) ;
99+ isBounceableTransactionVerified . should . equal ( true ) ;
100+ } ) ;
101+
102+ it ( 'should succeed to verify transaction when recipients amount are numbers' , async function ( ) {
103+ const txParamsWithNumberAmounts = JSON . parse ( JSON . stringify ( txParams ) ) ;
104+ txParamsWithNumberAmounts . recipients [ 0 ] . amount = 20000000 ;
105+ const verification = { } ;
106+ await testnetJettonToken
107+ . verifyTransaction ( {
108+ txParams : txParamsWithNumberAmounts ,
109+ txPrebuild,
110+ verification,
111+ } as any )
112+ . should . rejectedWith ( 'Tx outputs does not match with expected txParams recipients' ) ;
113+ } ) ;
114+
115+ it ( 'should succeed to verify transaction when recipients amount are strings' , async function ( ) {
116+ const txParamsWithNumberAmounts = JSON . parse ( JSON . stringify ( txParams ) ) ;
117+ txParamsWithNumberAmounts . recipients [ 0 ] . amount = '20000000' ;
118+ const verification = { } ;
119+ await testnetJettonToken
120+ . verifyTransaction ( {
121+ txParams : txParamsWithNumberAmounts ,
122+ txPrebuild,
123+ verification,
124+ } as any )
125+ . should . rejectedWith ( 'Tx outputs does not match with expected txParams recipients' ) ;
126+ } ) ;
127+
128+ it ( 'should succeed to verify transaction when recipients amounts are number and amount is same' , async function ( ) {
129+ const verification = { } ;
130+ await testnetJettonToken
131+ . verifyTransaction ( {
132+ txParams,
133+ txPrebuild,
134+ verification,
135+ } as any )
136+ . should . resolvedWith ( true ) ;
137+ } ) ;
138+
139+ it ( 'should succeed to verify transaction when recipients amounts are string and amount is same' , async function ( ) {
140+ const verification = { } ;
141+ await testnetJettonToken
142+ . verifyTransaction ( {
143+ txParams,
144+ txPrebuild,
145+ verification,
146+ } as any )
147+ . should . resolvedWith ( true ) ;
148+ } ) ;
149+
150+ it ( 'should succeed to verify transaction when recipient address are non bounceable' , async function ( ) {
151+ const txParamsWithNumberAmounts = JSON . parse ( JSON . stringify ( txParams ) ) ;
152+ txParamsWithNumberAmounts . recipients [ 0 ] . address = new Tonweb . Address (
153+ txParamsWithNumberAmounts . recipients [ 0 ] . address
154+ ) . toString ( true , true , false ) ;
155+ const verification = { } ;
156+ const isVerified = await testnetJettonToken . verifyTransaction ( {
157+ txParams : txParamsWithNumberAmounts ,
158+ txPrebuild,
159+ verification,
160+ } as any ) ;
161+ isVerified . should . equal ( true ) ;
162+ } ) ;
163+
164+ it ( 'should fail to verify transaction with invalid param' , async function ( ) {
165+ const txPrebuild = { } ;
166+ await testnetJettonToken
167+ . verifyTransaction ( {
168+ txParams,
169+ txPrebuild,
170+ } as any )
171+ . should . rejectedWith ( 'missing required tx prebuild property txHex' ) ;
172+ } ) ;
173+ } ) ;
174+
175+ it ( 'should succeed to verify transaction with recipient having memo' , async function ( ) {
176+ const txParams = {
177+ recipients : [ testData . signedTokenSendTransactionForMemoId . recipient ] ,
178+ } ;
179+ const txPrebuild = {
180+ txHex : Buffer . from ( testData . signedTokenSendTransactionForMemoId . tx , 'base64' ) . toString ( 'hex' ) ,
181+ txInfo : { } ,
182+ } ;
183+ const verification = { } ;
184+ const isTransactionVerified = await testnetJettonToken . verifyTransaction ( {
185+ txParams,
186+ txPrebuild,
187+ verification,
188+ } as any ) ;
189+ isTransactionVerified . should . equal ( true ) ;
190+ } ) ;
191+ } ) ;
192+
193+ describe ( 'Explain Jetton Transaction: ' , ( ) => {
194+ it ( 'should explain a jetton transfer transaction' , async function ( ) {
195+ const explainedTransaction = ( await testnetJettonToken . explainTransaction ( {
196+ txHex : Buffer . from ( testData . signedTokenSendTransaction . tx , 'base64' ) . toString ( 'hex' ) ,
197+ } ) ) as TransactionExplanation ;
198+ explainedTransaction . should . deepEqual ( {
199+ displayOrder : [ 'id' , 'outputs' , 'outputAmount' , 'changeOutputs' , 'changeAmount' , 'fee' , 'withdrawAmount' ] ,
200+ id : testData . signedTokenSendTransaction . txId ,
201+ outputs : [
202+ {
203+ address : testData . signedTokenSendTransaction . recipient . address ,
204+ amount : testData . signedTokenSendTransaction . recipient . amount ,
205+ } ,
206+ ] ,
207+ outputAmount : testData . signedTokenSendTransaction . recipient . amount ,
208+ changeOutputs : [ ] ,
209+ changeAmount : '0' ,
210+ fee : { fee : 'UNKNOWN' } ,
211+ withdrawAmount : undefined ,
212+ } ) ;
213+ } ) ;
214+
215+ it ( 'should explain a non-bounceable jetton transfer transaction' , async function ( ) {
216+ const explainedTransaction = ( await testnetJettonToken . explainTransaction ( {
217+ txHex : Buffer . from ( testData . signedTokenSendTransaction . txBounceable , 'base64' ) . toString ( 'hex' ) ,
218+ toAddressBounceable : false ,
219+ fromAddressBounceable : false ,
220+ } ) ) as TransactionExplanation ;
221+ explainedTransaction . should . deepEqual ( {
222+ displayOrder : [ 'id' , 'outputs' , 'outputAmount' , 'changeOutputs' , 'changeAmount' , 'fee' , 'withdrawAmount' ] ,
223+ id : testData . signedTokenSendTransaction . txIdBounceable ,
224+ outputs : [
225+ {
226+ address : testData . signedTokenSendTransaction . recipientBounceable . address ,
227+ amount : testData . signedTokenSendTransaction . recipientBounceable . amount ,
228+ } ,
229+ ] ,
230+ outputAmount : testData . signedTokenSendTransaction . recipientBounceable . amount ,
231+ changeOutputs : [ ] ,
232+ changeAmount : '0' ,
233+ fee : { fee : 'UNKNOWN' } ,
234+ withdrawAmount : undefined ,
235+ } ) ;
236+ } ) ;
237+
238+ it ( 'should fail to explain transaction with missing params' , async function ( ) {
239+ try {
240+ await testnetJettonToken . explainTransaction ( { } ) ;
241+ } catch ( error ) {
242+ should . equal ( error . message , 'Invalid transaction' ) ;
243+ }
244+ } ) ;
245+
246+ it ( 'should fail to explain transaction with invalid params' , async function ( ) {
247+ try {
248+ await testnetJettonToken . explainTransaction ( { txHex : 'randomString' } ) ;
249+ } catch ( error ) {
250+ should . equal ( error . message , 'Invalid transaction' ) ;
251+ }
252+ } ) ;
253+ } ) ;
254+
255+ describe ( 'Parse Jetton Transactions: ' , ( ) => {
256+ const transactionsList = [ testData . signedTokenSendTransaction . tx ] ;
257+ const transactionInputsResponseList = [
258+ [
259+ {
260+ address : 'EQCqQzfyg0cZ-8t9v2YoHmFFxG5jgjvQRTZ2yeDjO5z5ZRy9' ,
261+ amount : testData . tokenRecipients [ 0 ] . amount ,
262+ } ,
263+ ] ,
264+ ] ;
265+
266+ const transactionInputsResponseBounceableList = [
267+ [
268+ {
269+ address : testData . tokenSender . address ,
270+ amount : testData . tokenRecipients [ 0 ] . amount ,
271+ } ,
272+ ] ,
273+ ] ;
274+
275+ const transactionOutputsResponseList = [
276+ [
277+ {
278+ address : 'EQB-CM6DF-jpq9XVdiSdefAMU5KC1gpZuYBFp-Q65aUhnx5K' ,
279+ amount : testData . tokenRecipients [ 0 ] . amount ,
280+ } ,
281+ ] ,
282+ ] ;
283+
284+ const transactionOutputsResponseBounceableList = [
285+ [
286+ {
287+ address : testData . tokenRecipients [ 0 ] . address ,
288+ amount : testData . tokenRecipients [ 0 ] . amount ,
289+ } ,
290+ ] ,
291+ ] ;
292+
293+ transactionsList . forEach ( ( _ , index ) => {
294+ const transaction = transactionsList [ index ] ;
295+ const transactionInputsResponse = transactionInputsResponseList [ index ] ;
296+ const transactionInputsResponseBounceable = transactionInputsResponseBounceableList [ index ] ;
297+ const transactionOutputsResponse = transactionOutputsResponseList [ index ] ;
298+ const transactionOutputsResponseBounceable = transactionOutputsResponseBounceableList [ index ] ;
299+
300+ it ( 'should parse a TON transaction' , async function ( ) {
301+ const parsedTransaction = await testnetJettonToken . parseTransaction ( {
302+ txHex : Buffer . from ( transaction , 'base64' ) . toString ( 'hex' ) ,
303+ } ) ;
304+
305+ parsedTransaction . should . deepEqual ( {
306+ inputs : transactionInputsResponse ,
307+ outputs : transactionOutputsResponse ,
308+ } ) ;
309+ } ) ;
310+
311+ it ( 'should parse a non-bounceable TON transaction' , async function ( ) {
312+ const parsedTransaction = await testnetJettonToken . parseTransaction ( {
313+ txHex : Buffer . from ( transaction , 'base64' ) . toString ( 'hex' ) ,
314+ toAddressBounceable : false ,
315+ fromAddressBounceable : false ,
316+ } as TonParseTransactionOptions ) ;
317+
318+ parsedTransaction . should . deepEqual ( {
319+ inputs : transactionInputsResponseBounceable ,
320+ outputs : transactionOutputsResponseBounceable ,
321+ } ) ;
322+ } ) ;
323+
324+ it ( 'should fail to parse a TON transaction when explainTransaction response is undefined' , async function ( ) {
325+ const stub = sinon . stub ( Ton . prototype , 'explainTransaction' ) ;
326+ stub . resolves ( undefined ) ;
327+ await testnetJettonToken
328+ . parseTransaction ( { txHex : transaction } )
329+ . should . be . rejectedWith ( 'invalid raw transaction' ) ;
330+ stub . restore ( ) ;
331+ } ) ;
332+ } ) ;
333+ } ) ;
49334} ) ;
0 commit comments