@0xobelisk/client 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 (38) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +1 -0
  3. package/dist/index.d.ts +6 -0
  4. package/dist/index.js +757 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/index.mjs +755 -0
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/libs/suiAccountManager/crypto.d.ts +1 -0
  9. package/dist/libs/suiAccountManager/index.d.ts +35 -0
  10. package/dist/libs/suiAccountManager/keypair.d.ts +21 -0
  11. package/dist/libs/suiAccountManager/types.d.ts +9 -0
  12. package/dist/libs/suiAccountManager/util.d.ts +29 -0
  13. package/dist/libs/suiRpcProvider/defaultChainConfigs.d.ts +8 -0
  14. package/dist/libs/suiRpcProvider/faucet.d.ts +8 -0
  15. package/dist/libs/suiRpcProvider/index.d.ts +40 -0
  16. package/dist/libs/suiRpcProvider/types.d.ts +14 -0
  17. package/dist/libs/suiTxBuilder/index.d.ts +544 -0
  18. package/dist/libs/suiTxBuilder/types.d.ts +12 -0
  19. package/dist/libs/suiTxBuilder/util.d.ts +76 -0
  20. package/dist/obelisk.d.ts +2857 -0
  21. package/dist/test/tsconfig.tsbuildinfo +1 -0
  22. package/dist/types/index.d.ts +11 -0
  23. package/package.json +152 -0
  24. package/src/index.ts +10 -0
  25. package/src/libs/suiAccountManager/crypto.ts +7 -0
  26. package/src/libs/suiAccountManager/index.ts +72 -0
  27. package/src/libs/suiAccountManager/keypair.ts +38 -0
  28. package/src/libs/suiAccountManager/types.ts +10 -0
  29. package/src/libs/suiAccountManager/util.ts +70 -0
  30. package/src/libs/suiRpcProvider/defaultChainConfigs.ts +30 -0
  31. package/src/libs/suiRpcProvider/faucet.ts +57 -0
  32. package/src/libs/suiRpcProvider/index.ts +114 -0
  33. package/src/libs/suiRpcProvider/types.ts +17 -0
  34. package/src/libs/suiTxBuilder/index.ts +245 -0
  35. package/src/libs/suiTxBuilder/types.ts +32 -0
  36. package/src/libs/suiTxBuilder/util.ts +84 -0
  37. package/src/obelisk.ts +297 -0
  38. package/src/types/index.ts +17 -0
@@ -0,0 +1,114 @@
1
+ import {
2
+ Connection,
3
+ JsonRpcProvider,
4
+ getObjectType,
5
+ getObjectId,
6
+ getObjectFields,
7
+ getObjectDisplay,
8
+ getObjectVersion,
9
+ } from '@mysten/sui.js';
10
+ import { requestFaucet } from './faucet';
11
+ import { getDefaultNetworkParams } from './defaultChainConfigs';
12
+ import type { ObjectData, SuiRpcProviderParams } from './types';
13
+
14
+ export class SuiRpcProvider {
15
+ public fullnodeUrl: string;
16
+ public faucetUrl?: string;
17
+ public provider: JsonRpcProvider;
18
+ /**
19
+ *
20
+ * @param networkType, 'testnet' | 'mainnet' | 'devnet' | 'localnet', default is 'devnet'
21
+ * @param fullnodeUrl, the fullnode url, default is the preconfig fullnode url for the given network type
22
+ * @param faucetUrl, the faucet url, default is the preconfig faucet url for the given network type
23
+ */
24
+ constructor({
25
+ fullnodeUrl,
26
+ faucetUrl,
27
+ networkType,
28
+ }: SuiRpcProviderParams = {}) {
29
+ // Get the default fullnode url and faucet url for the given network type, default is 'testnet'
30
+ const defaultNetworkParams = getDefaultNetworkParams(
31
+ networkType || 'devnet'
32
+ );
33
+ // Set fullnodeUrl and faucetUrl, if they are not provided, use the default value.
34
+ this.fullnodeUrl = fullnodeUrl || defaultNetworkParams.fullnode;
35
+ this.faucetUrl = faucetUrl || defaultNetworkParams.faucet;
36
+
37
+ // Init the provider
38
+ const connection = new Connection({
39
+ fullnode: this.fullnodeUrl,
40
+ faucet: this.faucetUrl,
41
+ });
42
+ this.provider = new JsonRpcProvider(connection);
43
+ }
44
+
45
+ /**
46
+ * Request some SUI from faucet
47
+ * @Returns {Promise<boolean>}, true if the request is successful, false otherwise.
48
+ */
49
+ async requestFaucet(addr: string) {
50
+ return requestFaucet(addr, this.provider);
51
+ }
52
+
53
+ async getBalance(addr: string, coinType?: string) {
54
+ return this.provider.getBalance({ owner: addr, coinType });
55
+ }
56
+
57
+ async getObjects(ids: string[]) {
58
+ const options = { showContent: true, showDisplay: true, showType: true };
59
+ const objects = await this.provider.multiGetObjects({ ids, options });
60
+ const parsedObjects = objects.map((object) => {
61
+ const objectId = getObjectId(object);
62
+ const objectType = getObjectType(object);
63
+ const objectVersion = getObjectVersion(object);
64
+ const objectFields = getObjectFields(object);
65
+ const objectDisplay = getObjectDisplay(object);
66
+ return {
67
+ objectId,
68
+ objectType,
69
+ objectVersion,
70
+ objectFields,
71
+ objectDisplay,
72
+ };
73
+ });
74
+ return parsedObjects as ObjectData[];
75
+ }
76
+
77
+ /**
78
+ * @description Select coins that add up to the given amount.
79
+ * @param addr the address of the owner
80
+ * @param amount the amount that is needed for the coin
81
+ * @param coinType the coin type, default is '0x2::SUI::SUI'
82
+ */
83
+ async selectCoins(
84
+ addr: string,
85
+ amount: number,
86
+ coinType: string = '0x2::SUI::SUI'
87
+ ) {
88
+ const coins = await this.provider.getCoins({ owner: addr, coinType });
89
+ const selectedCoins: {
90
+ objectId: string;
91
+ digest: string;
92
+ version: string;
93
+ }[] = [];
94
+ let totalAmount = 0;
95
+ // Sort the coins by balance in descending order
96
+ coins.data.sort((a, b) => parseInt(b.balance) - parseInt(a.balance));
97
+ for (const coinData of coins.data) {
98
+ selectedCoins.push({
99
+ objectId: coinData.coinObjectId,
100
+ digest: coinData.digest,
101
+ version: coinData.version,
102
+ });
103
+ totalAmount = totalAmount + parseInt(coinData.balance);
104
+ if (totalAmount >= amount) {
105
+ break;
106
+ }
107
+ }
108
+
109
+ if (!selectedCoins.length) {
110
+ throw new Error('No valid coins found for the transaction.');
111
+ }
112
+ return selectedCoins;
113
+ }
114
+ }
@@ -0,0 +1,17 @@
1
+ import { DisplayFieldsResponse, ObjectContentFields } from '@mysten/sui.js';
2
+
3
+ export type NetworkType = 'testnet' | 'mainnet' | 'devnet' | 'localnet';
4
+
5
+ export type ObjectData = {
6
+ objectId: string;
7
+ objectType: string;
8
+ objectVersion: number;
9
+ objectDisplay: DisplayFieldsResponse;
10
+ objectFields: ObjectContentFields;
11
+ };
12
+
13
+ export type SuiRpcProviderParams = {
14
+ fullnodeUrl?: string;
15
+ faucetUrl?: string;
16
+ networkType?: NetworkType;
17
+ };
@@ -0,0 +1,245 @@
1
+ import {
2
+ TransactionBlock,
3
+ SUI_SYSTEM_STATE_OBJECT_ID,
4
+ TransactionExpiration,
5
+ SuiObjectRef,
6
+ SharedObjectRef,
7
+ JsonRpcProvider,
8
+ TransactionType,
9
+ Transactions,
10
+ ObjectCallArg,
11
+ } from '@mysten/sui.js';
12
+ import { convertArgs } from './util';
13
+ import type { SuiTxArg, SuiObjectArg, SuiVecTxArg } from './types';
14
+
15
+ export class SuiTxBlock {
16
+ public txBlock: TransactionBlock;
17
+ constructor(transaction?: TransactionBlock) {
18
+ this.txBlock = new TransactionBlock(transaction);
19
+ }
20
+
21
+ //======== override methods of TransactionBlock ============
22
+
23
+ address(value: string) {
24
+ return this.txBlock.pure(value, 'address');
25
+ }
26
+ pure(value: unknown, type?: string) {
27
+ return this.txBlock.pure(value, type);
28
+ }
29
+ object(value: string | ObjectCallArg) {
30
+ return this.txBlock.object(value);
31
+ }
32
+ objectRef(ref: SuiObjectRef) {
33
+ return this.txBlock.objectRef(ref);
34
+ }
35
+ sharedObjectRef(ref: SharedObjectRef) {
36
+ return this.txBlock.sharedObjectRef(ref);
37
+ }
38
+ setSender(sender: string) {
39
+ return this.txBlock.setSender(sender);
40
+ }
41
+ setSenderIfNotSet(sender: string) {
42
+ return this.txBlock.setSenderIfNotSet(sender);
43
+ }
44
+ setExpiration(expiration?: TransactionExpiration) {
45
+ return this.txBlock.setExpiration(expiration);
46
+ }
47
+ setGasPrice(price: number | bigint) {
48
+ return this.txBlock.setGasPrice(price);
49
+ }
50
+ setGasBudget(budget: number | bigint) {
51
+ return this.txBlock.setGasBudget(budget);
52
+ }
53
+ setGasOwner(owner: string) {
54
+ return this.txBlock.setGasOwner(owner);
55
+ }
56
+ setGasPayment(payments: SuiObjectRef[]) {
57
+ return this.txBlock.setGasPayment(payments);
58
+ }
59
+
60
+ add(transaction: TransactionType) {
61
+ return this.txBlock.add(transaction);
62
+ }
63
+ serialize() {
64
+ return this.txBlock.serialize();
65
+ }
66
+ build(
67
+ params: {
68
+ provider?: JsonRpcProvider;
69
+ onlyTransactionKind?: boolean;
70
+ } = {}
71
+ ) {
72
+ return this.txBlock.build(params);
73
+ }
74
+ getDigest({ provider }: { provider?: JsonRpcProvider } = {}) {
75
+ return this.txBlock.getDigest({ provider });
76
+ }
77
+
78
+ get gas() {
79
+ return this.txBlock.gas;
80
+ }
81
+ get blockData() {
82
+ return this.txBlock.blockData;
83
+ }
84
+
85
+ transferObjects(objects: SuiObjectArg[], recipient: string) {
86
+ const tx = this.txBlock;
87
+ tx.transferObjects(convertArgs(this.txBlock, objects), tx.pure(recipient));
88
+ return this;
89
+ }
90
+ splitCoins(coin: SuiObjectArg, amounts: number[]) {
91
+ const tx = this.txBlock;
92
+ const coinObject = convertArgs(this.txBlock, [coin])[0];
93
+ const res = tx.splitCoins(
94
+ coinObject,
95
+ amounts.map((m) => tx.pure(m))
96
+ );
97
+ return amounts.map((_, i) => res[i]);
98
+ }
99
+ mergeCoins(destination: SuiObjectArg, sources: SuiObjectArg[]) {
100
+ const destinationObject = convertArgs(this.txBlock, [destination])[0];
101
+ const sourceObjects = convertArgs(this.txBlock, sources);
102
+ return this.txBlock.mergeCoins(destinationObject, sourceObjects);
103
+ }
104
+ publish(...args: Parameters<(typeof Transactions)['Publish']>) {
105
+ return this.txBlock.publish(...args);
106
+ }
107
+ upgrade(...args: Parameters<(typeof Transactions)['Upgrade']>) {
108
+ return this.txBlock.upgrade(...args);
109
+ }
110
+ makeMoveVec(...args: Parameters<(typeof Transactions)['MakeMoveVec']>) {
111
+ return this.txBlock.makeMoveVec(...args);
112
+ }
113
+
114
+ /**
115
+ * @description Move call
116
+ * @param target `${string}::${string}::${string}`, e.g. `0x3::sui_system::request_add_stake`
117
+ * @param args the arguments of the move call, such as `['0x1', '0x2']`
118
+ * @param typeArgs the type arguments of the move call, such as `['0x2::sui::SUI']`
119
+ */
120
+ moveCall(
121
+ target: string,
122
+ args: (SuiTxArg | SuiVecTxArg)[] = [],
123
+ typeArgs: string[] = []
124
+ ) {
125
+ // a regex for pattern `${string}::${string}::${string}`
126
+ const regex =
127
+ /(?<package>[a-zA-Z0-9]+)::(?<module>[a-zA-Z0-9_]+)::(?<function>[a-zA-Z0-9_]+)/;
128
+ const match = target.match(regex);
129
+ if (match === null)
130
+ throw new Error(
131
+ 'Invalid target format. Expected `${string}::${string}::${string}`'
132
+ );
133
+ const convertedArgs = convertArgs(this.txBlock, args);
134
+ const tx = this.txBlock;
135
+ return tx.moveCall({
136
+ target: target as `${string}::${string}::${string}`,
137
+ arguments: convertedArgs,
138
+ typeArguments: typeArgs,
139
+ });
140
+ }
141
+
142
+ //======== enhance methods ============
143
+ transferSuiToMany(recipients: string[], amounts: number[]) {
144
+ // require recipients.length === amounts.length
145
+ if (recipients.length !== amounts.length) {
146
+ throw new Error(
147
+ 'transferSuiToMany: recipients.length !== amounts.length'
148
+ );
149
+ }
150
+
151
+ const tx = this.txBlock;
152
+ const coins = tx.splitCoins(
153
+ tx.gas,
154
+ amounts.map((amount) => tx.pure(amount))
155
+ );
156
+ recipients.forEach((recipient, index) => {
157
+ tx.transferObjects([coins[index]], tx.pure(recipient));
158
+ });
159
+ return this;
160
+ }
161
+
162
+ transferSui(recipient: string, amount: number) {
163
+ return this.transferSuiToMany([recipient], [amount]);
164
+ }
165
+
166
+ takeAmountFromCoins(coins: SuiObjectArg[], amount: number) {
167
+ const tx = this.txBlock;
168
+ const coinObjects = convertArgs(this.txBlock, coins);
169
+ const mergedCoin = coinObjects[0];
170
+ if (coins.length > 1) {
171
+ tx.mergeCoins(mergedCoin, coinObjects.slice(1));
172
+ }
173
+ const [sendCoin] = tx.splitCoins(mergedCoin, [tx.pure(amount)]);
174
+ return [sendCoin, mergedCoin];
175
+ }
176
+
177
+ splitSUIFromGas(amounts: number[]) {
178
+ const tx = this.txBlock;
179
+ return tx.splitCoins(
180
+ tx.gas,
181
+ amounts.map((m) => tx.pure(m))
182
+ );
183
+ }
184
+
185
+ splitMultiCoins(coins: SuiObjectArg[], amounts: number[]) {
186
+ const tx = this.txBlock;
187
+ const coinObjects = convertArgs(this.txBlock, coins);
188
+ const mergedCoin = coinObjects[0];
189
+ if (coins.length > 1) {
190
+ tx.mergeCoins(mergedCoin, coinObjects.slice(1));
191
+ }
192
+ const splitedCoins = tx.splitCoins(
193
+ mergedCoin,
194
+ amounts.map((m) => tx.pure(m))
195
+ );
196
+ return { splitedCoins, mergedCoin };
197
+ }
198
+
199
+ transferCoinToMany(
200
+ inputCoins: SuiObjectArg[],
201
+ sender: string,
202
+ recipients: string[],
203
+ amounts: number[]
204
+ ) {
205
+ // require recipients.length === amounts.length
206
+ if (recipients.length !== amounts.length) {
207
+ throw new Error(
208
+ 'transferSuiToMany: recipients.length !== amounts.length'
209
+ );
210
+ }
211
+ const tx = this.txBlock;
212
+ const { splitedCoins, mergedCoin } = this.splitMultiCoins(
213
+ inputCoins,
214
+ amounts
215
+ );
216
+ recipients.forEach((recipient, index) => {
217
+ tx.transferObjects([splitedCoins[index]], tx.pure(recipient));
218
+ });
219
+ tx.transferObjects([mergedCoin], tx.pure(sender));
220
+ return this;
221
+ }
222
+
223
+ transferCoin(
224
+ inputCoins: SuiObjectArg[],
225
+ sender: string,
226
+ recipient: string,
227
+ amount: number
228
+ ) {
229
+ return this.transferCoinToMany(inputCoins, sender, [recipient], [amount]);
230
+ }
231
+
232
+ stakeSui(amount: number, validatorAddr: string) {
233
+ const tx = this.txBlock;
234
+ const [stakeCoin] = tx.splitCoins(tx.gas, [tx.pure(amount)]);
235
+ tx.moveCall({
236
+ target: '0x3::sui_system::request_add_stake',
237
+ arguments: [
238
+ tx.object(SUI_SYSTEM_STATE_OBJECT_ID),
239
+ stakeCoin,
240
+ tx.pure(validatorAddr),
241
+ ],
242
+ });
243
+ return tx;
244
+ }
245
+ }
@@ -0,0 +1,32 @@
1
+ import {
2
+ SharedObjectRef,
3
+ SuiObjectRef,
4
+ TransactionArgument,
5
+ } from '@mysten/sui.js';
6
+
7
+ export type SuiTxArg = TransactionArgument | string | number | bigint | boolean;
8
+
9
+ export type SuiObjectArg =
10
+ | SharedObjectRef
11
+ | SuiObjectRef
12
+ | string
13
+ | TransactionArgument;
14
+
15
+ export type SuiVecTxArg =
16
+ | { value: SuiTxArg[]; vecType: SuiInputTypes }
17
+ | SuiTxArg[];
18
+
19
+ /**
20
+ * These are the basics types that can be used in the SUI
21
+ */
22
+ export type SuiBasicTypes =
23
+ | 'address'
24
+ | 'bool'
25
+ | 'u8'
26
+ | 'u16'
27
+ | 'u32'
28
+ | 'u64'
29
+ | 'u128'
30
+ | 'u256';
31
+
32
+ export type SuiInputTypes = 'object' | SuiBasicTypes;
@@ -0,0 +1,84 @@
1
+ import {
2
+ normalizeSuiObjectId,
3
+ TransactionArgument,
4
+ TransactionBlock,
5
+ } from '@mysten/sui.js';
6
+ import { SuiTxArg, SuiInputTypes } from './types';
7
+
8
+ export const getDefaultSuiInputType = (value: any): SuiInputTypes => {
9
+ if (typeof value === 'string' && value.startsWith('0x')) {
10
+ return 'object';
11
+ } else if (typeof value === 'number' || typeof value === 'bigint') {
12
+ return 'u64';
13
+ } else if (typeof value === 'boolean') {
14
+ return 'bool';
15
+ } else {
16
+ return 'object';
17
+ }
18
+ };
19
+
20
+ /**
21
+ * Since we know the elements in the array are the same type
22
+ * If type is not provided, we will try to infer the type from the first element
23
+ * By default,
24
+ *
25
+ * string starting with `0x` =====> object id
26
+ * number, bigint ====> u64
27
+ * boolean =====> bool
28
+ *
29
+ *
30
+ * If type is provided, we will use the type to convert the array
31
+ * @param args
32
+ * @param type 'address' | 'bool' | 'u8' | 'u16' | 'u32' | 'u64' | 'u128' | 'u256' | 'object'
33
+ */
34
+ export function makeVecParam(
35
+ txBlock: TransactionBlock,
36
+ args: SuiTxArg[],
37
+ type?: SuiInputTypes
38
+ ) {
39
+ if (args.length === 0)
40
+ throw new Error('Transaction builder error: Empty array is not allowed');
41
+ const defaultSuiType = getDefaultSuiInputType(args[0]);
42
+ if (type === 'object' || (!type && defaultSuiType === 'object')) {
43
+ const objects = args.map((arg) =>
44
+ typeof arg === 'string'
45
+ ? txBlock.object(normalizeSuiObjectId(arg))
46
+ : (arg as any)
47
+ );
48
+ return txBlock.makeMoveVec({ objects });
49
+ } else {
50
+ const vecType = type || defaultSuiType;
51
+ return txBlock.pure(args, `vector<${vecType}>`);
52
+ }
53
+ }
54
+
55
+ export function isMoveVecArg(arg: any) {
56
+ const isFullMoveVecArg =
57
+ arg && arg.value && Array.isArray(arg.value) && arg.vecType;
58
+ const isSimpleMoveVecArg = Array.isArray(arg);
59
+ return isFullMoveVecArg || isSimpleMoveVecArg;
60
+ }
61
+
62
+ export function convertArgs(
63
+ txBlock: TransactionBlock,
64
+ args: any[]
65
+ ): TransactionArgument[] {
66
+ return args.map((arg) => {
67
+ if (typeof arg === 'string' && arg.startsWith('0x')) {
68
+ // We always treat string starting with `0x` as object id
69
+ return txBlock.object(normalizeSuiObjectId(arg));
70
+ } else if (isMoveVecArg(arg)) {
71
+ // if it's an array arg, we will convert it to move vec
72
+ const vecType = arg.vecType || undefined;
73
+ return vecType
74
+ ? makeVecParam(txBlock, arg.value, vecType)
75
+ : makeVecParam(txBlock, arg);
76
+ } else if (typeof arg !== 'object') {
77
+ // Other basic types such as string, number, boolean are converted to pure value
78
+ return txBlock.pure(arg);
79
+ } else {
80
+ // We do nothing, because it's most likely already a move value
81
+ return arg;
82
+ }
83
+ });
84
+ }