Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TS SDK] Update CoinClient to address #5648 and #5720 #5723

Merged
merged 1 commit into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions ecosystem/typescript/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ All notable changes to the Aptos Node SDK will be captured in this file. This ch

## Unreleased

- add missing fields to TokenData class
- add PropertyMap and PropertyValue type to match on-chain data
- support token property map deseralizer to read the property map in the original data format.
- Add missing fields to TokenData class
- Add PropertyMap and PropertyValue type to match on-chain data
- Support token property map deseralizer to read the property map in the original data format.
- Allow `checkBalance` in `CoinClient` to take in a `MaybeHexString` as well as `AptosAccount`, since users might want to check the balance of accounts they don't own (which is generally how you use `AptosAccount`).
- Similar to `checkBalance`, allow `transfer` in `CoinClient` to take in a `MaybeHexString` for the `receiver` argument.
- Add a new `createReceiverIfMissing` argument to `transfer` in `CoinClient`. If set, the `0x1::aptos_account::transfer` function will be called instead of `0x1::coin::transfer`, which will create the account on chain if it doesn't exist instead of failing.


## 1.3.17 (2022-11-08)
Expand Down
25 changes: 22 additions & 3 deletions ecosystem/typescript/sdk/src/abis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,26 @@ export const TOKEN_TRANSFER_OPT_IN =

/*
Follow these steps to get the ABI strings:
1. Compile the Move packages with Aptos CLI. e.g. aptos move compile --package-dir ./aptos-move/framework/aptos-token
2. Find the ABI files under the `build` directory and convert the ABI files to hex strings. On Mac and Linux, this can
be done with `cat <ABI_FILE_PATH> | od -v -t x1 -A n | tr -d ' \n'`

Go to the package directory of the relevant Move module, e.g. if you're trying
to get the ABI for the `transfer` function of `aptos_account.move`, go to
the directory `aptos-move/framework/aptos-framework`.

Compile the Move packages with the Aptos CLI:
```
aptos move compile --included-artifacts all
```
This `--included-artifacts all` argument is necessary to generate ABIs.

Find the ABI files under the `build` directory and convert the ABI files to hex strings.
On Mac and Linux, this can be done with this command:
```
cat <ABI_FILE_PATH> | od -v -t x1 -A n | tr -d ' \n'
```
For example:
```
cat build/AptosFramework/abis/aptos_account/transfer.abi | od -v -t x1 -A n | tr -d ' \n'
```
*/
export const TOKEN_ABIS = [
// aptos-token/build/AptosToken/abis/token/create_collection_script.abi
Expand Down Expand Up @@ -39,4 +56,6 @@ export const TOKEN_ABIS = [
export const COIN_ABIS = [
// aptos-framework/build/AptosFramework/abis/coin/transfer.abi
"01087472616E73666572000000000000000000000000000000000000000000000000000000000000000104636F696E3C205472616E73666572732060616D6F756E7460206F6620636F696E732060436F696E54797065602066726F6D206066726F6D6020746F2060746F602E0109636F696E5F747970650202746F0406616D6F756E7402",
// aptos-framework/build/AptosFramework/abis/aptos_account/transfer.abi
"01087472616e7366657200000000000000000000000000000000000000000000000000000000000000010d6170746f735f6163636f756e7400000202746f0406616d6f756e7402",
];
12 changes: 11 additions & 1 deletion ecosystem/typescript/sdk/src/aptos_account.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

import { AptosAccount, AptosAccountObject } from "./aptos_account";
import { AptosAccount, AptosAccountObject, getAddressFromAccountOrAddress } from "./aptos_account";
import { HexString } from "./hex_string";

const aptosAccountObject: AptosAccountObject = {
address: "0x978c213990c4833df71548df7ce49d54c759d6b6d932de22b24d56060b7af2aa",
Expand Down Expand Up @@ -74,3 +75,12 @@ test("Gets the resource account address", () => {
"0xcbed05b37b6981a57f535c1f5d136734df822abaf4cd30c51c9b4d60eae79d5d",
);
});

test("Test getAddressFromAccountOrAddress", () => {
const account = AptosAccount.fromAptosAccountObject(aptosAccountObject);
expect(getAddressFromAccountOrAddress(aptosAccountObject.address!).toString()).toBe(aptosAccountObject.address);
expect(getAddressFromAccountOrAddress(HexString.ensure(aptosAccountObject.address!)).toString()).toBe(
aptosAccountObject.address,
);
expect(getAddressFromAccountOrAddress(account).toString()).toBe(aptosAccountObject.address);
});
5 changes: 5 additions & 0 deletions ecosystem/typescript/sdk/src/aptos_account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,8 @@ export class AptosAccount {
};
}
}

// Returns an account address as a HexString given either an AptosAccount or a MaybeHexString.
export function getAddressFromAccountOrAddress(accountOrAddress: AptosAccount | MaybeHexString): HexString {
return accountOrAddress instanceof AptosAccount ? accountOrAddress.address() : HexString.ensure(accountOrAddress);
}
11 changes: 10 additions & 1 deletion ecosystem/typescript/sdk/src/coin_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AptosAccount } from "./aptos_account";
import { CoinClient } from "./coin_client";

test(
"transferCoins and checkBalance works",
"transfer and checkBalance works",
async () => {
const client = new AptosClient(NODE_URL);
const faucetClient = getFaucetClient();
Expand All @@ -21,6 +21,15 @@ test(
await client.waitForTransaction(await coinClient.transfer(alice, bob, 42), { checkSuccess: true });

expect(await coinClient.checkBalance(bob)).toBe(BigInt(42));

// Test that `createReceiverIfMissing` works.
const jemima = new AptosAccount();
await client.waitForTransaction(await coinClient.transfer(alice, jemima, 717, { createReceiverIfMissing: true }), {
checkSuccess: true,
});

// Check that using a string address instead of an account works with `checkBalance`.
expect(await coinClient.checkBalance(jemima.address().hex())).toBe(BigInt(717));
},
longTestTimeout,
);
54 changes: 37 additions & 17 deletions ecosystem/typescript/sdk/src/coin_client.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

import { AptosAccount } from "./aptos_account";
import { AptosAccount, getAddressFromAccountOrAddress } from "./aptos_account";
import { AptosClient, OptionalTransactionArgs } from "./aptos_client";
import { HexString } from "./hex_string";
import { HexString, MaybeHexString } from "./hex_string";
import { TransactionBuilderABI } from "./transaction_builder";
import { COIN_ABIS } from "./abis";
import { APTOS_COIN } from "./utils";
Expand All @@ -28,7 +28,14 @@ export class CoinClient {

/**
* Generate, sign, and submit a transaction to the Aptos blockchain API to
* transfer AptosCoin from one account to another.
* transfer coins from one account to another. By default it transfers
* 0x1::aptos_coin::AptosCoin, but you can specify a different coin type
* with the `coinType` argument.
*
* You may set `createReceiverIfMissing` to true if you want to create the
* receiver account if it does not exist on chain yet. If you do not set
* this to true, the transaction will fail if the receiver account does not
* exist on-chain.
*
* @param from Account sending the coins
* @param to Account to receive the coins
Expand All @@ -40,44 +47,57 @@ export class CoinClient {
// :!:>transfer
async transfer(
from: AptosAccount,
to: AptosAccount,
to: AptosAccount | MaybeHexString,
amount: number | bigint,
extraArgs?: OptionalTransactionArgs & {
// The coin type to use, defaults to 0x1::aptos_coin::AptosCoin
coinType?: string;
// If set, create the `receiver` account if it doesn't exist on-chain.
// This is done by calling `0x1::aptos_account::transfer` instead, which
// will create the account on-chain first if it doesn't exist before
// transferring the coins to it.
createReceiverIfMissing?: boolean;
},
): Promise<string> {
// If none is explicitly given, use 0x1::aptos_coin::AptosCoin as the coin type.
const coinTypeToTransfer = extraArgs?.coinType ?? APTOS_COIN;
const payload = this.transactionBuilder.buildTransactionPayload(
"0x1::coin::transfer",
[coinTypeToTransfer],
[to.address(), amount],
);

// If we should create the receiver account if it doesn't exist on-chain,
// use the `0x1::aptos_account::transfer` function.
const func = extraArgs?.createReceiverIfMissing ? "0x1::aptos_account::transfer" : "0x1::coin::transfer";

// If we're using the `0x1::aptos_account::transfer` function, we don't
// need type args.
const typeArgs = extraArgs?.createReceiverIfMissing ? [] : [coinTypeToTransfer];

// Get the receiver address from the AptosAccount or MaybeHexString.
const toAddress = getAddressFromAccountOrAddress(to);

const payload = this.transactionBuilder.buildTransactionPayload(func, typeArgs, [toAddress, amount]);

return this.aptosClient.generateSignSubmitTransaction(from, payload, extraArgs);
} // <:!:transfer

/**
* Generate, submit, and wait for a transaction to transfer AptosCoin from
* one account to another.
*
* If the transaction is submitted successfully, it returns the response
* from the API indicating that the transaction was submitted.
* Get the balance of the account. By default it checks the balance of
* 0x1::aptos_coin::AptosCoin, but you can specify a different coin type.
*
* @param account Account that you want to check the balance of.
* @param account Account that you want to get the balance of.
* @param extraArgs Extra args for checking the balance.
* @returns Promise that resolves to the balance as a bigint.
*/
// :!:>checkBalance
async checkBalance(
account: AptosAccount,
account: AptosAccount | MaybeHexString,
extraArgs?: {
// The coin type to use, defaults to 0x1::aptos_coin::AptosCoin
coinType?: string;
},
): Promise<bigint> {
const coinType = extraArgs?.coinType ?? APTOS_COIN;
const typeTag = `0x1::coin::CoinStore<${coinType}>`;
const resources = await this.aptosClient.getAccountResources(account.address());
const address = getAddressFromAccountOrAddress(account);
const resources = await this.aptosClient.getAccountResources(address);
const accountResource = resources.find((r) => r.type === typeTag);
return BigInt((accountResource!.data as any).coin.value);
} // <:!:checkBalance
Expand Down