@thalalabs/surf 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +196 -0
  3. package/build/cjs/core/Client.js +80 -0
  4. package/build/cjs/core/Client.js.map +1 -0
  5. package/build/cjs/core/WalletClient.js +52 -0
  6. package/build/cjs/core/WalletClient.js.map +1 -0
  7. package/build/cjs/core/createEntryPayload.js +91 -0
  8. package/build/cjs/core/createEntryPayload.js.map +1 -0
  9. package/build/cjs/core/createViewPayload.js +78 -0
  10. package/build/cjs/core/createViewPayload.js.map +1 -0
  11. package/build/cjs/core/index.js +13 -0
  12. package/build/cjs/core/index.js.map +1 -0
  13. package/build/cjs/ensureTypes.js +40 -0
  14. package/build/cjs/ensureTypes.js.map +1 -0
  15. package/build/cjs/hooks/index.js +8 -0
  16. package/build/cjs/hooks/index.js.map +1 -0
  17. package/build/cjs/hooks/useSubmitTransaction.js +88 -0
  18. package/build/cjs/hooks/useSubmitTransaction.js.map +1 -0
  19. package/build/cjs/hooks/useWalletClient.js +14 -0
  20. package/build/cjs/hooks/useWalletClient.js.map +1 -0
  21. package/build/cjs/index.js +8 -0
  22. package/build/cjs/index.js.map +1 -0
  23. package/build/cjs/package.json +1 -0
  24. package/build/cjs/types/abi.js +3 -0
  25. package/build/cjs/types/abi.js.map +1 -0
  26. package/build/cjs/types/abiClient.js +3 -0
  27. package/build/cjs/types/abiClient.js.map +1 -0
  28. package/build/cjs/types/client.js +3 -0
  29. package/build/cjs/types/client.js.map +1 -0
  30. package/build/cjs/types/common.js +3 -0
  31. package/build/cjs/types/common.js.map +1 -0
  32. package/build/cjs/types/index.js +3 -0
  33. package/build/cjs/types/index.js.map +1 -0
  34. package/build/cjs/types/walletClient.js +3 -0
  35. package/build/cjs/types/walletClient.js.map +1 -0
  36. package/build/esm/core/Client.js +75 -0
  37. package/build/esm/core/Client.js.map +1 -0
  38. package/build/esm/core/WalletClient.js +48 -0
  39. package/build/esm/core/WalletClient.js.map +1 -0
  40. package/build/esm/core/createEntryPayload.js +87 -0
  41. package/build/esm/core/createEntryPayload.js.map +1 -0
  42. package/build/esm/core/createViewPayload.js +74 -0
  43. package/build/esm/core/createViewPayload.js.map +1 -0
  44. package/build/esm/core/index.js +5 -0
  45. package/build/esm/core/index.js.map +1 -0
  46. package/build/esm/ensureTypes.js +34 -0
  47. package/build/esm/ensureTypes.js.map +1 -0
  48. package/build/esm/hooks/index.js +3 -0
  49. package/build/esm/hooks/index.js.map +1 -0
  50. package/build/esm/hooks/useSubmitTransaction.js +84 -0
  51. package/build/esm/hooks/useSubmitTransaction.js.map +1 -0
  52. package/build/esm/hooks/useWalletClient.js +10 -0
  53. package/build/esm/hooks/useWalletClient.js.map +1 -0
  54. package/build/esm/index.js +2 -0
  55. package/build/esm/index.js.map +1 -0
  56. package/build/esm/package.json +1 -0
  57. package/build/esm/types/abi.js +2 -0
  58. package/build/esm/types/abi.js.map +1 -0
  59. package/build/esm/types/abiClient.js +2 -0
  60. package/build/esm/types/abiClient.js.map +1 -0
  61. package/build/esm/types/client.js +2 -0
  62. package/build/esm/types/client.js.map +1 -0
  63. package/build/esm/types/common.js +2 -0
  64. package/build/esm/types/common.js.map +1 -0
  65. package/build/esm/types/index.js +2 -0
  66. package/build/esm/types/index.js.map +1 -0
  67. package/build/esm/types/walletClient.js +2 -0
  68. package/build/esm/types/walletClient.js.map +1 -0
  69. package/build/types/core/Client.d.ts +20 -0
  70. package/build/types/core/Client.d.ts.map +1 -0
  71. package/build/types/core/WalletClient.d.ts +17 -0
  72. package/build/types/core/WalletClient.d.ts.map +1 -0
  73. package/build/types/core/createEntryPayload.d.ts +4 -0
  74. package/build/types/core/createEntryPayload.d.ts.map +1 -0
  75. package/build/types/core/createViewPayload.d.ts +4 -0
  76. package/build/types/core/createViewPayload.d.ts.map +1 -0
  77. package/build/types/core/index.d.ts +5 -0
  78. package/build/types/core/index.d.ts.map +1 -0
  79. package/build/types/ensureTypes.d.ts +4 -0
  80. package/build/types/ensureTypes.d.ts.map +1 -0
  81. package/build/types/hooks/index.d.ts +3 -0
  82. package/build/types/hooks/index.d.ts.map +1 -0
  83. package/build/types/hooks/useSubmitTransaction.d.ts +19 -0
  84. package/build/types/hooks/useSubmitTransaction.d.ts.map +1 -0
  85. package/build/types/hooks/useWalletClient.d.ts +8 -0
  86. package/build/types/hooks/useWalletClient.d.ts.map +1 -0
  87. package/build/types/index.d.ts +3 -0
  88. package/build/types/index.d.ts.map +1 -0
  89. package/build/types/types/abi.d.ts +31 -0
  90. package/build/types/types/abi.d.ts.map +1 -0
  91. package/build/types/types/abiClient.d.ts +18 -0
  92. package/build/types/types/abiClient.d.ts.map +1 -0
  93. package/build/types/types/client.d.ts +24 -0
  94. package/build/types/types/client.d.ts.map +1 -0
  95. package/build/types/types/common.d.ts +60 -0
  96. package/build/types/types/common.d.ts.map +1 -0
  97. package/build/types/types/index.d.ts +5 -0
  98. package/build/types/types/index.d.ts.map +1 -0
  99. package/build/types/types/walletClient.d.ts +9 -0
  100. package/build/types/types/walletClient.d.ts.map +1 -0
  101. package/package.json +78 -0
  102. package/src/core/Client.ts +120 -0
  103. package/src/core/WalletClient.ts +64 -0
  104. package/src/core/__tests__/createEntryPayload.test.ts +262 -0
  105. package/src/core/__tests__/createViewPayload.test.ts +297 -0
  106. package/src/core/__tests__/submitTransaction.test.ts +112 -0
  107. package/src/core/__tests__/useABI.test.ts +139 -0
  108. package/src/core/__tests__/view.test.ts +145 -0
  109. package/src/core/createEntryPayload.ts +128 -0
  110. package/src/core/createViewPayload.ts +100 -0
  111. package/src/core/index.ts +4 -0
  112. package/src/ensureTypes.ts +42 -0
  113. package/src/hooks/index.ts +2 -0
  114. package/src/hooks/useSubmitTransaction.ts +117 -0
  115. package/src/hooks/useWalletClient.ts +10 -0
  116. package/src/index.ts +10 -0
  117. package/src/types/abi.ts +35 -0
  118. package/src/types/abiClient.ts +19 -0
  119. package/src/types/client.ts +32 -0
  120. package/src/types/common.ts +157 -0
  121. package/src/types/index.ts +9 -0
  122. package/src/types/walletClient.ts +10 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * These test cases depends on network, it call the real contract.
3
+ */
4
+
5
+ import { AptosAccount } from 'aptos';
6
+ import { COIN_ABI } from '../../abi/coin';
7
+ import { createClient } from '../Client';
8
+ import { createEntryPayload } from '../createEntryPayload';
9
+
10
+ describe('call entry functions', () => {
11
+ const client = createClient({
12
+ nodeUrl: 'https://fullnode.testnet.aptoslabs.com/v1',
13
+ });
14
+
15
+ const account = new AptosAccount(
16
+ undefined,
17
+ '0xac914efd2367c7aa42c95d100592c099e487d2270bf0e0761e5fe93ff4016593',
18
+ );
19
+
20
+ // Act before assertions
21
+ beforeAll(async () => {});
22
+
23
+ // Teardown (cleanup) after assertions
24
+ afterAll(() => {});
25
+
26
+ it('basic', async () => {
27
+ const entryPayload = createEntryPayload(COIN_ABI, {
28
+ function: 'transfer',
29
+ arguments: ['0x1', 1],
30
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
31
+ });
32
+
33
+ const result = await client.simulateTransaction(entryPayload, { account });
34
+
35
+ expect(result.hash).toBeDefined();
36
+ expect((result as any).payload).toMatchInlineSnapshot(`
37
+ {
38
+ "arguments": [
39
+ "0x1",
40
+ "1",
41
+ ],
42
+ "function": "0x1::coin::transfer",
43
+ "type": "entry_function_payload",
44
+ "type_arguments": [
45
+ "0x1::aptos_coin::AptosCoin",
46
+ ],
47
+ }
48
+ `);
49
+ }, 60000);
50
+
51
+ it('vector', async () => {
52
+ const entryPayload = createEntryPayload(TEST_ABI, {
53
+ function: 'test_run_function',
54
+ arguments: [[1, 2, 3, 10, 20, 30]],
55
+ type_arguments: [],
56
+ });
57
+
58
+ const result = await client.simulateTransaction(entryPayload, { account });
59
+
60
+ expect(result.hash).toBeDefined();
61
+ expect((result as any).payload).toMatchInlineSnapshot(`
62
+ {
63
+ "arguments": [
64
+ "0x0102030a141e",
65
+ ],
66
+ "function": "0x3d097bb505c9e5d8a96e367f371168240025877f6be8d4a88eacaafb709fe5c9::test::test_run_function",
67
+ "type": "entry_function_payload",
68
+ "type_arguments": [],
69
+ }
70
+ `);
71
+ }, 60000);
72
+ });
73
+
74
+ const TEST_ABI = {
75
+ address: '0x3d097bb505c9e5d8a96e367f371168240025877f6be8d4a88eacaafb709fe5c9',
76
+ name: 'test',
77
+ friends: [],
78
+ exposed_functions: [
79
+ {
80
+ name: 'test_run_function',
81
+ visibility: 'public',
82
+ is_entry: true,
83
+ is_view: false,
84
+ generic_type_params: [],
85
+ params: ['&signer', 'vector<u8>'],
86
+ return: [],
87
+ },
88
+ {
89
+ name: 'test_view_function',
90
+ visibility: 'public',
91
+ is_entry: false,
92
+ is_view: true,
93
+ generic_type_params: [],
94
+ params: ['vector<u8>'],
95
+ return: ['u8'],
96
+ },
97
+ ],
98
+ structs: [
99
+ {
100
+ name: 'RunFunctionStruct',
101
+ is_native: false,
102
+ abilities: ['key'],
103
+ generic_type_params: [],
104
+ fields: [
105
+ {
106
+ name: 'sum',
107
+ type: 'u8',
108
+ },
109
+ ],
110
+ },
111
+ ],
112
+ } as const;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * These test cases depends on network, it call the real contract.
3
+ */
4
+
5
+ import { AptosAccount } from 'aptos';
6
+ import { COIN_ABI } from '../../abi/coin';
7
+ import { createClient } from '../Client';
8
+
9
+ describe('useABI', () => {
10
+ const client = createClient({
11
+ nodeUrl: 'https://fullnode.testnet.aptoslabs.com/v1',
12
+ });
13
+
14
+ const account = new AptosAccount(
15
+ undefined,
16
+ '0xac914efd2367c7aa42c95d100592c099e487d2270bf0e0761e5fe93ff4016593',
17
+ );
18
+
19
+ // Act before assertions
20
+ beforeAll(async () => {});
21
+
22
+ // Teardown (cleanup) after assertions
23
+ afterAll(() => {});
24
+
25
+ it('basic type checking', async () => {
26
+ // no need to run, type check only
27
+ () => {
28
+ // @ts-expect-error cannot call a function not exist
29
+ client.useABI(COIN_ABI).view.not_exist_func({
30
+ arguments: ['0x1'],
31
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
32
+ });
33
+
34
+ // @ts-expect-error cannot call a entry function from view
35
+ client.useABI(COIN_ABI).view.transfer({
36
+ arguments: ['0x1'],
37
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
38
+ });
39
+
40
+ // @ts-expect-error cannot call a view function from entry
41
+ client.useABI(COIN_ABI).entry.balance({
42
+ arguments: ['0x1'],
43
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
44
+ });
45
+
46
+ client.useABI(TEST_ABI).view.address_as_input({
47
+ // @ts-expect-error require two args
48
+ arguments: ['0x1'],
49
+ type_arguments: [],
50
+ });
51
+
52
+ client.useABI(TEST_ABI).view.address_as_input({
53
+ // @ts-expect-error require address
54
+ arguments: ['0x1', 1],
55
+ type_arguments: [],
56
+ });
57
+
58
+ client.useABI(COIN_ABI).entry.transfer({
59
+ arguments: ['0x1', 1],
60
+ // @ts-expect-error require a type argument
61
+ type_arguments: [],
62
+ account
63
+ });
64
+
65
+ // @ts-expect-error account is required for entry function
66
+ client.useABI(COIN_ABI).entry.transfer({
67
+ arguments: ['0x1', 1],
68
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
69
+ });
70
+ }
71
+ });
72
+
73
+ it('view', async () => {
74
+ const result = await client.useABI(COIN_ABI).view.name({
75
+ arguments: [],
76
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
77
+ });
78
+ expect(result).toMatchInlineSnapshot(`
79
+ [
80
+ "Aptos Coin",
81
+ ]
82
+ `);
83
+
84
+ const result2 = await client.useABI(COIN_ABI).view.decimals({
85
+ arguments: [],
86
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
87
+ });
88
+ expect(result2).toMatchInlineSnapshot(`
89
+ [
90
+ 8,
91
+ ]
92
+ `);
93
+ }, 60000);
94
+
95
+ it('entry', async () => {
96
+ const result = await client.useABI(COIN_ABI).entry.transfer({
97
+ arguments: ['0x1', 1],
98
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
99
+ account,
100
+ isSimulation: true,
101
+ });
102
+ expect(result.hash).toBeDefined();
103
+ expect((result as any).payload).toMatchInlineSnapshot(`
104
+ {
105
+ "arguments": [
106
+ "0x1",
107
+ "1",
108
+ ],
109
+ "function": "0x1::coin::transfer",
110
+ "type": "entry_function_payload",
111
+ "type_arguments": [
112
+ "0x1::aptos_coin::AptosCoin",
113
+ ],
114
+ }
115
+ `);
116
+ }, 60000);
117
+ });
118
+
119
+ const TEST_ABI = {
120
+ "address": "0x123",
121
+ "name": "test",
122
+ "friends": [],
123
+ "exposed_functions": [
124
+ {
125
+ "name": "address_as_input",
126
+ "visibility": "public",
127
+ "is_entry": false,
128
+ "is_view": true,
129
+ "generic_type_params": [],
130
+ "params": [
131
+ "address",
132
+ "address",
133
+ ],
134
+ "return": []
135
+ },
136
+ ],
137
+ "structs": []
138
+ } as const;
139
+
@@ -0,0 +1,145 @@
1
+ /**
2
+ * These test cases depends on network, it call the real contract.
3
+ */
4
+
5
+ import { COIN_ABI } from '../../abi/coin';
6
+ import { createClient } from '../Client';
7
+ import { createViewPayload } from '../createViewPayload';
8
+
9
+ describe('call view functions', () => {
10
+ const client = createClient({
11
+ nodeUrl: 'https://fullnode.testnet.aptoslabs.com/v1',
12
+ });
13
+
14
+ const clientMain = createClient({
15
+ nodeUrl: 'https://fullnode.mainnet.aptoslabs.com/v1',
16
+ });
17
+
18
+ // Act before assertions
19
+ beforeAll(async () => { });
20
+
21
+ // Teardown (cleanup) after assertions
22
+ afterAll(() => { });
23
+
24
+ it('basic', async () => {
25
+ const viewPayload = createViewPayload(COIN_ABI, {
26
+ function: 'name',
27
+ arguments: [],
28
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
29
+ });
30
+ const result = await client.view(viewPayload);
31
+ expect(result).toMatchInlineSnapshot(`
32
+ [
33
+ "Aptos Coin",
34
+ ]
35
+ `);
36
+
37
+ const viewPayload2 = createViewPayload(COIN_ABI, {
38
+ function: 'decimals',
39
+ arguments: [],
40
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
41
+ });
42
+ const result2 = await client.view(viewPayload2);
43
+ expect(result2).toMatchInlineSnapshot(`
44
+ [
45
+ 8,
46
+ ]
47
+ `);
48
+ }, 60000);
49
+
50
+ it('vector', async () => {
51
+ const viewPayload = createViewPayload(TEST_ABI, {
52
+ function: 'test_view_function',
53
+ arguments: [[1, 2, 3, 10, 50]],
54
+ type_arguments: [],
55
+ });
56
+ const result = await client.view(viewPayload);
57
+ expect(result).toMatchInlineSnapshot(`
58
+ [
59
+ 66,
60
+ ]
61
+ `);
62
+ }, 60000);
63
+
64
+ it('struct', async () => {
65
+ const viewPayload = createViewPayload(TIERED_ORACLE_ABI, {
66
+ function: 'get_last_price',
67
+ arguments: [],
68
+ type_arguments: ['0x1::aptos_coin::AptosCoin'],
69
+ });
70
+
71
+ // The declaration in Move:
72
+ // struct FixedPoint64 has copy, drop, store { value: u128 }
73
+ const result = await clientMain.view(viewPayload);
74
+ expect(result.length).toBe(1);
75
+ expect((result[0] as any).v).toBeDefined();
76
+ expect(typeof (result[0] as any).v).toEqual("string");
77
+ }, 60000);
78
+ });
79
+
80
+ const TEST_ABI = {
81
+ address: '0x3d097bb505c9e5d8a96e367f371168240025877f6be8d4a88eacaafb709fe5c9',
82
+ name: 'test',
83
+ friends: [],
84
+ exposed_functions: [
85
+ {
86
+ name: 'test_run_function',
87
+ visibility: 'public',
88
+ is_entry: true,
89
+ is_view: false,
90
+ generic_type_params: [],
91
+ params: ['&signer', 'vector<u8>'],
92
+ return: [],
93
+ },
94
+ {
95
+ name: 'test_view_function',
96
+ visibility: 'public',
97
+ is_entry: false,
98
+ is_view: true,
99
+ generic_type_params: [],
100
+ params: ['vector<u8>'],
101
+ return: ['u8'],
102
+ },
103
+ ],
104
+ structs: [
105
+ {
106
+ name: 'RunFunctionStruct',
107
+ is_native: false,
108
+ abilities: ['key'],
109
+ generic_type_params: [],
110
+ fields: [
111
+ {
112
+ name: 'sum',
113
+ type: 'u8',
114
+ },
115
+ ],
116
+ },
117
+ ],
118
+ } as const;
119
+
120
+ const TIERED_ORACLE_ABI = {
121
+ "address": "0x92e95ed77b5ac815d3fbc2227e76db238339e9ca43ace45031ec2589bea5b8c",
122
+ "name": "tiered_oracle",
123
+ "friends": [
124
+ "0x92e95ed77b5ac815d3fbc2227e76db238339e9ca43ace45031ec2589bea5b8c::oracle"
125
+ ],
126
+ "exposed_functions": [
127
+ {
128
+ "name": "get_last_price",
129
+ "visibility": "public",
130
+ "is_entry": false,
131
+ "is_view": true,
132
+ "generic_type_params": [
133
+ {
134
+ "constraints": []
135
+ }
136
+ ],
137
+ "params": [],
138
+ "return": [
139
+ "0x4dcae85fc5559071906cd5c76b7420fcbb4b0a92f00ab40ffc394aadbbff5ee9::fixed_point64::FixedPoint64"
140
+ ]
141
+ },
142
+
143
+ ],
144
+ "structs": []
145
+ } as const;
@@ -0,0 +1,128 @@
1
+ import { BCS, TxnBuilderTypes, TypeTagParser } from "aptos";
2
+ import { ensureBigInt, ensureBoolean, ensureNumber } from "../ensureTypes";
3
+ import { ABIRoot, EntryPayload } from "../types";
4
+ import { EntryFunctionName, EntryRequestPayload } from "../types/common";
5
+
6
+ export function createEntryPayload<
7
+ T extends ABIRoot,
8
+ TFuncName extends EntryFunctionName<T>
9
+ >(
10
+ abi: T,
11
+ payload: EntryRequestPayload<T, TFuncName>
12
+ ): EntryPayload {
13
+ // TODO: remove unused variables
14
+ const fnAbi = abi.exposed_functions.filter(f => f.name === payload.function)[0];
15
+ const typeArguments: string[] = payload.type_arguments as any[];
16
+ const valArguments: any[] = payload.arguments as any[];
17
+ const abiArgs = fnAbi.params[0] === '&signer'
18
+ ? (fnAbi.params as string[]).slice(1)
19
+ : fnAbi.params as string[];
20
+
21
+ // Validations
22
+ if (fnAbi === undefined) throw new Error(`Function ${payload.function} not found in ABI`);
23
+ if (abiArgs.length !== valArguments.length) throw new Error(`Function ${payload.function} expects ${fnAbi.params.length} arguments, but ${payload.arguments.length} were provided`);
24
+ if (fnAbi.generic_type_params.length !== typeArguments.length) throw new Error(`Function ${payload.function} expects ${fnAbi.generic_type_params.length} type arguments, but ${payload.type_arguments.length} were provided`);
25
+
26
+ // TODO: make entryRequest lazy
27
+ return {
28
+ rawPayload: {
29
+ ...payload,
30
+ function: `${abi.address}::${abi.name}::${payload.function}`,
31
+ } as any,
32
+ entryRequest: TxnBuilderTypes.EntryFunction.natural(
33
+ `${abi.address}::${abi.name}`, // module id
34
+ payload.function, // function name
35
+ typeArguments // type arguments
36
+ .map((arg) => {
37
+ // The StructTag.fromString not support nested struct tag before aptos@1.8.4.
38
+ // So we use the TypeTagParser to parse the string literal into a TypeTagStruct
39
+ // For better compatibility.
40
+ // The next line of code is simpler, but not compatible with aptos below 1.8.3.
41
+ // return new TxnBuilderTypes.TypeTagStruct(TxnBuilderTypes.StructTag.fromString(arg));
42
+
43
+ // Use the TypeTagParser to parse the string literal into a TypeTagStruct
44
+ const typeTagStruct = new TypeTagParser(arg).parseTypeTag() as TxnBuilderTypes.TypeTagStruct;
45
+
46
+ // Convert and return as a StructTag
47
+ return new TxnBuilderTypes.TypeTagStruct(new TxnBuilderTypes.StructTag(
48
+ typeTagStruct.value.address,
49
+ typeTagStruct.value.module_name,
50
+ typeTagStruct.value.name,
51
+ typeTagStruct.value.type_args,
52
+ ));
53
+ }),
54
+ valArguments.map( // arguments
55
+ (arg, i) => {
56
+ const type = abiArgs[i];
57
+ const serializer = new BCS.Serializer();
58
+ argToBCS(type, arg, serializer);
59
+ return serializer.getBytes();
60
+ }
61
+ )
62
+ )
63
+ };
64
+ }
65
+
66
+
67
+ function argToBCS(type: string, arg: any, serializer: BCS.Serializer) {
68
+
69
+ const regex = /vector<([^]+)>/;
70
+ const match = type.match(regex);
71
+ if (match) { // It's vector
72
+ const innerType = match[1];
73
+ if (innerType === 'u8') {
74
+ if (arg instanceof Uint8Array) { // TODO: add type support for Uint8Array
75
+ serializer.serializeBytes(arg);
76
+ return;
77
+ }
78
+
79
+ if (typeof arg === "string") { // TODO: add type support for string
80
+ serializer.serializeStr(arg);
81
+ return;
82
+ }
83
+ }
84
+
85
+ if (!Array.isArray(arg)) {
86
+ throw new Error("Invalid vector args.");
87
+ }
88
+
89
+ serializer.serializeU32AsUleb128(arg.length);
90
+
91
+ arg.forEach((arg) => argToBCS(innerType, arg, serializer));
92
+ return;
93
+ }
94
+
95
+ // TODO: it's struct
96
+
97
+ switch (type) { // It's primitive
98
+ case 'bool':
99
+ serializer.serializeBool(ensureBoolean(arg));
100
+ break;
101
+ case 'address':
102
+ TxnBuilderTypes.AccountAddress.fromHex(arg as string).serialize(serializer);
103
+ break;
104
+ case 'u8':
105
+ serializer.serializeU8(ensureNumber(arg));
106
+ break;
107
+ case 'u16':
108
+ serializer.serializeU16(ensureNumber(arg));
109
+ break;
110
+ case 'u32':
111
+ serializer.serializeU32(ensureNumber(arg));
112
+ break;
113
+ case 'u64':
114
+ serializer.serializeU64(ensureBigInt(arg));
115
+ break;
116
+ case 'u128':
117
+ serializer.serializeU128(ensureBigInt(arg));
118
+ break;
119
+ case 'u256':
120
+ serializer.serializeU256(ensureBigInt(arg));
121
+ break;
122
+ case '0x1::string::String':
123
+ serializer.serializeStr(arg as string);
124
+ break;
125
+ default:
126
+ throw new Error(`type "${type}" not supported`);
127
+ }
128
+ }
@@ -0,0 +1,100 @@
1
+ import { HexString } from "aptos";
2
+ import { ABIRoot, ViewPayload } from "../types";
3
+ import { ExtractReturnType, ViewFunctionName, ViewRequestPayload } from "../types/common";
4
+ import { ensureNumber } from "../ensureTypes";
5
+
6
+ // TODO: support vector<u8> input with Uint8Array
7
+ // TODO: support vector<u8> input with string
8
+ export function createViewPayload<
9
+ T extends ABIRoot,
10
+ TFuncName extends ViewFunctionName<T>
11
+ >(
12
+ abi: T,
13
+ payload: ViewRequestPayload<T, TFuncName>
14
+ ):
15
+ ViewPayload<ExtractReturnType<T, TFuncName>> {
16
+ const fnAbi = abi.exposed_functions.filter(f => f.name === payload.function)[0];
17
+ const type_arguments: string[] = payload.type_arguments as any[];
18
+ const val_arguments: any[] = payload.arguments as any[];
19
+
20
+ // Validations
21
+ if (fnAbi === undefined) throw new Error(`Function ${payload.function} not found in ABI`);
22
+ if (fnAbi.params.length !== val_arguments.length) throw new Error(`Function ${payload.function} expects ${fnAbi.params.length} arguments, but ${payload.arguments.length} were provided`);
23
+ if (fnAbi.generic_type_params.length !== type_arguments.length) throw new Error(`Function ${payload.function} expects ${fnAbi.generic_type_params.length} type arguments, but ${payload.type_arguments.length} were provided`);
24
+
25
+ // TODO: do serialization here
26
+ const args = fnAbi.params.map((type, i) => {
27
+ if (['u8', 'u16', 'u32'].includes(type)) {
28
+ return ensureNumber(payload.arguments[i] as number);
29
+ }
30
+ else if (['u64', 'u128', 'u256'].includes(type)) {
31
+ return payload.arguments[i].toString();
32
+ }
33
+ else if (type.includes("vector")) {
34
+ return encodeVector(type, payload.arguments[i] as any[]);
35
+ }
36
+ else {
37
+ return payload.arguments[i];
38
+ }
39
+ });
40
+
41
+ // used to decode the return value in response
42
+ const decoders = fnAbi.return.map((type) => {
43
+ if (['u64', 'u128', 'u256'].includes(type)) {
44
+ return decodeBigint;
45
+ }
46
+ else {
47
+ return null;
48
+ }
49
+ });
50
+
51
+ return {
52
+ viewRequest: {
53
+ function: `${abi.address}::${abi.name}::${payload.function}`,
54
+ arguments: args,
55
+ type_arguments: payload.type_arguments as string[],
56
+ },
57
+ decoders,
58
+ };
59
+ }
60
+
61
+ function decodeBigint(value: string): bigint {
62
+ return BigInt(value);
63
+ }
64
+
65
+ function encodeVector(type: string, value: any[]) {
66
+ const regex = /vector<([^]+)>/;
67
+ const match = type.match(regex);
68
+ if (!match) {
69
+ // Should never happen
70
+ throw new Error(`Unsupported type: ${type}`);
71
+ }
72
+
73
+ if (match[1] === "u8") {
74
+ return (
75
+ HexString.fromUint8Array(
76
+ new Uint8Array(
77
+ value.map((v: number) => {
78
+ const result = ensureNumber(v);
79
+ if (result < 0 || result > 255)
80
+ throw new Error(`Invalid u8 value: ${result}`);
81
+ return result;
82
+ }),
83
+ ),
84
+ ) as any
85
+ ).hexString;
86
+ } else if (["u16", "u32"].includes(match[1])) {
87
+ // TODO: Figure out how to encode
88
+ return value;
89
+ } else if (["u64", "u128", "u256"].includes(match[1])) {
90
+ // TODO: Figure out how to encode
91
+ return value.map((v: bigint) => v.toString());
92
+ } else if (match[1] === "bool") {
93
+ // TODO: Figure out how to encode
94
+ return value;
95
+ } else {
96
+ // 1. Address type no need to encode
97
+ // 2. TODO: Figure out how to encode Struct type
98
+ return value;
99
+ }
100
+ }
@@ -0,0 +1,4 @@
1
+ export { WalletClient as MoveTsWalletClient } from "./WalletClient";
2
+ export { Client as MoveTsClient, createClient } from "./Client";
3
+ export { createViewPayload } from "./createViewPayload";
4
+ export { createEntryPayload } from "./createEntryPayload";
@@ -0,0 +1,42 @@
1
+ function assertType(val: any, types: string[] | string, message?: string) {
2
+ if (!types?.includes(typeof val)) {
3
+ throw new Error(
4
+ message || `Invalid arg: ${val} type should be ${types instanceof Array ? types.join(" or ") : types}`,
5
+ );
6
+ }
7
+ }
8
+
9
+ export function ensureBoolean(val: boolean | string): boolean {
10
+ assertType(val, ["boolean", "string"]);
11
+ if (typeof val === "boolean") {
12
+ return val;
13
+ }
14
+
15
+ if (val === "true") {
16
+ return true;
17
+ }
18
+ if (val === "false") {
19
+ return false;
20
+ }
21
+
22
+ throw new Error("Invalid boolean string.");
23
+ }
24
+
25
+ export function ensureNumber(val: number | string): number {
26
+ assertType(val, ["number", "string"]);
27
+ if (typeof val === "number") {
28
+ return val;
29
+ }
30
+
31
+ const res = Number.parseInt(val, 10);
32
+ if (Number.isNaN(res)) {
33
+ throw new Error("Invalid number string.");
34
+ }
35
+
36
+ return res;
37
+ }
38
+
39
+ export function ensureBigInt(val: number | bigint | string): bigint {
40
+ assertType(val, ["number", "bigint", "string"]);
41
+ return BigInt(val);
42
+ }
@@ -0,0 +1,2 @@
1
+ export { submitTransactionOptions, useSubmitTransaction } from "./useSubmitTransaction";
2
+ export { useWalletClient } from "./useWalletClient";