Skip to content

Commit a19ac5e

Browse files
baltiyalbhavidhingra
authored andcommitted
feat(sdk-coin-apt): addition of test case for apt transaction builder
Ticket: COIN-2258
1 parent 6857221 commit a19ac5e

File tree

10 files changed

+427
-15
lines changed

10 files changed

+427
-15
lines changed

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

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ import {
1111
VerifyAddressOptions,
1212
VerifyTransactionOptions,
1313
} from '@bitgo/sdk-core';
14-
import { BaseCoin as StaticsBaseCoin } from '@bitgo/statics';
15-
import { KeyPair as AptKeyPair } from './lib';
14+
import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics';
15+
import { KeyPair as AptKeyPair, TransactionBuilderFactory, TransferTransaction } from './lib';
1616
import utils from './lib/utils';
17+
import * as _ from 'lodash';
18+
import BigNumber from 'bignumber.js';
19+
20+
export interface AptParseTransactionOptions extends ParseTransactionOptions {
21+
txHex: string;
22+
}
1723

1824
export class Apt extends BaseCoin {
1925
protected readonly _staticsCoin: Readonly<StaticsBaseCoin>;
@@ -64,7 +70,40 @@ export class Apt extends BaseCoin {
6470
}
6571

6672
async verifyTransaction(params: VerifyTransactionOptions): Promise<boolean> {
67-
throw new Error('Method not implemented.');
73+
const coinConfig = coins.get(this.getChain());
74+
const { txPrebuild: txPrebuild, txParams: txParams } = params;
75+
const transaction = new TransferTransaction(coinConfig);
76+
const rawTx = txPrebuild.txHex;
77+
if (!rawTx) {
78+
throw new Error('missing required tx prebuild property txHex');
79+
}
80+
transaction.fromRawTransaction(rawTx);
81+
const explainedTx = transaction.explainTransaction();
82+
if (txParams.recipients !== undefined) {
83+
const filteredRecipients = txParams.recipients?.map((recipient) => {
84+
return {
85+
address: recipient.address, // TODO: check this
86+
amount: BigInt(recipient.amount),
87+
};
88+
});
89+
const filteredOutputs = explainedTx.outputs.map((output) => {
90+
return {
91+
address: output.address,
92+
amount: BigInt(output.amount),
93+
};
94+
});
95+
if (!_.isEqual(filteredOutputs, filteredRecipients)) {
96+
throw new Error('Tx outputs does not match with expected txParams recipients');
97+
}
98+
let totalAmount = new BigNumber(0);
99+
for (const recipients of txParams.recipients) {
100+
totalAmount = totalAmount.plus(recipients.amount);
101+
}
102+
if (!totalAmount.isEqualTo(explainedTx.outputAmount)) {
103+
throw new Error('Tx total amount does not match with expected total amount field');
104+
}
105+
}
106+
return true;
68107
}
69108

70109
async isWalletAddress(params: VerifyAddressOptions): Promise<boolean> {
@@ -76,8 +115,26 @@ export class Apt extends BaseCoin {
76115
return true;
77116
}
78117

79-
parseTransaction(params: ParseTransactionOptions): Promise<ParsedTransaction> {
80-
throw new Error('Method not implemented.');
118+
async parseTransaction(params: AptParseTransactionOptions): Promise<ParsedTransaction> {
119+
const coinConfig = coins.get(this.getChain());
120+
const factory = new TransactionBuilderFactory(coinConfig);
121+
const transactionBuilder = factory.from(params.txHex);
122+
const rebuiltTransaction = await transactionBuilder.build();
123+
const parsedTransaction = rebuiltTransaction.toJson();
124+
return {
125+
inputs: [
126+
{
127+
address: parsedTransaction.sender,
128+
value: parsedTransaction.recipient.amount,
129+
},
130+
],
131+
outputs: [
132+
{
133+
address: parsedTransaction.recipient.address,
134+
value: parsedTransaction.recipient.amount,
135+
},
136+
],
137+
};
81138
}
82139

83140
generateKeyPair(seed?: Buffer): KeyPair {

modules/sdk-coin-apt/src/lib/iface.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { ITransactionExplanation, TransactionFee } from '@bitgo/sdk-core';
22

3+
export enum AptTransactionType {
4+
Transfer = 'Transfer',
5+
TokenTransfer = 'TokenTransfer',
6+
}
37
export type TransactionExplanation = ITransactionExplanation<TransactionFee>;
48

59
/**

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
Ed25519PublicKey,
1616
Ed25519Signature,
1717
generateUserTransactionHash,
18+
Hex,
1819
RawTransaction,
1920
SignedTransaction,
2021
SimpleTransaction,
@@ -26,6 +27,7 @@ import utils from '../utils';
2627
export abstract class Transaction extends BaseTransaction {
2728
protected _rawTransaction: RawTransaction;
2829
protected _signature: Signature;
30+
public txRecipient: TransactionRecipient; //TODO: check and fix - layering, and usage.
2931

3032
static DEFAULT_PUBLIC_KEY = Buffer.alloc(32);
3133
static DEFAULT_SIGNATURE = Buffer.alloc(64);
@@ -86,7 +88,7 @@ export abstract class Transaction extends BaseTransaction {
8688
let publicKeyBuffer = Transaction.DEFAULT_PUBLIC_KEY;
8789
let signatureBuffer = Transaction.DEFAULT_SIGNATURE;
8890
if (this._signature && this._signature.publicKey && this._signature.signature) {
89-
publicKeyBuffer = Buffer.from(this._signature.publicKey.pub, 'hex');
91+
publicKeyBuffer = Buffer.from(Hex.fromHexString(this._signature.publicKey.pub).toUint8Array());
9092
signatureBuffer = this._signature.signature;
9193
}
9294
const publicKey = new Ed25519PublicKey(publicKeyBuffer);
@@ -103,7 +105,6 @@ export abstract class Transaction extends BaseTransaction {
103105
if (!Transaction.DEFAULT_PUBLIC_KEY.equals(publicKeyBuffer) && !Transaction.DEFAULT_SIGNATURE.equals(signature)) {
104106
this._signatures.push(signature.toString('hex'));
105107
this._signature = { publicKey, signature };
106-
this.serialize();
107108
}
108109
}
109110

@@ -119,18 +120,18 @@ export abstract class Transaction extends BaseTransaction {
119120
}
120121

121122
loadInputsAndOutputs(): void {
122-
const txRecipient = this.recipient;
123+
this.txRecipient = this.recipient;
123124
this._inputs = [
124125
{
125126
address: this.sender,
126-
value: txRecipient.amount as string,
127+
value: this.txRecipient.amount as string,
127128
coin: this._coinConfig.name,
128129
},
129130
];
130131
this._outputs = [
131132
{
132-
address: txRecipient.address,
133-
value: txRecipient.amount as string,
133+
address: this.txRecipient.address,
134+
value: this.txRecipient.amount as string,
134135
coin: this._coinConfig.name,
135136
},
136137
];
@@ -144,9 +145,8 @@ export abstract class Transaction extends BaseTransaction {
144145
this.loadInputsAndOutputs();
145146

146147
const authenticator = signedTxn.authenticator as TransactionAuthenticatorEd25519;
147-
const publicKey = Buffer.from(authenticator.public_key.toUint8Array());
148148
const signature = Buffer.from(authenticator.signature.toUint8Array());
149-
this.addSignature({ pub: publicKey.toString() }, signature);
149+
this.addSignature({ pub: authenticator.public_key.toString() }, signature);
150150
} catch (e) {
151151
console.error('invalid raw transaction', e);
152152
throw new Error('invalid raw transaction');
@@ -155,6 +155,7 @@ export abstract class Transaction extends BaseTransaction {
155155

156156
/** @inheritDoc */
157157
explainTransaction(): TransactionExplanation {
158+
//TODO: explain transaction to take input as params then take build txn and return the explanation
158159
const displayOrder = ['id', 'outputs', 'outputAmount', 'changeOutputs', 'changeAmount', 'fee', 'withdrawAmount'];
159160

160161
const outputs: TransactionRecipient[] = [this.recipient];

modules/sdk-coin-apt/src/lib/transaction/transferTransaction.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { TxData } from '../iface';
33
import { TransactionPayloadEntryFunction } from '@aptos-labs/ts-sdk';
44

55
export class TransferTransaction extends Transaction {
6+
constructor(coinConfig) {
7+
super(coinConfig);
8+
}
69
toJson(): TxData {
710
const rawTxn = this._rawTransaction;
811
const payload = this._rawTransaction.payload as TransactionPayloadEntryFunction;

modules/sdk-coin-apt/src/lib/transferBuilder.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
11
import { TransactionBuilder } from './transactionBuilder';
22
import { BaseCoin as CoinConfig } from '@bitgo/statics';
3-
import { TransactionType } from '@bitgo/sdk-core';
3+
import { Recipient, TransactionType } from '@bitgo/sdk-core';
44
import { TransferTransaction } from './transaction/transferTransaction';
55

66
export class TransferBuilder extends TransactionBuilder {
77
constructor(_coinConfig: Readonly<CoinConfig>) {
88
super(_coinConfig);
9+
this.transaction = new TransferTransaction(_coinConfig);
910
}
1011

1112
protected get transactionType(): TransactionType {
1213
return TransactionType.Send;
1314
}
1415

16+
send(txRecipient: Recipient): this {
17+
this.transaction.txRecipient = txRecipient;
18+
return this;
19+
}
20+
1521
/**
1622
* Initialize the transaction builder fields using the decoded transaction data
1723
*

modules/sdk-coin-apt/src/lib/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ export class Utils implements BaseUtils {
6767
if (payload instanceof TransactionPayloadEntryFunction) {
6868
const entryFunction = payload.entryFunction;
6969
address = entryFunction.args[0].toString();
70-
amount = entryFunction.args[1].toString();
70+
const amountBuffer = Buffer.from(entryFunction.args[1].bcsToBytes());
71+
amount = amountBuffer.readBigUint64LE().toString();
7172
}
7273
return { address, amount };
7374
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { Recipient } from '@bitgo/sdk-core';
2+
3+
export const AMOUNT = 1000;
4+
5+
export const addresses = {
6+
validAddresses: [
7+
'0xf7405c28a02cf5bab4ea4498240bb3579db45951794eb1c843bef0534c093ad9',
8+
'0x1aed808916ab9b1b30b07abb53561afd46847285ce28651221d406173a372449',
9+
],
10+
invalidAddresses: [
11+
'randomString',
12+
'0xc4173a804406a365e69dfb297ddfgsdcvf',
13+
'5ne7phA48Jrvpn39AtupB8ZkCCAy8gLTfpGihZPuDqen',
14+
],
15+
};
16+
17+
export const sender = {
18+
address: '0x1aed808916ab9b1b30b07abb53561afd46847285ce28651221d406173a372449',
19+
privateKey: '0x54e1a88eb2b881fe6c222985d0fabc9ba3aca35743dd1d19db18a9a355acbaaa',
20+
publicKey: '0xf73836f42257240e43d439552471fc9dbcc3f1af5bd0b4ed83f44b5f66146442',
21+
};
22+
23+
export const recipients: Recipient[] = [
24+
{
25+
address: addresses.validAddresses[0],
26+
amount: AMOUNT.toString(),
27+
},
28+
];
29+
30+
export const TRANSFER =
31+
'0xc8f02d25aa698b3e9fbd8a08e8da4c8ee261832a25a4cde8731b5ec356537d09170000000000000002000000000000000000000000000000000000000000000000000000000000000104636f696e087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010a6170746f735f636f696e094170746f73436f696e000220f7405c28a02cf5bab4ea4498240bb3579db45951794eb1c843bef0534c093ad908e803000000000000400d0300000000006400000000000000207c7667000000000200202121dcd098069ae535697dd019cfd8677ca7aba0adac1d1959cbce6dc54b12594010f340ec153b724c4dc1c9a435d0fafed1775d851c1e8d965925a7879550c69a4677925d9198334a72ae7ce8998226ff0a83743c7ba8a2831136c072bf21c404';

0 commit comments

Comments
 (0)