Skip to content

Commit

Permalink
add transfer coin built in function
Browse files Browse the repository at this point in the history
  • Loading branch information
0xmaayan committed Oct 11, 2023
1 parent 6953235 commit 8bd5e09
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/api/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,10 @@ export class Account {
}

/**
* Queries the count of an account's coins
* Queries the count of an account's coins aggregated
*
* @param accountAddress The account address we want to get the total count for
* @returns An object { count : number }
* @returns An object { count : number } where `number` is the aggregated count of all account's coin
*/
async getAccountCoinsCount(args: { accountAddress: HexInput }): Promise<GetAccountCoinsCountResponse> {
const count = getAccountCoinsCount({ aptosConfig: this.config, ...args });
Expand Down
7 changes: 6 additions & 1 deletion src/api/aptos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { Account } from "./account";
import { AptosConfig } from "./aptos_config";
import { Coin } from "./coin";
import { Faucet } from "./faucet";
import { General } from "./general";
import { Transaction } from "./transaction";
Expand All @@ -13,6 +14,8 @@ export class Aptos {

readonly account: Account;

readonly coin: Coin;

readonly faucet: Faucet;

readonly general: General;
Expand Down Expand Up @@ -41,14 +44,15 @@ export class Aptos {
constructor(settings?: AptosConfig) {
this.config = new AptosConfig(settings);
this.account = new Account(this.config);
this.coin = new Coin(this.config);
this.faucet = new Faucet(this.config);
this.general = new General(this.config);
this.transaction = new Transaction(this.config);
this.transactionSubmission = new TransactionSubmission(this.config);
}
}

export interface Aptos extends Account, Faucet, General, Transaction, TransactionSubmission {}
export interface Aptos extends Account, Coin, Faucet, General, Transaction, TransactionSubmission {}

/**
In TypeScript, we can’t inherit or extend from more than one class,
Expand All @@ -72,6 +76,7 @@ function applyMixin(targetClass: any, baseClass: any, baseClassProp: string) {
}

applyMixin(Aptos, Account, "account");
applyMixin(Aptos, Coin, "coin");
applyMixin(Aptos, Faucet, "faucet");
applyMixin(Aptos, General, "general");
applyMixin(Aptos, Transaction, "transaction");
Expand Down
40 changes: 40 additions & 0 deletions src/api/coin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

import { Account } from "../core";
import { transaferCoinTransaction } from "../internal/coin";
import { SingleSignerTransaction, GenerateTransactionOptions } from "../transactions/types";
import { AnyNumber, HexInput, MoveResourceType } from "../types";
import { AptosConfig } from "./aptos_config";

/**
* A class to handle all `Coin` operations
*/
export class Coin {
readonly config: AptosConfig;

constructor(config: AptosConfig) {
this.config = config;
}

/**
* Generate a transfer coin transaction that can be simulated and/or signed and submitted
*
* @param args.sender The sender account
* @param args.recipient The recipient address
* @param args.amount The amount to transfer
* @param args.coinType optional. The coin struct type to transfer. Default to 0x1::aptos_coin::AptosCoin
*
* @returns SingleSignerTransaction
*/
async transaferCoinTransaction(args: {
sender: Account;
recipient: HexInput;
amount: AnyNumber;
coinType?: MoveResourceType;
options?: GenerateTransactionOptions;
}): Promise<SingleSignerTransaction> {
const response = await transaferCoinTransaction({ aptosConfig: this.config, ...args });
return response;
}
}
29 changes: 29 additions & 0 deletions src/api/transaction_submission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,4 +141,33 @@ export class TransactionSubmission {
const data = await submitTransaction({ aptosConfig: this.config, ...args });
return data;
}

/**
* Sign and submit a single signer transaction to chain
*
* @param args.signer The signer account to sign the transaction
* @param args.transaction A raw transaction type (note that it holds the raw transaction as a bcs serialized data)
* ```
* {
* rawTransaction: Uint8Array,
* secondarySignerAddresses? : Array<AccountAddress>,
* feePayerAddress?: AccountAddress
* }
* ```
*
* @return PendingTransactionResponse
*/
async signAndSubmitTransaction(args: {
signer: Account;
transaction: AnyRawTransaction;
}): Promise<PendingTransactionResponse> {
const { signer, transaction } = args;
const authenticator = signTransaction({ signer, transaction });
const response = await submitTransaction({
aptosConfig: this.config,
transaction,
senderAuthenticator: authenticator,
});
return response;
}
}
32 changes: 32 additions & 0 deletions src/internal/coin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { AptosConfig } from "../api/aptos_config";
import { U64 } from "../bcs/serializable/move-primitives";
import { Account, AccountAddress } from "../core";
import { GenerateTransactionOptions, SingleSignerTransaction } from "../transactions/types";
import { StructTag, TypeTagStruct } from "../transactions/typeTag/typeTag";
import { HexInput, AnyNumber, MoveResourceType } from "../types";
import { APTOS_COIN } from "../utils/const";
import { generateTransaction } from "./transaction_submission";

export async function transaferCoinTransaction(args: {
aptosConfig: AptosConfig;
sender: Account;
recipient: HexInput;
amount: AnyNumber;
coinType?: MoveResourceType;
options?: GenerateTransactionOptions;
}): Promise<SingleSignerTransaction> {
const { aptosConfig, sender, recipient, amount, coinType, options } = args;
const coinStructType = coinType ?? APTOS_COIN;
const transaction = await generateTransaction({
aptosConfig,
sender: sender.accountAddress.toString(),
data: {
function: "0x1::aptos_account::transfer_coins",
type_arguments: [new TypeTagStruct(StructTag.fromString(coinStructType))],
arguments: [AccountAddress.fromHexInput({ input: recipient }), new U64(amount)],
},
options,
});

return transaction as SingleSignerTransaction;
}
76 changes: 76 additions & 0 deletions tests/e2e/api/coin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { AptosConfig, Network, Aptos, Account, Deserializer } from "../../../src";
import { waitForTransaction } from "../../../src/internal/transaction";
import { RawTransaction, TransactionPayloadEntryFunction } from "../../../src/transactions/instances";
import { TypeTagStruct } from "../../../src/transactions/typeTag/typeTag";
import { SigningScheme } from "../../../src/types";

describe("coin", () => {
test("it generates a transfer coin transaction with AptosCoin coin type", async () => {
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);
const sender = Account.generate({ scheme: SigningScheme.Ed25519 });
const recipient = Account.generate({ scheme: SigningScheme.Ed25519 });
await aptos.fundAccount({ accountAddress: sender.accountAddress.toString(), amount: 100000000 });

const transaction = await aptos.transaferCoinTransaction({
sender,
recipient: recipient.accountAddress.toString(),
amount: 10,
});

const txnDeserializer = new Deserializer(transaction.rawTransaction);
const rawTransaction = RawTransaction.deserialize(txnDeserializer);
const typeArgs = (rawTransaction.payload as TransactionPayloadEntryFunction).entryFunction.type_args;
expect((typeArgs[0] as TypeTagStruct).value.address.toString()).toBe("0x1");
expect((typeArgs[0] as TypeTagStruct).value.module_name.identifier).toBe("aptos_coin");
expect((typeArgs[0] as TypeTagStruct).value.name.identifier).toBe("AptosCoin");
});

test("it generates a transfer coin transaction with a custom coin type", async () => {
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);
const sender = Account.generate({ scheme: SigningScheme.Ed25519 });
const recipient = Account.generate({ scheme: SigningScheme.Ed25519 });
await aptos.fundAccount({ accountAddress: sender.accountAddress.toString(), amount: 100000000 });

const transaction = await aptos.transaferCoinTransaction({
sender,
recipient: recipient.accountAddress.toString(),
amount: 10,
coinType: "0x1::my_coin::type",
});

const txnDeserializer = new Deserializer(transaction.rawTransaction);
const rawTransaction = RawTransaction.deserialize(txnDeserializer);
const typeArgs = (rawTransaction.payload as TransactionPayloadEntryFunction).entryFunction.type_args;
expect((typeArgs[0] as TypeTagStruct).value.address.toString()).toBe("0x1");
expect((typeArgs[0] as TypeTagStruct).value.module_name.identifier).toBe("my_coin");
expect((typeArgs[0] as TypeTagStruct).value.name.identifier).toBe("type");
});

test("it transfers APT coin aomunt from sender to recipient", async () => {
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);
const sender = Account.generate({ scheme: SigningScheme.Ed25519 });
const recipient = Account.generate({ scheme: SigningScheme.Ed25519 });

await aptos.fundAccount({ accountAddress: sender.accountAddress.toString(), amount: 100000000 });
const senderCoinsBefore = await aptos.getAccountCoinsData({ accountAddress: sender.accountAddress.toString() });

const transaction = await aptos.transaferCoinTransaction({
sender,
recipient: recipient.accountAddress.toString(),
amount: 10,
});
const response = await aptos.signAndSubmitTransaction({ signer: sender, transaction });

await waitForTransaction({ aptosConfig: config, txnHash: response.hash });

const recipientCoins = await aptos.getAccountCoinsData({ accountAddress: recipient.accountAddress.toString() });
const senderCoinsAfter = await aptos.getAccountCoinsData({ accountAddress: sender.accountAddress.toString() });

expect(recipientCoins[0].amount).toBe(10);
expect(recipientCoins[0].asset_type).toBe("0x1::aptos_coin::AptosCoin");
expect(senderCoinsAfter[0].amount).toBeLessThan(senderCoinsBefore[0].amount);
});
});

0 comments on commit 8bd5e09

Please sign in to comment.