From 7af3db1354c2ff629178bf6fbdac490623d020b5 Mon Sep 17 00:00:00 2001 From: Greg Nazario Date: Tue, 24 Oct 2023 22:06:36 -0700 Subject: [PATCH] [account] Add ability for custom typed resource calls (#109) --- CHANGELOG.md | 1 + examples/typescript/multi_agent_transfer.ts | 8 ++- examples/typescript/simple_transfer.ts | 8 ++- examples/typescript/transfer_coin.ts | 8 ++- src/api/account.ts | 11 ++-- src/internal/account.ts | 13 +++-- tests/e2e/api/account.test.ts | 58 ++++++++++++++++++--- tests/e2e/api/faucet.test.ts | 5 +- tests/e2e/api/general.test.ts | 2 +- 9 files changed, 87 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 659a279b3..b8bf65e91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to the Aptos TypeScript SDK will be captured in this file. T - Fix client config not being added to the request - Support to config a custom client instance - Changed all Regex based inputs requiring a `0x` to be optional. This is to allow for easier copy/pasting of addresses and keys. +- Change GetAccountResource to take in a generic output type that matches the struct ## 0.0.0 (2023-10-18) diff --git a/examples/typescript/multi_agent_transfer.ts b/examples/typescript/multi_agent_transfer.ts index 8e6bad176..5de01d1a6 100644 --- a/examples/typescript/multi_agent_transfer.ts +++ b/examples/typescript/multi_agent_transfer.ts @@ -20,8 +20,12 @@ const TRANSFER_AMOUNT = 10; * */ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { - let resource = await aptos.getAccountResource({ accountAddress: address.toUint8Array(), resourceType: COIN_STORE }); - let amount = Number((resource.data as { coin: { value: string } }).coin.value); + type Coin = { coin: { value: string } }; + let resource = await aptos.getAccountResource({ + accountAddress: address.toUint8Array(), + resourceType: COIN_STORE, + }); + let amount = Number(resource.coin.value); console.log(`${name}'s balance is: ${amount}`); return amount; diff --git a/examples/typescript/simple_transfer.ts b/examples/typescript/simple_transfer.ts index c91a0873f..0560b2d72 100644 --- a/examples/typescript/simple_transfer.ts +++ b/examples/typescript/simple_transfer.ts @@ -20,8 +20,12 @@ const TRANSFER_AMOUNT = 100; * */ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { - let resource = await aptos.getAccountResource({ accountAddress: address.toUint8Array(), resourceType: COIN_STORE }); - let amount = Number((resource.data as { coin: { value: string } }).coin.value); + type Coin = { coin: { value: string } }; + let resource = await aptos.getAccountResource({ + accountAddress: address.toUint8Array(), + resourceType: COIN_STORE, + }); + let amount = Number(resource.coin.value); console.log(`${name}'s balance is: ${amount}`); return amount; diff --git a/examples/typescript/transfer_coin.ts b/examples/typescript/transfer_coin.ts index 3561a328b..7dd330da3 100644 --- a/examples/typescript/transfer_coin.ts +++ b/examples/typescript/transfer_coin.ts @@ -19,8 +19,12 @@ const TRANSFER_AMOUNT = 1_000_000; * */ const balance = async (aptos: Aptos, name: string, address: AccountAddress) => { - let resource = await aptos.getAccountResource({ accountAddress: address.toUint8Array(), resourceType: COIN_STORE }); - let amount = Number((resource.data as { coin: { value: string } }).coin.value); + type Coin = { coin: { value: string } }; + let resource = await aptos.getAccountResource({ + accountAddress: address.toUint8Array(), + resourceType: COIN_STORE, + }); + let amount = Number(resource.coin.value); console.log(`${name}'s balance is: ${amount}`); return amount; diff --git a/src/api/account.ts b/src/api/account.ts index 9687e2665..6c3427699 100644 --- a/src/api/account.ts +++ b/src/api/account.ts @@ -155,8 +155,10 @@ export class Account { } /** - * Queries a specific account resource given account address and resource type + * Queries a specific account resource given account address and resource type. Note that the default is `any` in order + * to allow for ease of accessing properties of the object. * + * @type The typed output of the resource * @param args.accountAddress Aptos account address * @param args.resourceType String representation of an on-chain Move struct type, i.e "0x1::aptos_coin::AptosCoin" * @param args.options.ledgerVersion The ledger version to query, if not provided it will get the latest version @@ -166,17 +168,16 @@ export class Account { * @example An example of an account resource * ``` * { - * type: "0x1::aptos_coin::AptosCoin", * data: { value: 6 } * } * ``` */ - async getAccountResource(args: { + async getAccountResource(args: { accountAddress: HexInput; resourceType: MoveResourceType; options?: LedgerVersion; - }): Promise { - return getResource({ aptosConfig: this.config, ...args }); + }): Promise { + return getResource({ aptosConfig: this.config, ...args }); } /** diff --git a/src/internal/account.ts b/src/internal/account.ts index 20aa454d2..c2b9befae 100644 --- a/src/internal/account.ts +++ b/src/internal/account.ts @@ -155,12 +155,12 @@ export async function getResources(args: { }); } -export async function getResource(args: { +export async function getResource(args: { aptosConfig: AptosConfig; accountAddress: HexInput; resourceType: MoveResourceType; options?: LedgerVersion; -}): Promise { +}): Promise { const { aptosConfig, accountAddress, resourceType, options } = args; const { data } = await getAptosFullNode<{}, MoveResource>({ aptosConfig, @@ -168,7 +168,7 @@ export async function getResource(args: { path: `accounts/${AccountAddress.fromHexInput(accountAddress).toString()}/resource/${resourceType}`, params: { ledger_version: options?.ledgerVersion }, }); - return data; + return data.data as T; } export async function lookupOriginalAccountAddress(args: { @@ -177,7 +177,10 @@ export async function lookupOriginalAccountAddress(args: { options?: LedgerVersion; }): Promise { const { aptosConfig, authenticationKey, options } = args; - const resource = await getResource({ + type OriginatingAddress = { + address_map: { handle: string }; + }; + const resource = await getResource({ aptosConfig, accountAddress: "0x1", resourceType: "0x1::account::OriginatingAddress", @@ -186,7 +189,7 @@ export async function lookupOriginalAccountAddress(args: { const { address_map: { handle }, - } = resource.data as any; + } = resource; // If the address is not found in the address map, which means its not rotated // then return the address as is diff --git a/tests/e2e/api/account.test.ts b/tests/e2e/api/account.test.ts index 7344b5a94..21c4515ae 100644 --- a/tests/e2e/api/account.test.ts +++ b/tests/e2e/api/account.test.ts @@ -68,22 +68,64 @@ describe("account api", () => { expect(data.length).toBeGreaterThan(0); }); - test("it fetches an account resource", async () => { + test("it fetches an account resource without a type", async () => { const config = new AptosConfig({ network: Network.LOCAL }); const aptos = new Aptos(config); const data = await aptos.getAccountResource({ accountAddress: "0x1", resourceType: "0x1::account::Account", }); - expect(data).toHaveProperty("type"); - expect(data.type).toBe("0x1::account::Account"); + expect(data).toHaveProperty("sequence_number"); + expect(data.sequence_number).toBe("0"); + expect(data).toHaveProperty("authentication_key"); + expect(data.authentication_key).toBe("0x0000000000000000000000000000000000000000000000000000000000000001"); + }); + + test("it fetches an account resource typed", async () => { + const config = new AptosConfig({ network: Network.LOCAL }); + const aptos = new Aptos(config); + type AccountRes = { + authentication_key: string; + coin_register_events: { + counter: string; + guid: { + id: { + addr: string; + creation_num: string; + }; + }; + }; + guid_creation_num: string; + key_rotation_events: { + counter: string; + guid: { + id: { + addr: string; + creation_num: string; + }; + }; + }; + sequence_number: string; + }; + + const resource = await aptos.getAccountResource({ + accountAddress: "0x1", + resourceType: "0x1::account::Account", + }); + expect(resource).toHaveProperty("sequence_number"); + expect(resource.sequence_number).toBe("0"); + expect(resource).toHaveProperty("authentication_key"); + expect(resource.authentication_key).toBe("0x0000000000000000000000000000000000000000000000000000000000000001"); }); test("it fetches account transactions", async () => { const config = new AptosConfig({ network: Network.LOCAL }); const aptos = new Aptos(config); const senderAccount = Account.generate(); - await aptos.fundAccount({ accountAddress: senderAccount.accountAddress.toString(), amount: FUND_AMOUNT }); + await aptos.fundAccount({ + accountAddress: senderAccount.accountAddress.toString(), + amount: FUND_AMOUNT, + }); const bob = Account.generate(); const rawTxn = await aptos.generateTransaction({ sender: senderAccount.accountAddress.toString(), @@ -220,15 +262,15 @@ describe("account api", () => { expect(data.length).toBeGreaterThan(0); }); - test("it fetches an account resource", async () => { + test("it fetches an account resource with partial information", async () => { const config = new AptosConfig({ network: Network.LOCAL }); const aptos = new Aptos(config); - const data = await aptos.getAccountResource({ + const data = await aptos.getAccountResource<{ authentication_key: string }>({ accountAddress: "0x1", resourceType: "0x1::account::Account", }); - expect(data).toHaveProperty("type"); - expect(data.type).toBe("0x1::account::Account"); + expect(data).toHaveProperty("authentication_key"); + expect(data.authentication_key).toBe("0x0000000000000000000000000000000000000000000000000000000000000001"); }); }); }); diff --git a/tests/e2e/api/faucet.test.ts b/tests/e2e/api/faucet.test.ts index 7866451b5..fa6386be9 100644 --- a/tests/e2e/api/faucet.test.ts +++ b/tests/e2e/api/faucet.test.ts @@ -14,11 +14,12 @@ describe("Faucet", () => { await aptos.fundAccount({ accountAddress: testAccount.accountAddress.toString(), amount: FUND_AMOUNT }); // Check the balance - const resource = await aptos.getAccountResource({ + type Coin = { coin: { value: string } }; + const resource = await aptos.getAccountResource({ accountAddress: testAccount.accountAddress.toString(), resourceType: "0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>", }); - const amount = Number((resource.data as { coin: { value: string } }).coin.value); + const amount = Number(resource.coin.value); expect(amount).toBe(FUND_AMOUNT); }); }); diff --git a/tests/e2e/api/general.test.ts b/tests/e2e/api/general.test.ts index 634a81ef5..5cb9352ca 100644 --- a/tests/e2e/api/general.test.ts +++ b/tests/e2e/api/general.test.ts @@ -65,7 +65,7 @@ describe("general api", () => { }, ], }, - } = resource.data as any; + } = resource as any; const supply = await aptos.getTableItem({ handle,