From 975006b4a661f4b6d4143873257fdeb44af284be Mon Sep 17 00:00:00 2001 From: owanemi Date: Sun, 20 Apr 2025 01:23:00 +0100 Subject: [PATCH 01/30] chore: install sui wallet dependencies --- package.json | 1 + yarn.lock | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/package.json b/package.json index 9309c6c..fa5be27 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ }, "dependencies": { "@bitgo/utxo-lib": "https://github.com/ren-forks/bitgo-utxo-lib#b848585e65b42c48b98c207e72d7d3006c9a5da0", + "@mysten/sui": "^1.28.0", "@solana/spl-token": "^0.2.0", "@solana/web3.js": "^1.39.1", "@truffle/hdwallet-provider": "^2.0.5", diff --git a/yarn.lock b/yarn.lock index 0201e56..6b1d202 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,19 @@ # yarn lockfile v1 +"@0no-co/graphql.web@^1.0.5": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@0no-co/graphql.web/-/graphql.web-1.1.2.tgz#9af8deaf3f236c1c6ee99cc5349051475e5dcc83" + integrity sha512-N2NGsU5FLBhT8NZ+3l2YrzZSHITjNXNuDhC4iDiikv0IujaJ0Xc6xIxQZ/Ek3Cb+rgPjnLHYyJm11tInuJn+cw== + +"@0no-co/graphqlsp@^1.12.13": + version "1.12.16" + resolved "https://registry.yarnpkg.com/@0no-co/graphqlsp/-/graphqlsp-1.12.16.tgz#58fe7bad53b3ad9fdf2d5f41ddeb9b418d289a03" + integrity sha512-B5pyYVH93Etv7xjT6IfB7QtMBdaaC07yjbhN6v8H7KgFStMkPvi+oWYBTibMFRMY89qwc9H8YixXg8SXDVgYWw== + dependencies: + "@gql.tada/internal" "^1.0.0" + graphql "^15.5.0 || ^16.0.0 || ^17.0.0" + "@adraffy/ens-normalize@1.10.1": version "1.10.1" resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" @@ -1315,6 +1328,27 @@ "@ethersproject/properties" "^5.8.0" "@ethersproject/strings" "^5.8.0" +"@gql.tada/cli-utils@1.6.3": + version "1.6.3" + resolved "https://registry.yarnpkg.com/@gql.tada/cli-utils/-/cli-utils-1.6.3.tgz#b893cec74908da4df0602691e2e0b1497fda8cda" + integrity sha512-jFFSY8OxYeBxdKi58UzeMXG1tdm4FVjXa8WHIi66Gzu9JWtCE6mqom3a8xkmSw+mVaybFW5EN2WXf1WztJVNyQ== + dependencies: + "@0no-co/graphqlsp" "^1.12.13" + "@gql.tada/internal" "1.0.8" + graphql "^15.5.0 || ^16.0.0 || ^17.0.0" + +"@gql.tada/internal@1.0.8", "@gql.tada/internal@^1.0.0": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@gql.tada/internal/-/internal-1.0.8.tgz#3ba9fa6534809788bbbe103492f70b8e9d754027" + integrity sha512-XYdxJhtHC5WtZfdDqtKjcQ4d7R1s0d1rnlSs3OcBEUbYiPoJJfZU7tWsVXuv047Z6msvmr4ompJ7eLSK5Km57g== + dependencies: + "@0no-co/graphql.web" "^1.0.5" + +"@graphql-typed-document-node/core@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + "@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0": version "9.3.0" resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb" @@ -1559,6 +1593,38 @@ resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== +"@mysten/bcs@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@mysten/bcs/-/bcs-1.6.0.tgz#ccd7153cef7a83a402724c8fb3b2603323a4aedc" + integrity sha512-ydDRYdIkIFCpHCcPvAkMC91fVwumjzbTgjqds0KsphDQI3jUlH3jFG5lfYNTmV6V3pkhOiRk1fupLBcsQsiszg== + dependencies: + "@scure/base" "^1.2.4" + +"@mysten/sui@^1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@mysten/sui/-/sui-1.28.0.tgz#32322ade494a64284e1bf09a995b46de72a93935" + integrity sha512-ABcKc+QBpazBl5/ByLChxHOiPjqxISSdXnBuU1rLm1frp5tjMSCChiL7Reth2zcxWO2qYFK70ewEkYVtJvJQvw== + dependencies: + "@graphql-typed-document-node/core" "^3.2.0" + "@mysten/bcs" "1.6.0" + "@mysten/utils" "0.0.0" + "@noble/curves" "^1.8.1" + "@noble/hashes" "^1.7.1" + "@scure/base" "^1.2.4" + "@scure/bip32" "^1.6.2" + "@scure/bip39" "^1.5.4" + gql.tada "^1.8.2" + graphql "^16.9.0" + poseidon-lite "^0.2.0" + valibot "^0.36.0" + +"@mysten/utils@0.0.0": + version "0.0.0" + resolved "https://registry.yarnpkg.com/@mysten/utils/-/utils-0.0.0.tgz#e088ddd10d2e99c9cecbf2bc93f999d299cc1b06" + integrity sha512-KRI57Qow3E7TGqczimazwGf7+fwukdOi+6a31igSCzz0kPjAXbyK1a1gXaxeLMF8xEZ07ouW3RnsWt+EaUuHUw== + dependencies: + "@scure/base" "^1.2.4" + "@noble/curves@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35" @@ -1580,6 +1646,13 @@ dependencies: "@noble/hashes" "1.7.1" +"@noble/curves@^1.8.1", "@noble/curves@~1.8.1": + version "1.8.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.8.2.tgz#8f24c037795e22b90ae29e222a856294c1d9ffc7" + integrity sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g== + dependencies: + "@noble/hashes" "1.7.2" + "@noble/hashes@1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183" @@ -1600,6 +1673,11 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.1.tgz#5738f6d765710921e7a751e00c20ae091ed8db0f" integrity sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ== +"@noble/hashes@1.7.2", "@noble/hashes@^1.7.1", "@noble/hashes@~1.7.1": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.7.2.tgz#d53c65a21658fb02f3303e7ee3ba89d6754c64b4" + integrity sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ== + "@noble/hashes@~1.1.1": version "1.1.5" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.5.tgz#1a0377f3b9020efe2fae03290bd2a12140c95c11" @@ -1746,6 +1824,11 @@ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== +"@scure/base@^1.2.4", "@scure/base@~1.2.2", "@scure/base@~1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.2.4.tgz#002eb571a35d69bdb4c214d0995dff76a8dcd2a9" + integrity sha512-5Yy9czTO47mqz+/J8GM6GIId4umdCk1wc1q8rKERQulIoc8VP9pzDcghv10Tl2E7R96ZUx/PhND3ESYUQX8NuQ== + "@scure/base@~1.1.0", "@scure/base@~1.1.6": version "1.1.9" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.9.tgz#e5e142fbbfe251091f9c5f1dd4c834ac04c3dbd1" @@ -1769,6 +1852,15 @@ "@noble/hashes" "~1.4.0" "@scure/base" "~1.1.6" +"@scure/bip32@^1.6.2": + version "1.6.2" + resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.6.2.tgz#093caa94961619927659ed0e711a6e4bf35bffd0" + integrity sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw== + dependencies: + "@noble/curves" "~1.8.1" + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.2" + "@scure/bip39@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.1.0.tgz#92f11d095bae025f166bef3defcc5bf4945d419a" @@ -1785,6 +1877,14 @@ "@noble/hashes" "~1.4.0" "@scure/base" "~1.1.6" +"@scure/bip39@^1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.5.4.tgz#07fd920423aa671be4540d59bdd344cc1461db51" + integrity sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA== + dependencies: + "@noble/hashes" "~1.7.1" + "@scure/base" "~1.2.4" + "@sideway/address@^4.1.5": version "4.1.5" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5" @@ -5820,11 +5920,26 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +gql.tada@^1.8.2: + version "1.8.10" + resolved "https://registry.yarnpkg.com/gql.tada/-/gql.tada-1.8.10.tgz#096a1b30d3c6fc74212fe07d507f01a4095f7f67" + integrity sha512-FrvSxgz838FYVPgZHGOSgbpOjhR+yq44rCzww3oOPJYi0OvBJjAgCiP6LEokZIYND2fUTXzQAyLgcvgw1yNP5A== + dependencies: + "@0no-co/graphql.web" "^1.0.5" + "@0no-co/graphqlsp" "^1.12.13" + "@gql.tada/cli-utils" "1.6.3" + "@gql.tada/internal" "1.0.8" + graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +"graphql@^15.5.0 || ^16.0.0 || ^17.0.0", graphql@^16.9.0: + version "16.10.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.10.0.tgz#24c01ae0af6b11ea87bf55694429198aaa8e220c" + integrity sha512-AjqGKbDGUFRKIRCP9tCKiIGHyriz2oHEbPIbEtcSLSs4YjReZOIPQQWek4+6hjw62H9QShXHyaGivGiYVLeYFQ== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -8322,6 +8437,11 @@ pn@^1.1.0: resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== +poseidon-lite@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/poseidon-lite/-/poseidon-lite-0.2.1.tgz#7ad98e3a3aa5b91a1fd3a61a87460e9e46fd76d6" + integrity sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog== + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -10467,6 +10587,11 @@ v8-to-istanbul@^4.1.3: convert-source-map "^1.6.0" source-map "^0.7.3" +valibot@^0.36.0: + version "0.36.0" + resolved "https://registry.yarnpkg.com/valibot/-/valibot-0.36.0.tgz#74e746694b1abcc1879e4393db551d4ce1e10578" + integrity sha512-CjF1XN4sUce8sBK9TixrDqFM7RwNkuXdJu174/AwmQUB62QbCQADg5lLe8ldBalFgtj1uKj+pKwDJiNo4Mn+eQ== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From 32bae98ee0f33acb829068b89f697fefef502728 Mon Sep 17 00:00:00 2001 From: owanemi Date: Mon, 21 Apr 2025 15:07:23 +0100 Subject: [PATCH 02/30] added suiHelper types --- src/common/helpers/suiHelper.ts | 20 ++++++++++++++++++++ src/common/utils/types.ts | 7 +++++-- 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/common/helpers/suiHelper.ts diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts new file mode 100644 index 0000000..5564a4b --- /dev/null +++ b/src/common/helpers/suiHelper.ts @@ -0,0 +1,20 @@ +import * as sui from '@mysten/sui'; +import * as bip39 from 'bip39'; + +import { + BalancePayload, + CreateWalletPayload, + TransferPayload, +} from '../utils/types'; + +const createWallet = ({ derivationPath }: CreateWalletPayload) => { + const path = derivationPath || "m/44'/784'/0'/0'/0'"; + const mnemonic = bip39.generateMnemonic(); + const seed = bip39.mnemonicToSeedSync(mnemonic); + + console.log(sui); // Example usage to avoid unused import error +}; + +export default { + createWallet, +}; \ No newline at end of file diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 32004e3..5f6bbeb 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -3,6 +3,7 @@ import ethereumHelper from '../../common/helpers/ethereumHelper'; import solanaHelper from '../../common/helpers/solanaHelper'; import wavesHelper from '../../common/helpers/wavesHelper'; import tronHelper from '../../common/helpers/tronHelper'; +import suiHelper from '../../common/helpers/suiHelper'; export type Network = | 'ethereum' @@ -10,7 +11,8 @@ export type Network = | 'tron' | 'waves' | 'bitcoin' - | 'bitcoin-testnet'; + | 'bitcoin-testnet' + | 'sui'; export type NetworkHelper = { [key in T]: @@ -18,7 +20,8 @@ export type NetworkHelper = { | typeof ethereumHelper | typeof solanaHelper | typeof wavesHelper - | typeof tronHelper; + | typeof tronHelper + | typeof suiHelper; }; export interface TransferPayload { From 246bd1e70c23c6f7de70e7cb57b9cdabb1e1e794 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 23 Apr 2025 10:28:04 +0100 Subject: [PATCH 03/30] feat(utils): added sui provider --- src/common/utils/sui.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/common/utils/sui.ts diff --git a/src/common/utils/sui.ts b/src/common/utils/sui.ts new file mode 100644 index 0000000..cf6e090 --- /dev/null +++ b/src/common/utils/sui.ts @@ -0,0 +1,9 @@ +import { SuiClient } from '@mysten/sui/client'; + +const provider = (rpcUrl?: string) => { + return new SuiClient({ + url: rpcUrl as string + }); +}; + +export default provider; From 2e7ec41f5c0b27108bd697845cf4a46d52b6d9c0 Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 17:04:18 +0100 Subject: [PATCH 04/30] feat: added createWallet function --- src/common/helpers/suiHelper.ts | 46 +++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 5564a4b..5ad6da0 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -1,20 +1,50 @@ -import * as sui from '@mysten/sui'; -import * as bip39 from 'bip39'; - +import provider from '../utils/sui'; +import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; import { BalancePayload, CreateWalletPayload, + GenerateWalletFromMnemonicPayload, + GetAddressFromPrivateKeyPayload, + GetTransactionPayload, + GetWalletFromEncryptedjsonPayload, + IGetTokenInfoPayload, + ISmartContractCallPayload, + ITokenInfo, + IResponse, TransferPayload, } from '../utils/types'; +import * as bip39 from 'bip39'; +import { successResponse } from '../utils'; + + + +const getConnection = (rpcUrl?: string) => { + const connection = provider(rpcUrl); -const createWallet = ({ derivationPath }: CreateWalletPayload) => { + return connection; +}; + +const createWallet = ({ derivationPath }: CreateWalletPayload): IResponse => { + // default ed25519 derivation path for sui const path = derivationPath || "m/44'/784'/0'/0'/0'"; + const mnemonic = bip39.generateMnemonic(); - const seed = bip39.mnemonicToSeedSync(mnemonic); - console.log(sui); // Example usage to avoid unused import error + const keypair = Ed25519Keypair.deriveKeypair(mnemonic, path); + + const publicKey = keypair.getPublicKey(); + const address = publicKey.toSuiAddress(); + + // get the secret key(Bech32-encoded, sui standard) + const secretKey = keypair.getSecretKey(); + + return successResponse({ + address, + privateKey: secretKey, + mnemonic, + }); }; export default { - createWallet, -}; \ No newline at end of file + createWallet +} \ No newline at end of file From 610916a359ace8fd5c3d0b1c6986ed120ef09c3d Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 18:22:30 +0100 Subject: [PATCH 05/30] feat: implemented generateWalletFromMnemonic function --- src/common/helpers/suiHelper.ts | 34 ++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 5ad6da0..83d149a 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -15,8 +15,7 @@ import { } from '../utils/types'; import * as bip39 from 'bip39'; import { successResponse } from '../utils'; - - +import { keyPair } from '@waves/ts-lib-crypto'; const getConnection = (rpcUrl?: string) => { const connection = provider(rpcUrl); @@ -35,16 +34,37 @@ const createWallet = ({ derivationPath }: CreateWalletPayload): IResponse => { const publicKey = keypair.getPublicKey(); const address = publicKey.toSuiAddress(); - // get the secret key(Bech32-encoded, sui standard) + // get the private/secret key(Bech32-encoded, sui standard) const secretKey = keypair.getSecretKey(); return successResponse({ - address, + address: address, + privateKey: secretKey, + mnemonic: mnemonic, + }); +}; + +const generateWalletFromMnemonic = ({ + mnemonic, + derivationPath, +}: GenerateWalletFromMnemonicPayload): IResponse => { + const path = derivationPath || "m/44'/784'/0'/0'/0'"; + + const keyPair = Ed25519Keypair.deriveKeypair(mnemonic, path); + + const publicKey = keyPair.getPublicKey(); + const address = publicKey.toSuiAddress(); + + const secretKey = keyPair.getSecretKey(); + + return successResponse({ + address: address, privateKey: secretKey, - mnemonic, + mnemonic: mnemonic, }); }; export default { - createWallet -} \ No newline at end of file + createWallet, + generateWalletFromMnemonic, +}; From 4b0465ff21c886beb8eedfc7923ea4085ccca03f Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 19:13:55 +0100 Subject: [PATCH 06/30] feat: implemented generateAddressFromPrivateKey function --- src/common/helpers/suiHelper.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 83d149a..1f06e73 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -15,7 +15,6 @@ import { } from '../utils/types'; import * as bip39 from 'bip39'; import { successResponse } from '../utils'; -import { keyPair } from '@waves/ts-lib-crypto'; const getConnection = (rpcUrl?: string) => { const connection = provider(rpcUrl); @@ -64,7 +63,21 @@ const generateWalletFromMnemonic = ({ }); }; +const getAddressFromPrivateKey = ({ + privateKey, +}: GetAddressFromPrivateKeyPayload): IResponse => { + const keypair = Ed25519Keypair.fromSecretKey(privateKey, { skipValidation: false }); + const publicKey = keypair.getPublicKey(); + const address = publicKey.toSuiAddress(); + + return successResponse({ + address, + }); +}; + + export default { createWallet, generateWalletFromMnemonic, + getAddressFromPrivateKey, }; From 65ff23f5d4aca5d086fdd7dff1329bb3dea4af04 Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 20:25:45 +0100 Subject: [PATCH 07/30] feat: implemented getBalance function --- src/common/helpers/suiHelper.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 1f06e73..3899d61 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -1,12 +1,12 @@ import provider from '../utils/sui'; import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; +import { MIST_PER_SUI } from '@mysten/sui/utils'; import { BalancePayload, CreateWalletPayload, GenerateWalletFromMnemonicPayload, GetAddressFromPrivateKeyPayload, GetTransactionPayload, - GetWalletFromEncryptedjsonPayload, IGetTokenInfoPayload, ISmartContractCallPayload, ITokenInfo, @@ -66,18 +66,40 @@ const generateWalletFromMnemonic = ({ const getAddressFromPrivateKey = ({ privateKey, }: GetAddressFromPrivateKeyPayload): IResponse => { - const keypair = Ed25519Keypair.fromSecretKey(privateKey, { skipValidation: false }); + const keypair = Ed25519Keypair.fromSecretKey(privateKey, { + skipValidation: false, + }); + const publicKey = keypair.getPublicKey(); const address = publicKey.toSuiAddress(); return successResponse({ - address, + address: address, }); }; +const getBalance = async (args: BalancePayload): Promise => { + const connection = getConnection(args.rpcUrl); + + if (args.tokenAddress) { + const balance = await connection.getBalance({ + owner: args.address, + coinType: args.tokenAddress, + }); + return successResponse({ + balance: parseFloat(balance.totalBalance) / Number(MIST_PER_SUI), + }); + } + + const balance = await connection.getBalance({ owner: args.address }); + return successResponse({ + balance: parseFloat(balance.totalBalance) / Number(MIST_PER_SUI), + }); +}; export default { createWallet, generateWalletFromMnemonic, getAddressFromPrivateKey, + getBalance, }; From 521fb6c6cadee2d3f6434f04cffcfc0a809e2600 Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 20:48:56 +0100 Subject: [PATCH 08/30] added coin decimal division for getBalance --- src/common/helpers/suiHelper.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 3899d61..ccdcc85 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -86,8 +86,15 @@ const getBalance = async (args: BalancePayload): Promise => { owner: args.address, coinType: args.tokenAddress, }); + + // Fetch token metadata to get decimals + const metadata = await connection.getCoinMetadata({ + coinType: args.tokenAddress, + }); + + const decimals = metadata ? metadata.decimals : 0; return successResponse({ - balance: parseFloat(balance.totalBalance) / Number(MIST_PER_SUI), + balance: parseFloat(balance.totalBalance) / Math.pow(10, decimals), }); } From 8c85aac58be4aaa4aa7a1bb557ebc3463fe5c11d Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 21:51:34 +0100 Subject: [PATCH 09/30] feat: implemented transfer function --- src/common/helpers/suiHelper.ts | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index ccdcc85..5e930cd 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -1,6 +1,7 @@ import provider from '../utils/sui'; import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519'; import { MIST_PER_SUI } from '@mysten/sui/utils'; +import { Transaction } from '@mysten/sui/transactions'; import { BalancePayload, CreateWalletPayload, @@ -104,9 +105,68 @@ const getBalance = async (args: BalancePayload): Promise => { }); }; +const transfer = async (args: TransferPayload): Promise => { + try { + const connection = provider(args.rpcUrl); + + const senderKeypair = Ed25519Keypair.fromSecretKey(args.privateKey); + + const txb = new Transaction(); + + if (args.tokenAddress) { + // Fetch token decimals + const metadata = await connection.getCoinMetadata({ + coinType: args.tokenAddress, + }); + const decimals = metadata?.decimals || 0; + const rawAmount = BigInt( + Math.floor(args.amount * Math.pow(10, decimals)) + ); + + // Fetch sender's coins for the token + const { data: coins } = await connection.getCoins({ + owner: senderKeypair.getPublicKey().toSuiAddress(), + coinType: args.tokenAddress, + }); + + if (!coins.length) throw new Error('No coins found.'); + + // Split the coin for the amount to transfer + const [coin] = txb.splitCoins(txb.object(coins[0].coinObjectId), [ + txb.pure.u64(rawAmount), + ]); + txb.transferObjects([coin], txb.pure.address(args.recipientAddress)); + } else { + // native sui transfer + const amountInMist = BigInt( + Math.floor(args.amount * Number(MIST_PER_SUI)) + ); + const [coin] = txb.splitCoins(txb.gas, [txb.pure.u64(amountInMist)]); + txb.transferObjects([coin], txb.pure.address(args.recipientAddress)); + } + + // Sign and execute the transaction + const result = await connection.signAndExecuteTransaction({ + signer: senderKeypair, + transaction: txb, + options: { + showEffects: true, + showObjectChanges: true, + }, + }); + + return successResponse({ + ...result, + }); + } catch (error) { + throw error; + } +}; + export default { createWallet, generateWalletFromMnemonic, getAddressFromPrivateKey, getBalance, + transfer, }; From 3429346921e569006b29618852d09c8dc8a6c600 Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 22:00:57 +0100 Subject: [PATCH 10/30] feat: implemented getTransaction function --- src/common/helpers/suiHelper.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 5e930cd..936dae3 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -163,10 +163,37 @@ const transfer = async (args: TransferPayload): Promise => { } }; +const getTransaction = async ( + args: GetTransactionPayload +): Promise => { + const connection = getConnection(args.rpcUrl); + + try { + // Use getTransactionBlock for Sui + const tx = await connection.getTransactionBlock({ + digest: args.hash, + options: { + showInput: true, + showEffects: true, + showEvents: true, + showObjectChanges: true, + showBalanceChanges: true, + }, + }); + + return successResponse({ + ...tx, + }); + } catch (error) { + throw error; + } +}; + export default { createWallet, generateWalletFromMnemonic, getAddressFromPrivateKey, getBalance, transfer, + getTransaction, }; From 9dd9af11d1fbf0ace53c10a42181ec4c12f207a4 Mon Sep 17 00:00:00 2001 From: owanemi Date: Thu, 24 Apr 2025 22:24:15 +0100 Subject: [PATCH 11/30] feat: implemented getTokenInfo function --- src/common/helpers/suiHelper.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 936dae3..c8928d3 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -189,6 +189,34 @@ const getTransaction = async ( } }; +const getTokenInfo = async (args: IGetTokenInfoPayload): Promise => { + try { + const connection = getConnection(args.rpcUrl); + + const metadata = await connection.getCoinMetadata({ coinType: args.address }); + if (!metadata) { + throw new Error('Token metadata not found'); + } + + const supply = await connection.getTotalSupply({ coinType: args.address }); + + const data: ITokenInfo = { + name: metadata.name, + symbol: metadata.symbol, + address: args.address, + decimals: metadata.decimals, + logoUrl: metadata.iconUrl ?? undefined, + totalSupply: supply.value.toString(), + }; + + return successResponse({ ...data }); + } catch (error) { + throw error; + } +}; + + + export default { createWallet, generateWalletFromMnemonic, @@ -196,4 +224,5 @@ export default { getBalance, transfer, getTransaction, + getTokenInfo, }; From bda9524871824b1097d4ee584afcfd824d185a3a Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 11:26:38 +0100 Subject: [PATCH 12/30] updated SmartContractPayload Interface to account for sui --- src/common/utils/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 5f6bbeb..07e2e27 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -134,6 +134,8 @@ export interface ISmartContractCallPayload { feeLimit?: number; nonce?: number; privateKey?: string; + typeArguments?: string[]; + paramTypes?: string[]; } export interface INetworkHelper { From f2b81f6126fe48b0f4fb980a6c24c9057616afba Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 12:54:56 +0100 Subject: [PATCH 13/30] added module property for SmartContractPayload Interface --- src/common/utils/types.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 07e2e27..e8dcfdd 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -4,6 +4,7 @@ import solanaHelper from '../../common/helpers/solanaHelper'; import wavesHelper from '../../common/helpers/wavesHelper'; import tronHelper from '../../common/helpers/tronHelper'; import suiHelper from '../../common/helpers/suiHelper'; +import { Arguments } from '@truffle/hdwallet-provider/dist/constructor/LegacyConstructor'; export type Network = | 'ethereum' @@ -134,8 +135,8 @@ export interface ISmartContractCallPayload { feeLimit?: number; nonce?: number; privateKey?: string; - typeArguments?: string[]; paramTypes?: string[]; + module?: string; } export interface INetworkHelper { From 46af824177ac4d3650684cc58b790b4ce1d9e84e Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 13:08:30 +0100 Subject: [PATCH 14/30] added packageId property for SmartContractPayload Interface --- src/common/utils/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index e8dcfdd..5849040 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -4,7 +4,6 @@ import solanaHelper from '../../common/helpers/solanaHelper'; import wavesHelper from '../../common/helpers/wavesHelper'; import tronHelper from '../../common/helpers/tronHelper'; import suiHelper from '../../common/helpers/suiHelper'; -import { Arguments } from '@truffle/hdwallet-provider/dist/constructor/LegacyConstructor'; export type Network = | 'ethereum' @@ -137,6 +136,7 @@ export interface ISmartContractCallPayload { privateKey?: string; paramTypes?: string[]; module?: string; + packageId?: string; } export interface INetworkHelper { From 3d8ded25ae016b6c00ea42561b6ca59d6fd88087 Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 15:34:14 +0100 Subject: [PATCH 15/30] added sender property for SmartContractPayload Interface --- src/common/utils/types.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 5849040..4a03e17 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -134,9 +134,8 @@ export interface ISmartContractCallPayload { feeLimit?: number; nonce?: number; privateKey?: string; - paramTypes?: string[]; - module?: string; - packageId?: string; + paramTypes?: string[]; + sender?: string; } export interface INetworkHelper { From 06dae0121628e18ec39e69459cb17b6f6c835e80 Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 15:35:36 +0100 Subject: [PATCH 16/30] feat: implemented smartContractCall for sui --- src/common/helpers/suiHelper.ts | 106 +++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index c8928d3..612103e 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -16,6 +16,7 @@ import { } from '../utils/types'; import * as bip39 from 'bip39'; import { successResponse } from '../utils'; +import { PureTypeName } from '@mysten/sui/dist/cjs/bcs'; const getConnection = (rpcUrl?: string) => { const connection = provider(rpcUrl); @@ -193,7 +194,9 @@ const getTokenInfo = async (args: IGetTokenInfoPayload): Promise => { try { const connection = getConnection(args.rpcUrl); - const metadata = await connection.getCoinMetadata({ coinType: args.address }); + const metadata = await connection.getCoinMetadata({ + coinType: args.address, + }); if (!metadata) { throw new Error('Token metadata not found'); } @@ -215,7 +218,107 @@ const getTokenInfo = async (args: IGetTokenInfoPayload): Promise => { } }; +const smartContractCall = async ( + args: ISmartContractCallPayload +): Promise => { + const connection = getConnection(args.rpcUrl); + const txb = new Transaction(); + + // Validate params and paramTypes length match + if (args.params.length !== (args.paramTypes ?? []).length) { + throw new Error('Number of params and paramTypes must match'); + } + + // serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. + const moveCallArgs = args.params.map((param, idx) => { + + const type = (args.paramTypes ?? [])[idx]; + + // Handle vector and option types + if (type.startsWith('vector<') && type.endsWith('>')) { + const innerType = type.slice(7, -1); // e.g., 'u8' from 'vector' + return txb.pure.vector(innerType as PureTypeName, param); + } + if (type.startsWith('option<') && type.endsWith('>')) { + const innerType = type.slice(7, -1); // e.g., 'u64' from 'option' + return txb.pure.option(innerType as PureTypeName, param); + } + + // Handle primitives + switch (type) { + case 'address': + return txb.pure.address(param); + case 'string': + return txb.pure.string(param); + case 'u8': + return txb.pure.u8(param); + case 'u16': + return txb.pure.u16(param); + case 'u32': + return txb.pure.u32(param); + case 'u64': + return txb.pure.u64(param); + case 'u128': + return txb.pure.u128(param); + case 'u256': + return txb.pure.u256(param); + case 'bool': + return txb.pure.bool(param); + default: + throw new Error(`Unsupported parameter type: ${type}`); + } + }); + + // Build moveCall + txb.moveCall({ + target: args.contractAddress, //It should be in the form(0xAddress::module_name::function_name) + arguments: moveCallArgs, + }); + + // Set gas budget + txb.setGasBudget(args.gasLimit || 20000000); // Default to 0.02 SUI + + // to call/simulate a non state-changing function as sui move functions aren't explicitly marked as `view` + if (args.methodType === 'read') { + const sender = args.sender || '0x0'; + const result = await connection.devInspectTransactionBlock({ + sender, + transactionBlock: txb, + }); + + if (result.effects.status.status !== 'success') { + throw new Error(result.effects.status.error || 'View call failed'); + } + + return successResponse({ data: result }); + } + if (args.methodType === 'write') { + if (!args.privateKey) throw new Error('Private key required'); + const keypair = Ed25519Keypair.fromSecretKey(args.privateKey); + + try { + const result = await connection.signAndExecuteTransaction({ + signer: keypair, + transaction: txb, + options: { + showEffects: true, + showObjectChanges: true, + }, + }); + + if (!result.effects || result.effects.status.status !== 'success') { + throw new Error(result.effects?.status.error || 'Transaction failed'); + } + + return successResponse({ digest: result.digest, data: result }); + } catch (error) { + throw error; + } + } + + throw new Error('Invalid methodType. Expected "read" or "write".'); +}; export default { createWallet, @@ -225,4 +328,5 @@ export default { transfer, getTransaction, getTokenInfo, + smartContractCall, }; From 496d3dad1330a24e6e5a5df261a3a1821f10cd82 Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 15:45:11 +0100 Subject: [PATCH 17/30] chore: format with prettier --- src/common/utils/sui.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/utils/sui.ts b/src/common/utils/sui.ts index cf6e090..84a63a8 100644 --- a/src/common/utils/sui.ts +++ b/src/common/utils/sui.ts @@ -2,7 +2,7 @@ import { SuiClient } from '@mysten/sui/client'; const provider = (rpcUrl?: string) => { return new SuiClient({ - url: rpcUrl as string + url: rpcUrl as string, }); }; From c3268f4d36cf678d914db609cf5293ea225b81e0 Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 18:07:36 +0100 Subject: [PATCH 18/30] added suiHelper to wallet index file --- src/services/wallet/index.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/services/wallet/index.ts b/src/services/wallet/index.ts index 79bd8d8..e39dcb3 100644 --- a/src/services/wallet/index.ts +++ b/src/services/wallet/index.ts @@ -5,6 +5,7 @@ import ethereumHelper from '../../common/helpers/ethereumHelper'; import solanaHelper from '../../common/helpers/solanaHelper'; import wavesHelper from '../../common/helpers/wavesHelper'; import tronHelper from '../../common/helpers/tronHelper'; +import suiHelper from '../../common/helpers/suiHelper'; import { TransferPayload, @@ -31,6 +32,7 @@ const networkHelpers: Record = { waves: wavesHelper, bitcoin: bitcoinHelper, 'bitcoin-testnet': bitcoinHelper, + sui: suiHelper, }; /** @@ -61,6 +63,7 @@ const supportedFeatures: Record = { 'bitcoin-testnet': [...baseFeatures], waves: [...baseFeatures, 'getTokenInfo', 'smartContractCall'], tron: [...baseFeatures, 'getTokenInfo', 'smartContractCall'], + sui: [...baseFeatures, 'getTokenInfo', 'smartContractCall'], }; /** @@ -109,9 +112,7 @@ function generateMnemonic(numWords: number = 12): string { * @throws {Error} When an unsupported or invalid network is provided. * @remarks Supported networks: Ethereum, Solana, and Bitcoin variants. */ -function getAddressFromPrivateKey( - args: GetAddressFromPrivateKeyPayload -) { +function getAddressFromPrivateKey(args: GetAddressFromPrivateKeyPayload) { if (!isFeatureSupported(args.network, 'getAddressFromPrivateKey')) { throw new Error( `getAddressFromPrivateKey is not supported for ${args.network}` @@ -129,9 +130,7 @@ function getAddressFromPrivateKey( * @throws {Error} When an unsupported or invalid network is provided. * @remarks Supported networks: Ethereum, Solana, Bitcoin variants, and Waves. */ -function generateWalletFromMnemonic( - args: GenerateWalletFromMnemonicPayload -) { +function generateWalletFromMnemonic(args: GenerateWalletFromMnemonicPayload) { if (!isFeatureSupported(args.network, 'generateWalletFromMnemonic')) { throw new Error( `generateWalletFromMnemonic is not supported for ${args.network}` From e1f89e813baadc48f363e155767339c04f873a9b Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 20:00:56 +0100 Subject: [PATCH 19/30] added typeArguments property to smartContractPayloadInterface --- src/common/utils/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/utils/types.ts b/src/common/utils/types.ts index 4a03e17..ee8139d 100644 --- a/src/common/utils/types.ts +++ b/src/common/utils/types.ts @@ -136,6 +136,7 @@ export interface ISmartContractCallPayload { privateKey?: string; paramTypes?: string[]; sender?: string; + typeArguments?: string[]; } export interface INetworkHelper { From bce096ad558cc642f5e989f87f20163840f75322 Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 20:09:15 +0100 Subject: [PATCH 20/30] added typeArguments for move calls --- src/common/helpers/suiHelper.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 612103e..0d2b7f6 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -20,7 +20,6 @@ import { PureTypeName } from '@mysten/sui/dist/cjs/bcs'; const getConnection = (rpcUrl?: string) => { const connection = provider(rpcUrl); - return connection; }; @@ -229,9 +228,8 @@ const smartContractCall = async ( throw new Error('Number of params and paramTypes must match'); } - // serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. + // handle objects and serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. const moveCallArgs = args.params.map((param, idx) => { - const type = (args.paramTypes ?? [])[idx]; // Handle vector and option types @@ -244,7 +242,7 @@ const smartContractCall = async ( return txb.pure.option(innerType as PureTypeName, param); } - // Handle primitives + // Handle primitive types and objects(stored onchain with objectId) switch (type) { case 'address': return txb.pure.address(param); @@ -264,6 +262,8 @@ const smartContractCall = async ( return txb.pure.u256(param); case 'bool': return txb.pure.bool(param); + case 'object': + return txb.object(param); default: throw new Error(`Unsupported parameter type: ${type}`); } @@ -271,14 +271,15 @@ const smartContractCall = async ( // Build moveCall txb.moveCall({ - target: args.contractAddress, //It should be in the form(0xAddress::module_name::function_name) + target: args.contractAddress, //it should be in the form (0xAddress::module_name::function_name) arguments: moveCallArgs, + typeArguments: args.typeArguments ?? [], }); // Set gas budget - txb.setGasBudget(args.gasLimit || 20000000); // Default to 0.02 SUI + txb.setGasBudget(args.gasLimit ?? 0); + - // to call/simulate a non state-changing function as sui move functions aren't explicitly marked as `view` if (args.methodType === 'read') { const sender = args.sender || '0x0'; const result = await connection.devInspectTransactionBlock({ From 93a0254c8a00b329eb444dd9fcef638d928fba4f Mon Sep 17 00:00:00 2001 From: owanemi Date: Fri, 25 Apr 2025 21:25:17 +0100 Subject: [PATCH 21/30] finished sui wallet tests for all fucntions --- test/wallet.sui.test.ts | 192 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 test/wallet.sui.test.ts diff --git a/test/wallet.sui.test.ts b/test/wallet.sui.test.ts new file mode 100644 index 0000000..d8dc372 --- /dev/null +++ b/test/wallet.sui.test.ts @@ -0,0 +1,192 @@ +import { + createWallet, + generateMnemonic, + generateWalletFromMnemonic, + getAddressFromPrivateKey, + getBalance, + transfer, + getTransaction, + getTokenInfo, + smartContractCall, +} from '../src'; + +describe('MultichainCryptoWallet Sui tests', () => { + const suiTestnetRpc = 'https://fullnode.testnet.sui.io:443'; + const testPrivateKey = + 'suiprivkey1qpppfvzg767qahlw6eu09m2ql3uvc59xqgt3l0un06lvnf8yjxac6v37z3e'; + const USDC_TESTNET_TOKEN = + '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC'; + + const nftName = 'NFT that has usdc logo'; + const nftDescription = 'A test nft'; + const recipientAddress = + '0x7264e741063b6b064cdb780b44578db213cdff9e5641abb2c34a5b5c55307579'; + const nftImgUrl = 'https://circle.com/usdc-icon'; + + const packageId = + '0x086162ecfab930c92b2773f0f878f4998bad6c4fd9d2135fc58f8592ed9f4854'; + const moduleName = 'Nft'; + const moduleMethod = 'mint'; + + const NFT_MINT_CONTRACT = `${packageId}::${moduleName}::${moduleMethod}`; + + it('generateMnemonic', () => { + const mnemonic = generateMnemonic(); + expect(typeof mnemonic).toBe('string'); + }); + + it('createWallet', () => { + const wallet = createWallet({ + derivationPath: "m/44'/784'/0'/0'/0'", // Default Sui derivation path + network: 'sui', + }); + + expect(typeof wallet).toBe('object'); + expect(wallet.data).toHaveProperty('address'); + expect(wallet.data).toHaveProperty('privateKey'); + expect(wallet.data).toHaveProperty('mnemonic'); + }); + + it('generateWalletFromMnemonic', () => { + const wallet = generateWalletFromMnemonic({ + mnemonic: + 'ship friend modify merit dune tower ritual off assault resemble vintage solid', + derivationPath: "m/44'/784'/0'/0'/0'", + network: 'sui', + }); + + expect(typeof wallet).toBe('object'); + expect(wallet.data).toHaveProperty('address'); + expect(wallet.data).toHaveProperty('privateKey'); + expect(wallet.data).toHaveProperty('mnemonic'); + }); + + it('getAddressFromPrivateKey', () => { + const address = getAddressFromPrivateKey({ + privateKey: testPrivateKey, + network: 'sui', + }); + + expect(typeof address).toBe('object'); + expect(address.data).toHaveProperty('address'); + expect(typeof address.data.address).toBe('string'); + }); + + it('getBalance native SUI', async () => { + const data = await getBalance({ + address: + '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + network: 'sui', + rpcUrl: suiTestnetRpc, + }); + + expect(typeof data).toBe('object'); + expect(data.data).toHaveProperty('balance'); + expect(typeof data.data.balance).toBe('number'); + }); + + it('getBalance USDC testnet token', async () => { + const data = await getBalance({ + address: + '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + tokenAddress: USDC_TESTNET_TOKEN, + network: 'sui', + rpcUrl: suiTestnetRpc, + }); + + expect(typeof data).toBe('object'); + expect(data.data).toHaveProperty('balance'); + expect(typeof data.data.balance).toBe('number'); + }); + + it('transfer SUI', async () => { + const response = await transfer({ + recipientAddress: + '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + amount: 0.01, // Small amount for testing + network: 'sui', + rpcUrl: suiTestnetRpc, + privateKey: testPrivateKey, + }); + + expect(typeof response).toBe('object'); + expect(response.data).toHaveProperty('digest'); + }); + + it('transfer USDC Token on Sui Testnet', async () => { + const response = await transfer({ + recipientAddress: + '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + tokenAddress: USDC_TESTNET_TOKEN, + amount: 0.1, + network: 'sui', + rpcUrl: suiTestnetRpc, + privateKey: testPrivateKey, + }); + + expect(typeof response).toBe('object'); + expect(response.data).toHaveProperty('digest'); + }); + + it('getTransaction from hash', async () => { + const receipt = await getTransaction({ + rpcUrl: suiTestnetRpc, + hash: 'AsU5WsBm8kZtuC2hQNyX3zv3CpvHUznE3mLEVewsgp4V', + network: 'sui', + }); + + expect(typeof receipt).toBe('object'); + expect(receipt.data).toHaveProperty('digest'); + }); + + it('getTokenInfo', async () => { + const data = await getTokenInfo({ + address: USDC_TESTNET_TOKEN, + network: 'sui', + rpcUrl: suiTestnetRpc, + }); + + expect(data).toBeDefined(); + expect(typeof data).toBe('object'); + expect(typeof (data && data.data)).toBe('object'); + expect(typeof (data && data.data.name)).toBe('string'); + expect(typeof (data && data.data.symbol)).toBe('string'); + expect(typeof (data && data.data.address)).toBe('string'); + expect(typeof (data && data.data.decimals)).toBe('number'); + expect(typeof (data && data.data.totalSupply)).toBe('string'); + }); + + + it('smartContractCall write (mint an NFT on testnet)', async () => { + const response = await smartContractCall({ + contractAddress: NFT_MINT_CONTRACT, + params: [nftName, nftDescription, recipientAddress, nftImgUrl], + paramTypes: ['string', 'string', 'address', 'string'], + method: moduleMethod, + methodType: 'write', + network: 'sui', + rpcUrl: suiTestnetRpc, + privateKey: testPrivateKey, + gasLimit: 1000000, + }); + + expect(typeof response).toBe('object'); + }); + + // Sui does not have "view" functions, but you can simulate any function call (dry run) to see what would happen/retrieve data, + it('smartContractCall read (getting owner of a global counter object)', async () => { + const response = await smartContractCall({ + contractAddress: '0x775d945700b8e8033df0a2d2b9d1d22ae01e952f47ebe913438c03a17287798c::counter::owner', + params: [], + paramTypes: [], + method: 'owner', + methodType: 'read', + network: 'sui', + rpcUrl: suiTestnetRpc, + sender: '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + }); + + expect(typeof response).toBe('object'); + }); + +}); From 783ab065b53fd34709ab86ed2735f82a1f01bb8f Mon Sep 17 00:00:00 2001 From: owanemi Date: Sat, 26 Apr 2025 00:14:44 +0100 Subject: [PATCH 22/30] update mysten/sui dependency --- package.json | 2 +- src/common/helpers/suiHelper.ts | 61 ++++++++++++++++----------------- yarn.lock | 8 ++--- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/package.json b/package.json index fa5be27..9c66fb8 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ }, "dependencies": { "@bitgo/utxo-lib": "https://github.com/ren-forks/bitgo-utxo-lib#b848585e65b42c48b98c207e72d7d3006c9a5da0", - "@mysten/sui": "^1.28.0", + "@mysten/sui": "^1.28.2", "@solana/spl-token": "^0.2.0", "@solana/web3.js": "^1.39.1", "@truffle/hdwallet-provider": "^2.0.5", diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 0d2b7f6..f59b2c1 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -108,9 +108,7 @@ const getBalance = async (args: BalancePayload): Promise => { const transfer = async (args: TransferPayload): Promise => { try { const connection = provider(args.rpcUrl); - const senderKeypair = Ed25519Keypair.fromSecretKey(args.privateKey); - const txb = new Transaction(); if (args.tokenAddress) { @@ -119,9 +117,7 @@ const transfer = async (args: TransferPayload): Promise => { coinType: args.tokenAddress, }); const decimals = metadata?.decimals || 0; - const rawAmount = BigInt( - Math.floor(args.amount * Math.pow(10, decimals)) - ); + const rawAmount = BigInt(Math.floor(args.amount * Math.pow(10, decimals))); // Fetch sender's coins for the token const { data: coins } = await connection.getCoins({ @@ -132,17 +128,19 @@ const transfer = async (args: TransferPayload): Promise => { if (!coins.length) throw new Error('No coins found.'); // Split the coin for the amount to transfer - const [coin] = txb.splitCoins(txb.object(coins[0].coinObjectId), [ - txb.pure.u64(rawAmount), + const [coin] = (txb as any).splitCoins((txb as any).object(coins[0].coinObjectId), [ + (txb as any).pure.u64(rawAmount), ]); - txb.transferObjects([coin], txb.pure.address(args.recipientAddress)); + + // Bypass type check for transferObjects + (txb as any).transferObjects([coin], (txb as any).pure.address(args.recipientAddress)); } else { - // native sui transfer - const amountInMist = BigInt( - Math.floor(args.amount * Number(MIST_PER_SUI)) - ); - const [coin] = txb.splitCoins(txb.gas, [txb.pure.u64(amountInMist)]); - txb.transferObjects([coin], txb.pure.address(args.recipientAddress)); + // Native SUI transfer + const amountInMist = BigInt(Math.floor(args.amount * Number(MIST_PER_SUI))); + // Bypass type check for gas + const [coin] = (txb as any).splitCoins((txb as any).gas, [(txb as any).pure.u64(amountInMist)]); + // Bypass type check for transferObjects + (txb as any).transferObjects([coin], (txb as any).pure.address(args.recipientAddress)); } // Sign and execute the transaction @@ -228,57 +226,56 @@ const smartContractCall = async ( throw new Error('Number of params and paramTypes must match'); } - // handle objects and serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. + // Handle objects and serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. const moveCallArgs = args.params.map((param, idx) => { const type = (args.paramTypes ?? [])[idx]; // Handle vector and option types if (type.startsWith('vector<') && type.endsWith('>')) { const innerType = type.slice(7, -1); // e.g., 'u8' from 'vector' - return txb.pure.vector(innerType as PureTypeName, param); + return (txb as any).pure.vector(innerType as PureTypeName, param); } if (type.startsWith('option<') && type.endsWith('>')) { const innerType = type.slice(7, -1); // e.g., 'u64' from 'option' - return txb.pure.option(innerType as PureTypeName, param); + return (txb as any).pure.option(innerType as PureTypeName, param); } - // Handle primitive types and objects(stored onchain with objectId) + // Handle primitive types and objects (stored onchain with objectId) switch (type) { case 'address': - return txb.pure.address(param); + return (txb as any).pure.address(param); case 'string': - return txb.pure.string(param); + return (txb as any).pure.string(param); case 'u8': - return txb.pure.u8(param); + return (txb as any).pure.u8(param); case 'u16': - return txb.pure.u16(param); + return (txb as any).pure.u16(param); case 'u32': - return txb.pure.u32(param); + return (txb as any).pure.u32(param); case 'u64': - return txb.pure.u64(param); + return (txb as any).pure.u64(param); case 'u128': - return txb.pure.u128(param); + return (txb as any).pure.u128(param); case 'u256': - return txb.pure.u256(param); + return (txb as any).pure.u256(param); case 'bool': - return txb.pure.bool(param); + return (txb as any).pure.bool(param); case 'object': - return txb.object(param); + return (txb as any).object(param); default: throw new Error(`Unsupported parameter type: ${type}`); } }); // Build moveCall - txb.moveCall({ - target: args.contractAddress, //it should be in the form (0xAddress::module_name::function_name) + (txb as any).moveCall({ + target: args.contractAddress, // it should be in the form (0xAddress::module_name::function_name) arguments: moveCallArgs, typeArguments: args.typeArguments ?? [], }); // Set gas budget - txb.setGasBudget(args.gasLimit ?? 0); - + (txb as any).setGasBudget(args.gasLimit ?? 0); if (args.methodType === 'read') { const sender = args.sender || '0x0'; diff --git a/yarn.lock b/yarn.lock index 6b1d202..1876a4a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1600,10 +1600,10 @@ dependencies: "@scure/base" "^1.2.4" -"@mysten/sui@^1.28.0": - version "1.28.0" - resolved "https://registry.yarnpkg.com/@mysten/sui/-/sui-1.28.0.tgz#32322ade494a64284e1bf09a995b46de72a93935" - integrity sha512-ABcKc+QBpazBl5/ByLChxHOiPjqxISSdXnBuU1rLm1frp5tjMSCChiL7Reth2zcxWO2qYFK70ewEkYVtJvJQvw== +"@mysten/sui@^1.28.2": + version "1.28.2" + resolved "https://registry.yarnpkg.com/@mysten/sui/-/sui-1.28.2.tgz#ded2ae122c53ac3bb6f05d731b5847e447512eb2" + integrity sha512-d+lSp3rAtuOX0taIiIv0KNILDsbmAB9koNGHBinfREraGnE9tUFW315UByuyvuZ9K53ji4i2risdtwxCQ1a8Zw== dependencies: "@graphql-typed-document-node/core" "^3.2.0" "@mysten/bcs" "1.6.0" From 145089a39e415237472c3fd9ee7c377d840ad42c Mon Sep 17 00:00:00 2001 From: owanemi Date: Sat, 26 Apr 2025 00:56:19 +0100 Subject: [PATCH 23/30] added typed transaction builder for transfer and contract call --- src/common/helpers/suiHelper.ts | 98 ++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index f59b2c1..802f417 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -111,6 +111,29 @@ const transfer = async (args: TransferPayload): Promise => { const senderKeypair = Ed25519Keypair.fromSecretKey(args.privateKey); const txb = new Transaction(); + // Create a typed version of the transaction builder + const tx = txb as unknown as { + splitCoins: (coin: any, amounts: any[]) => any[]; + pure: { + u64: (value: number | bigint) => any; + address: (addr: string) => any; + vector: (type: string, values: any[]) => any; + option: (type: string, value: any) => any; + string: (value: string) => any; + u8: (value: number) => any; + u16: (value: number) => any; + u32: (value: number) => any; + u128: (value: number | bigint) => any; + u256: (value: number | bigint) => any; + bool: (value: boolean) => any; + }; + object: (id: string) => any; + transferObjects: (objects: any[], address: any) => void; + gas: any; + setGasBudget: (budget: number | bigint) => void; + moveCall: (args: any) => any; + }; + if (args.tokenAddress) { // Fetch token decimals const metadata = await connection.getCoinMetadata({ @@ -128,19 +151,17 @@ const transfer = async (args: TransferPayload): Promise => { if (!coins.length) throw new Error('No coins found.'); // Split the coin for the amount to transfer - const [coin] = (txb as any).splitCoins((txb as any).object(coins[0].coinObjectId), [ - (txb as any).pure.u64(rawAmount), + const [coin] = tx.splitCoins(tx.object(coins[0].coinObjectId), [ + tx.pure.u64(rawAmount), ]); - // Bypass type check for transferObjects - (txb as any).transferObjects([coin], (txb as any).pure.address(args.recipientAddress)); + // Transfer the coin to the recipient + tx.transferObjects([coin], tx.pure.address(args.recipientAddress)); } else { // Native SUI transfer const amountInMist = BigInt(Math.floor(args.amount * Number(MIST_PER_SUI))); - // Bypass type check for gas - const [coin] = (txb as any).splitCoins((txb as any).gas, [(txb as any).pure.u64(amountInMist)]); - // Bypass type check for transferObjects - (txb as any).transferObjects([coin], (txb as any).pure.address(args.recipientAddress)); + const [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(amountInMist)]); + tx.transferObjects([coin], tx.pure.address(args.recipientAddress)); } // Sign and execute the transaction @@ -221,61 +242,86 @@ const smartContractCall = async ( const connection = getConnection(args.rpcUrl); const txb = new Transaction(); + // Create a typed version of the transaction builder + const tx = txb as unknown as { + splitCoins: (coin: any, amounts: any[]) => any[]; + pure: { + u64: (value: number | bigint) => any; + address: (addr: string) => any; + vector: (type: string, values: any[]) => any; + option: (type: string, value: any) => any; + string: (value: string) => any; + u8: (value: number) => any; + u16: (value: number) => any; + u32: (value: number) => any; + u128: (value: number | bigint) => any; + u256: (value: number | bigint) => any; + bool: (value: boolean) => any; + }; + object: (id: string) => any; + transferObjects: (objects: any[], address: any) => void; + gas: any; + setGasBudget: (budget: number | bigint) => void; + moveCall: (args: any) => any; + }; + // Validate params and paramTypes length match if (args.params.length !== (args.paramTypes ?? []).length) { throw new Error('Number of params and paramTypes must match'); } - // Handle objects and serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. + // Handle objects and serialize parameters const moveCallArgs = args.params.map((param, idx) => { const type = (args.paramTypes ?? [])[idx]; // Handle vector and option types if (type.startsWith('vector<') && type.endsWith('>')) { const innerType = type.slice(7, -1); // e.g., 'u8' from 'vector' - return (txb as any).pure.vector(innerType as PureTypeName, param); + return tx.pure.vector(innerType as PureTypeName, param); } if (type.startsWith('option<') && type.endsWith('>')) { const innerType = type.slice(7, -1); // e.g., 'u64' from 'option' - return (txb as any).pure.option(innerType as PureTypeName, param); + return tx.pure.option(innerType as PureTypeName, param); } - // Handle primitive types and objects (stored onchain with objectId) + // Handle primitive types and objects switch (type) { case 'address': - return (txb as any).pure.address(param); + return tx.pure.address(param); case 'string': - return (txb as any).pure.string(param); + return tx.pure.string(param); case 'u8': - return (txb as any).pure.u8(param); + return tx.pure.u8(param); case 'u16': - return (txb as any).pure.u16(param); + return tx.pure.u16(param); case 'u32': - return (txb as any).pure.u32(param); + return tx.pure.u32(param); case 'u64': - return (txb as any).pure.u64(param); + return tx.pure.u64(param); case 'u128': - return (txb as any).pure.u128(param); + return tx.pure.u128(param); case 'u256': - return (txb as any).pure.u256(param); + return tx.pure.u256(param); case 'bool': - return (txb as any).pure.bool(param); + return tx.pure.bool(param); case 'object': - return (txb as any).object(param); + return tx.object(param); default: throw new Error(`Unsupported parameter type: ${type}`); } }); // Build moveCall - (txb as any).moveCall({ - target: args.contractAddress, // it should be in the form (0xAddress::module_name::function_name) + tx.moveCall({ + target: args.contractAddress, // in the form (0xAddress::module_name::function_name) arguments: moveCallArgs, typeArguments: args.typeArguments ?? [], }); // Set gas budget - (txb as any).setGasBudget(args.gasLimit ?? 0); + if (args.gasLimit) { + tx.setGasBudget(args.gasLimit); + } if (args.methodType === 'read') { const sender = args.sender || '0x0'; @@ -327,4 +373,4 @@ export default { getTransaction, getTokenInfo, smartContractCall, -}; +}; \ No newline at end of file From bbd6702404fda390261aff6b3bb4fa90fa0b2c62 Mon Sep 17 00:00:00 2001 From: owanemi Date: Tue, 29 Apr 2025 15:59:58 +0100 Subject: [PATCH 24/30] fix ESM module test errors --- .babelrc | 19 +++ jest.config.js | 16 +- jest.setup.js | 14 +- package.json | 22 ++- yarn.lock | 433 ++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 468 insertions(+), 36 deletions(-) create mode 100644 .babelrc diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..5091977 --- /dev/null +++ b/.babelrc @@ -0,0 +1,19 @@ +{ + "env": { + "test": { + "presets": [ + ["@babel/preset-env", { "targets": { "node": "current" } }], + "@babel/preset-typescript" + ], + "plugins": [ + "@babel/plugin-transform-modules-commonjs" + ] + }, + "production": { + "presets": [ + ["@babel/preset-env", { "targets": { "node": "current" }, "modules": false }], + "@babel/preset-typescript" + ] + } + } +} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index 9bb76ea..f6783e8 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,14 +1,28 @@ const config = { - testTimeout: 100000, + testTimeout: 100000, moduleNameMapper: { '^axios$': 'axios/dist/axios.js', }, globals: { 'ts-jest': { isolatedModules: true, + useESM: true, }, }, + preset: 'ts-jest/presets/default-esm', + extensionsToTreatAsEsm: ['.ts', '.tsx'], setupFiles: ['./jest.setup.js'], + transform: { + '^.+\\.(ts|tsx|js|jsx)$': ['babel-jest', { + presets: [ + ['@babel/preset-env', { targets: { node: 'current' } }], + '@babel/preset-typescript' + ], + }] + }, + transformIgnorePatterns: [ + '/node_modules/(?!(@mysten/sui|valibot)/)' + ], }; module.exports = config; diff --git a/jest.setup.js b/jest.setup.js index 82e0868..9f7f24e 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1,17 +1,25 @@ const crypto = require('crypto'); +const { TextEncoder, TextDecoder } = require('util'); +const fetch = require('node-fetch'); +// Add TextEncoder/TextDecoder to global +global.TextEncoder = TextEncoder; +global.TextDecoder = TextDecoder; +global.fetch = fetch; + +// Setup crypto Object.defineProperty(global, 'crypto', { value: { getRandomValues: arr => crypto.randomFillSync(arr), + subtle: crypto.subtle }, }); +// Patch @noble/hashes try { const noble = require('@noble/hashes/utils'); if (noble) { - noble.randomBytes = length => { - return crypto.randomBytes(length); - }; + noble.randomBytes = (length) => crypto.randomBytes(length); } } catch (e) { console.warn('Could not patch @noble/hashes'); diff --git a/package.json b/package.json index 9c66fb8..f1aa763 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,13 @@ }, "scripts": { "start": "tsdx watch", - "build": "tsdx build", - "test": "tsdx test", - "test:btc": "tsdx test --testPathPattern=bitcoin", - "test:eth": "tsdx test --testPathPattern=ethereum", - "test:sol": "tsdx test --testPathPattern=solana", - "test:tron": "tsdx test --testPathPattern=tron", - "test:waves": "tsdx test --testPathPattern=waves", + "build": "cross-env NODE_ENV=production tsdx build", + "test": "cross-env NODE_ENV=test tsdx test", + "test:btc": "cross-env NODE_ENV=test tsdx test --testPathPattern=bitcoin", + "test:eth": "cross-env NODE_ENV=test tsdx test --testPathPattern=ethereum", + "test:sol": "cross-env NODE_ENV=test tsdx test --testPathPattern=solana", + "test:tron": "cross-env NODE_ENV=test tsdx test --testPathPattern=tron", + "test:waves": "cross-env NODE_ENV=test tsdx test --testPathPattern=waves", "lint": "tsdx lint", "prepare": "tsdx build", "size": "size-limit", @@ -76,9 +76,17 @@ } ], "devDependencies": { + "@babel/core": "^7.26.10", + "@babel/plugin-transform-modules-commonjs": "^7.26.3", + "@babel/preset-env": "^7.26.9", + "@babel/preset-typescript": "^7.27.0", "@size-limit/preset-small-lib": "^7.0.8", + "babel-jest": "^29.7.0", + "cross-env": "^7.0.3", "husky": "^7.0.4", + "node-fetch": "2.6.7", "size-limit": "^7.0.8", + "ts-jest": "^29.3.2", "tsdx": "^0.14.1", "tslib": "^2.3.1", "typescript": "^4.6.3" diff --git a/yarn.lock b/yarn.lock index 1876a4a..9df05ca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,7 +42,7 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367" integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.4.4", "@babel/core@^7.7.5": +"@babel/core@^7.1.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.26.10", "@babel/core@^7.4.4", "@babel/core@^7.7.5": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.10.tgz#5c876f83c8c4dcb233ee4b670c0606f2ac3000f9" integrity sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ== @@ -74,6 +74,17 @@ "@jridgewell/trace-mapping" "^0.3.25" jsesc "^3.0.2" +"@babel/generator@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.0.tgz#764382b5392e5b9aff93cadb190d0745866cbc2c" + integrity sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw== + dependencies: + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/helper-annotate-as-pure@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4" @@ -105,6 +116,19 @@ "@babel/traverse" "^7.26.9" semver "^6.3.1" +"@babel/helper-create-class-features-plugin@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz#518fad6a307c6a96f44af14912b2c20abe9bfc30" + integrity sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-member-expression-to-functions" "^7.25.9" + "@babel/helper-optimise-call-expression" "^7.25.9" + "@babel/helper-replace-supers" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/traverse" "^7.27.0" + semver "^6.3.1" + "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9": version "7.26.3" resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz#5169756ecbe1d95f7866b90bb555b022595302a0" @@ -171,7 +195,7 @@ dependencies: "@babel/types" "^7.25.9" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.26.5", "@babel/helper-plugin-utils@^7.8.0": version "7.26.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz#18580d00c9934117ad719392c4f6585c9333cc35" integrity sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg== @@ -241,6 +265,13 @@ dependencies: "@babel/types" "^7.26.10" +"@babel/parser@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.0.tgz#3d7d6ee268e41d2600091cbd4e145ffee85a44ec" + integrity sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg== + dependencies: + "@babel/types" "^7.27.0" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe" @@ -307,13 +338,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-import-assertions@^7.26.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz#620412405058efa56e4a564903b79355020f445f" @@ -321,14 +359,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-import-attributes@^7.26.0": +"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.26.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7" integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A== dependencies: "@babel/helper-plugin-utils" "^7.25.9" -"@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -342,7 +380,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-jsx@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290" + integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -356,7 +401,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -384,6 +429,27 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.25.9": + version "7.25.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399" + integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.9" + "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" @@ -760,6 +826,17 @@ dependencies: "@babel/helper-plugin-utils" "^7.26.5" +"@babel/plugin-transform-typescript@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.0.tgz#a29fd3481da85601c7e34091296e9746d2cccba8" + integrity sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.9" + "@babel/helper-create-class-features-plugin" "^7.27.0" + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9" + "@babel/plugin-syntax-typescript" "^7.25.9" + "@babel/plugin-transform-unicode-escapes@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz#a75ef3947ce15363fccaa38e2dd9bc70b2788b82" @@ -791,7 +868,7 @@ "@babel/helper-create-regexp-features-plugin" "^7.25.9" "@babel/helper-plugin-utils" "^7.25.9" -"@babel/preset-env@^7.11.0": +"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.26.9": version "7.26.9" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.26.9.tgz#2ec64e903d0efe743699f77a10bdf7955c2123c3" integrity sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ== @@ -875,6 +952,17 @@ "@babel/types" "^7.4.4" esutils "^2.0.2" +"@babel/preset-typescript@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.27.0.tgz#4dcb8827225975f4290961b0b089f9c694ca50c7" + integrity sha512-vxaPFfJtHhgeOVXRKuHpHPAOgymmy8V8I65T1q53R7GCZlefKeCaTyDs3zOPHTTbmquvNlQYC5klEvWsBAtrBQ== + dependencies: + "@babel/helper-plugin-utils" "^7.26.5" + "@babel/helper-validator-option" "^7.25.9" + "@babel/plugin-syntax-jsx" "^7.25.9" + "@babel/plugin-transform-modules-commonjs" "^7.26.3" + "@babel/plugin-transform-typescript" "^7.27.0" + "@babel/runtime@^7.0.0", "@babel/runtime@^7.25.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" @@ -891,6 +979,15 @@ "@babel/parser" "^7.26.9" "@babel/types" "^7.26.9" +"@babel/template@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.0.tgz#b253e5406cc1df1c57dcd18f11760c2dbf40c0b4" + integrity sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/parser" "^7.27.0" + "@babel/types" "^7.27.0" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.11.5", "@babel/traverse@^7.25.9", "@babel/traverse@^7.26.10", "@babel/traverse@^7.26.5", "@babel/traverse@^7.26.8", "@babel/traverse@^7.26.9", "@babel/traverse@^7.7.0": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.10.tgz#43cca33d76005dbaa93024fae536cc1946a4c380" @@ -904,6 +1001,19 @@ debug "^4.3.1" globals "^11.1.0" +"@babel/traverse@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.0.tgz#11d7e644779e166c0442f9a07274d02cd91d4a70" + integrity sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA== + dependencies: + "@babel/code-frame" "^7.26.2" + "@babel/generator" "^7.27.0" + "@babel/parser" "^7.27.0" + "@babel/template" "^7.27.0" + "@babel/types" "^7.27.0" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.10", "@babel/types@^7.26.9", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": version "7.26.10" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.10.tgz#396382f6335bd4feb65741eacfc808218f859259" @@ -912,6 +1022,14 @@ "@babel/helper-string-parser" "^7.25.9" "@babel/helper-validator-identifier" "^7.25.9" +"@babel/types@^7.27.0": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.0.tgz#ef9acb6b06c3173f6632d993ecb6d4ae470b4559" + integrity sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg== + dependencies: + "@babel/helper-string-parser" "^7.25.9" + "@babel/helper-validator-identifier" "^7.25.9" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -1483,6 +1601,13 @@ optionalDependencies: node-notifier "^6.0.0" +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + "@jest/source-map@^25.5.0": version "25.5.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-25.5.0.tgz#df5c20d6050aa292c2c6d3f0d2c7606af315bd1b" @@ -1535,6 +1660,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + "@jest/types@^25.5.0": version "25.5.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" @@ -1545,6 +1691,18 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.3.5": version "0.3.8" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" @@ -1569,7 +1727,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1902,6 +2060,11 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.6.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -2033,7 +2196,7 @@ keccak "3.0.2" secp256k1 "4.0.3" -"@types/babel__core@^7.1.7": +"@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -2124,7 +2287,7 @@ dependencies: bignumber.js "7.2.1" -"@types/graceful-fs@^4.1.2": +"@types/graceful-fs@^4.1.2", "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== @@ -2156,6 +2319,13 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + "@types/jest@^25.2.1": version "25.2.3" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-25.2.3.tgz#33d27e4c4716caae4eced355097a47ad363fdcaf" @@ -2312,6 +2482,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^2.12.0": version "2.34.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" @@ -2792,6 +2969,11 @@ async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0: dependencies: lodash "^4.17.14" +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2889,6 +3071,19 @@ babel-jest@^25.5.1: graceful-fs "^4.2.4" slash "^3.0.0" +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-plugin-annotate-pure-calls@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/babel-plugin-annotate-pure-calls/-/babel-plugin-annotate-pure-calls-0.4.0.tgz#78aa00fd878c4fcde4d49f3da397fcf5defbcce8" @@ -2899,7 +3094,7 @@ babel-plugin-dev-expression@^0.2.1: resolved "https://registry.yarnpkg.com/babel-plugin-dev-expression/-/babel-plugin-dev-expression-0.2.3.tgz#8aaf52155dfb063ed4ddec6280456fbc256fead4" integrity sha512-rP5LK9QQTzCW61nVVzw88En1oK8t8gTsIeC6E61oelxNsU842yMjF0G1MxhvUpCkxCEIj7sE8/e5ieTheT//uw== -babel-plugin-istanbul@^6.0.0: +babel-plugin-istanbul@^6.0.0, babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== @@ -2919,6 +3114,16 @@ babel-plugin-jest-hoist@^25.5.0: "@babel/types" "^7.3.3" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-plugin-macros@^2.6.1: version "2.8.0" resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" @@ -2981,6 +3186,27 @@ babel-preset-current-node-syntax@^0.1.2: "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" +babel-preset-current-node-syntax@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + babel-preset-jest@^25.5.0: version "25.5.0" resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-25.5.0.tgz#c1d7f191829487a907764c65307faa0e66590b49" @@ -2989,6 +3215,14 @@ babel-preset-jest@^25.5.0: babel-plugin-jest-hoist "^25.5.0" babel-preset-current-node-syntax "^0.1.2" +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + backoff@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" @@ -3208,6 +3442,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" @@ -3270,7 +3511,7 @@ browserslist@^4.24.0, browserslist@^4.24.4: node-releases "^2.0.19" update-browserslist-db "^1.1.1" -bs-logger@0.x: +bs-logger@0.x, bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== @@ -3491,7 +3732,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -3541,6 +3782,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + ci-job-number@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/ci-job-number/-/ci-job-number-1.2.2.tgz#f4e5918fcaeeda95b604f214be7d7d4a961fe0c0" @@ -3819,6 +4065,13 @@ create-hmac@1.1.7, create-hmac@^1.1.3, create-hmac@^1.1.4, create-hmac@^1.1.7: safe-buffer "^5.0.1" sha.js "^2.4.8" +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + cross-fetch@^2.1.0: version "2.2.6" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" @@ -3845,7 +4098,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^7.0.0, cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -4179,6 +4432,13 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + electron-to-chromium@^1.5.73: version "1.5.123" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.123.tgz#fae5bdba0ba27045895176327aa79831aba0790c" @@ -5460,7 +5720,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.8" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -5513,6 +5773,13 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -5689,7 +5956,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.1.2, fsevents@~2.3.2: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -5930,7 +6197,7 @@ gql.tada@^1.8.2: "@gql.tada/cli-utils" "1.6.3" "@gql.tada/internal" "1.0.8" -graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -6719,6 +6986,16 @@ iterator.prototype@^1.1.4: has-symbols "^1.1.0" set-function-name "^2.0.2" +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + jayson@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.3.tgz#db9be2e4287d9fef4fc05b5fe367abe792c2eee8" @@ -6868,6 +7145,25 @@ jest-haste-map@^25.5.1: optionalDependencies: fsevents "^2.1.2" +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + jest-jasmine2@^25.5.4: version "25.5.4" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-25.5.4.tgz#66ca8b328fb1a3c5364816f8958f6970a8526968" @@ -6940,6 +7236,11 @@ jest-regex-util@^25.2.1, jest-regex-util@^25.2.6: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-25.2.6.tgz#d847d38ba15d2118d3b06390056028d0f2fd3964" integrity sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + jest-resolve-dependencies@^25.5.4: version "25.5.4" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-25.5.4.tgz#85501f53957c8e3be446e863a74777b5a17397a7" @@ -7060,6 +7361,18 @@ jest-util@^25.5.0: is-ci "^2.0.0" make-dir "^3.0.0" +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^25.5.0: version "25.5.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-25.5.0.tgz#fb4c93f332c2e4cf70151a628e58a35e459a413a" @@ -7113,6 +7426,16 @@ jest-worker@^25.5.0: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@^25.3.0: version "25.5.4" resolved "https://registry.yarnpkg.com/jest/-/jest-25.5.4.tgz#f21107b6489cfe32b076ce2adcadee3587acb9db" @@ -7479,7 +7802,7 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.memoize@4.x: +lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== @@ -7591,7 +7914,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x: +make-error@1.x, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -7690,7 +8013,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@4.x, micromatch@^4.0.2, micromatch@^4.0.8: +micromatch@4.x, micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== @@ -7778,6 +8101,13 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.6, minimist@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -7982,6 +8312,13 @@ node-addon-api@^5.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7, node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -8405,7 +8742,7 @@ picocolors@^1.0.0, picocolors@^1.1.1: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -8425,6 +8762,11 @@ pirates@^4.0.1: resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -9286,7 +9628,7 @@ semver@7.3.5: dependencies: lru-cache "^6.0.0" -semver@^7.1.1, semver@^7.3.2, semver@^7.5.3: +semver@^7.1.1, semver@^7.3.2, semver@^7.5.3, semver@^7.7.1: version "7.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== @@ -9490,7 +9832,7 @@ side-channel@^1.0.6, side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -9935,6 +10277,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" @@ -10168,6 +10517,22 @@ ts-jest@^25.3.1: semver "6.x" yargs-parser "18.x" +ts-jest@^29.3.2: + version "29.3.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.3.2.tgz#0576cdf0a507f811fe73dcd16d135ce89f8156cb" + integrity sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug== + dependencies: + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.1" + type-fest "^4.39.1" + yargs-parser "^21.1.1" + tsconfig-paths@^3.15.0: version "3.15.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" @@ -10316,6 +10681,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^4.39.1: + version "4.40.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.40.1.tgz#d78a09f08dd1081a434dd377967650cfd565401d" + integrity sha512-9YvLNnORDpI+vghLU/Nf+zSv0kL47KbVJ1o3sKgoTefl6i+zebxbiDQWoe/oWWqPhIgQdRZRT1KA9sCPL810SA== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -10658,7 +11028,7 @@ wait-on@7.0.1: minimist "^1.2.7" rxjs "^7.8.0" -walker@^1.0.7, walker@~1.0.5: +walker@^1.0.7, walker@^1.0.8, walker@~1.0.5: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -11101,6 +11471,14 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" @@ -11229,6 +11607,11 @@ yargs-parser@18.x, yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^15.3.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" From 65feac395bd08436f114dd7d8809b17fe9256e47 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 00:42:53 +0100 Subject: [PATCH 25/30] resolve ESM module issue --- jest.config.js | 3 +- src/common/helpers/suiHelper.ts | 69 ++++++----------------------- test/wallet.sui.test.ts | 77 +++++++++++++++------------------ 3 files changed, 50 insertions(+), 99 deletions(-) diff --git a/jest.config.js b/jest.config.js index f6783e8..d06f182 100644 --- a/jest.config.js +++ b/jest.config.js @@ -10,10 +10,9 @@ const config = { }, }, preset: 'ts-jest/presets/default-esm', - extensionsToTreatAsEsm: ['.ts', '.tsx'], setupFiles: ['./jest.setup.js'], transform: { - '^.+\\.(ts|tsx|js|jsx)$': ['babel-jest', { + '^.+\\.(ts|js)$': ['babel-jest', { presets: [ ['@babel/preset-env', { targets: { node: 'current' } }], '@babel/preset-typescript' diff --git a/src/common/helpers/suiHelper.ts b/src/common/helpers/suiHelper.ts index 802f417..7e2725a 100644 --- a/src/common/helpers/suiHelper.ts +++ b/src/common/helpers/suiHelper.ts @@ -110,29 +110,7 @@ const transfer = async (args: TransferPayload): Promise => { const connection = provider(args.rpcUrl); const senderKeypair = Ed25519Keypair.fromSecretKey(args.privateKey); const txb = new Transaction(); - - // Create a typed version of the transaction builder - const tx = txb as unknown as { - splitCoins: (coin: any, amounts: any[]) => any[]; - pure: { - u64: (value: number | bigint) => any; - address: (addr: string) => any; - vector: (type: string, values: any[]) => any; - option: (type: string, value: any) => any; - string: (value: string) => any; - u8: (value: number) => any; - u16: (value: number) => any; - u32: (value: number) => any; - u128: (value: number | bigint) => any; - u256: (value: number | bigint) => any; - bool: (value: boolean) => any; - }; - object: (id: string) => any; - transferObjects: (objects: any[], address: any) => void; - gas: any; - setGasBudget: (budget: number | bigint) => void; - moveCall: (args: any) => any; - }; + const tx = txb as any; if (args.tokenAddress) { // Fetch token decimals @@ -140,7 +118,9 @@ const transfer = async (args: TransferPayload): Promise => { coinType: args.tokenAddress, }); const decimals = metadata?.decimals || 0; - const rawAmount = BigInt(Math.floor(args.amount * Math.pow(10, decimals))); + const rawAmount = BigInt( + Math.floor(args.amount * Math.pow(10, decimals)) + ); // Fetch sender's coins for the token const { data: coins } = await connection.getCoins({ @@ -155,11 +135,12 @@ const transfer = async (args: TransferPayload): Promise => { tx.pure.u64(rawAmount), ]); - // Transfer the coin to the recipient tx.transferObjects([coin], tx.pure.address(args.recipientAddress)); } else { // Native SUI transfer - const amountInMist = BigInt(Math.floor(args.amount * Number(MIST_PER_SUI))); + const amountInMist = BigInt( + Math.floor(args.amount * Number(MIST_PER_SUI)) + ); const [coin] = tx.splitCoins(tx.gas, [tx.pure.u64(amountInMist)]); tx.transferObjects([coin], tx.pure.address(args.recipientAddress)); } @@ -241,36 +222,14 @@ const smartContractCall = async ( ): Promise => { const connection = getConnection(args.rpcUrl); const txb = new Transaction(); - - // Create a typed version of the transaction builder - const tx = txb as unknown as { - splitCoins: (coin: any, amounts: any[]) => any[]; - pure: { - u64: (value: number | bigint) => any; - address: (addr: string) => any; - vector: (type: string, values: any[]) => any; - option: (type: string, value: any) => any; - string: (value: string) => any; - u8: (value: number) => any; - u16: (value: number) => any; - u32: (value: number) => any; - u128: (value: number | bigint) => any; - u256: (value: number | bigint) => any; - bool: (value: boolean) => any; - }; - object: (id: string) => any; - transferObjects: (objects: any[], address: any) => void; - gas: any; - setGasBudget: (budget: number | bigint) => void; - moveCall: (args: any) => any; - }; + const tx = txb as any; // Validate params and paramTypes length match if (args.params.length !== (args.paramTypes ?? []).length) { throw new Error('Number of params and paramTypes must match'); } - // Handle objects and serialize parameters + // Handle objects and serialize parameters as the arguments expected by the MoveVM are in binary format (BCS) when sending transactions. const moveCallArgs = args.params.map((param, idx) => { const type = (args.paramTypes ?? [])[idx]; @@ -284,7 +243,7 @@ const smartContractCall = async ( return tx.pure.option(innerType as PureTypeName, param); } - // Handle primitive types and objects + // Handle primitive types and objects (stored onchain with objectId) switch (type) { case 'address': return tx.pure.address(param); @@ -313,15 +272,13 @@ const smartContractCall = async ( // Build moveCall tx.moveCall({ - target: args.contractAddress, // in the form (0xAddress::module_name::function_name) + target: args.contractAddress, // it should be in the form (0xAddress::module_name::function_name) arguments: moveCallArgs, typeArguments: args.typeArguments ?? [], }); // Set gas budget - if (args.gasLimit) { - tx.setGasBudget(args.gasLimit); - } + tx.setGasBudget(args.gasLimit ?? 0); if (args.methodType === 'read') { const sender = args.sender || '0x0'; @@ -373,4 +330,4 @@ export default { getTransaction, getTokenInfo, smartContractCall, -}; \ No newline at end of file +}; diff --git a/test/wallet.sui.test.ts b/test/wallet.sui.test.ts index d8dc372..ebba532 100644 --- a/test/wallet.sui.test.ts +++ b/test/wallet.sui.test.ts @@ -25,7 +25,7 @@ describe('MultichainCryptoWallet Sui tests', () => { const packageId = '0x086162ecfab930c92b2773f0f878f4998bad6c4fd9d2135fc58f8592ed9f4854'; - const moduleName = 'Nft'; + const moduleName = 'nft'; const moduleMethod = 'mint'; const NFT_MINT_CONTRACT = `${packageId}::${moduleName}::${moduleMethod}`; @@ -42,9 +42,9 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof wallet).toBe('object'); - expect(wallet.data).toHaveProperty('address'); - expect(wallet.data).toHaveProperty('privateKey'); - expect(wallet.data).toHaveProperty('mnemonic'); + expect(wallet).toHaveProperty('address'); + expect(wallet).toHaveProperty('privateKey'); + expect(wallet).toHaveProperty('mnemonic'); }); it('generateWalletFromMnemonic', () => { @@ -56,9 +56,9 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof wallet).toBe('object'); - expect(wallet.data).toHaveProperty('address'); - expect(wallet.data).toHaveProperty('privateKey'); - expect(wallet.data).toHaveProperty('mnemonic'); + expect(wallet).toHaveProperty('address'); + expect(wallet).toHaveProperty('privateKey'); + expect(wallet).toHaveProperty('mnemonic'); }); it('getAddressFromPrivateKey', () => { @@ -68,8 +68,8 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof address).toBe('object'); - expect(address.data).toHaveProperty('address'); - expect(typeof address.data.address).toBe('string'); + expect(address).toHaveProperty('address'); + expect(typeof address.address).toBe('string'); }); it('getBalance native SUI', async () => { @@ -81,8 +81,8 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof data).toBe('object'); - expect(data.data).toHaveProperty('balance'); - expect(typeof data.data.balance).toBe('number'); + expect(data).toHaveProperty('balance'); + expect(typeof data.balance).toBe('number'); }); it('getBalance USDC testnet token', async () => { @@ -95,28 +95,26 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof data).toBe('object'); - expect(data.data).toHaveProperty('balance'); - expect(typeof data.data.balance).toBe('number'); + expect(data).toHaveProperty('balance'); + expect(typeof data.balance).toBe('number'); }); it('transfer SUI', async () => { const response = await transfer({ - recipientAddress: - '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', - amount: 0.01, // Small amount for testing + recipientAddress: recipientAddress, + amount: 0.01, network: 'sui', rpcUrl: suiTestnetRpc, privateKey: testPrivateKey, }); expect(typeof response).toBe('object'); - expect(response.data).toHaveProperty('digest'); + expect(response).toHaveProperty('digest'); }); it('transfer USDC Token on Sui Testnet', async () => { const response = await transfer({ - recipientAddress: - '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + recipientAddress: recipientAddress, tokenAddress: USDC_TESTNET_TOKEN, amount: 0.1, network: 'sui', @@ -125,7 +123,7 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof response).toBe('object'); - expect(response.data).toHaveProperty('digest'); + expect(response).toHaveProperty('digest'); }); it('getTransaction from hash', async () => { @@ -136,26 +134,26 @@ describe('MultichainCryptoWallet Sui tests', () => { }); expect(typeof receipt).toBe('object'); - expect(receipt.data).toHaveProperty('digest'); + expect(receipt).toHaveProperty('digest'); }); - it('getTokenInfo', async () => { - const data = await getTokenInfo({ + it('getTokenInfo (USDC Testnet Coin)', async () => { + const tokenInfo = await getTokenInfo({ address: USDC_TESTNET_TOKEN, network: 'sui', rpcUrl: suiTestnetRpc, }); - expect(data).toBeDefined(); - expect(typeof data).toBe('object'); - expect(typeof (data && data.data)).toBe('object'); - expect(typeof (data && data.data.name)).toBe('string'); - expect(typeof (data && data.data.symbol)).toBe('string'); - expect(typeof (data && data.data.address)).toBe('string'); - expect(typeof (data && data.data.decimals)).toBe('number'); - expect(typeof (data && data.data.totalSupply)).toBe('string'); - }); + expect(tokenInfo).toBeDefined(); + expect(typeof tokenInfo).toBe('object'); + expect(tokenInfo).toHaveProperty('name'); + expect(tokenInfo).toHaveProperty('symbol'); + expect(tokenInfo).toHaveProperty('address'); + expect(tokenInfo).toHaveProperty('decimals'); + expect(tokenInfo).toHaveProperty('logoUrl'); + expect(tokenInfo).toHaveProperty('totalSupply'); + }); it('smartContractCall write (mint an NFT on testnet)', async () => { const response = await smartContractCall({ @@ -167,18 +165,16 @@ describe('MultichainCryptoWallet Sui tests', () => { network: 'sui', rpcUrl: suiTestnetRpc, privateKey: testPrivateKey, - gasLimit: 1000000, + gasLimit: 10000000, }); - expect(typeof response).toBe('object'); }); - // Sui does not have "view" functions, but you can simulate any function call (dry run) to see what would happen/retrieve data, - it('smartContractCall read (getting owner of a global counter object)', async () => { + it('smartContractCall read (getting owner of a global counter object)', async () => { const response = await smartContractCall({ - contractAddress: '0x775d945700b8e8033df0a2d2b9d1d22ae01e952f47ebe913438c03a17287798c::counter::owner', - params: [], - paramTypes: [], + contractAddress: '0x7190cfaecbe30eea5afd180c426b4a14f5ca5a333cc96a12aecc86eb2d508f7e::counter::owner', + params: ['0xaf7a0a1346420a575015429cc4289a1d55faf37d93fa69bb07a1619b3be5665c'], //This is the counter object we want to get its owner + paramTypes: ['object'], method: 'owner', methodType: 'read', network: 'sui', @@ -188,5 +184,4 @@ describe('MultichainCryptoWallet Sui tests', () => { expect(typeof response).toBe('object'); }); - -}); +}); \ No newline at end of file From e7353b20e3dffba83cdcdd353b46af7e24c7c687 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 02:01:07 +0100 Subject: [PATCH 26/30] added sui to test script to package.json --- package.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f1aa763..f4ad015 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,13 @@ "scripts": { "start": "tsdx watch", "build": "cross-env NODE_ENV=production tsdx build", - "test": "cross-env NODE_ENV=test tsdx test", - "test:btc": "cross-env NODE_ENV=test tsdx test --testPathPattern=bitcoin", - "test:eth": "cross-env NODE_ENV=test tsdx test --testPathPattern=ethereum", - "test:sol": "cross-env NODE_ENV=test tsdx test --testPathPattern=solana", - "test:tron": "cross-env NODE_ENV=test tsdx test --testPathPattern=tron", - "test:waves": "cross-env NODE_ENV=test tsdx test --testPathPattern=waves", + "test": "tsdx test", + "test:btc": "tsdx test --testPathPattern=bitcoin", + "test:eth": "tsdx test --testPathPattern=ethereum", + "test:sol": "tsdx test --testPathPattern=solana", + "test:tron": "tsdx test --testPathPattern=tron", + "test:waves": "tsdx test --testPathPattern=waves", + "test:sui": "tsdx test --testPathPattern=sui", "lint": "tsdx lint", "prepare": "tsdx build", "size": "size-limit", From 3a5b5a1f8153133b99206fe80a2d7e8bdc09f452 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 02:01:40 +0100 Subject: [PATCH 27/30] account for Sui features on readme --- README.md | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cdfd4f8..85bbe9f 100644 --- a/README.md +++ b/README.md @@ -137,11 +137,15 @@ const wallet = await multichainWallet.createWallet({ network: 'waves', }); -// Creating a Tron wallet +// Creating a Tron wallet. const wallet = await multichainWallet.createWallet({ network: 'tron', }); +//Creating a Sui wallet. +const wallet = await multichainWallet.createWallet({ + network: 'sui', +}) ``` #### Response @@ -202,6 +206,13 @@ const data = await multichainWallet.getBalance({ address: 'TDdHvW9nU1JaX1P7roYtDvjErTTR17GPJJ', rpcUrl: 'https://nile.trongrid.io', }); + +// Get the Sui balance of an address. +const data = await multichainWallet.getBalance({ + network: 'sui', + address: '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + rpcUrl: 'https://fullnode.testnet.sui.io:443', +}); ``` #### Tokens @@ -231,13 +242,21 @@ const data = await multichainWallet.getBalance({ tokenAddress: '39pnv8FVf3BX3xwtC6uhFxffy2sE3seXCPsf25eNn6qG', }); -// Get the balance of a token on tron. +// Get the balance of a token on Tron. const data = await multichainWallet.getBalance({ network: 'tron', address: 'TDdHvW9nU1JaX1P7roYtDvjErTTR17GPJJ', rpcUrl: 'https://nile.trongrid.io', tokenAddress: 'TXLAQ63Xg1NAzckPwKHvzw7CSEmLMEqcdj', }); + +// Get the balance of a token on Sui. +const data = await multichainWallet.getBalance({ + network: 'sui', + address: '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', + rpcUrl: 'https://fullnode.testnet.sui.io:443', + tokenAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC', +}); ``` #### Response @@ -299,6 +318,14 @@ const wallet = multichainWallet.generateWalletFromMnemonic({ 'mushroom deliver work spray hire nuclear wrong deputy march six midnight outside motor differ adult', network: 'tron', }); + +// Generate a Sui Wallet from mnemonic. +const wallet = multichainWallet.generateWalletFromMnemonic({ + mnemonic: + 'ship friend modify merit dune tower ritual off assault resemble vintage solid', + derivationPath: "m/44'/784'/0'/0'/0'", // Leave empty to use default derivation path + network: 'sui', +}); ``` #### Response @@ -342,6 +369,14 @@ const address = multichainWallet.getAddressFromPrivateKey({ 'fa01dc6efd5fd64e4897aadf255ae715cf34138c7ada5f6a7efb0bdd0bd9c8c4', network: 'tron', }); + +// Get the address from the private key on the Sui network. +const address = multichainWallet.getAddressFromPrivateKey({ + privateKey: + 'suiprivkey1qpppfvzg767qahlw6eu09m2ql3uvc59xqgt3l0un06lvnf8yjxac6v37z3e', + network: 'sui', +}); + ``` #### Response @@ -391,6 +426,13 @@ const receipt = await multichainWallet.getTransaction({ network: 'tron', rpcUrl: 'https://nile.trongrid.io', }); + +// Get the transaction receipt on Sui network. +const receipt = await multichainWallet.getTransaction({ + hash: 'AsU5WsBm8kZtuC2hQNyX3zv3CpvHUznE3mLEVewsgp4V', + network: 'sui', + rpcUrl: 'https://fullnode.testnet.sui.io:443', +}); ``` #### Response @@ -623,6 +665,38 @@ const transfer = await multichainWallet.transfer({ ..object; } ``` +#### Sui Network + +Allows for the transfer of SUI and Sui tokens. + +```javascript +// Transferring SUI from one address to another. +const transfer = await multichainWallet.transfer({ + recipientAddress: '0x7264e741063b6b064cdb780b44578db213cdff9e5641abb2c34a5b5c55307579', + amount: 0.1, + network: sui, + rpcUrl: 'https://fullnode.testnet.sui.io:443', + privateKey: 'suiprivkey1qpppfvzg767qahlw6eu09m2ql3uvc59xqgt3l0un06lvnf8yjxac6v37z3e', +}) + +// Transferring Sui coins from one address to another. +const transfer = await multichainWallet.transfer({ + recipientAddress: '0x7264e741063b6b064cdb780b44578db213cdff9e5641abb2c34a5b5c55307579', + tokenAddress: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC', + amount: 0.1, + network: sui, + rpcUrl: 'https://fullnode.testnet.sui.io:443', + privateKey: 'suiprivkey1qpppfvzg767qahlw6eu09m2ql3uvc59xqgt3l0un06lvnf8yjxac6v37z3e', +}) +``` + +#### Response +```bash +{ + digest + ..object; +} +``` ### Encryptions @@ -777,6 +851,30 @@ const info = await multichainWallet.getTokenInfo({ } ``` +#### Get Sui Coin Info + +Allows for fetching Sui coin + +```javascript +const info = await multichainWallet.getTokenInfo({ + address: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC', + network: 'sui', + rpcUrl: 'https://nile.trongrid.io', +}); +``` + +#### Response +```javascript +{ + name: 'USDC', + symbol: 'USDC', + address: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC', + decimals: 6, + logoUrl: 'https://www.circle.com/hubfs/Brand/USDC/USDC_icon_32x32.png', + totalSupply: '2526980560742103' +} +``` + ### Smart Contract Call This can be used to make custom smart contract interaction by specifying the contract ABI and function types. @@ -911,6 +1009,35 @@ const data = await multichainWallet.smartContractCall({ }); ``` +#### Sui network +```javascript +// Calling a write smart contract function +const data = await multichainWallet.smartContractCall({ + contractAddress: '0x086162ecfab930c92b2773f0f878f4998bad6c4fd9d2135fc58f8592ed9f4854::nft::mint', // The contractAddress is the form `packageId::module_name::method` + params: ['nftName', 'nftDescription', '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', 'nftImgUrl'], + paramTypes: ['string', 'string', 'address', 'string'], + method: 'mint', + methodType: 'write', + network: 'sui', + rpcUrl: 'https://fullnode.testnet.sui.io:443', + privateKey: testPrivateKey, + gasLimit: 10_000_000, // 0.01 SUI +}) + +// Calling a read smart contract function +const data = await multichainWallet.smartContractCall({ + // This calls the owner function to retrieve the owner of a counter object in a module + contractAddress: '0x086162ecfab930c92b2773f0f878f4998bad6c4fd9d2135fc58f8592ed9f4854::counter::owner', // The contractAddress is the form `packageId::module_name::method` + params: ['0xaf7a0a1346420a575015429cc4289a1d55faf37d93fa69bb07a1619b3be5665c'], //This is the counter object we want to get its owner + paramTypes: ['object'], + method: 'owner', + methodType: 'read', + network: 'sui', + rpcUrl: 'https://fullnode.testnet.sui.io:443', + sender: '0xc8ef1c69d448b8c373c6de6f7170b0dc4ab8804591601c77ac6d6d0aad9fb914', +}) +``` + Some of the parameters available in this function are: - The **method** parameter is the name of the smart contract function to be interacted with. @@ -927,6 +1054,11 @@ The optional parameters that the object takes in are: value, contractAbi, gas pr - The **private key** is a string parameter that can be passed to use as the signer. It is used to sign the transaction. This parameter is not needed when calling a smart contract read function. - The **payment** (only on Waves) payment is the payment (WAVES or Waves Asset) sent to the smart contract while interacting with it. If the smart contract function does not require any payment. - The **feeLimt** (only on Tron) is the max amount of fee you're willing to pay for the transaction +- The **paramTypes** (only on Sui) it is the list of types for each parameter expected by the function e.g `u64`, `address`, `vector`. Used to define the function's signature and how to encode the arguments. +- The **typeArguments** (only on Sui) this is an optional field, they are concrete types for generic parameters, basically for interacting with the specific type of an object. Example, in this move function `public fun transfer(coin: Coin, recipient: address)` This function can transfer any kind of coin, but you must specify the actual coin type when you call it. An example of calling the fucntion: +`transfer<0x2::usdc::USDC>(my_usdc_coin, recipient_address)` +Here, `0x2::usdc::USDC` is the typeArgument for `T` and `my_usdc_coin` is the objectId of your usdc coin +- The **sender** (only on Sui) this is the sui address only for view transactions. #### Response From ffe5a43f74dfa66450cb3dde04421428b1d7a429 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 02:13:06 +0100 Subject: [PATCH 28/30] added sui to test script to package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f4ad015..f2b56c7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ }, "scripts": { "start": "tsdx watch", - "build": "cross-env NODE_ENV=production tsdx build", + "build": "tsdx build", "test": "tsdx test", "test:btc": "tsdx test --testPathPattern=bitcoin", "test:eth": "tsdx test --testPathPattern=ethereum", From 4ed218797e07dc2adcc90ee8d821e07e2cdddce9 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 02:28:23 +0100 Subject: [PATCH 29/30] update readme methods for sui --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 85bbe9f..962ac9a 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The following methods are available with this SDK: - [Response](#response-8) - [Tron Network](#tron-network) - [Response](#response-9) + - [Sui Network](#response-11) - [Encryptions](#encryptions) - [Encrypt Private Key](#encrypt-private-key) - [Response](#response-10) @@ -84,11 +85,13 @@ The following methods are available with this SDK: - [Response](#response-14) - [Get TRC20 Token Info](#get-tron-token-info) - [Response](#response-15) + - [Get Sui Coin Info](#get-sui-coin-info) + - [Response](#response-16) - [Smart Contract Call](#smart-contract-call) - [Ethereum network](#ethereum-network-1) - [Waves network](#waves-network-1) - [Tron network](#tron-network-1) - - [Response](#response-17) + - [Sui Network](#sui-network-1) - [Want to contribute?](#want-to-contribute) ### Generate mnemonic From ea270d9a4ea81e21773cbfadd414502f1ff114b6 Mon Sep 17 00:00:00 2001 From: owanemi Date: Wed, 30 Apr 2025 03:24:54 +0100 Subject: [PATCH 30/30] update README with correct sui rpcUrl --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 962ac9a..da48616 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,8 @@ The following methods are available with this SDK: - [Response](#response-8) - [Tron Network](#tron-network) - [Response](#response-9) - - [Sui Network](#response-11) + - [Sui Network](#Sui-Network) + - [Response](#response-11) - [Encryptions](#encryptions) - [Encrypt Private Key](#encrypt-private-key) - [Response](#response-10) @@ -862,7 +863,7 @@ Allows for fetching Sui coin const info = await multichainWallet.getTokenInfo({ address: '0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC', network: 'sui', - rpcUrl: 'https://nile.trongrid.io', + rpcUrl: 'https://fullnode.testnet.sui.io:443', }); ```