Skip to content

Commit

Permalink
feat(sdk-coin-apt): restructuring code
Browse files Browse the repository at this point in the history
Ticket: COIN-2894

TICKET: COIN-2894
  • Loading branch information
baltiyal committed Jan 27, 2025
1 parent 76457f1 commit 12813d2
Show file tree
Hide file tree
Showing 11 changed files with 94 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class FungibleTokenTransfer extends Transaction {
};
}

getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
protected getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
let address = 'INVALID';
let amount = '0';
if (payload instanceof TransactionPayloadEntryFunction) {
Expand Down
8 changes: 4 additions & 4 deletions modules/sdk-coin-apt/src/lib/transaction/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ export abstract class Transaction extends BaseTransaction {
this._type = transactionType;
}

protected abstract buildRawTransaction(): void;

protected abstract fromDeserializedSignedTransaction(signedTxn: SignedTransaction): void;

canSign(_key: BaseKey): boolean {
return false;
}
Expand Down Expand Up @@ -212,8 +216,6 @@ export abstract class Transaction extends BaseTransaction {
];
}

protected abstract fromDeserializedSignedTransaction(signedTxn: SignedTransaction): void;

fromRawTransaction(rawTransaction: string): void {
let signedTxn: SignedTransaction;
try {
Expand All @@ -238,8 +240,6 @@ export abstract class Transaction extends BaseTransaction {
}
}

protected abstract buildRawTransaction(): void;

public getFee(): string {
return new BigNumber(this.gasUsed).multipliedBy(this.gasUnitPrice).toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class TransferTransaction extends Transaction {
};
}

getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
protected getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
let address = 'INVALID';
let amount = '0';
if (payload instanceof TransactionPayloadEntryFunction) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { TransactionBuilder } from './transactionBuilder';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { FungibleTokenTransfer } from '../transaction/fungibleTokenTransfer';
import { TransactionType } from '@bitgo/sdk-core';
import { TransactionRecipient, TransactionType } from '@bitgo/sdk-core';
import { Transaction } from '../transaction/transaction';
import BigNumber from 'bignumber.js';
import utils from '../utils';
import { TransactionPayload, TransactionPayloadEntryFunction } from '@aptos-labs/ts-sdk';

export class FungibleTokenTransferBuilder extends TransactionBuilder {
//REMOVE COMMENT
Expand Down Expand Up @@ -38,6 +40,39 @@ export class FungibleTokenTransferBuilder extends TransactionBuilder {
this.validateAddress({ address: transaction.fungibleTokenAddress });
}

getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
let address = 'INVALID';
let amount = '0';
if (payload instanceof TransactionPayloadEntryFunction) {
const entryFunction = payload.entryFunction;
address = entryFunction.args[1].toString();
const amountBuffer = Buffer.from(entryFunction.args[2].bcsToBytes());
amount = amountBuffer.readBigUint64LE().toString();
}
return { address, amount };
}

isValidRawTransaction(rawTransaction: string): boolean {
try {
const signedTxn = utils.deserializeSignedTransaction(rawTransaction);
const rawTxn = signedTxn.raw_txn;
const senderAddress = rawTxn.sender.toString();
const recipient = this.getRecipientFromTransactionPayload(rawTxn.payload);
const fungibleTokenAddress = utils.getFungibleTokenAddressFromTransactionPayload(rawTxn.payload);
const recipientAddress = recipient.address;
const recipientAmount = new BigNumber(recipient.amount);
return (
utils.isValidAddress(senderAddress) &&
utils.isValidAddress(recipientAddress) &&
utils.isValidAddress(fungibleTokenAddress) &&
!recipientAmount.isLessThan(0)
);
} catch (e) {
console.error('invalid fungible raw transaction', e);
return false;
}
}

/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction {
this.transaction.fromRawTransaction(rawTransaction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
*/
protected abstract get transactionType(): TransactionType;

/**
* Initialize the transaction builder fields using the decoded transaction data
*
* @param {Transaction} tx the transaction data
*/
abstract initBuilder(tx: Transaction): void;

/** @inheritdoc */
protected get transaction(): Transaction {
return this._transaction;
Expand All @@ -37,6 +44,8 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
this._transaction = transaction;
}

abstract validateTransaction(transaction?: Transaction): void;

/**
* Sets the sender of this transaction.
*
Expand Down Expand Up @@ -88,13 +97,6 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
this.transaction.addFeePayerSignature(publicKey, signature);
}

/**
* Initialize the transaction builder fields using the decoded transaction data
*
* @param {Transaction} tx the transaction data
*/
abstract initBuilder(tx: Transaction): void;

// region Validators
/** @inheritdoc */
validateAddress(address: BaseAddress, addressFormat?: string): void {
Expand All @@ -107,13 +109,15 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
validateKey(key: BaseKey): void {
throw new Error('Method not implemented.');
}
//TODO: shift this to specific implementation

abstract isValidRawTransaction(rawTransaction: string): boolean;

/** @inheritdoc */
validateRawTransaction(rawTransaction: string): void {
if (!rawTransaction) {
throw new ParseTransactionError('Invalid raw transaction: Undefined');
}
if (!utils.isValidRawTransaction(rawTransaction)) {
if (!this.isValidRawTransaction(rawTransaction)) {
throw new ParseTransactionError('Invalid raw transaction');
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { TransactionBuilder } from './transactionBuilder';
import { BaseCoin as CoinConfig } from '@bitgo/statics';
import { TransactionType } from '@bitgo/sdk-core';
import { TransactionRecipient, TransactionType } from '@bitgo/sdk-core';
import { TransferTransaction } from '../transaction/transferTransaction';
import { Transaction } from '../transaction/transaction';
import BigNumber from 'bignumber.js';
import utils from '../utils';
import { TransactionPayload, TransactionPayloadEntryFunction } from '@aptos-labs/ts-sdk';

export class TransferBuilder extends TransactionBuilder {
constructor(_coinConfig: Readonly<CoinConfig>) {
Expand Down Expand Up @@ -34,6 +36,35 @@ export class TransferBuilder extends TransactionBuilder {
this.validateValue(new BigNumber(transaction.recipient.amount));
}

getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
let address = 'INVALID';
let amount = '0';
if (payload instanceof TransactionPayloadEntryFunction) {
const entryFunction = payload.entryFunction;
address = entryFunction.args[0].toString();
const amountBuffer = Buffer.from(entryFunction.args[1].bcsToBytes());
amount = amountBuffer.readBigUint64LE().toString();
}
return { address, amount };
}

isValidRawTransaction(rawTransaction: string): boolean {
try {
const signedTxn = utils.deserializeSignedTransaction(rawTransaction);
const rawTxn = signedTxn.raw_txn;
const senderAddress = rawTxn.sender.toString();
const recipient = this.getRecipientFromTransactionPayload(rawTxn.payload);
const recipientAddress = recipient.address;
const recipientAmount = new BigNumber(recipient.amount);
return (
utils.isValidAddress(senderAddress) && utils.isValidAddress(recipientAddress) && !recipientAmount.isLessThan(0)
);
} catch (e) {
console.error('invalid raw transaction', e);
return false;
}
}

/** @inheritdoc */
protected fromImplementation(rawTransaction: string): Transaction {
this.transaction.fromRawTransaction(rawTransaction);
Expand Down
1 change: 0 additions & 1 deletion modules/sdk-coin-apt/src/lib/transactionBuilderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export class TransactionBuilderFactory extends BaseTransactionBuilderFactory {

/** @inheritdoc */
from(signedRawTxn: string): TransactionBuilder {
utils.validateRawTransaction(signedRawTxn);
try {
const signedTxn = this.parseTransaction(signedRawTxn);
const txnType = this.getTransactionTypeFromSignedTxn(signedTxn);
Expand Down
40 changes: 0 additions & 40 deletions modules/sdk-coin-apt/src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ import {
InvalidTransactionError,
isValidEd25519PublicKey,
isValidEd25519SecretKey,
ParseTransactionError,
TransactionRecipient,
TransactionType,
} from '@bitgo/sdk-core';
import {
Expand Down Expand Up @@ -69,18 +67,6 @@ export class Utils implements BaseUtils {
return accountAddress.toString();
}

getRecipientFromTransactionPayload(payload: TransactionPayload): TransactionRecipient {
let address = 'INVALID';
let amount = '0';
if (payload instanceof TransactionPayloadEntryFunction) {
const entryFunction = payload.entryFunction;
address = entryFunction.args[0].toString();
const amountBuffer = Buffer.from(entryFunction.args[1].bcsToBytes());
amount = amountBuffer.readBigUint64LE().toString();
}
return { address, amount };
}

getFungibleTokenAddressFromTransactionPayload(payload: TransactionPayload): string {
let fungibleTokenAddress = 'INVALID';
if (payload instanceof TransactionPayloadEntryFunction && payload.entryFunction.args.length === 3) {
Expand All @@ -106,32 +92,6 @@ export class Utils implements BaseUtils {
}
}

isValidRawTransaction(rawTransaction: string): boolean {
try {
const signedTxn = this.deserializeSignedTransaction(rawTransaction);
const rawTxn = signedTxn.raw_txn;
const senderAddress = rawTxn.sender.toString();
const recipient = utils.getRecipientFromTransactionPayload(rawTxn.payload);
const recipientAddress = recipient.address;
const recipientAmount = new BigNumber(recipient.amount);
return (
this.isValidAddress(senderAddress) && this.isValidAddress(recipientAddress) && !recipientAmount.isLessThan(0)
);
} catch (e) {
console.error('invalid raw transaction', e);
return false;
}
}

validateRawTransaction(rawTransaction: string): void {
if (!rawTransaction) {
throw new ParseTransactionError('Invalid raw transaction: Undefined');
}
if (!this.isValidRawTransaction(rawTransaction)) {
throw new ParseTransactionError('Invalid raw transaction');
}
}

deserializeSignedTransaction(rawTransaction: string): SignedTransaction {
const txnBytes = Hex.fromHexString(rawTransaction).toUint8Array();
const deserializer = new Deserializer(txnBytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { getBuilderFactory } from '../getBuilderFactory';
import { coins } from '@bitgo/statics';
import { TransferTransaction } from '../../../src';
import * as testData from '../../resources/apt';
import utils from '../../../src/lib/utils';
import { TransactionType } from '@bitgo/sdk-core';
import should from 'should';
import { FungibleTokenTransfer } from '../../../src/lib/transaction/fungibleTokenTransfer';
Expand Down Expand Up @@ -47,7 +46,7 @@ describe('Apt Token Transfer Builder', () => {
coin: 'tapt:usdt',
});
const rawTx = tx.toBroadcastFormat();
should.equal(utils.isValidRawTransaction(rawTx), true);
should.equal(txBuilder.isValidRawTransaction(rawTx), true);
rawTx.should.equal(
'0x1aed808916ab9b1b30b07abb53561afd46847285ce28651221d406173a3724490e00000000000000020000000000000000000000000000000000000000000000000000000000000001167072696d6172795f66756e6769626c655f73746f7265087472616e73666572010700000000000000000000000000000000000000000000000000000000000000010e66756e6769626c655f6173736574084d65746164617461000320d5d0d561493ea2b9410f67da804653ae44e793c2423707d4f11edb2e3819205020f7405c28a02cf5bab4ea4498240bb3579db45951794eb1c843bef0534c093ad9080100000000000000400d03000000000064000000000000008b037d670000000002030020000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dbc87a1c816d9bcd06b683c37e80c7162e4d48da7812198b830e4d5d8e0629f2002000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
);
Expand Down Expand Up @@ -77,7 +76,7 @@ describe('Apt Token Transfer Builder', () => {
should.equal(tx.expirationTime, 1737893604);
should.equal(tx.type, TransactionType.SendToken);
const rawTx = tx.toBroadcastFormat();
should.equal(utils.isValidRawTransaction(rawTx), true);
should.equal(txBuilder.isValidRawTransaction(rawTx), true);
should.equal(rawTx, testData.FUNGIBLE_TOKEN_TRANSFER);
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { coins } from '@bitgo/statics';
import { TransactionBuilderFactory, TransferTransaction } from '../../../src';
import * as testData from '../../resources/apt';
import utils from '../../../src/lib/utils';
import { TransactionType } from '@bitgo/sdk-core';
import should from 'should';

Expand Down Expand Up @@ -43,7 +42,7 @@ describe('Apt Transfer Transaction', () => {
coin: 'tapt',
});
const rawTx = tx.toBroadcastFormat();
should.equal(utils.isValidRawTransaction(rawTx), true);
should.equal(txBuilder.isValidRawTransaction(rawTx), true);
rawTx.should.equal(
'0x1aed808916ab9b1b30b07abb53561afd46847285ce28651221d406173a3724490e000000000000000200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e74087472616e73666572000220f7405c28a02cf5bab4ea4498240bb3579db45951794eb1c843bef0534c093ad908e803000000000000400d03000000000064000000000000008b037d670000000002030020000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dbc87a1c816d9bcd06b683c37e80c7162e4d48da7812198b830e4d5d8e0629f2002000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
);
Expand Down Expand Up @@ -72,7 +71,7 @@ describe('Apt Transfer Transaction', () => {
should.equal(tx.expirationTime, 1737528215);
should.equal(tx.type, TransactionType.Send);
const rawTx = tx.toBroadcastFormat();
should.equal(utils.isValidRawTransaction(rawTx), true);
should.equal(txBuilder.isValidRawTransaction(rawTx), true);
should.equal(rawTx, testData.TRANSFER);
});

Expand Down
14 changes: 3 additions & 11 deletions modules/sdk-coin-apt/test/unit/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as testData from '../resources/apt';
import should from 'should';
import utils from '../../src/lib/utils';
import { SignedTransaction, TransactionAuthenticatorFeePayer } from '@aptos-labs/ts-sdk';
import { TransferBuilder } from '../../src';
import { coins } from '@bitgo/statics';

describe('Aptos util library', function () {
describe('isValidAddress', function () {
Expand All @@ -23,16 +25,6 @@ describe('Aptos util library', function () {
});
});

describe('isValidRawTransaction', function () {
it('should succeed to validate a valid raw transaction', function () {
should.equal(utils.isValidRawTransaction(testData.TRANSFER), true);
});
it('should fail to validate an invalid raw transaction', function () {
should.doesNotThrow(() => utils.isValidRawTransaction(testData.INVALID_TRANSFER));
should.equal(utils.isValidRawTransaction(testData.INVALID_TRANSFER), false);
});
});

describe('isValidDeserialize', function () {
it('should succeed to correctly deserialize serialized transaction', function () {
const signedTxn: SignedTransaction = utils.deserializeSignedTransaction(testData.TRANSFER);
Expand All @@ -42,7 +34,7 @@ describe('Aptos util library', function () {
'0xdbc87a1c816d9bcd06b683c37e80c7162e4d48da7812198b830e4d5d8e0629f2'
);
const rawTx = signedTxn.raw_txn;
const recipient = utils.getRecipientFromTransactionPayload(rawTx.payload);
const recipient = new TransferBuilder(coins.get('tapt')).getRecipientFromTransactionPayload(rawTx.payload);
should.equal(rawTx.sender.toString(), testData.sender2.address);
should.equal(rawTx.max_gas_amount, 200000);
should.equal(rawTx.gas_unit_price, 100);
Expand Down

0 comments on commit 12813d2

Please sign in to comment.