diff --git a/.env.example b/.env.example index 0e20491..799d0b8 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,4 @@ -# EVM CHAINS +# EVM Chains EVM_RPC_URL='https://sepolia.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161' EVM_WS_URL='wss://sepolia.infura.io/ws/v3/9aa3d95b3bc440fa88ea12eaa4456161' @@ -13,7 +13,7 @@ EVM_TRANSACTION_LISTENER_TEST_IS_ACTIVE=false EVM_COIN_BALANCE_TEST_AMOUNT=0.01 EVM_TOKEN_BALANCE_TEST_AMOUNT=1000 EVM_NFT_BALANCE_TEST_AMOUNT=2 -EVM_TRANSFER_TEST_AMOUNT=0.0001 +EVM_TRANSFER_TEST_AMOUNT=0.01 EVM_TOKEN_TRANSFER_TEST_AMOUNT=1 EVM_TOKEN_APPROVE_TEST_AMOUNT=100 EVM_NFT_TRANSFER_ID=7 @@ -43,9 +43,9 @@ EVM_ETHER_TRANSFER_TX='0x566002399664e92f82ed654c181095bdd7ff3d3f1921d9632575858 EVM_TOKEN_TRANSFER_TX='0xdabda3905e585db91768f2ef877f7fbef7c0e8612c0a09c7b379981bdbc48975' EVM_NFT_TRANSFER_TX='0x272a4698cd2062f2463481cf9eb78b68b35d59938383679b7642e6d669ac87eb' # Models -# EVM CHAINS +# EVM Chains -#TRON +#Tron # Assets TRON_COIN_TRANSFER_TEST_IS_ACTIVE=false TRON_TOKEN_TRANSFER_TEST_IS_ACTIVE=false @@ -82,4 +82,58 @@ TRON_MODEL_TEST_RECEIVER='TS1WYZNoNw32hog68m5GyhwZnkhf6HNzhi' TRON_TRX_TRANSFER_TX='8697ad2c4e1713227c16a65a5845636458df2d3db3adf526e07e17699bc6b3c4' TRON_TOKEN_TRANSFER_TX='bd0ba6ebb8d2f910b27de1565c66cc89337b792dfdb6484847c817ccbd240760' TRON_NFT_TRANSFER_TX='d5dd97c09efdb93f36808a9f8e14642ef226880aa91a846583d4ce98c0084637' -#TRON \ No newline at end of file +#Tron + +#Bitcoin +BTC_TRANSFER_TEST_IS_ACTIVE=false +BTC_LISTENER_TEST_IS_ACTIVE=false +BTC_BLOCKCYPHER_TOKEN='49d43a59a4f24d31a9731eb067ab971c' +BTC_SENDER_PRIVATE_KEY='cNHUtnWqwAwGajUGjyHLNbUcfHaDC3ujqjc6qcZik5Xa58Hj46vG' +BTC_SENDER_ADDRESS='tb1q8juz7c302wdcpfz83zvvyf4jxc8sfq4wyth3pr' +BTC_RECEIVER_ADDRESS='tb1q9uxj8p043sjkm0qzlsys7677mv98j76k8cvgtg' +BTC_TRANSFER_AMOUNT=0.00001 +#Bitcoin + +#Solana +# Assets +SOL_COIN_TRANSFER_TEST_IS_ACTIVE=false +SOL_TOKEN_TRANSFER_TEST_IS_ACTIVE=false +SOL_TOKEN_APPROVE_TEST_IS_ACTIVE=false +SOL_TOKEN_TRANSFER_FROM_TEST_IS_ACTIVE=false +SOL_NFT_TRANSACTION_TEST_IS_ACTIVE=false +SOL_TRANSACTION_LISTENER_TEST_IS_ACTIVE=false + +SOL_COIN_BALANCE_TEST_AMOUNT=1 +SOL_TOKEN_BALANCE_TEST_AMOUNT=20 +SOL_NFT_BALANCE_TEST_AMOUNT=2 +SOL_TRANSFER_TEST_AMOUNT=0.001 +SOL_TOKEN_TRANSFER_TEST_AMOUNT=1 +SOL_TOKEN_APPROVE_TEST_AMOUNT=10 +#NFT ID +SOL_NFT_TRANSFER_ID='FxN19KB5UeZJFwxLFgT57WvYYXYhBFKxVumfq37xU4Ck' +SOL_NFT_TRANSFER_ID2='EBQjkpi6VdY3WF9ihi1sVhjkNDjfCorg1LJGd3Vnn9Ec' +SOL_TOKEN_PROGRAM='TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA' +SOL_BALANCE_TEST_ADDRESS='2i6NifwwBGJKUEhYhqbGwu66kDhbfyjgp7zPN5dQsKsE' +SOL_SENDER_PRIVATE_KEY='2hh51RHd1cEgiuEj2azZJFNphh27S8578otEHw8WvUia1yEBaW7o7XNuxdV1qQYbvxL5FHrcHpbZMCCxULTkCHRq' +SOL_RECEIVER_PRIVATE_KEY='57XnG9wtVMVV5BZnZbmaN3JTQ7Mzkmbyh4ooMC45YypJz3gF16nGfCJw3hWGQjLFbKmruaF3N3BH3fJAGD6stGCb' +SOL_SENDER_TEST_ADDRESS='7bn9So6CKmdn2vHYZU5oG6gaVEewW3N7U8vJoNmSv2vB' +SOL_RECEIVER_TEST_ADDRESS='GHVMV3zZscR8V4K5GEgQTUjuV4jEixB9a4QX3KhgvVKy' +SOL_TOKEN_TEST_ADDRESS='2ZHwL3dXk3szRgiBLZi244NmKs2VmoBx764AYMY2tQfx' +SOL_TOKEN_2022_TEST_ADDRESS='FQPbc46pp1b3QWHFJFfsvQrv7YedX8XEum5c18mLnipE' +#Collection Mint Address +SOL_NFT_TEST_ADDRESS='9B8bxQWovwm5na85xtDPuAyUVingcVdqWk3d9yQV2zsA' +# Assets + +# Models +SOL_NFT_ID='BFqd1SZFWMci42bUrhxzWhnvodCnG32xKYZkSp2rXVAf' +SOL_TOKEN_AMOUNT=50000 +SOL_COIN_AMOUNT=10 + +SOL_MODEL_TEST_SENDER='37p742pby4ACHiGcT3d58gsjmC3Kd9bH2L89E3hY8FHZ' +SOL_MODEL_TEST_RECEIVER='7bn9So6CKmdn2vHYZU5oG6gaVEewW3N7U8vJoNmSv2vB' + +SOL_TRANSFER_TX='2RDU1otuPR6UtevwYCQWnngvvjPiTFuHFdyCnzwQVR8wyZ7niqACt2QBmfuyD5aXJbEXSEUcqFquiCEtcQZzkWif' +SOL_TOKEN_TRANSFER_TX='4XLpHmpiKXXDM7pAg8CXeSLjw7SYKZaSzJjXHP2E1vL2ndvrJ6GnuHUvaQpY3LHQeJww8fzFLJ9MiLnvgsyyyt3i' +SOL_TOKEN_2022_TRANSFER_TX='3c2Myd3k4Pw1NbsCjuskkZCtbD9HRTjoyoxh2u7qsVLgFN1RbRYAXXRKzBRzwTAmv2pXDjArbotzVL6AVehBMeyg' +SOL_NFT_TRANSFER_TX='3vrCoNVmeNgGG4LB1qvvdx21TYm6dnPBmhFqXChsusuLn5ZEjFZNFG3BwQQ8fodBYiPXG8QokdBLWjRtxgi7tnRD' +#Solana \ No newline at end of file diff --git a/package.json b/package.json index 22035f9..47d94e0 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "type": "module", "scripts": { "test": "vitest", + "test-ui": "vitest watch --ui", "coverage": "vitest run --coverage", "format": "prettier --write packages/", "lint": "eslint . --ext .ts --ignore-path .gitignore" @@ -12,6 +13,7 @@ "@types/node": "^20.11.20", "@typescript-eslint/eslint-plugin": "^6.21.0", "@vitest/coverage-istanbul": "^1.5.3", + "@vitest/ui": "^1.6.0", "esbuild": "^0.20.2", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", diff --git a/packages/networks/bitcoin/.eslintrc.json b/packages/networks/bitcoin/.eslintrc.json new file mode 100644 index 0000000..b62472f --- /dev/null +++ b/packages/networks/bitcoin/.eslintrc.json @@ -0,0 +1,7 @@ +{ + "extends": [ + "plugin:require-extensions/recommended", + "../../../.eslintrc.json" + ], + "plugins": ["require-extensions"] +} \ No newline at end of file diff --git a/packages/networks/bitcoin/.npmignore b/packages/networks/bitcoin/.npmignore new file mode 100644 index 0000000..4f4a3d7 --- /dev/null +++ b/packages/networks/bitcoin/.npmignore @@ -0,0 +1,6 @@ +src +tests +node_modules +.eslintrc.cjs +pnpm-lock.yaml +tsconfig.json \ No newline at end of file diff --git a/packages/networks/bitcoin/README.md b/packages/networks/bitcoin/README.md new file mode 100644 index 0000000..e69de29 diff --git a/packages/networks/bitcoin/esbuild.ts b/packages/networks/bitcoin/esbuild.ts new file mode 100644 index 0000000..5714b9c --- /dev/null +++ b/packages/networks/bitcoin/esbuild.ts @@ -0,0 +1,3 @@ +void import('../../../esbuild.ts').then((module) => { + module.default() +}) diff --git a/packages/networks/bitcoin/index.html b/packages/networks/bitcoin/index.html new file mode 100644 index 0000000..2324a82 --- /dev/null +++ b/packages/networks/bitcoin/index.html @@ -0,0 +1,324 @@ + + + + + + + Browser Tests + + + + +
+ +
+ +
+
+ Adapter id: +
+
+ Adapter name: +
+
+ Adapter icon: icon +
+
+ Platforms: +
+
+ Download link: +
+
+ Deep link: +
+
+ Connected address: +
+ +
+ Result: +
+ +
+ Result: +
+
+ + + + \ No newline at end of file diff --git a/packages/networks/bitcoin/package-lock.json b/packages/networks/bitcoin/package-lock.json new file mode 100644 index 0000000..312fc86 --- /dev/null +++ b/packages/networks/bitcoin/package-lock.json @@ -0,0 +1,772 @@ +{ + "name": "@multiplechain/bitcoin", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@multiplechain/bitcoin", + "version": "0.1.0", + "license": "MIT", + "dependencies": { + "@multiplechain/types": "^0.1.55", + "@multiplechain/utils": "^0.1.18", + "axios": "^1.6.8", + "bitcore-lib": "^10.0.28", + "ws": "^8.17.0" + }, + "devDependencies": { + "@types/bitcore-lib": "^0.15.6" + } + }, + "node_modules/@multiplechain/types": { + "version": "0.1.55", + "resolved": "https://registry.npmjs.org/@multiplechain/types/-/types-0.1.55.tgz", + "integrity": "sha512-9fYrLaDxX2pj9zfIbmvk1hPF3FH/bK+Q3uTF+k3zdsitP/HzQ1S9zImNz20Tvoqkk1ns+/8ecE0Y6GNowsDOQA==" + }, + "node_modules/@multiplechain/utils": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/@multiplechain/utils/-/utils-0.1.18.tgz", + "integrity": "sha512-UCoOOBJrawp/lInepxuoEiYwId0wMPg7rX8p78FLqzGl8f/b93sAtv7sP87/VVKwhdoEuNZ/uQjckycmNeks/w==", + "dependencies": { + "@types/ws": "^8.5.10", + "bignumber.js": "^9.1.2", + "web3-utils": "^4.2.0", + "ws": "^8.16.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/base": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.6.tgz", + "integrity": "sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@types/bitcore-lib": { + "version": "0.15.6", + "resolved": "https://registry.npmjs.org/@types/bitcore-lib/-/bitcore-lib-0.15.6.tgz", + "integrity": "sha512-CtKDBgSBubPXZ0wFeCiUCSdzH+cuy6nFya3FboOqf44evi+OmkQPqEg3ASMpmPDYE8vkcxV302Iu8lZqCjYieg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.12.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.11.tgz", + "integrity": "sha512-vDg9PZ/zi+Nqp6boSOT7plNuthRugEKixDv5sFTIpkE89MmNtEArAShI4mxuX2+UrLEe9pxC1vm2cjm9YlWbJw==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/bigi": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz", + "integrity": "sha512-ddkU+dFIuEIW8lE7ZwdIAf2UPoM90eaprg5m3YXAVVTmKlqV/9BX4A2M8BOK2yOq6/VgZFVhK6QAxJebhlbhzw==" + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/bip-schnorr": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/bip-schnorr/-/bip-schnorr-0.6.4.tgz", + "integrity": "sha512-dNKw7Lea8B0wMIN4OjEmOk/Z5qUGqoPDY0P2QttLqGk1hmDPytLWW8PR5Pb6Vxy6CprcdEgfJpOjUu+ONQveyg==", + "dependencies": { + "bigi": "^1.4.2", + "ecurve": "^1.0.6", + "js-sha256": "^0.9.0", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bitcore-lib": { + "version": "10.0.28", + "resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-10.0.28.tgz", + "integrity": "sha512-uOWHpWbUxEj411p+tp6DCb9NfZdsCAHl6Z/rs96mquQMsef29fOqWUyk4Bl7yLf+KwzU5ZKy0HIPnjGFlmpXpg==", + "dependencies": { + "bech32": "=2.0.0", + "bip-schnorr": "=0.6.4", + "bn.js": "=4.11.8", + "bs58": "^4.0.1", + "buffer-compare": "=1.1.1", + "elliptic": "^6.5.3", + "inherits": "=2.0.1", + "lodash": "^4.17.20" + } + }, + "node_modules/bitcore-lib/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==" + }, + "node_modules/bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer-compare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz", + "integrity": "sha512-O6NvNiHZMd3mlIeMDjP6t/gPG75OqGPeiRZXoMQZJ6iy9GofCls4Ijs5YkPZZwoysizLiedhticmdyx/GyHghA==" + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ecurve": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz", + "integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==", + "dependencies": { + "bigi": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/elliptic": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.5.tgz", + "integrity": "sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/web3-errors": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/web3-errors/-/web3-errors-1.1.4.tgz", + "integrity": "sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==", + "dependencies": { + "web3-types": "^1.3.1" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-types": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/web3-types/-/web3-types-1.6.0.tgz", + "integrity": "sha512-qgOtADqlD5hw+KPKBUGaXAcdNLL0oh6qTeVgXwewCfbL/lG9R+/GrgMQB1gbTJ3cit8hMwtH8KX2Em6OwO0HRw==", + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-utils": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-4.2.3.tgz", + "integrity": "sha512-m5plKTC2YtQntHITQRyIePw52UVP1IrShhmA2FACtn4zmc5ADmrXOlQWiPzxFP/18eRJsAaUAw2+CQn1u4WPxQ==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "eventemitter3": "^5.0.1", + "web3-errors": "^1.1.4", + "web3-types": "^1.6.0", + "web3-validator": "^2.0.5" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/web3-validator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/web3-validator/-/web3-validator-2.0.5.tgz", + "integrity": "sha512-2gLOSW8XqEN5pw5jVUm20EB7A8SbQiekpAtiI0JBmCIV0a2rp97v8FgWY5E3UEqnw5WFfEqvcDVW92EyynDTyQ==", + "dependencies": { + "ethereum-cryptography": "^2.0.0", + "util": "^0.12.5", + "web3-errors": "^1.1.4", + "web3-types": "^1.5.0", + "zod": "^3.21.4" + }, + "engines": { + "node": ">=14", + "npm": ">=6.12.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ws": { + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz", + "integrity": "sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/packages/networks/bitcoin/package.json b/packages/networks/bitcoin/package.json new file mode 100644 index 0000000..7040f81 --- /dev/null +++ b/packages/networks/bitcoin/package.json @@ -0,0 +1,75 @@ +{ + "name": "@multiplechain/bitcoin", + "version": "0.4.0", + "type": "module", + "main": "dist/index.cjs", + "module": "dist/index.es.js", + "unpkg": "dist/index.umd.js", + "browser": "dist/index.umd.js", + "jsdelivr": "dist/index.umd.js", + "exports": { + ".": { + "import": { + "default": "./dist/index.es.js", + "types": "./dist/browser/index.d.ts" + }, + "require": { + "default": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "./node": { + "default": "./dist/index.cjs", + "types": "./dist/index.d.ts" + }, + "./browser": { + "default": "./dist/index.es.js", + "types": "./dist/browser/index.d.ts" + } + }, + "files": [ + "dist", + "README.md", + "!tsconfig.tsbuildinfo" + ], + "scripts": { + "dev": "vite", + "clean": "rm -rf dist", + "watch": "tsc --watch", + "build:vite": "vite build", + "build:node": "tsx esbuild.ts", + "typecheck": "tsc --noEmit", + "lint": "eslint . --ext .ts", + "test": "vitest run --dir tests", + "test-ui": "vitest watch --ui", + "prepublishOnly": "pnpm run build", + "build": "pnpm run build:vite && pnpm run build:node" + }, + "keywords": [ + "web3", + "crypto", + "blockchain", + "multiple-chain" + ], + "author": "MultipleChain", + "license": "MIT", + "homepage": "https://github.com/MultipleChain/js/tree/master/packages/networks/network-name", + "repository": { + "type": "git", + "url": "git+https://github.com/MultipleChain/js.git" + }, + "bugs": { + "url": "https://github.com/MultipleChain/js/issues" + }, + "dependencies": { + "@multiplechain/types": "^0.1.56", + "@multiplechain/utils": "^0.1.20", + "axios": "^1.6.8", + "bitcore-lib": "^10.0.28", + "sats-connect": "^2.3.1", + "ws": "^8.17.0" + }, + "devDependencies": { + "@types/bitcore-lib": "^0.15.6" + } +} diff --git a/packages/networks/bitcoin/pnpm-lock.yaml b/packages/networks/bitcoin/pnpm-lock.yaml new file mode 100644 index 0000000..3cc25a4 --- /dev/null +++ b/packages/networks/bitcoin/pnpm-lock.yaml @@ -0,0 +1,630 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@multiplechain/types': + specifier: ^0.1.56 + version: 0.1.56 + '@multiplechain/utils': + specifier: ^0.1.20 + version: 0.1.20 + axios: + specifier: ^1.6.8 + version: 1.6.8 + bitcore-lib: + specifier: ^10.0.28 + version: 10.0.28 + sats-connect: + specifier: ^2.3.1 + version: 2.3.1(typescript@5.4.4) + ws: + specifier: ^8.17.0 + version: 8.17.0 + +devDependencies: + '@types/bitcore-lib': + specifier: ^0.15.6 + version: 0.15.6 + +packages: + + /@multiplechain/types@0.1.56: + resolution: {integrity: sha512-tnkgDwW0AWxEfhE/392LR6ZPE7Pxz5/Ei1XYsQISGkOfYYZrsvJXr69fXTjDOHCq7RCuQqytKmhnKs5K4xHd7w==} + dev: false + + /@multiplechain/utils@0.1.20: + resolution: {integrity: sha512-4eEs4YR/V4F2Qnkl5KTZvPpewRQiX7C193d0tjpQuIfyumTEBJtdHYm1CW9CoJ6EjQUaB0oqSRKXomhzfK1qkw==} + dependencies: + '@types/ws': 8.5.10 + bignumber.js: 9.1.2 + web3-utils: 4.2.1 + ws: 8.17.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@noble/curves@1.3.0: + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + dependencies: + '@noble/hashes': 1.3.3 + dev: false + + /@noble/hashes@1.3.3: + resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} + engines: {node: '>= 16'} + dev: false + + /@noble/secp256k1@1.7.1: + resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} + dev: false + + /@sats-connect/core@0.0.7: + resolution: {integrity: sha512-4m5amq+orHDbqLqCRWojvDQigKAys33Ntwc7U5xNtFeib4j+DpYz6lVAL/s3cay1kq03WUZ+Gil3l5rv+5bQWQ==} + dependencies: + axios: 1.6.8 + bitcoin-address-validation: 2.2.3 + buffer: 6.0.3 + jsontokens: 4.0.1 + lodash.omit: 4.5.0 + transitivePeerDependencies: + - debug + dev: false + + /@sats-connect/core@0.0.8: + resolution: {integrity: sha512-vb7drnd8lFfO4ahCzaVAFkX1eHF1J7jheJl2V/JuuJd5f1sy6nHeNzKMp1zmiuql8uNwe0Sx1WrK1I+4tUmDHg==} + dependencies: + axios: 1.6.8 + bitcoin-address-validation: 2.2.3 + buffer: 6.0.3 + jsontokens: 4.0.1 + lodash.omit: 4.5.0 + transitivePeerDependencies: + - debug + dev: false + + /@sats-connect/make-default-provider-config@0.0.4(typescript@5.4.4): + resolution: {integrity: sha512-PsLzg1hV3FxMXUp9XrOUmDJgbuyR4VDHq/7mh1O1CtC3dDZQnJFa+Ue43duPMmUaRGinuVKtS2hnMhPLyURdGA==} + peerDependencies: + typescript: 5.4.4 + dependencies: + '@sats-connect/core': 0.0.7 + '@sats-connect/ui': 0.0.5-c661c02 + bowser: 2.11.0 + typescript: 5.4.4 + transitivePeerDependencies: + - debug + dev: false + + /@sats-connect/ui@0.0.5-c661c02: + resolution: {integrity: sha512-6MUXFDGTapBhZAxb6deAdqKuB64GOe6k927gGww5JYwVnOUCaHGDcfaZ/lwexzYL45u8RJof12I4np7MgS+Bwg==} + dev: false + + /@sats-connect/ui@0.0.6: + resolution: {integrity: sha512-H3bFFhr9CcY1oNosNi/QJszmMHSht4U19bUWfM3vzayAKgV4ebY6iUnRK5g3p2rVLLWVzlpaw1J9m+7JWwyBfA==} + dev: false + + /@scure/base@1.1.6: + resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} + dev: false + + /@scure/bip32@1.3.3: + resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} + dependencies: + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.6 + dev: false + + /@scure/bip39@1.2.2: + resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} + dependencies: + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.6 + dev: false + + /@types/bitcore-lib@0.15.6: + resolution: {integrity: sha512-CtKDBgSBubPXZ0wFeCiUCSdzH+cuy6nFya3FboOqf44evi+OmkQPqEg3ASMpmPDYE8vkcxV302Iu8lZqCjYieg==} + dependencies: + '@types/node': 20.12.7 + dev: true + + /@types/node@20.12.7: + resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + dependencies: + undici-types: 5.26.5 + + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 20.12.7 + dev: false + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: false + + /axios@1.6.8: + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /base58-js@1.0.5: + resolution: {integrity: sha512-LkkAPP8Zu+c0SVNRTRVDyMfKVORThX+rCViget00xdgLRrKkClCTz1T7cIrpr69ShwV5XJuuoZvMvJ43yURwkA==} + engines: {node: '>= 8'} + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /bech32@2.0.0: + resolution: {integrity: sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==} + dev: false + + /bigi@1.4.2: + resolution: {integrity: sha512-ddkU+dFIuEIW8lE7ZwdIAf2UPoM90eaprg5m3YXAVVTmKlqV/9BX4A2M8BOK2yOq6/VgZFVhK6QAxJebhlbhzw==} + dev: false + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + dev: false + + /bip-schnorr@0.6.4: + resolution: {integrity: sha512-dNKw7Lea8B0wMIN4OjEmOk/Z5qUGqoPDY0P2QttLqGk1hmDPytLWW8PR5Pb6Vxy6CprcdEgfJpOjUu+ONQveyg==} + engines: {node: '>=8.0.0'} + dependencies: + bigi: 1.4.2 + ecurve: 1.0.6 + js-sha256: 0.9.0 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: false + + /bitcoin-address-validation@2.2.3: + resolution: {integrity: sha512-1uGCGl26Ye8JG5qcExtFLQfuib6qEZWNDo1ZlLlwp/z7ygUFby3IxolgEfgMGaC+LG9csbVASLcH8fRLv7DIOg==} + dependencies: + base58-js: 1.0.5 + bech32: 2.0.0 + sha256-uint8array: 0.10.7 + dev: false + + /bitcore-lib@10.0.28: + resolution: {integrity: sha512-uOWHpWbUxEj411p+tp6DCb9NfZdsCAHl6Z/rs96mquQMsef29fOqWUyk4Bl7yLf+KwzU5ZKy0HIPnjGFlmpXpg==} + dependencies: + bech32: 2.0.0 + bip-schnorr: 0.6.4 + bn.js: 4.11.8 + bs58: 4.0.1 + buffer-compare: 1.1.1 + elliptic: 6.5.5 + inherits: 2.0.1 + lodash: 4.17.21 + dev: false + + /bn.js@4.11.8: + resolution: {integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==} + dev: false + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + dev: false + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + dev: false + + /bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + dependencies: + base-x: 3.0.9 + dev: false + + /buffer-compare@1.1.1: + resolution: {integrity: sha512-O6NvNiHZMd3mlIeMDjP6t/gPG75OqGPeiRZXoMQZJ6iy9GofCls4Ijs5YkPZZwoysizLiedhticmdyx/GyHghA==} + dev: false + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: false + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + dev: false + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + + /ecurve@1.0.6: + resolution: {integrity: sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==} + dependencies: + bigi: 1.4.2 + safe-buffer: 5.2.1 + dev: false + + /elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: false + + /ethereum-cryptography@2.1.3: + resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} + dependencies: + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/bip32': 1.3.3 + '@scure/bip39': 1.2.2 + dev: false + + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: false + + /follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: false + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + dev: false + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + dev: false + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: false + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: false + + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /inherits@2.0.1: + resolution: {integrity: sha512-8nWq2nLTAwd02jTqJExUYFSD/fKq6VH9Y/oG2accc/kdI0V98Bag8d5a4gi3XHz73rDWa2PvTtvcWYquKqSENA==} + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: false + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: false + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + dev: false + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + dev: false + + /jsontokens@4.0.1: + resolution: {integrity: sha512-+MO415LEN6M+3FGsRz4wU20g7N2JA+2j9d9+pGaNJHviG4L8N0qzavGyENw6fJqsq9CcrHOIL6iWX5yeTZ86+Q==} + dependencies: + '@noble/hashes': 1.3.3 + '@noble/secp256k1': 1.7.1 + base64-js: 1.5.1 + dev: false + + /lodash.omit@4.5.0: + resolution: {integrity: sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + dev: false + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: false + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /sats-connect@2.3.1(typescript@5.4.4): + resolution: {integrity: sha512-3KzqRO5KVBlge7Q4a/L828SfCkFD+M4MVdtgJZS+L+oHiDYoXlLkvnu3almh9Ynhcm0HnsGmVH1pKVL0lonjyQ==} + dependencies: + '@sats-connect/core': 0.0.8 + '@sats-connect/make-default-provider-config': 0.0.4(typescript@5.4.4) + '@sats-connect/ui': 0.0.6 + transitivePeerDependencies: + - debug + - typescript + dev: false + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + dev: false + + /sha256-uint8array@0.10.7: + resolution: {integrity: sha512-1Q6JQU4tX9NqsDGodej6pkrUVQVNapLZnvkwIhddH/JqzBZF1fSaxSWNY6sziXBE8aEa2twtGkXUrwzGeZCMpQ==} + dev: false + + /typescript@5.4.4: + resolution: {integrity: sha512-dGE2Vv8cpVvw28v8HCPqyb08EzbBURxDpuhJvTrusShUfGnhHBafDsLdS1EhhxyL6BJQE+2cT3dDPAv+MQ6oLw==} + engines: {node: '>=14.17'} + hasBin: true + dev: false + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 + dev: false + + /web3-errors@1.1.4: + resolution: {integrity: sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + web3-types: 1.5.0 + dev: false + + /web3-types@1.5.0: + resolution: {integrity: sha512-geWuMIeegQ8AedKAO6wO4G4j1gyQ1F/AyKLMw2vud4bsfZayyzWJgCMDZtjYMm5uo2a7i8j1W3/4QFmzlSy5cw==} + engines: {node: '>=14', npm: '>=6.12.0'} + dev: false + + /web3-utils@4.2.1: + resolution: {integrity: sha512-Fk29BlEqD9Q9Cnw4pBkKw7czcXiRpsSco/BzEUl4ye0ZTSHANQFfjsfQmNm4t7uY11u6Ah+8F3tNjBeU4CA80A==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + ethereum-cryptography: 2.1.3 + eventemitter3: 5.0.1 + web3-errors: 1.1.4 + web3-types: 1.5.0 + web3-validator: 2.0.4 + dev: false + + /web3-validator@2.0.4: + resolution: {integrity: sha512-qRxVePwdW+SByOmTpDZFWHIUAa7PswvxNszrOua6BoGqAhERo5oJZBN+EbWtK/+O+ApNxt5FR3nCPmiZldiOQA==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + ethereum-cryptography: 2.1.3 + util: 0.12.5 + web3-errors: 1.1.4 + web3-types: 1.5.0 + zod: 3.22.4 + dev: false + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: false + + /ws@8.17.0: + resolution: {integrity: sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: false diff --git a/packages/networks/bitcoin/src/assets/Coin.ts b/packages/networks/bitcoin/src/assets/Coin.ts new file mode 100644 index 0000000..a50d1ea --- /dev/null +++ b/packages/networks/bitcoin/src/assets/Coin.ts @@ -0,0 +1,109 @@ +import axios from 'axios' +import { Provider } from '../services/Provider.ts' +import { fromSatoshi, toSatoshi } from '../utils.ts' +import { Transaction, Script, Address } from 'bitcore-lib' +import { ErrorTypeEnum, type CoinInterface } from '@multiplechain/types' +import { CoinTransactionSigner } from '../services/TransactionSigner.ts' + +export class Coin implements CoinInterface { + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {Provider} provider network provider + */ + constructor(provider?: Provider) { + this.provider = provider ?? Provider.instance + } + + /** + * @returns {string} Coin name + */ + getName(): string { + return 'Bitcoin' + } + + /** + * @returns {string} Coin symbol + */ + getSymbol(): string { + return 'BTC' + } + + /** + * @returns {number} Decimal value of the coin + */ + getDecimals(): number { + return 8 + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of COIN + */ + async getBalance(owner: string): Promise { + const addressStatsApi = this.provider.createEndpoint('address/' + owner) + const addressStats = await axios.get(addressStatsApi).then((res) => res.data) + const balanceSat = + addressStats.chain_stats.funded_txo_sum - addressStats.chain_stats.spent_txo_sum + return fromSatoshi(balanceSat) + } + + /** + * @param {string} sender Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + amount: number + ): Promise { + if (amount < 0) { + throw new Error(ErrorTypeEnum.INVALID_AMOUNT) + } + + if (amount > (await this.getBalance(sender))) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + if (sender === receiver) { + throw new Error(ErrorTypeEnum.INVALID_ADDRESS) + } + + const inputs = [] + const transaction = new Transaction() + const senderAddress = new Address(sender) + const satoshiToSend = toSatoshi(amount) + + const utxos = await axios + .get(this.provider.createEndpoint('address/' + sender + '/utxo')) + .then((res) => res.data) + + for (const utxo of utxos) { + inputs.push( + new Transaction.UnspentOutput({ + txId: utxo.txid, + satoshis: utxo.value, + address: senderAddress, + outputIndex: utxo.vout, + script: Script.fromAddress(senderAddress) + }) + ) + } + + transaction.from(inputs) + transaction.change(sender) + transaction.to(receiver, satoshiToSend) + + return new CoinTransactionSigner({ + sender, + receiver, + amount: satoshiToSend, + bitcoreLib: transaction + }) + } +} diff --git a/packages/networks/bitcoin/src/assets/Contract.ts b/packages/networks/bitcoin/src/assets/Contract.ts new file mode 100644 index 0000000..14044c0 --- /dev/null +++ b/packages/networks/bitcoin/src/assets/Contract.ts @@ -0,0 +1,59 @@ +import { Provider } from '../services/Provider.ts' +import type { ContractInterface } from '@multiplechain/types' + +export class Contract implements ContractInterface { + /** + * Contract address + */ + address: string + + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {string} address Contract address + * @param {Provider} provider Blockchain network provider + */ + constructor(address: string, provider?: Provider) { + this.address = address + this.provider = provider ?? Provider.instance + throw new Error('This class is not implemented for Bitcoin.') + } + + /** + * @returns {string} Contract address + */ + getAddress(): string { + return this.address + } + + /** + * @param {string} method Method name + * @param {any[]} args Method parameters + * @returns {Promise} Method result + */ + async callMethod(method: string, ...args: any[]): Promise { + return {} + } + + /** + * @param {string} method Method name + * @param {any[]} args Sender wallet address + * @returns {Promise} Encoded method data + */ + async getMethodData(method: string, ...args: any[]): Promise { + return {} + } + + /** + * @param {string} method Method name + * @param {string} from Sender wallet address + * @param {any[]} args Method parameters + * @returns {Promise} Encoded method data + */ + async createTransactionData(method: string, from: string, ...args: any[]): Promise { + return '' + } +} diff --git a/packages/networks/bitcoin/src/assets/NFT.ts b/packages/networks/bitcoin/src/assets/NFT.ts new file mode 100644 index 0000000..0a89a51 --- /dev/null +++ b/packages/networks/bitcoin/src/assets/NFT.ts @@ -0,0 +1,96 @@ +import { Contract } from './Contract.ts' +import type { NftInterface } from '@multiplechain/types' +import { NftTransactionSigner } from '../services/TransactionSigner.ts' + +export class NFT extends Contract implements NftInterface { + /** + * @returns {Promise} NFT name + */ + async getName(): Promise { + return 'example' + } + + /** + * @returns {Promise} NFT symbol + */ + async getSymbol(): Promise { + return 'example' + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of NFT + */ + async getBalance(owner: string): Promise { + return 0 + } + + /** + * @param {number | string} nftId NFT ID + * @returns {Promise} Wallet address of the owner of the NFT + */ + async getOwner(nftId: number | string): Promise { + return 'example' + } + + /** + * @param {number | string} nftId NFT ID + * @returns {Promise} URI of the NFT + */ + async getTokenURI(nftId: number | string): Promise { + return 'example' + } + + /** + * @param {number | string} nftId ID of the NFT that will be transferred + * @returns {Promise} Wallet address of the approved spender + */ + async getApproved(nftId: number | string): Promise { + return 'example' + } + + /** + * @param {string} sender Sender address + * @param {string} receiver Receiver address + * @param {number | string} nftId NFT ID + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + nftId: number | string + ): Promise { + return new NftTransactionSigner('example') + } + + /** + * @param {string} spender Spender address + * @param {string} owner Owner address + * @param {string} receiver Receiver address + * @param {number | string} nftId NFT ID + * @returns {Promise} Transaction signer + */ + async transferFrom( + spender: string, + owner: string, + receiver: string, + nftId: number | string + ): Promise { + return new NftTransactionSigner('example') + } + + /** + * Gives permission to the spender to spend owner's tokens + * @param {string} owner Address of owner of the tokens that will be used + * @param {string} spender Address of the spender that will use the tokens of owner + * @param {number | string} nftId ID of the NFT that will be transferred + * @returns {Promise} Transaction signer + */ + async approve( + owner: string, + spender: string, + nftId: number | string + ): Promise { + return new NftTransactionSigner('example') + } +} diff --git a/packages/networks/bitcoin/src/assets/Token.ts b/packages/networks/bitcoin/src/assets/Token.ts new file mode 100644 index 0000000..a090488 --- /dev/null +++ b/packages/networks/bitcoin/src/assets/Token.ts @@ -0,0 +1,92 @@ +import { Contract } from './Contract.ts' +import type { TokenInterface } from '@multiplechain/types' +import { TokenTransactionSigner } from '../services/TransactionSigner.ts' + +export class Token extends Contract implements TokenInterface { + /** + * @returns {Promise} Token name + */ + async getName(): Promise { + return 'example' + } + + /** + * @returns {Promise} Token symbol + */ + async getSymbol(): Promise { + return 'example' + } + + /** + * @returns {Promise} Decimal value of the token + */ + async getDecimals(): Promise { + return 18 + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of TOKEN + */ + async getBalance(owner: string): Promise { + return 0 + } + + /** + * @returns {Promise} Total supply of the token + */ + async getTotalSupply(): Promise { + return 0 + } + + /** + * @param {string} owner Address of owner of the tokens that is being used + * @param {string} spender Address of the spender that is using the tokens of owner + * @returns {Promise} Amount of tokens that the spender is allowed to spend + */ + async getAllowance(owner: string, spender: string): Promise { + return 0 + } + + /** + * transfer() method is the main method for processing transfers for fungible assets (TOKEN, COIN) + * @param {string} sender Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + amount: number + ): Promise { + return new TokenTransactionSigner('example') + } + + /** + * @param {string} spender Address of the spender of transaction + * @param {string} owner Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of tokens that will be transferred + * @returns {Promise} Transaction signer + */ + async transferFrom( + spender: string, + owner: string, + receiver: string, + amount: number + ): Promise { + return new TokenTransactionSigner('example') + } + + /** + * Gives permission to the spender to spend owner's tokens + * @param {string} owner Address of owner of the tokens that will be used + * @param {string} spender Address of the spender that will use the tokens of owner + * @param {number} amount Amount of the tokens that will be used + * @returns {Promise} Transaction signer + */ + async approve(owner: string, spender: string, amount: number): Promise { + return new TokenTransactionSigner('example') + } +} diff --git a/packages/networks/bitcoin/src/assets/index.ts b/packages/networks/bitcoin/src/assets/index.ts new file mode 100644 index 0000000..7ea522f --- /dev/null +++ b/packages/networks/bitcoin/src/assets/index.ts @@ -0,0 +1,4 @@ +export * from './NFT.ts' +export * from './Coin.ts' +export * from './Token.ts' +export * from './Contract.ts' diff --git a/packages/networks/bitcoin/src/browser/Wallet.ts b/packages/networks/bitcoin/src/browser/Wallet.ts new file mode 100644 index 0000000..cb8e8d0 --- /dev/null +++ b/packages/networks/bitcoin/src/browser/Wallet.ts @@ -0,0 +1,168 @@ +import { + type WalletInterface, + type WalletAdapterInterface, + type WalletPlatformEnum, + type TransactionSignerInterface, + type ProviderInterface, + ErrorTypeEnum +} from '@multiplechain/types' +import { Provider } from '../services/Provider.ts' +import type { TransactionData } from '../services/TransactionSigner.ts' + +export interface BitcoinWalletAdapter { + getAddress: () => Promise + signMessage: (message: string) => Promise + sendBitcoin: (to: string, amount: number) => Promise + on: (event: string, callback: (data: any) => void) => void +} + +const rejectMap = (error: any, reject: (a: any) => any): any => { + console.error('MultipleChain Bitcoin Wallet Error:', error) + + if (typeof error === 'object') { + if (error.code === 4001 || String(error.message).includes('User rejected the request')) { + return reject(ErrorTypeEnum.WALLET_REQUEST_REJECTED) + } else if (String(error).includes('is not valid JSON')) { + return reject(ErrorTypeEnum.UNACCEPTED_CHAIN) + } + } + + return reject(error) +} + +export class Wallet implements WalletInterface { + adapter: WalletAdapterInterface + + walletProvider: BitcoinWalletAdapter + + networkProvider: Provider + + /** + * @param {WalletAdapterInterface} adapter + * @param {Provider} provider + */ + constructor(adapter: WalletAdapterInterface, provider?: Provider) { + this.adapter = adapter + this.networkProvider = provider ?? Provider.instance + } + + /** + * @returns {string} + */ + getId(): string { + return this.adapter.id + } + + /** + * @returns {string} + */ + getName(): string { + return this.adapter.name + } + + /** + * @returns {string} + */ + getIcon(): string { + return this.adapter.icon + } + + /** + * @returns {WalletPlatformEnum[]} + */ + getPlatforms(): WalletPlatformEnum[] { + return this.adapter.platforms + } + + /** + * @returns {string} + */ + getDownloadLink(): string | undefined { + return this.adapter.downloadLink + } + + /** + * @param {string} url + * @param {object} ops + * @returns {string} + */ + createDeepLink(url: string, ops?: object): string | null { + if (this.adapter.createDeepLink === undefined) { + return null + } + + return this.adapter.createDeepLink(url, ops) + } + + /** + * @param {ProviderInterface} provider + * @param {Object} ops + * @returns {Promise} + */ + async connect(provider?: ProviderInterface, ops?: object): Promise { + return await new Promise((resolve, reject) => { + this.adapter + .connect(provider, ops) + .then(async (provider) => { + this.walletProvider = provider as BitcoinWalletAdapter + resolve(await this.getAddress()) + }) + .catch((error) => { + const customReject = (error: any): void => { + if (error.message === ErrorTypeEnum.WALLET_REQUEST_REJECTED) { + reject(new Error(ErrorTypeEnum.WALLET_CONNECT_REJECTED)) + } else { + reject(error) + } + } + rejectMap(error, customReject) + }) + }) + } + + /** + * @returns {boolean} + */ + async isDetected(): Promise { + return await this.adapter.isDetected() + } + + /** + * @returns {boolean} + */ + async isConnected(): Promise { + return await this.adapter.isConnected() + } + + /** + * @returns {Promise} + */ + async getAddress(): Promise { + return await this.walletProvider.getAddress() + } + + /** + * @param {string} message + */ + async signMessage(message: string): Promise { + return await this.walletProvider.signMessage(message) + } + + /** + * @param {TransactionSignerInterface} transactionSigner + * @returns {Promise} + */ + async sendTransaction(transactionSigner: TransactionSignerInterface): Promise { + const data = (await transactionSigner.getRawData()) as TransactionData + return await this.walletProvider.sendBitcoin(data.receiver, data.amount) + } + + /** + * @param {string} eventName + * @param {Function} callback + * @returns {void} + */ + on(eventName: string, callback: (...args: any[]) => void): void { + this.walletProvider.on(eventName, callback) + } +} diff --git a/packages/networks/bitcoin/src/browser/adapters/Leather.ts b/packages/networks/bitcoin/src/browser/adapters/Leather.ts new file mode 100644 index 0000000..3f363fa --- /dev/null +++ b/packages/networks/bitcoin/src/browser/adapters/Leather.ts @@ -0,0 +1,105 @@ +import icons from './icons.ts' +import { WalletPlatformEnum } from '@multiplechain/types' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import type { BitcoinWalletAdapter } from '../Wallet.ts' + +declare global { + interface Window { + btc: { + listen?: (event: string, callback: (data: any) => void) => void + } + LeatherProvider: { + request: (method: string, params: any) => Promise + } + } +} + +let connected = false + +const Leather: WalletAdapterInterface = { + id: 'leather', + name: 'Leather', + icon: icons.Leather, + platforms: [WalletPlatformEnum.BROWSER], + downloadLink: 'https://leather.io/install-extension', + isDetected: () => Boolean(window.LeatherProvider), + isConnected: async () => connected, + connect: async (provider?: ProviderInterface): Promise => { + return await new Promise((resolve, reject) => { + const leather = window.LeatherProvider + + const network = provider !== undefined && provider?.isTestnet() ? 'testnet' : 'mainnet' + + const walletAdapter: BitcoinWalletAdapter = { + on: (event, callback) => { + if (window.btc?.listen !== undefined) { + window.btc.listen(event, callback) + } + }, + signMessage: async (message: string) => { + const response = await leather.request('signMessage', { + message, + network, + account: 0, + paymentType: 'p2wpkh' + }) + + return response.result.signature as string + }, + sendBitcoin: async (to: string, amount: number) => { + return await new Promise((resolve, reject) => { + try { + leather + .request('sendTransfer', { + address: to, + amount, + network + }) + .then((response) => { + resolve(response.result.txid as string) + }) + .catch(({ error }) => { + reject(error) + }) + } catch (error) { + reject(error) + } + }) + }, + getAddress: async () => '' + } + + const connect = async (): Promise => { + const addresses = ( + await leather.request('getAddresses', { + network + }) + ).result.addresses + + const bitcoin = addresses.find((address: any) => address.type === 'p2wpkh') + + // for ordinals & BRC-20 integrations + // const ordinals = addresses.find(address => address.type == 'p2tr'); + + walletAdapter.getAddress = async () => { + return bitcoin.address + } + + return walletAdapter + } + + try { + connect() + .then((walletAdapter) => { + connected = true + resolve(walletAdapter) + }) + .catch(reject) + } catch (error) { + reject(error) + } + }) + } +} + +export default Leather diff --git a/packages/networks/bitcoin/src/browser/adapters/UniSat.ts b/packages/networks/bitcoin/src/browser/adapters/UniSat.ts new file mode 100644 index 0000000..b089c8c --- /dev/null +++ b/packages/networks/bitcoin/src/browser/adapters/UniSat.ts @@ -0,0 +1,60 @@ +import icons from './icons.ts' +import { WalletPlatformEnum } from '@multiplechain/types' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import type { BitcoinWalletAdapter } from '../Wallet.ts' + +declare global { + interface Window { + unisat: { + _isConnected: boolean + getAccounts: () => Promise + requestAccounts: () => Promise + signMessage: (message: string) => Promise + switchNetwork: (network: string) => Promise + on: (event: string, callback: (data: any) => void) => void + sendBitcoin: (to: string, amount: number) => Promise + } + } +} + +const UniSat: WalletAdapterInterface = { + id: 'unisat', + name: 'UniSat', + icon: icons.UniSat, + platforms: [WalletPlatformEnum.BROWSER], + downloadLink: 'https://unisat.io/download', + isDetected: () => Boolean(window.unisat?.requestAccounts), + isConnected: async () => window?.unisat?._isConnected ?? false, + connect: async (provider?: ProviderInterface): Promise => { + return await new Promise((resolve, reject) => { + const network = provider !== undefined && provider?.isTestnet() ? 'testnet' : 'livenet' + + const walletAdapter: BitcoinWalletAdapter = { + on: window.unisat.on, + signMessage: window.unisat.signMessage, + sendBitcoin: window.unisat.sendBitcoin, + getAddress: async () => { + return (await window.unisat.getAccounts())[0] + } + } + + try { + window.unisat + .requestAccounts() + .then(() => { + window.unisat + .switchNetwork(network) + .then(() => { + resolve(walletAdapter) + }) + .catch(reject) + }) + .catch(reject) + } catch (error) { + reject(error) + } + }) + } +} + +export default UniSat diff --git a/packages/networks/bitcoin/src/browser/adapters/Xverse.ts b/packages/networks/bitcoin/src/browser/adapters/Xverse.ts new file mode 100644 index 0000000..ef50592 --- /dev/null +++ b/packages/networks/bitcoin/src/browser/adapters/Xverse.ts @@ -0,0 +1,139 @@ +import icons from './icons.ts' +import type { BitcoinWalletAdapter } from '../Wallet.ts' +import { + ErrorTypeEnum, + WalletPlatformEnum, + type ProviderInterface, + type WalletAdapterInterface +} from '@multiplechain/types' +import { + getAddress, + sendBtcTransaction, + BitcoinNetworkType, + signMessage, + AddressPurpose +} from 'sats-connect' + +let connected = false + +const Xverse: WalletAdapterInterface = { + id: 'xverse', + name: 'Xverse', + icon: icons.Xverse, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://www.xverse.app/download', + isDetected: () => Boolean(window.XverseProviders?.BitcoinProvider), + isConnected: async () => connected, + connect: async (provider?: ProviderInterface): Promise => { + return await new Promise((resolve, reject) => { + const type = + provider !== undefined && provider?.isTestnet() + ? BitcoinNetworkType.Testnet + : BitcoinNetworkType.Mainnet + + const walletAdapter: BitcoinWalletAdapter = { + on: (_event: string, _callback: (data: any) => void) => {}, + signMessage: async (message: string) => { + const address = await walletAdapter.getAddress() + return await new Promise((resolve, reject) => { + signMessage({ + payload: { + network: { + type + }, + address, + message + }, + onFinish: (signature) => { + resolve(signature) + }, + onCancel: () => { + reject(ErrorTypeEnum.WALLET_REQUEST_REJECTED) + } + }).catch(reject) + }) + }, + sendBitcoin: async (to: string, amount: number) => { + const senderAddress = await walletAdapter.getAddress() + return await new Promise((resolve, reject) => { + sendBtcTransaction({ + payload: { + network: { + type + }, + recipients: [ + { + address: to, + amountSats: BigInt(amount) + } + ], + senderAddress + }, + onFinish: (txId) => { + resolve(txId) + }, + onCancel: () => { + reject(ErrorTypeEnum.WALLET_REQUEST_REJECTED) + } + }).catch(reject) + }) + }, + getAddress: async () => '' + } + + const connect = async (): Promise => { + return await new Promise((resolve, reject) => { + try { + getAddress({ + payload: { + purposes: [AddressPurpose.Payment, AddressPurpose.Ordinals], + message: 'Address for receiving Ordinals and payments', + network: { + type + } + }, + onFinish: (response) => { + const addresses = Object.values(response.addresses) + const bitcoin = addresses.find( + (address) => address.purpose === AddressPurpose.Payment + ) + + // for ordinals & BRC-20 integrations + // const ordinals = addresses.find(address => address.purpose == 'ordinals'); + + if (bitcoin === undefined) { + reject(ErrorTypeEnum.WALLET_CONNECTION_FAILED) + return + } + + walletAdapter.getAddress = async () => { + return bitcoin.address + } + + resolve(walletAdapter) + }, + onCancel: () => { + reject(ErrorTypeEnum.WALLET_REQUEST_REJECTED) + } + }).catch(reject) + } catch (error) { + reject(error) + } + }) + } + + try { + connect() + .then((walletAdapter) => { + connected = true + resolve(walletAdapter) + }) + .catch(reject) + } catch (error) { + reject(error) + } + }) + } +} + +export default Xverse diff --git a/packages/networks/bitcoin/src/browser/adapters/icons.ts b/packages/networks/bitcoin/src/browser/adapters/icons.ts new file mode 100644 index 0000000..5417b1d --- /dev/null +++ b/packages/networks/bitcoin/src/browser/adapters/icons.ts @@ -0,0 +1,6 @@ +export default { + UniSat: 'data:image/png;base64,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', + Xverse: 'data:image/png;base64,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', + Leather: + 'data:image/png;base64,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' +} diff --git a/packages/networks/bitcoin/src/browser/adapters/index.ts b/packages/networks/bitcoin/src/browser/adapters/index.ts new file mode 100644 index 0000000..6408790 --- /dev/null +++ b/packages/networks/bitcoin/src/browser/adapters/index.ts @@ -0,0 +1,3 @@ +export { default as UniSat } from './UniSat.ts' +export { default as Xverse } from './Xverse.ts' +export { default as Leather } from './Leather.ts' diff --git a/packages/networks/bitcoin/src/browser/index.ts b/packages/networks/bitcoin/src/browser/index.ts new file mode 100644 index 0000000..787e9bd --- /dev/null +++ b/packages/networks/bitcoin/src/browser/index.ts @@ -0,0 +1,25 @@ +import { Wallet } from './Wallet.ts' +import * as adapterList from './adapters/index.ts' +import type { + WalletAdapterListType, + WalletAdapterInterface, + RegisterWalletAdapterType +} from '@multiplechain/types' + +const adapters: WalletAdapterListType = {} + +const registerAdapter: RegisterWalletAdapterType = (adapter: WalletAdapterInterface): void => { + if (Object.values(adapters).find((a) => a.id === adapter.id) !== undefined) { + throw new Error(`Adapter with id ${adapter.id} already exists`) + } + + adapters[adapter.id] = adapter +} + +export * from '../index.ts' + +export const browser = { + Wallet, + registerAdapter, + adapters: Object.assign(adapters, adapterList) +} diff --git a/packages/networks/bitcoin/src/index.ts b/packages/networks/bitcoin/src/index.ts new file mode 100644 index 0000000..7b0e1cd --- /dev/null +++ b/packages/networks/bitcoin/src/index.ts @@ -0,0 +1,8 @@ +export * from './services/Provider.ts' + +export * as assets from './assets/index.ts' +export * as models from './models/index.ts' +export * as services from './services/index.ts' + +export * as utils from './utils.ts' +export * as types from '@multiplechain/types' diff --git a/packages/networks/bitcoin/src/models/CoinTransaction.ts b/packages/networks/bitcoin/src/models/CoinTransaction.ts new file mode 100644 index 0000000..d681e05 --- /dev/null +++ b/packages/networks/bitcoin/src/models/CoinTransaction.ts @@ -0,0 +1,63 @@ +import { fromSatoshi } from '../utils.ts' +import { Transaction } from './Transaction.ts' +import { TransactionStatusEnum } from '@multiplechain/types' +import { AssetDirectionEnum, type CoinTransactionInterface } from '@multiplechain/types' + +export class CoinTransaction extends Transaction implements CoinTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + async getReceiver(): Promise { + const data = await this.getData() + return data?.vout[0].scriptpubkey_address ?? '' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + return await this.getSigner() + } + + /** + * @returns {Promise} Amount of coin that will be transferred + */ + async getAmount(): Promise { + const data = await this.getData() + return fromSatoshi(data?.vout[0].value ?? 0) + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (asset) + * @param {string} address - Wallet address of the receiver or sender of the transaction, dependant on direction + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + amount: number + ): Promise { + const status = await this.getStatus() + + if (status === TransactionStatusEnum.PENDING) { + return TransactionStatusEnum.PENDING + } + + if ((await this.getAmount()) !== amount) { + return TransactionStatusEnum.FAILED + } + + if (direction === AssetDirectionEnum.INCOMING) { + if ((await this.getReceiver()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } else { + if ((await this.getSender()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } + + return TransactionStatusEnum.CONFIRMED + } +} diff --git a/packages/networks/bitcoin/src/models/ContractTransaction.ts b/packages/networks/bitcoin/src/models/ContractTransaction.ts new file mode 100644 index 0000000..4813a5a --- /dev/null +++ b/packages/networks/bitcoin/src/models/ContractTransaction.ts @@ -0,0 +1,21 @@ +import { Transaction } from './Transaction.ts' +import type { Provider } from '../services/Provider.ts' +import type { ContractTransactionInterface } from '@multiplechain/types' + +export class ContractTransaction extends Transaction implements ContractTransactionInterface { + /** + * @param {string} id Transaction id + * @param {Provider} provider Blockchain network provider + */ + constructor(id: string, provider?: Provider) { + super(id, provider) + throw new Error('This class is not implemented for Bitcoin.') + } + + /** + * @returns {Promise} Contract address of the transaction + */ + async getAddress(): Promise { + return 'example' + } +} diff --git a/packages/networks/bitcoin/src/models/NftTransaction.ts b/packages/networks/bitcoin/src/models/NftTransaction.ts new file mode 100644 index 0000000..09b8d80 --- /dev/null +++ b/packages/networks/bitcoin/src/models/NftTransaction.ts @@ -0,0 +1,41 @@ +import { ContractTransaction } from './ContractTransaction.ts' +import { TransactionStatusEnum } from '@multiplechain/types' +import type { NftTransactionInterface, AssetDirectionEnum } from '@multiplechain/types' + +export class NftTransaction extends ContractTransaction implements NftTransactionInterface { + /** + * @returns {Promise} Receiver wallet address + */ + async getReceiver(): Promise { + return 'example' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + return 'example' + } + + /** + * @returns {Promise} NFT ID + */ + async getNftId(): Promise { + return 0 + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (nft) + * @param {string} address - Wallet address of the receiver or sender of the transaction, dependant on direction + * @param {number} nftId ID of the NFT that will be transferred + * @override verifyTransfer() in AssetTransactionInterface + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + nftId: number | string + ): Promise { + return TransactionStatusEnum.PENDING + } +} diff --git a/packages/networks/bitcoin/src/models/TokenTransaction.ts b/packages/networks/bitcoin/src/models/TokenTransaction.ts new file mode 100644 index 0000000..b1ea29e --- /dev/null +++ b/packages/networks/bitcoin/src/models/TokenTransaction.ts @@ -0,0 +1,40 @@ +import { ContractTransaction } from './ContractTransaction.ts' +import { TransactionStatusEnum } from '@multiplechain/types' +import type { AssetDirectionEnum, TokenTransactionInterface } from '@multiplechain/types' + +export class TokenTransaction extends ContractTransaction implements TokenTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + async getReceiver(): Promise { + return 'example' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + return 'example' + } + + /** + * @returns {Promise} Amount of tokens that will be transferred + */ + async getAmount(): Promise { + return 0 + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (token) + * @param {string} address - Wallet address of the owner or spender of the transaction, dependant on direction + * @param {number} amount Amount of tokens that will be approved + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + amount: number + ): Promise { + return TransactionStatusEnum.PENDING + } +} diff --git a/packages/networks/bitcoin/src/models/Transaction.ts b/packages/networks/bitcoin/src/models/Transaction.ts new file mode 100644 index 0000000..4cdeed8 --- /dev/null +++ b/packages/networks/bitcoin/src/models/Transaction.ts @@ -0,0 +1,205 @@ +import { fromSatoshi, sleep } from '../utils.ts' +import axios, { type AxiosError } from 'axios' +import { Provider } from '../services/Provider.ts' +import type { TransactionInterface } from '@multiplechain/types' +import { ErrorTypeEnum, TransactionStatusEnum } from '@multiplechain/types' + +export interface VinObject { + txid: string + vout: number + prevout: { + scriptpubkey: string + scriptpubkey_asm: string + scriptpubkey_type: string + scriptpubkey_address: string + value: number + } + scriptsig: string + scriptsig_asm: string + witness: string[] + is_coinbase: boolean + sequence: number +} + +export interface VoutObject { + scriptpubkey: string + scriptpubkey_asm: string + scriptpubkey_type: string + scriptpubkey_address: string + value: number +} + +export interface TransactionData { + txid: string + version: number + locktime: number + vin: VinObject[] + vout: VoutObject[] + size: number + weight: number + fee: number + status: { + confirmed: boolean + block_height: number + block_hash: string + block_time: number + } +} + +let counter = 0 + +export class Transaction implements TransactionInterface { + /** + * Each transaction has its own unique ID defined by the user + */ + id: string + + /** + * Blockchain network provider + */ + provider: Provider + + /** + * Transaction data + */ + data: TransactionData | null = null + + /** + * @param {string} id Transaction id + * @param {Provider} provider Blockchain network provider + */ + constructor(id: string, provider?: Provider) { + this.id = id + this.provider = provider ?? Provider.instance + } + + /** + * @returns {Promise} Transaction data + */ + async getData(): Promise { + if (this.data !== null) { + return this.data + } + try { + const data = (await axios.get(this.provider.createEndpoint('tx/' + this.id))).data + + if (data?.txid !== this.id) { + return (this.data = null) + } + + return (this.data = data as TransactionData) + } catch (error) { + const axiosError = error as AxiosError + // Returns empty data when the transaction is first created. For this reason, it would be better to check it intermittently and give an error if it still does not exist. Average 10 seconds. + if (String(axiosError?.response?.data).includes('Transaction not found')) { + if (counter > 5) { + throw new Error(ErrorTypeEnum.TRANSACTION_NOT_FOUND) + } + counter++ + await sleep(2000) + return await this.getData() + } + throw new Error(ErrorTypeEnum.RPC_REQUEST_ERROR) + } + } + + /** + * @param {number} ms - Milliseconds to wait for the transaction to be confirmed. Default is 4000ms + * @returns {Promise} Status of the transaction + */ + async wait(ms: number = 4000): Promise { + return await new Promise((resolve, reject) => { + const check = async (): Promise => { + try { + const status = await this.getStatus() + if (status === TransactionStatusEnum.CONFIRMED) { + resolve(TransactionStatusEnum.CONFIRMED) + return + } else if (status === TransactionStatusEnum.FAILED) { + reject(TransactionStatusEnum.FAILED) + return + } + setTimeout(check, ms) + } catch (error) { + reject(TransactionStatusEnum.FAILED) + } + } + void check() + }) + } + + /** + * @returns {string} Transaction ID + */ + getId(): string { + return this.id + } + + /** + * @returns {string} Transaction URL + */ + getUrl(): string { + return this.provider.explorer + 'tx/' + this.id + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSigner(): Promise { + const data = await this.getData() + return data?.vin[0].prevout.scriptpubkey_address ?? '' + } + + /** + * @returns {Promise} Transaction fee + */ + async getFee(): Promise { + const data = await this.getData() + return fromSatoshi(data?.fee ?? 0) + } + + /** + * @returns {Promise} Block number that transaction + */ + async getBlockNumber(): Promise { + const data = await this.getData() + return data?.status?.block_height ?? 0 + } + + /** + * @returns {Promise} Block timestamp that transaction + */ + async getBlockTimestamp(): Promise { + const data = await this.getData() + return data?.status?.block_time ?? 0 + } + + /** + * @returns {Promise} Confirmation count of the block + */ + async getBlockConfirmationCount(): Promise { + const data = await this.getData() + if (data === null) { + return 0 + } + const latestBlock = await axios.get(this.provider.createEndpoint('blocks/tip/height')) + return (latestBlock.data as number) - data?.status?.block_height + } + + /** + * @returns {Promise} Status of the transaction + */ + async getStatus(): Promise { + const data = await this.getData() + if (data === null) { + return TransactionStatusEnum.PENDING + } else if (data.status?.block_height !== undefined) { + if (data.status.confirmed) { + return TransactionStatusEnum.CONFIRMED + } else { + return TransactionStatusEnum.FAILED + } + } + return TransactionStatusEnum.PENDING + } +} diff --git a/packages/networks/bitcoin/src/models/index.ts b/packages/networks/bitcoin/src/models/index.ts new file mode 100644 index 0000000..cc0a27c --- /dev/null +++ b/packages/networks/bitcoin/src/models/index.ts @@ -0,0 +1,5 @@ +export * from './Transaction.ts' +export * from './NftTransaction.ts' +export * from './CoinTransaction.ts' +export * from './TokenTransaction.ts' +export * from './ContractTransaction.ts' diff --git a/packages/networks/bitcoin/src/services/Provider.ts b/packages/networks/bitcoin/src/services/Provider.ts new file mode 100644 index 0000000..30086e2 --- /dev/null +++ b/packages/networks/bitcoin/src/services/Provider.ts @@ -0,0 +1,156 @@ +import axios from 'axios' +import { checkWebSocket } from '@multiplechain/utils' +import { ErrorTypeEnum, type ProviderInterface } from '@multiplechain/types' + +export interface BitcoinNetworkConfigInterface { + testnet: boolean + blockCypherToken?: string +} + +export class Provider implements Omit { + /** + * Network configuration of the provider + */ + network: BitcoinNetworkConfigInterface + + /** + * API URL + */ + api: string + + /** + * Explorer URL + */ + explorer: string + + /** + * Websocket URL + */ + wsUrl: string + + /** + * BlockCypher token + */ + blockCypherToken?: string + + /** + * Default BlockCypher token + */ + defaultBlockCypherToken = '49d43a59a4f24d31a9731eb067ab971c' + + /** + * Static instance of the provider + */ + private static _instance: Provider + + /** + * @param network - Network configuration of the provider + */ + constructor(network: BitcoinNetworkConfigInterface) { + this.update(network) + } + + /** + * Get the static instance of the provider + * @returns {Provider} Provider + */ + static get instance(): Provider { + if (Provider._instance === undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_NOT_INITIALIZED) + } + return Provider._instance + } + + /** + * Initialize the static instance of the provider + * @param {BitcoinNetworkConfigInterface} network - Network configuration of the provider + * @returns {void} + */ + static initialize(network: BitcoinNetworkConfigInterface): void { + if (Provider._instance !== undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_ALREADY_INITIALIZED) + } + Provider._instance = new Provider(network) + } + + /** + * Check RPC connection + * @param {string} url - RPC URL + * @returns {Promise} + */ + async checkRpcConnection(url?: string): Promise { + try { + const response = await axios.get(url ?? this.createEndpoint('blocks/tip/height')) + + if (response.status !== 200) { + return new Error(response.statusText + ': ' + JSON.stringify(response.data)) + } + + return true + } catch (error) { + return error as Error + } + } + + /** + * Check WS connection + * @param {string} url - Websocket URL + * @returns {Promise} + */ + async checkWsConnection(url?: string): Promise { + try { + const result: any = await checkWebSocket(url ?? this.wsUrl) + + if (result instanceof Error) { + return result + } + + return true + } catch (error) { + return error as Error + } + } + + /** + * Update network configuration of the provider + * @param network - Network configuration of the provider + */ + update(network: BitcoinNetworkConfigInterface): void { + this.network = network + Provider._instance = this + this.blockCypherToken = this.network.blockCypherToken + if (this.network.testnet) { + this.api = 'https://blockstream.info/testnet/api/' + this.explorer = 'https://blockstream.info/testnet/' + const token = this.network.blockCypherToken ?? this.defaultBlockCypherToken + this.wsUrl = 'wss://socket.blockcypher.com/v1/btc/test3?token=' + token + } else { + this.api = 'https://blockstream.info/api/' + this.explorer = 'https://blockstream.info/' + if (this.network.blockCypherToken !== undefined) { + this.wsUrl = + 'wss://socket.blockcypher.com/v1/btc/main?token=' + + this.network.blockCypherToken + } else { + this.wsUrl = 'wss://ws.blockchain.info/inv' + } + } + } + + /** + * Create a new endpoint + * @param {string} endpoint - Endpoint + * @returns {string} Endpoint + */ + createEndpoint(endpoint: string): string { + return this.api + endpoint + } + + /** + * Get the current network configuration is testnet or not + * @returns boolean + */ + isTestnet(): boolean { + return this.network?.testnet ?? false + } +} diff --git a/packages/networks/bitcoin/src/services/TransactionListener.ts b/packages/networks/bitcoin/src/services/TransactionListener.ts new file mode 100644 index 0000000..04fa972 --- /dev/null +++ b/packages/networks/bitcoin/src/services/TransactionListener.ts @@ -0,0 +1,352 @@ +import type { + TransactionTypeEnum, + DynamicTransactionType, + TransactionListenerInterface, + DynamicTransactionListenerFilterType +} from '@multiplechain/types' +import WebSocket from 'ws' +import { Provider } from './Provider.ts' +import { fromSatoshi } from '../utils.ts' +import { Transaction } from '../models/Transaction.ts' +import type { NftTransaction } from '../models/NftTransaction.ts' +import { CoinTransaction } from '../models/CoinTransaction.ts' +import type { TokenTransaction } from '../models/TokenTransaction.ts' +import type { ContractTransaction } from '../models/ContractTransaction.ts' +import { checkWebSocket, objectsEqual } from '@multiplechain/utils' +import { TransactionListenerProcessIndex } from '@multiplechain/types' + +interface Values { + txId: string + amount?: number + sender?: string + receiver?: string +} + +type TransactionListenerTriggerType = DynamicTransactionType< + T, + Transaction, + ContractTransaction, + CoinTransaction, + TokenTransaction, + NftTransaction +> + +type TransactionListenerCallbackType< + T extends TransactionTypeEnum, + Transaction = TransactionListenerTriggerType +> = (transaction: Transaction) => void + +export class TransactionListener< + T extends TransactionTypeEnum, + DTransaction extends TransactionListenerTriggerType, + CallBackType extends TransactionListenerCallbackType +> implements TransactionListenerInterface +{ + /** + * Transaction type + */ + type: T + + /** + * Transaction listener callback + */ + callbacks: CallBackType[] = [] + + /** + * Transaction listener filter + */ + filter?: DynamicTransactionListenerFilterType | Record + + /** + * Provider + */ + provider: Provider + + /** + * Listener status + */ + status: boolean = false + + /** + * Triggered transactions + */ + triggeredTransactions: string[] = [] + + /** + * WebSocket + */ + webSocket: WebSocket + + /** + * Dynamic stop method + */ + dynamicStop: () => void = () => {} + + /** + * @param {T} type - Transaction type + * @param {DynamicTransactionListenerFilterType} filter - Transaction listener filter + * @param {Provider} provider - Provider + */ + constructor(type: T, filter?: DynamicTransactionListenerFilterType, provider?: Provider) { + this.type = type + this.filter = filter ?? {} + this.provider = provider ?? Provider.instance + } + + /** + * Close the listener + * @returns {void} + */ + stop(): void { + if (this.status) { + this.status = false + this.dynamicStop() + } + } + + /** + * Start the listener + * @returns {void} + */ + start(): void { + if (!this.status) { + this.status = true + // @ts-expect-error allow dynamic access + this[TransactionListenerProcessIndex[this.type]]() + } + } + + /** + * Get the listener status + * @returns {boolean} Listener status + */ + getStatus(): boolean { + return this.status + } + + /** + * Listen to the transaction events + * @param {CallBackType} callback - Transaction listener callback + * @returns {Promise} + */ + async on(callback: CallBackType): Promise { + if (this.webSocket === undefined) { + try { + await checkWebSocket(this.provider.wsUrl) + this.webSocket = new WebSocket(this.provider.wsUrl) + } catch (error) { + throw new Error( + 'WebSocket connection is not available' + + (error instanceof Error ? ': ' + error.message : '') + ) + } + } + + this.start() + this.callbacks.push(callback) + + return true + } + + /** + * Trigger the event when a transaction is detected + * @param {TransactionListenerTriggerType} transaction - Transaction data + * @returns {void} + */ + trigger(transaction: TransactionListenerTriggerType): void { + if (!this.triggeredTransactions.includes(transaction.id)) { + this.triggeredTransactions.push(transaction.id) + this.callbacks.forEach((callback) => { + callback(transaction as unknown as DTransaction) + }) + } + } + + isBlockCypherProcess(): boolean { + return this.provider.isTestnet() || this.provider.blockCypherToken !== undefined + } + + /** + * Create message for the listener + * @param {string} receiver - Receiver address + * @returns {string} Message + */ + createMessage(receiver?: string): string { + let message + if (this.isBlockCypherProcess()) { + interface Config { + event: string + token: string + address?: string + } + + const config: Config = { + event: 'unconfirmed-tx', + token: this.provider.blockCypherToken ?? this.provider.defaultBlockCypherToken + } + + if (receiver !== undefined) { + config.address = receiver + } + + message = JSON.stringify(config) + } else { + message = JSON.stringify({ + op: 'unconfirmed_sub' + }) + } + + this.dynamicStop = () => { + if (!this.isBlockCypherProcess()) { + this.webSocket.send( + JSON.stringify({ + op: 'unconfirmed_unsub' + }) + ) + } + this.webSocket.close() + } + + return message + } + + /** + * Parse the data + * @param {any} data - Data + * @returns {Values} Parsed data + */ + getValues(data: any): Values { + const values: Values = { + txId: '' + } + + if (this.isBlockCypherProcess()) { + values.txId = data.hash + values.sender = data.inputs[0].addresses[0] + values.receiver = data.outputs[0].addresses[0] + values.amount = fromSatoshi(data.outputs[0].value as number) + } else { + values.txId = data.x.hash + values.receiver = data.x.out[0].addr + values.sender = data.x.inputs[0].prev_out.addr + values.amount = fromSatoshi(data.x.out[0].value as number) + } + + return values + } + + /** + * General transaction process + * @returns {void} + */ + generalProcess(): void { + const message = this.createMessage() + + this.webSocket.addEventListener('open', () => { + this.webSocket.send(message) + }) + + this.webSocket.addEventListener('message', async (res) => { + const values = this.getValues(JSON.parse(res.data as string)) + + if ( + this.filter?.signer !== undefined && + values.sender !== this.filter.signer.toLowerCase() + ) { + return + } + + this.trigger(new Transaction(values.txId)) + }) + } + + /** + * Contract transaction process + * @returns {void} + */ + contractProcess(): void { + throw new Error('This method is not implemented for Bitcoin.') + } + + /** + * Coin transaction process + * @returns {void} + */ + coinProcess(): void { + const filter = this.filter as DynamicTransactionListenerFilterType + + if ( + filter.signer !== undefined && + filter.sender !== undefined && + filter.signer !== filter.sender + ) { + throw new Error( + 'Sender and signer must be the same in coin transactions. Or only one of them can be defined.' + ) + } + + const sender = filter.sender ?? filter.signer + + const message = this.createMessage(filter.receiver) + + this.webSocket.addEventListener('open', () => { + this.webSocket.send(message) + }) + + this.webSocket.addEventListener('message', async (res) => { + const data = JSON.parse(res.data as string) + + interface ParamsType { + sender?: string + receiver?: string + } + + const expectedParams: ParamsType = {} + const receivedParams: ParamsType = {} + + if (String(data.event).includes('events limit reached')) { + throw new Error('BlockCypher events limit reached.') + } + + const values = this.getValues(data) + + if (sender !== undefined) { + expectedParams.sender = sender.toLowerCase() + receivedParams.sender = values.sender?.toLowerCase() + } + + if (filter.receiver !== undefined) { + expectedParams.receiver = filter.receiver.toLowerCase() + receivedParams.receiver = values.receiver?.toLowerCase() + } + + if (!objectsEqual(expectedParams, receivedParams)) { + return + } + + const transaction = new CoinTransaction(values.txId) + + if (filter.amount !== undefined && values.amount !== filter.amount) { + return + } + + this.trigger(transaction) + }) + } + + /** + * Token transaction process + * @returns {void} + */ + tokenProcess(): void { + throw new Error('This method is not implemented for Bitcoin.') + } + + /** + * NFT transaction process + * @returns {void} + */ + nftProcess(): void { + throw new Error('This method is not implemented for Bitcoin.') + } +} diff --git a/packages/networks/bitcoin/src/services/TransactionSigner.ts b/packages/networks/bitcoin/src/services/TransactionSigner.ts new file mode 100644 index 0000000..15ae13a --- /dev/null +++ b/packages/networks/bitcoin/src/services/TransactionSigner.ts @@ -0,0 +1,115 @@ +import axios from 'axios' +import type { AxiosError } from 'axios' +import { Provider } from '../services/Provider.ts' +import { Transaction } from '../models/Transaction.ts' +import { NftTransaction } from '../models/NftTransaction.ts' +import { CoinTransaction } from '../models/CoinTransaction.ts' +import { TokenTransaction } from '../models/TokenTransaction.ts' +import { type TransactionSignerInterface } from '@multiplechain/types' +import type { Transaction as BitcoreLibTransactionData } from 'bitcore-lib' + +export interface TransactionData { + sender: string + receiver: string + amount: number + bitcoreLib: BitcoreLibTransactionData +} + +export class TransactionSigner implements TransactionSignerInterface { + /** + * Transaction data from the blockchain network + */ + rawData: TransactionData + + /** + * Signed transaction data + */ + signedData?: string + + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {TransactionData} rawData - Transaction data + */ + constructor(rawData: TransactionData, provider?: Provider) { + this.rawData = rawData + this.provider = provider ?? Provider.instance + } + + /** + * Sign the transaction + * @param {string} privateKey - Transaction data + * @returns {Promise} Signed transaction data + */ + async sign(privateKey: string): Promise { + this.rawData.bitcoreLib.sign(privateKey) + this.signedData = this.rawData.bitcoreLib.serialize() + return this + } + + /** + * Send the transaction to the blockchain network + * @returns {Promise} + */ + async send(): Promise { + try { + const result = await axios({ + method: 'POST', + url: `https://blockstream.info/testnet/api/tx`, + data: this.signedData + }) + return new Transaction(result.data as string) + } catch (error: any) { + throw new Error(JSON.stringify((error as AxiosError).response?.data)) + } + } + + /** + * Get the raw transaction data + * @returns Transaction data + */ + getRawData(): TransactionData { + return this.rawData + } + + /** + * Get the signed transaction data + * @returns Signed transaction data + */ + getSignedData(): string { + return this.signedData ?? '' + } +} + +export class CoinTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new CoinTransaction((await super.send()).getId()) + } +} + +export class TokenTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new TokenTransaction((await super.send()).getId()) + } +} + +export class NftTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new NftTransaction((await super.send()).getId()) + } +} diff --git a/packages/networks/bitcoin/src/services/index.ts b/packages/networks/bitcoin/src/services/index.ts new file mode 100644 index 0000000..549a382 --- /dev/null +++ b/packages/networks/bitcoin/src/services/index.ts @@ -0,0 +1,2 @@ +export * from './TransactionSigner.ts' +export * from './TransactionListener.ts' diff --git a/packages/networks/bitcoin/src/utils.ts b/packages/networks/bitcoin/src/utils.ts new file mode 100644 index 0000000..14bd3ec --- /dev/null +++ b/packages/networks/bitcoin/src/utils.ts @@ -0,0 +1,11 @@ +import { math } from '@multiplechain/utils' + +export * from '@multiplechain/utils' + +export const fromSatoshi = (amount: number): number => { + return math.div(amount, 100000000, 8) +} + +export const toSatoshi = (amount: number): number => { + return math.mul(amount, 100000000, 8) +} diff --git a/packages/networks/bitcoin/tests/assets.spec.ts b/packages/networks/bitcoin/tests/assets.spec.ts new file mode 100644 index 0000000..36147df --- /dev/null +++ b/packages/networks/bitcoin/tests/assets.spec.ts @@ -0,0 +1,63 @@ +import { describe, it, expect, assert } from 'vitest' + +import { Coin } from '../src/assets/Coin.ts' +import { math } from '@multiplechain/utils' +import { Transaction } from '../src/models/Transaction.ts' +import { TransactionStatusEnum } from '@multiplechain/types' +import { TransactionSigner } from '../src/services/TransactionSigner.ts' + +const testAmount = Number(process.env.BTC_TRANSFER_AMOUNT) +const senderTestAddress = String(process.env.BTC_SENDER_ADDRESS) +const receiverTestAddress = String(process.env.BTC_RECEIVER_ADDRESS) +const senderPrivateKey = String(process.env.BTC_SENDER_PRIVATE_KEY) +const transferTestIsActive = Boolean(process.env.BTC_TRANSFER_TEST_IS_ACTIVE !== 'false') + +const checkSigner = async (signer: TransactionSigner, privateKey?: string): Promise => { + expect(signer).toBeInstanceOf(TransactionSigner) + + const rawData = signer.getRawData() + + assert.isObject(rawData) + + await signer.sign(privateKey ?? senderPrivateKey) + + assert.isString(signer.getSignedData()) +} + +const checkTx = async (transaction: Transaction): Promise => { + expect(transaction).toBeInstanceOf(Transaction) + const status = await transaction.wait(10 * 1000) + expect(status).toBe(TransactionStatusEnum.CONFIRMED) +} + +describe('Coin', () => { + const coin = new Coin() + it('Name and symbol', () => { + expect(coin.getName()).toBe('Bitcoin') + expect(coin.getSymbol()).toBe('BTC') + }) + + it('Decimals', () => { + expect(coin.getDecimals()).toBe(8) + }) + + it('Balance', async () => { + const balance = await coin.getBalance('tb1qc240vx54n08hnhx8l4rqxjzcxf4f0ssq5asawm') + expect(balance).toBe(0.00003) + }) + + it('Transfer', async () => { + const signer = await coin.transfer(senderTestAddress, receiverTestAddress, testAmount) + + await checkSigner(signer) + + if (!transferTestIsActive) return + + const beforeBalance = await coin.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await coin.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, testAmount)) + }) +}) diff --git a/packages/networks/bitcoin/tests/models.spec.ts b/packages/networks/bitcoin/tests/models.spec.ts new file mode 100644 index 0000000..d4265de --- /dev/null +++ b/packages/networks/bitcoin/tests/models.spec.ts @@ -0,0 +1,78 @@ +import { describe, it, expect } from 'vitest' +import { Transaction } from '../src/models/Transaction.ts' +import { CoinTransaction } from '../src/models/CoinTransaction.ts' +import { AssetDirectionEnum, TransactionStatusEnum } from '@multiplechain/types' + +const testAmount = Number(process.env.BTC_TRANSFER_AMOUNT) +const senderTestAddress = String(process.env.BTC_SENDER_ADDRESS) +const receiverTestAddress = String(process.env.BTC_RECEIVER_ADDRESS) +const txId = '335c8a251e5f18121977c3159f46983d5943325abccc19e4718c49089553d60c' + +describe('Transaction', () => { + const tx = new Transaction(txId) + it('Id', async () => { + expect(tx.getId()).toBe(txId) + }) + + it('Data', async () => { + expect(await tx.getData()).toBeTypeOf('object') + }) + + it('Wait', async () => { + expect(await tx.wait()).toBe(TransactionStatusEnum.CONFIRMED) + }) + + it('URL', async () => { + expect(tx.getUrl()).toBe('https://blockstream.info/testnet/tx/' + txId) + }) + + it('Sender', async () => { + expect((await tx.getSigner()).toLowerCase()).toBe(senderTestAddress.toLowerCase()) + }) + + it('Fee', async () => { + expect(await tx.getFee()).toBe(0.00014) + }) + + it('Block Number', async () => { + expect(await tx.getBlockNumber()).toBe(2814543) + }) + + it('Block Timestamp', async () => { + expect(await tx.getBlockTimestamp()).toBe(1715328679) + }) + + it('Block Confirmation Count', async () => { + expect(await tx.getBlockConfirmationCount()).toBeGreaterThan(13) + }) + + it('Status', async () => { + expect(await tx.getStatus()).toBe(TransactionStatusEnum.CONFIRMED) + }) +}) + +describe('Coin Transaction', () => { + const tx = new CoinTransaction(txId) + + it('Receiver', async () => { + expect((await tx.getReceiver()).toLowerCase()).toBe(receiverTestAddress.toLowerCase()) + }) + + it('Amount', async () => { + expect(await tx.getAmount()).toBe(testAmount) + }) + + it('Verify Transfer', async () => { + expect( + await tx.verifyTransfer(AssetDirectionEnum.INCOMING, receiverTestAddress, testAmount) + ).toBe(TransactionStatusEnum.CONFIRMED) + + expect( + await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, senderTestAddress, testAmount) + ).toBe(TransactionStatusEnum.CONFIRMED) + + expect( + await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, receiverTestAddress, testAmount) + ).toBe(TransactionStatusEnum.FAILED) + }) +}) diff --git a/packages/networks/bitcoin/tests/services.spec.ts b/packages/networks/bitcoin/tests/services.spec.ts new file mode 100644 index 0000000..d5e59cb --- /dev/null +++ b/packages/networks/bitcoin/tests/services.spec.ts @@ -0,0 +1,67 @@ +import { describe, it, expect } from 'vitest' + +import { provider } from './setup.ts' +import { Provider } from '../src/services/Provider.ts' +import { TransactionListener } from '../src/services/TransactionListener.ts' +import { TransactionTypeEnum } from '@multiplechain/types' +import { CoinTransaction } from '../src/models/CoinTransaction.ts' +import { Coin } from '../src/assets/Coin.ts' +import { sleep } from '@multiplechain/utils' + +const senderTestAddress = String(process.env.BTC_SENDER_ADDRESS) +const receiverTestAddress = String(process.env.BTC_RECEIVER_ADDRESS) +const senderPrivateKey = String(process.env.BTC_SENDER_PRIVATE_KEY) +const listenerTestIsActive = Boolean(process.env.BTC_LISTENER_TEST_IS_ACTIVE !== 'false') + +describe('Provider', () => { + it('isTestnet', () => { + expect(provider.isTestnet()).toBe(true) + }) + + it('instance', () => { + expect(Provider.instance).toBe(provider) + }) + + it('checkRpcConnection', async () => { + expect(await provider.checkRpcConnection()).toBe(true) + }) + + it('checkWsConnection', async () => { + expect(await provider.checkWsConnection()).toBe(true) + }) +}) + +describe('Transaction Listener', () => { + if (!listenerTestIsActive) { + it('No test is active', () => { + expect(true).toBe(true) + }) + return + } + + it('Coin', async () => { + const listener = new TransactionListener(TransactionTypeEnum.COIN, { + signer: senderTestAddress, + receiver: receiverTestAddress + }) + + const signer = await new Coin().transfer(senderTestAddress, receiverTestAddress, 0.0001) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + expect(await waitListenerEvent()).toBeInstanceOf(CoinTransaction) + }) +}) diff --git a/packages/networks/bitcoin/tests/setup.ts b/packages/networks/bitcoin/tests/setup.ts new file mode 100644 index 0000000..6c04b6b --- /dev/null +++ b/packages/networks/bitcoin/tests/setup.ts @@ -0,0 +1,13 @@ +import { Provider } from '../src/services/Provider.ts' + +let provider: Provider + +try { + provider = Provider.instance +} catch (e) { + provider = new Provider({ + testnet: true + }) +} + +export { provider } diff --git a/packages/networks/bitcoin/tsconfig.json b/packages/networks/bitcoin/tsconfig.json new file mode 100644 index 0000000..e40c547 --- /dev/null +++ b/packages/networks/bitcoin/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "noEmit": true, + "composite": true, + "declaration": true, + "outDir": "./dist/esm", + "declarationDir": "./dist/types" + }, + "extends": "../../../tsconfig.json", + "include": [ + "src", + ".eslintrc.json", + "tests", + "vite.config.ts", + "esbuild.ts", + "vitest.config.ts", + "../../../esbuild.ts", + "../../../vite.config.ts", + "../../../vitest.config.ts", + ] +} diff --git a/packages/networks/bitcoin/vite.config.ts b/packages/networks/bitcoin/vite.config.ts new file mode 100644 index 0000000..87de654 --- /dev/null +++ b/packages/networks/bitcoin/vite.config.ts @@ -0,0 +1,10 @@ +import { mergeConfig } from 'vite' +import mainConfig from '../../../vite.config.ts' + +export default mergeConfig(mainConfig, { + build: { + lib: { + name: 'Bitcoin' + } + } +}) diff --git a/packages/networks/bitcoin/vite.svg b/packages/networks/bitcoin/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/packages/networks/bitcoin/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/networks/bitcoin/vitest.config.ts b/packages/networks/bitcoin/vitest.config.ts new file mode 100644 index 0000000..c96edcb --- /dev/null +++ b/packages/networks/bitcoin/vitest.config.ts @@ -0,0 +1,12 @@ +import { mergeConfig, defineConfig } from 'vitest/config' +import mainConfig from '../../../vite.config.ts' + +export default mergeConfig( + mainConfig, + defineConfig({ + test: { + testTimeout: 600000, + setupFiles: ['./tests/setup.ts'] + } + }) +) diff --git a/packages/networks/boilerplate/index.html b/packages/networks/boilerplate/index.html index 236da6d..4e508e4 100644 --- a/packages/networks/boilerplate/index.html +++ b/packages/networks/boilerplate/index.html @@ -187,9 +187,6 @@
Deep link:
-
- Chain id: -
Connected address:
@@ -215,7 +212,7 @@ + + \ No newline at end of file diff --git a/packages/networks/solana/package.json b/packages/networks/solana/package.json new file mode 100644 index 0000000..3c7990a --- /dev/null +++ b/packages/networks/solana/package.json @@ -0,0 +1,84 @@ +{ + "name": "@multiplechain/solana", + "version": "0.4.0", + "type": "module", + "main": "dist/index.cjs", + "module": "dist/index.es.js", + "unpkg": "dist/index.umd.js", + "browser": "dist/index.umd.js", + "jsdelivr": "dist/index.umd.js", + "exports": { + ".": { + "import": { + "default": "./dist/index.es.js", + "types": "./dist/browser/index.d.ts" + }, + "require": { + "default": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "./node": { + "default": "./dist/index.cjs", + "types": "./dist/index.d.ts" + }, + "./browser": { + "default": "./dist/index.es.js", + "types": "./dist/browser/index.d.ts" + } + }, + "files": [ + "dist", + "README.md", + "!tsconfig.tsbuildinfo" + ], + "scripts": { + "dev": "vite", + "clean": "rm -rf dist", + "watch": "tsc --watch", + "build:vite": "vite build", + "build:node": "tsx esbuild.ts", + "typecheck": "tsc --noEmit", + "lint": "eslint . --ext .ts", + "test": "vitest run --dir tests", + "test-ui": "vitest watch --ui", + "prepublishOnly": "pnpm run build", + "build": "pnpm run build:vite && pnpm run build:node" + }, + "keywords": [ + "web3", + "crypto", + "blockchain", + "multiple-chain" + ], + "author": "MultipleChain", + "license": "MIT", + "homepage": "https://github.com/MultipleChain/js/tree/master/packages/networks/network-name", + "repository": { + "type": "git", + "url": "git+https://github.com/MultipleChain/js.git" + }, + "bugs": { + "url": "https://github.com/MultipleChain/js/issues" + }, + "dependencies": { + "@metaplex-foundation/js": "^0.20.1", + "@multiplechain/solana-walletconnect": "^0.1.1", + "@multiplechain/types": "^0.1.56", + "@multiplechain/utils": "^0.1.20", + "@solana/spl-token": "^0.4.6", + "@solana/spl-token-metadata": "^0.1.4", + "@solana/wallet-adapter-base": "^0.9.23", + "@solana/wallet-adapter-bitkeep": "^0.3.20", + "@solana/wallet-adapter-coinbase": "^0.1.19", + "@solana/wallet-adapter-phantom": "^0.9.24", + "@solana/wallet-adapter-slope": "^0.5.21", + "@solana/wallet-adapter-solflare": "^0.6.28", + "@solana/wallet-adapter-tokenpocket": "^0.4.19", + "@solana/wallet-adapter-trust": "^0.1.13", + "@solana/web3.js": "^1.91.8", + "@web3modal/core": "^4.2.1", + "@web3modal/solana": "^4.2.1", + "axios": "^1.6.8" + } +} \ No newline at end of file diff --git a/packages/networks/solana/pnpm-lock.yaml b/packages/networks/solana/pnpm-lock.yaml new file mode 100644 index 0000000..45216c2 --- /dev/null +++ b/packages/networks/solana/pnpm-lock.yaml @@ -0,0 +1,6097 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@metaplex-foundation/js': + specifier: ^0.20.1 + version: 0.20.1(arweave@1.15.1)(fastestsmallesttextencoderdecoder@1.0.22) + '@multiplechain/solana-walletconnect': + specifier: ^0.1.1 + version: 0.1.1(@solana/web3.js@1.91.8)(vite@5.2.11) + '@multiplechain/types': + specifier: ^0.1.56 + version: 0.1.56 + '@multiplechain/utils': + specifier: ^0.1.20 + version: 0.1.20 + '@solana/spl-token': + specifier: ^0.4.6 + version: 0.4.6(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-token-metadata': + specifier: ^0.1.4 + version: 0.1.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/wallet-adapter-base': + specifier: ^0.9.23 + version: 0.9.23(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-bitkeep': + specifier: ^0.3.20 + version: 0.3.20(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-coinbase': + specifier: ^0.1.19 + version: 0.1.19(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-phantom': + specifier: ^0.9.24 + version: 0.9.24(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-slope': + specifier: ^0.5.21 + version: 0.5.21(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-solflare': + specifier: ^0.6.28 + version: 0.6.28(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-tokenpocket': + specifier: ^0.4.19 + version: 0.4.19(@solana/web3.js@1.91.8) + '@solana/wallet-adapter-trust': + specifier: ^0.1.13 + version: 0.1.13(@solana/web3.js@1.91.8) + '@solana/web3.js': + specifier: ^1.91.8 + version: 1.91.8 + '@web3modal/core': + specifier: ^4.2.1 + version: 4.2.1(react@18.3.1) + '@web3modal/solana': + specifier: ^4.2.1 + version: 4.2.1(react@18.3.1) + axios: + specifier: ^1.6.8 + version: 1.6.8(debug@4.3.4) + +packages: + + /@babel/runtime@7.24.5: + resolution: {integrity: sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: false + + /@esbuild/aix-ppc64@0.20.2: + resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm64@0.20.2: + resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm@0.20.2: + resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-x64@0.20.2: + resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-arm64@0.20.2: + resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-x64@0.20.2: + resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-arm64@0.20.2: + resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-x64@0.20.2: + resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm64@0.20.2: + resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm@0.20.2: + resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ia32@0.20.2: + resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-loong64@0.20.2: + resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-mips64el@0.20.2: + resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ppc64@0.20.2: + resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-riscv64@0.20.2: + resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-s390x@0.20.2: + resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-x64@0.20.2: + resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-x64@0.20.2: + resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openbsd-x64@0.20.2: + resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/sunos-x64@0.20.2: + resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-arm64@0.20.2: + resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-ia32@0.20.2: + resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-x64@0.20.2: + resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@ethereumjs/rlp@4.0.1: + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true + dev: false + + /@ethereumjs/util@8.1.0: + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} + dependencies: + '@ethereumjs/rlp': 4.0.1 + ethereum-cryptography: 2.1.3 + micro-ftch: 0.3.1 + dev: false + + /@ethersproject/abi@5.7.0: + resolution: {integrity: sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ethersproject/abstract-provider@5.7.0: + resolution: {integrity: sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + dev: false + + /@ethersproject/abstract-signer@5.7.0: + resolution: {integrity: sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==} + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + dev: false + + /@ethersproject/address@5.7.0: + resolution: {integrity: sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/rlp': 5.7.0 + dev: false + + /@ethersproject/base64@5.7.0: + resolution: {integrity: sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==} + dependencies: + '@ethersproject/bytes': 5.7.0 + dev: false + + /@ethersproject/basex@5.7.0: + resolution: {integrity: sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/properties': 5.7.0 + dev: false + + /@ethersproject/bignumber@5.7.0: + resolution: {integrity: sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + bn.js: 5.2.1 + dev: false + + /@ethersproject/bytes@5.7.0: + resolution: {integrity: sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/constants@5.7.0: + resolution: {integrity: sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==} + dependencies: + '@ethersproject/bignumber': 5.7.0 + dev: false + + /@ethersproject/contracts@5.7.0: + resolution: {integrity: sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==} + dependencies: + '@ethersproject/abi': 5.7.0 + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/transactions': 5.7.0 + dev: false + + /@ethersproject/hash@5.7.0: + resolution: {integrity: sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==} + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ethersproject/hdnode@5.7.0: + resolution: {integrity: sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==} + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wordlists': 5.7.0 + dev: false + + /@ethersproject/json-wallets@5.7.0: + resolution: {integrity: sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==} + dependencies: + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/pbkdf2': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + aes-js: 3.0.0 + scrypt-js: 3.0.1 + dev: false + + /@ethersproject/keccak256@5.7.0: + resolution: {integrity: sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==} + dependencies: + '@ethersproject/bytes': 5.7.0 + js-sha3: 0.8.0 + dev: false + + /@ethersproject/logger@5.7.0: + resolution: {integrity: sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==} + dev: false + + /@ethersproject/networks@5.7.1: + resolution: {integrity: sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/pbkdf2@5.7.0: + resolution: {integrity: sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/sha2': 5.7.0 + dev: false + + /@ethersproject/properties@5.7.0: + resolution: {integrity: sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==} + dependencies: + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/providers@5.7.2: + resolution: {integrity: sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==} + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/base64': 5.7.0 + '@ethersproject/basex': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/networks': 5.7.1 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/sha2': 5.7.0 + '@ethersproject/strings': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/web': 5.7.1 + bech32: 1.1.4 + ws: 7.4.6 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@ethersproject/random@5.7.0: + resolution: {integrity: sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/rlp@5.7.0: + resolution: {integrity: sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/sha2@5.7.0: + resolution: {integrity: sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + hash.js: 1.1.7 + dev: false + + /@ethersproject/signing-key@5.7.0: + resolution: {integrity: sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + bn.js: 5.2.1 + elliptic: 6.5.4 + hash.js: 1.1.7 + dev: false + + /@ethersproject/strings@5.7.0: + resolution: {integrity: sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/logger': 5.7.0 + dev: false + + /@ethersproject/transactions@5.7.0: + resolution: {integrity: sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==} + dependencies: + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/constants': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/rlp': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + dev: false + + /@ethersproject/wallet@5.7.0: + resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} + dependencies: + '@ethersproject/abstract-provider': 5.7.0 + '@ethersproject/abstract-signer': 5.7.0 + '@ethersproject/address': 5.7.0 + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/hdnode': 5.7.0 + '@ethersproject/json-wallets': 5.7.0 + '@ethersproject/keccak256': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/random': 5.7.0 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wordlists': 5.7.0 + dev: false + + /@ethersproject/web@5.7.1: + resolution: {integrity: sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==} + dependencies: + '@ethersproject/base64': 5.7.0 + '@ethersproject/bytes': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@ethersproject/wordlists@5.7.0: + resolution: {integrity: sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/logger': 5.7.0 + '@ethersproject/properties': 5.7.0 + '@ethersproject/strings': 5.7.0 + dev: false + + /@irys/arweave@0.0.2(debug@4.3.4): + resolution: {integrity: sha512-ddE5h4qXbl0xfGlxrtBIwzflaxZUDlDs43TuT0u1OMfyobHul4AA1VEX72Rpzw2bOh4vzoytSqA1jCM7x9YtHg==} + dependencies: + asn1.js: 5.4.1 + async-retry: 1.3.3 + axios: 1.6.8(debug@4.3.4) + base64-js: 1.5.1 + bignumber.js: 9.1.2 + transitivePeerDependencies: + - debug + dev: false + + /@irys/query@0.0.1(debug@4.3.4): + resolution: {integrity: sha512-7TCyR+Qn+F54IQQx5PlERgqNwgIQik8hY55iZl/silTHhCo1MI2pvx5BozqPUVCc8/KqRsc2nZd8Bc29XGUjRQ==} + engines: {node: '>=16.10.0'} + dependencies: + async-retry: 1.3.3 + axios: 1.6.8(debug@4.3.4) + transitivePeerDependencies: + - debug + dev: false + + /@irys/sdk@0.0.2(arweave@1.15.1)(debug@4.3.4): + resolution: {integrity: sha512-un/e/CmTpgT042gDwCN3AtISrR9OYGMY6V+442pFmSWKrwrsDoIXZ8VlLiYKnrtTm+yquGhjfYy0LDqGWq41pA==} + engines: {node: '>=16.10.0'} + hasBin: true + dependencies: + '@ethersproject/bignumber': 5.7.0 + '@ethersproject/contracts': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@ethersproject/wallet': 5.7.0 + '@irys/query': 0.0.1(debug@4.3.4) + '@near-js/crypto': 0.0.3 + '@near-js/keystores-browser': 0.0.3 + '@near-js/providers': 0.0.4 + '@near-js/transactions': 0.1.1 + '@solana/web3.js': 1.91.8 + '@supercharge/promise-pool': 3.2.0 + algosdk: 1.24.1 + aptos: 1.8.5(debug@4.3.4) + arbundles: 0.10.1(arweave@1.15.1)(debug@4.3.4) + async-retry: 1.3.3 + axios: 1.6.8(debug@4.3.4) + base64url: 3.0.1 + bignumber.js: 9.1.2 + bs58: 5.0.0 + commander: 8.3.0 + csv: 5.5.3 + inquirer: 8.2.6 + js-sha256: 0.9.0 + mime-types: 2.1.35 + near-seed-phrase: 0.2.0 + transitivePeerDependencies: + - arweave + - bufferutil + - debug + - encoding + - utf-8-validate + dev: false + + /@jnwng/walletconnect-solana@0.2.0(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-nyRq0xLEj9i2J4UXQ0Mr4KzsooTMbLu0ewHOqdQV7iZE0PfbtKa8poTSF4ZBAQD8hoMHEx+I7zGFCNMI9BTrTA==} + peerDependencies: + '@solana/web3.js': ^1.63.0 + dependencies: + '@solana/web3.js': 1.91.1 + '@walletconnect/qrcode-modal': 1.8.0 + '@walletconnect/sign-client': 2.13.0 + '@walletconnect/utils': 2.13.0 + bs58: 5.0.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@jridgewell/sourcemap-codec@1.4.15: + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + dev: false + + /@lit-labs/ssr-dom-shim@1.2.0: + resolution: {integrity: sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g==} + dev: false + + /@lit/reactive-element@2.0.4: + resolution: {integrity: sha512-GFn91inaUa2oHLak8awSIigYz0cU0Payr1rcFsrkf5OJ5eSPxElyZfKh0f2p9FsTiZWXQdWGJeXZICEfXXYSXQ==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.2.0 + dev: false + + /@metaplex-foundation/beet-solana@0.3.1: + resolution: {integrity: sha512-tgyEl6dvtLln8XX81JyBvWjIiEcjTkUwZbrM5dIobTmoqMuGewSyk9CClno8qsMsFdB5T3jC91Rjeqmu/6xk2g==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@solana/web3.js': 1.91.8 + bs58: 5.0.0 + debug: 4.3.4 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/beet-solana@0.4.0: + resolution: {integrity: sha512-B1L94N3ZGMo53b0uOSoznbuM5GBNJ8LwSeznxBxJ+OThvfHQ4B5oMUqb+0zdLRfkKGS7Q6tpHK9P+QK0j3w2cQ==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@solana/web3.js': 1.91.8 + bs58: 5.0.0 + debug: 4.3.4 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/beet-solana@0.4.1: + resolution: {integrity: sha512-/6o32FNUtwK8tjhotrvU/vorP7umBuRFvBZrC6XCk51aKidBHe5LPVPA5AjGPbV3oftMfRuXPNd9yAGeEqeCDQ==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@solana/web3.js': 1.91.8 + bs58: 5.0.0 + debug: 4.3.4 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/beet@0.4.0: + resolution: {integrity: sha512-2OAKJnLatCc3mBXNL0QmWVQKAWK2C7XDfepgL0p/9+8oSx4bmRAFHFqptl1A/C0U5O3dxGwKfmKluW161OVGcA==} + dependencies: + ansicolors: 0.3.2 + bn.js: 5.2.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@metaplex-foundation/beet@0.6.1: + resolution: {integrity: sha512-OYgnijLFzw0cdUlRKH5POp0unQECPOW9muJ2X3QIVyak5G6I6l/rKo72sICgPLIFKdmsi2jmnkuLY7wp14iXdw==} + dependencies: + ansicolors: 0.3.2 + bn.js: 5.2.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@metaplex-foundation/beet@0.7.1: + resolution: {integrity: sha512-hNCEnS2WyCiYyko82rwuISsBY3KYpe828ubsd2ckeqZr7tl0WVLivGkoyA/qdiaaHEBGdGl71OpfWa2rqL3DiA==} + dependencies: + ansicolors: 0.3.2 + bn.js: 5.2.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@metaplex-foundation/cusper@0.0.2: + resolution: {integrity: sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==} + dev: false + + /@metaplex-foundation/js@0.20.1(arweave@1.15.1)(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-aqiLoEiToXdfI5pS+17/GN/dIO2D31gLoVQvEKDQi9XcnOPVhfJerXDmwgKbhp79OGoYxtlvVw+b2suacoUzGQ==} + dependencies: + '@irys/sdk': 0.0.2(arweave@1.15.1)(debug@4.3.4) + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/mpl-auction-house': 2.5.1(fastestsmallesttextencoderdecoder@1.0.22) + '@metaplex-foundation/mpl-bubblegum': 0.6.2(fastestsmallesttextencoderdecoder@1.0.22) + '@metaplex-foundation/mpl-candy-guard': 0.3.2 + '@metaplex-foundation/mpl-candy-machine': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22) + '@metaplex-foundation/mpl-candy-machine-core': 0.1.2 + '@metaplex-foundation/mpl-token-metadata': 2.13.0(fastestsmallesttextencoderdecoder@1.0.22) + '@noble/ed25519': 1.7.3 + '@noble/hashes': 1.4.0 + '@solana/spl-account-compression': 0.1.10(@solana/web3.js@1.91.8) + '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + bignumber.js: 9.1.2 + bn.js: 5.2.1 + bs58: 5.0.0 + buffer: 6.0.3 + debug: 4.3.4 + eventemitter3: 4.0.7 + lodash.clonedeep: 4.5.0 + lodash.isequal: 4.5.0 + merkletreejs: 0.3.11 + mime: 3.0.0 + node-fetch: 2.7.0 + transitivePeerDependencies: + - arweave + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-auction-house@2.5.1(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-O+IAdYVaoOvgACB8pm+1lF5BNEjl0COkqny2Ho8KQZwka6aC/vHbZ239yRwAMtJhf5992BPFdT4oifjyE0O+Mw==} + dependencies: + '@metaplex-foundation/beet': 0.6.1 + '@metaplex-foundation/beet-solana': 0.3.1 + '@metaplex-foundation/cusper': 0.0.2 + '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-bubblegum@0.6.2(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-4tF7/FFSNtpozuIGD7gMKcqK2D49eVXZ144xiowC5H1iBeu009/oj2m8Tj6n4DpYFKWJ2JQhhhk0a2q7x0Begw==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.0 + '@metaplex-foundation/cusper': 0.0.2 + '@metaplex-foundation/mpl-token-metadata': 2.13.0(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-account-compression': 0.1.10(@solana/web3.js@1.91.8) + '@solana/spl-token': 0.1.8 + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + js-sha3: 0.8.0 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-candy-guard@0.3.2: + resolution: {integrity: sha512-QWXzPDz+6OR3957LtfW6/rcGvFWS/0AeHJa/BUO2VEVQxN769dupsKGtrsS8o5RzXCeap3wrCtDSNxN3dnWu4Q==} + dependencies: + '@metaplex-foundation/beet': 0.4.0 + '@metaplex-foundation/beet-solana': 0.3.1 + '@metaplex-foundation/cusper': 0.0.2 + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-candy-machine-core@0.1.2: + resolution: {integrity: sha512-jjDkRvMR+iykt7guQ7qVnOHTZedql0lq3xqWDMaenAUCH3Xrf2zKATThhJppIVNX1/YtgBOO3lGqhaFbaI4pCw==} + dependencies: + '@metaplex-foundation/beet': 0.4.0 + '@metaplex-foundation/beet-solana': 0.3.1 + '@metaplex-foundation/cusper': 0.0.2 + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-candy-machine@5.1.0(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-pjHpUpWVOCDxK3l6dXxfmJKNQmbjBqnm5ElOl1mJAygnzO8NIPQvrP89y6xSNyo8qZsJyt4ZMYUyD0TdbtKZXQ==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.1 + '@metaplex-foundation/cusper': 0.0.2 + '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - utf-8-validate + dev: false + + /@metaplex-foundation/mpl-token-metadata@2.13.0(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-Fl/8I0L9rv4bKTV/RAl5YIbJe9SnQPInKvLz+xR1fEc4/VQkuCn3RPgypfUMEKWmCznzaw4sApDxy6CFS4qmJw==} + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.1 + '@metaplex-foundation/cusper': 0.0.2 + '@solana/spl-token': 0.3.11(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + debug: 4.3.4 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - supports-color + - utf-8-validate + dev: false + + /@multiplechain/solana-walletconnect@0.1.1(@solana/web3.js@1.91.8)(vite@5.2.11): + resolution: {integrity: sha512-WEqxfzgZj+qjCikuOZG5UC6Kdro0UavagiZ+vzvJ19dKoIf97oY46B92jPkXQbAeWHDB1yJusJBRUJpfHt1qqQ==} + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@walletconnect/qrcode-modal': 1.8.0 + '@walletconnect/sign-client': 2.13.0 + '@walletconnect/utils': 2.13.0 + vite-plugin-node-polyfills: 0.21.0(vite@5.2.11) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@solana/web3.js' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - rollup + - uWebSockets.js + - utf-8-validate + - vite + dev: false + + /@multiplechain/types@0.1.56: + resolution: {integrity: sha512-tnkgDwW0AWxEfhE/392LR6ZPE7Pxz5/Ei1XYsQISGkOfYYZrsvJXr69fXTjDOHCq7RCuQqytKmhnKs5K4xHd7w==} + dev: false + + /@multiplechain/utils@0.1.20: + resolution: {integrity: sha512-4eEs4YR/V4F2Qnkl5KTZvPpewRQiX7C193d0tjpQuIfyumTEBJtdHYm1CW9CoJ6EjQUaB0oqSRKXomhzfK1qkw==} + dependencies: + '@types/ws': 8.5.10 + bignumber.js: 9.1.2 + web3-utils: 4.2.1 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@near-js/crypto@0.0.3: + resolution: {integrity: sha512-3WC2A1a1cH8Cqrx+0iDjp1ASEEhxN/KHEMENYb0KZH6Hp5bXIY7Akt4quC7JlgJS5ESvEiLa40tS5h0zAhBWGw==} + dependencies: + '@near-js/types': 0.0.3 + bn.js: 5.2.1 + borsh: 0.7.0 + tweetnacl: 1.0.3 + dev: false + + /@near-js/crypto@0.0.4: + resolution: {integrity: sha512-2mSIVv6mZway1rQvmkktrXAFoUvy7POjrHNH3LekKZCMCs7qMM/23Hz2+APgxZPqoV2kjarSNOEYJjxO7zQ/rQ==} + dependencies: + '@near-js/types': 0.0.4 + bn.js: 5.2.1 + borsh: 0.7.0 + tweetnacl: 1.0.3 + dev: false + + /@near-js/keystores-browser@0.0.3: + resolution: {integrity: sha512-Ve/JQ1SBxdNk3B49lElJ8Y54AoBY+yOStLvdnUIpe2FBOczzwDCkcnPcMDV0NMwVlHpEnOWICWHbRbAkI5Vs+A==} + dependencies: + '@near-js/crypto': 0.0.3 + '@near-js/keystores': 0.0.3 + dev: false + + /@near-js/keystores@0.0.3: + resolution: {integrity: sha512-mnwLYUt4Td8u1I4QE1FBx2d9hMt3ofiriE93FfOluJ4XiqRqVFakFYiHg6pExg5iEkej/sXugBUFeQ4QizUnew==} + dependencies: + '@near-js/crypto': 0.0.3 + '@near-js/types': 0.0.3 + dev: false + + /@near-js/keystores@0.0.4: + resolution: {integrity: sha512-+vKafmDpQGrz5py1liot2hYSjPGXwihveeN+BL11aJlLqZnWBgYJUWCXG+uyGjGXZORuy2hzkKK6Hi+lbKOfVA==} + dependencies: + '@near-js/crypto': 0.0.4 + '@near-js/types': 0.0.4 + dev: false + + /@near-js/providers@0.0.4: + resolution: {integrity: sha512-g/2pJTYmsIlTW4mGqeRlqDN9pZeN+1E2/wfoMIf3p++boBVxVlaSebtQgawXAf2lkfhb9RqXz5pHqewXIkTBSw==} + dependencies: + '@near-js/transactions': 0.1.0 + '@near-js/types': 0.0.3 + '@near-js/utils': 0.0.3 + bn.js: 5.2.1 + borsh: 0.7.0 + http-errors: 1.8.1 + optionalDependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + + /@near-js/signers@0.0.3: + resolution: {integrity: sha512-u1R+DDIua5PY1PDFnpVYqdMgQ7c4dyeZsfqMjE7CtgzdqupgTYCXzJjBubqMlAyAx843PoXmLt6CSSKcMm0WUA==} + dependencies: + '@near-js/crypto': 0.0.3 + '@near-js/keystores': 0.0.3 + js-sha256: 0.9.0 + dev: false + + /@near-js/signers@0.0.4: + resolution: {integrity: sha512-xCglo3U/WIGsz/izPGFMegS5Q3PxOHYB8a1E7RtVhNm5QdqTlQldLCm/BuMg2G/u1l1ZZ0wdvkqRTG9joauf3Q==} + dependencies: + '@near-js/crypto': 0.0.4 + '@near-js/keystores': 0.0.4 + js-sha256: 0.9.0 + dev: false + + /@near-js/transactions@0.1.0: + resolution: {integrity: sha512-OrrDFqhX0rtH+6MV3U3iS+zmzcPQI+L4GJi9na4Uf8FgpaVPF0mtSmVrpUrS5CC3LwWCzcYF833xGYbXOV4Kfg==} + dependencies: + '@near-js/crypto': 0.0.3 + '@near-js/signers': 0.0.3 + '@near-js/types': 0.0.3 + '@near-js/utils': 0.0.3 + bn.js: 5.2.1 + borsh: 0.7.0 + js-sha256: 0.9.0 + dev: false + + /@near-js/transactions@0.1.1: + resolution: {integrity: sha512-Fk83oLLFK7nz4thawpdv9bGyMVQ2i48iUtZEVYhuuuqevl17tSXMlhle9Me1ZbNyguJG/cWPdNybe1UMKpyGxA==} + dependencies: + '@near-js/crypto': 0.0.4 + '@near-js/signers': 0.0.4 + '@near-js/types': 0.0.4 + '@near-js/utils': 0.0.4 + bn.js: 5.2.1 + borsh: 0.7.0 + js-sha256: 0.9.0 + dev: false + + /@near-js/types@0.0.3: + resolution: {integrity: sha512-gC3iGUT+r2JjVsE31YharT+voat79ToMUMLCGozHjp/R/UW1M2z4hdpqTUoeWUBGBJuVc810gNTneHGx0jvzwQ==} + dependencies: + bn.js: 5.2.1 + dev: false + + /@near-js/types@0.0.4: + resolution: {integrity: sha512-8TTMbLMnmyG06R5YKWuS/qFG1tOA3/9lX4NgBqQPsvaWmDsa+D+QwOkrEHDegped0ZHQwcjAXjKML1S1TyGYKg==} + dependencies: + bn.js: 5.2.1 + dev: false + + /@near-js/utils@0.0.3: + resolution: {integrity: sha512-J72n/EL0VfLRRb4xNUF4rmVrdzMkcmkwJOhBZSTWz3PAZ8LqNeU9ZConPfMvEr6lwdaD33ZuVv70DN6IIjPr1A==} + dependencies: + '@near-js/types': 0.0.3 + bn.js: 5.2.1 + depd: 2.0.0 + mustache: 4.2.0 + dev: false + + /@near-js/utils@0.0.4: + resolution: {integrity: sha512-mPUEPJbTCMicGitjEGvQqOe8AS7O4KkRCxqd0xuE/X6gXF1jz1pYMZn4lNUeUz2C84YnVSGLAM0o9zcN6Y4hiA==} + dependencies: + '@near-js/types': 0.0.4 + bn.js: 5.2.1 + depd: 2.0.0 + mustache: 4.2.0 + dev: false + + /@noble/curves@1.3.0: + resolution: {integrity: sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==} + dependencies: + '@noble/hashes': 1.3.3 + dev: false + + /@noble/curves@1.4.0: + resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} + dependencies: + '@noble/hashes': 1.4.0 + dev: false + + /@noble/ed25519@1.7.3: + resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} + dev: false + + /@noble/hashes@1.1.3: + resolution: {integrity: sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==} + dev: false + + /@noble/hashes@1.3.3: + resolution: {integrity: sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==} + engines: {node: '>= 16'} + dev: false + + /@noble/hashes@1.4.0: + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + dev: false + + /@parcel/watcher-android-arm64@2.4.1: + resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-arm64@2.4.1: + resolution: {integrity: sha512-ln41eihm5YXIY043vBrrHfn94SIBlqOWmoROhsMVTSXGh0QahKGy77tfEywQ7v3NywyxBBkGIfrWRHm0hsKtzA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-x64@2.4.1: + resolution: {integrity: sha512-yrw81BRLjjtHyDu7J61oPuSoeYWR3lDElcPGJyOvIXmor6DEo7/G2u1o7I38cwlcoBHQFULqF6nesIX3tsEXMg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-freebsd-x64@2.4.1: + resolution: {integrity: sha512-TJa3Pex/gX3CWIx/Co8k+ykNdDCLx+TuZj3f3h7eOjgpdKM+Mnix37RYsYU4LHhiYJz3DK5nFCCra81p6g050w==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm-glibc@2.4.1: + resolution: {integrity: sha512-4rVYDlsMEYfa537BRXxJ5UF4ddNwnr2/1O4MHM5PjI9cvV2qymvhwZSFgXqbS8YoTk5i/JR0L0JDs69BUn45YA==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-glibc@2.4.1: + resolution: {integrity: sha512-BJ7mH985OADVLpbrzCLgrJ3TOpiZggE9FMblfO65PlOCdG++xJpKUJ0Aol74ZUIYfb8WsRlUdgrZxKkz3zXWYA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-musl@2.4.1: + resolution: {integrity: sha512-p4Xb7JGq3MLgAfYhslU2SjoV9G0kI0Xry0kuxeG/41UfpjHGOhv7UoUDAz/jb1u2elbhazy4rRBL8PegPJFBhA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-glibc@2.4.1: + resolution: {integrity: sha512-s9O3fByZ/2pyYDPoLM6zt92yu6P4E39a03zvO0qCHOTjxmt3GHRMLuRZEWhWLASTMSrrnVNWdVI/+pUElJBBBg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-musl@2.4.1: + resolution: {integrity: sha512-L2nZTYR1myLNST0O632g0Dx9LyMNHrn6TOt76sYxWLdff3cB22/GZX2UPtJnaqQPdCRoszoY5rcOj4oMTtp5fQ==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-wasm@2.4.1: + resolution: {integrity: sha512-/ZR0RxqxU/xxDGzbzosMjh4W6NdYFMqq2nvo2b8SLi7rsl/4jkL8S5stIikorNkdR50oVDvqb/3JT05WM+CRRA==} + engines: {node: '>= 10.0.0'} + dependencies: + is-glob: 4.0.3 + micromatch: 4.0.6 + napi-wasm: 1.1.0 + dev: false + bundledDependencies: + - napi-wasm + + /@parcel/watcher-win32-arm64@2.4.1: + resolution: {integrity: sha512-Uq2BPp5GWhrq/lcuItCHoqxjULU1QYEcyjSO5jqqOK8RNFDBQnenMMx4gAl3v8GiWa59E9+uDM7yZ6LxwUIfRg==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-ia32@2.4.1: + resolution: {integrity: sha512-maNRit5QQV2kgHFSYwftmPBxiuK5u4DXjbXx7q6eKjq5dsLXZ4FJiVvlcw35QXzk0KrUecJmuVFbj4uV9oYrcw==} + engines: {node: '>= 10.0.0'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-x64@2.4.1: + resolution: {integrity: sha512-+DvS92F9ezicfswqrvIRM2njcYJbd5mb9CUgtrHCHmvn7pPPa+nMDRu1o1bYYz/l5IB2NVGNJWiH7h1E58IF2A==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher@2.4.1: + resolution: {integrity: sha512-HNjmfLQEVRZmHRET336f20H/8kOozUGwk7yajvsonjNxbj2wBTK1WsQuHkD5yYh9RxFGL2EyDHryOihOwUoKDA==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.6 + node-addon-api: 7.1.0 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.4.1 + '@parcel/watcher-darwin-arm64': 2.4.1 + '@parcel/watcher-darwin-x64': 2.4.1 + '@parcel/watcher-freebsd-x64': 2.4.1 + '@parcel/watcher-linux-arm-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-glibc': 2.4.1 + '@parcel/watcher-linux-arm64-musl': 2.4.1 + '@parcel/watcher-linux-x64-glibc': 2.4.1 + '@parcel/watcher-linux-x64-musl': 2.4.1 + '@parcel/watcher-win32-arm64': 2.4.1 + '@parcel/watcher-win32-ia32': 2.4.1 + '@parcel/watcher-win32-x64': 2.4.1 + dev: false + + /@randlabs/communication-bridge@1.0.1: + resolution: {integrity: sha512-CzS0U8IFfXNK7QaJFE4pjbxDGfPjbXBEsEaCn9FN15F+ouSAEUQkva3Gl66hrkBZOGexKFEWMwUHIDKpZ2hfVg==} + requiresBuild: true + dev: false + optional: true + + /@randlabs/myalgo-connect@1.4.2: + resolution: {integrity: sha512-K9hEyUi7G8tqOp7kWIALJLVbGCByhilcy6123WfcorxWwiE1sbQupPyIU5f3YdQK6wMjBsyTWiLW52ZBMp7sXA==} + requiresBuild: true + dependencies: + '@randlabs/communication-bridge': 1.0.1 + dev: false + optional: true + + /@rollup/plugin-inject@5.0.5: + resolution: {integrity: sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@rollup/pluginutils': 5.1.0 + estree-walker: 2.0.2 + magic-string: 0.30.10 + dev: false + + /@rollup/pluginutils@5.1.0: + resolution: {integrity: sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.5 + estree-walker: 2.0.2 + picomatch: 2.3.1 + dev: false + + /@rollup/rollup-android-arm-eabi@4.17.2: + resolution: {integrity: sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-android-arm64@4.17.2: + resolution: {integrity: sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-darwin-arm64@4.17.2: + resolution: {integrity: sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-darwin-x64@4.17.2: + resolution: {integrity: sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.17.2: + resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.17.2: + resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.17.2: + resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-arm64-musl@4.17.2: + resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.17.2: + resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.17.2: + resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.17.2: + resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-x64-gnu@4.17.2: + resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-linux-x64-musl@4.17.2: + resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.17.2: + resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.17.2: + resolution: {integrity: sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@rollup/rollup-win32-x64-msvc@4.17.2: + resolution: {integrity: sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@scure/base@1.1.6: + resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} + dev: false + + /@scure/bip32@1.3.3: + resolution: {integrity: sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==} + dependencies: + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.6 + dev: false + + /@scure/bip39@1.1.0: + resolution: {integrity: sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==} + dependencies: + '@noble/hashes': 1.1.3 + '@scure/base': 1.1.6 + dev: false + + /@scure/bip39@1.2.2: + resolution: {integrity: sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==} + dependencies: + '@noble/hashes': 1.3.3 + '@scure/base': 1.1.6 + dev: false + + /@solana/buffer-layout-utils@0.2.0: + resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} + engines: {node: '>= 10'} + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/web3.js': 1.91.8 + bigint-buffer: 1.1.5 + bignumber.js: 9.1.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + dev: false + + /@solana/buffer-layout@4.0.1: + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} + dependencies: + buffer: 6.0.3 + dev: false + + /@solana/codecs-core@2.0.0-preview.2: + resolution: {integrity: sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg==} + dependencies: + '@solana/errors': 2.0.0-preview.2 + dev: false + + /@solana/codecs-data-structures@2.0.0-preview.2: + resolution: {integrity: sha512-Xf5vIfromOZo94Q8HbR04TbgTwzigqrKII0GjYr21K7rb3nba4hUW2ir8kguY7HWFBcjHGlU5x3MevKBOLp3Zg==} + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + dev: false + + /@solana/codecs-numbers@2.0.0-preview.2: + resolution: {integrity: sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw==} + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + dev: false + + /@solana/codecs-strings@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g==} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/errors': 2.0.0-preview.2 + fastestsmallesttextencoderdecoder: 1.0.22 + dev: false + + /@solana/codecs@2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-4HHzCD5+pOSmSB71X6w9ptweV48Zj1Vqhe732+pcAQ2cMNnN0gMPMdDq7j3YwaZDZ7yrILVV/3+HTnfT77t2yA==} + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-data-structures': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + '@solana/codecs-strings': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/options': 2.0.0-preview.2 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + dev: false + + /@solana/errors@2.0.0-preview.2: + resolution: {integrity: sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA==} + hasBin: true + dependencies: + chalk: 5.3.0 + commander: 12.0.0 + dev: false + + /@solana/options@2.0.0-preview.2: + resolution: {integrity: sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w==} + dependencies: + '@solana/codecs-core': 2.0.0-preview.2 + '@solana/codecs-numbers': 2.0.0-preview.2 + dev: false + + /@solana/spl-account-compression@0.1.10(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-IQAOJrVOUo6LCgeWW9lHuXo6JDbi4g3/RkQtvY0SyalvSWk9BIkHHe4IkAzaQw8q/BxEVBIjz8e9bNYWIAESNw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.50.1 + dependencies: + '@metaplex-foundation/beet': 0.7.1 + '@metaplex-foundation/beet-solana': 0.4.1 + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + borsh: 0.7.0 + js-sha3: 0.8.0 + typescript-collections: 1.3.3 + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + dev: false + + /@solana/spl-token-group@0.0.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-7+80nrEMdUKlK37V6kOe024+T7J4nNss0F8LQ9OOPYdWCCfJmsGUzVx2W3oeizZR4IHM6N4yC9v1Xqwc3BTPWw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + dependencies: + '@solana/codecs': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-type-length-value': 0.1.0 + '@solana/web3.js': 1.91.8 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + dev: false + + /@solana/spl-token-metadata@0.1.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + dependencies: + '@solana/codecs': 2.0.0-preview.2(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-type-length-value': 0.1.0 + '@solana/web3.js': 1.91.8 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + dev: false + + /@solana/spl-token@0.1.8: + resolution: {integrity: sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ==} + engines: {node: '>= 10'} + dependencies: + '@babel/runtime': 7.24.5 + '@solana/web3.js': 1.91.8 + bn.js: 5.2.1 + buffer: 6.0.3 + buffer-layout: 1.2.2 + dotenv: 10.0.0 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + dev: false + + /@solana/spl-token@0.3.11(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.88.0 + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/buffer-layout-utils': 0.2.0 + '@solana/spl-token-metadata': 0.1.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - utf-8-validate + dev: false + + /@solana/spl-token@0.4.6(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-1nCnUqfHVtdguFciVWaY/RKcQz1IF4b31jnKgAmjU9QVN1q7dRUkTEWJZgTYIEtsULjVnC9jRqlhgGN39WbKKA==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.91.6 + dependencies: + '@solana/buffer-layout': 4.0.1 + '@solana/buffer-layout-utils': 0.2.0 + '@solana/spl-token-group': 0.0.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/spl-token-metadata': 0.1.4(@solana/web3.js@1.91.8)(fastestsmallesttextencoderdecoder@1.0.22) + '@solana/web3.js': 1.91.8 + buffer: 6.0.3 + transitivePeerDependencies: + - bufferutil + - encoding + - fastestsmallesttextencoderdecoder + - utf-8-validate + dev: false + + /@solana/spl-type-length-value@0.1.0: + resolution: {integrity: sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==} + engines: {node: '>=16'} + dependencies: + buffer: 6.0.3 + dev: false + + /@solana/wallet-adapter-backpack@0.1.14(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-DfNLd5S1P7rmrgqMp+jRd21ryuXUxia1mu4qmZ+cau1NGFO2v5ep14LhzYXmqPde6kgbzPLPkLdRnkffLdI4TA==} + engines: {node: '>=16'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/web3.js': 1.91.1 + dev: false + + /@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-standard-features': 1.2.0 + '@solana/web3.js': 1.91.1 + '@wallet-standard/base': 1.0.1 + '@wallet-standard/features': 1.0.3 + eventemitter3: 4.0.7 + dev: false + + /@solana/wallet-adapter-base@0.9.23(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-apqMuYwFp1jFi55NxDfvXUX2x1T0Zh07MxhZ/nCCTGys5raSfYUh82zen2BLv8BSDj/JxZ2P/s7jrQZGrX8uAw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-standard-features': 1.2.0 + '@solana/web3.js': 1.91.8 + '@wallet-standard/base': 1.0.1 + '@wallet-standard/features': 1.0.3 + eventemitter3: 4.0.7 + dev: false + + /@solana/wallet-adapter-bitkeep@0.3.20(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-v6Jd13CZOPNIAX0nFlopAJ3HDvC+MhiB4sde3C8sSnNbjVi9h1WLHBmaUfgqU6mAyhDjWUZjKt4zYlMhLdp/bg==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + dev: false + + /@solana/wallet-adapter-coinbase@0.1.19(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-hcf9ieAbQxD2g8/5glXVAt67w+3iixpjMMZC7lT7Wa8SJZsq6lmISC9AtZctDEQcWSVV0IkedZp3bg6bp22kng==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + dev: false + + /@solana/wallet-adapter-phantom@0.9.24(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-D24AxRHmRJ4AYoRvijbiuUb9LmC4xLGKLMSJS2ly+zGxVmaPASPM/ThaY/DlYTDL31QvkYtl8RzSR4yIU1gpLg==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/web3.js': 1.91.1 + dev: false + + /@solana/wallet-adapter-phantom@0.9.24(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-D24AxRHmRJ4AYoRvijbiuUb9LmC4xLGKLMSJS2ly+zGxVmaPASPM/ThaY/DlYTDL31QvkYtl8RzSR4yIU1gpLg==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + dev: false + + /@solana/wallet-adapter-slope@0.5.21(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-4byuSwqkt8L3w7VzFvVPBN+lNkx7CmEc+FMFZUuo9pBDwwi6sDYZK/+wBBep7L7+xW81XKN9K4MsMOQAD2snSg==} + engines: {node: '>=16'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + bs58: 4.0.1 + dev: false + + /@solana/wallet-adapter-solflare@0.6.28(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-iiUQtuXp8p4OdruDawsm1dRRnzUCcsu+lKo8OezESskHtbmZw2Ifej0P99AbJbBAcBw7q4GPI6987Vh05Si5rw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/wallet-standard-chains': 1.1.0 + '@solana/web3.js': 1.91.1 + '@solflare-wallet/metamask-sdk': 1.0.3(@solana/web3.js@1.91.1) + '@solflare-wallet/sdk': 1.4.2(@solana/web3.js@1.91.1) + '@wallet-standard/wallet': 1.0.1 + dev: false + + /@solana/wallet-adapter-solflare@0.6.28(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-iiUQtuXp8p4OdruDawsm1dRRnzUCcsu+lKo8OezESskHtbmZw2Ifej0P99AbJbBAcBw7q4GPI6987Vh05Si5rw==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/wallet-standard-chains': 1.1.0 + '@solana/web3.js': 1.91.8 + '@solflare-wallet/metamask-sdk': 1.0.3(@solana/web3.js@1.91.8) + '@solflare-wallet/sdk': 1.4.2(@solana/web3.js@1.91.8) + '@wallet-standard/wallet': 1.0.1 + dev: false + + /@solana/wallet-adapter-tokenpocket@0.4.19(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-zKXTN+tuKIr/stSxUeG9XPBks9iqeliBWS9JF8eq+8u/Qb/bIDbNSQmd8Z5u1x2lf0puiStc9/iUu/+MLaOSVg==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + dev: false + + /@solana/wallet-adapter-trust@0.1.13(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-lkmPfNdyRgx+z0K7i2cDa3a6SOKXpi3FiaYSo8Zozoxkp+Ga/NXVWxlXtMca4GAc/MnJMVp7yF/31kyFIee+3A==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/web3.js': 1.91.1 + dev: false + + /@solana/wallet-adapter-trust@0.1.13(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-lkmPfNdyRgx+z0K7i2cDa3a6SOKXpi3FiaYSo8Zozoxkp+Ga/NXVWxlXtMca4GAc/MnJMVp7yF/31kyFIee+3A==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.8) + '@solana/web3.js': 1.91.8 + dev: false + + /@solana/wallet-adapter-walletconnect@0.1.16(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-jNaQwSho8hT7gF1ifePE8TJc1FULx8jCF16KX3fZPtzXDxKrj0R4VUpHMGcw4MlDknrnZNLOJAVvyiawAkPCRQ==} + engines: {node: '>=16'} + peerDependencies: + '@solana/web3.js': ^1.77.3 + dependencies: + '@jnwng/walletconnect-solana': 0.2.0(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/web3.js': 1.91.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@solana/wallet-standard-chains@1.1.0: + resolution: {integrity: sha512-IRJHf94UZM8AaRRmY18d34xCJiVPJej1XVwXiTjihHnmwD0cxdQbc/CKjrawyqFyQAKJx7raE5g9mnJsAdspTg==} + engines: {node: '>=16'} + dependencies: + '@wallet-standard/base': 1.0.1 + dev: false + + /@solana/wallet-standard-features@1.2.0: + resolution: {integrity: sha512-tUd9srDLkRpe1BYg7we+c4UhRQkq+XQWswsr/L1xfGmoRDF47BPSXf4zE7ZU2GRBGvxtGt7lwJVAufQyQYhxTQ==} + engines: {node: '>=16'} + dependencies: + '@wallet-standard/base': 1.0.1 + '@wallet-standard/features': 1.0.3 + dev: false + + /@solana/web3.js@1.91.1: + resolution: {integrity: sha512-cPgjZXm688oM9cULvJ8u2VH6Qp5rvptE1N1VODVxn2mAbpZsWrvWNPjmASkMYT/HzyrtqFkPvFdSHg8Xjt7aQA==} + dependencies: + '@babel/runtime': 7.24.5 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.0 + node-fetch: 2.7.0 + rpc-websockets: 7.11.0 + superstruct: 0.14.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + dev: false + + /@solana/web3.js@1.91.8: + resolution: {integrity: sha512-USa6OS1jbh8zOapRJ/CBZImZ8Xb7AJjROZl5adql9TpOoBN9BUzyyouS5oPuZHft7S7eB8uJPuXWYjMi6BHgOw==} + dependencies: + '@babel/runtime': 7.24.5 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@solana/buffer-layout': 4.0.1 + agentkeepalive: 4.5.0 + bigint-buffer: 1.1.5 + bn.js: 5.2.1 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.1.0 + node-fetch: 2.7.0 + rpc-websockets: 7.11.0 + superstruct: 0.14.2 + transitivePeerDependencies: + - bufferutil + - encoding + - utf-8-validate + dev: false + + /@solflare-wallet/metamask-sdk@1.0.3(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ==} + peerDependencies: + '@solana/web3.js': '*' + dependencies: + '@solana/wallet-standard-features': 1.2.0 + '@solana/web3.js': 1.91.1 + '@wallet-standard/base': 1.0.1 + bs58: 5.0.0 + eventemitter3: 5.0.1 + uuid: 9.0.1 + dev: false + + /@solflare-wallet/metamask-sdk@1.0.3(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-os5Px5PTMYKGS5tzOoyjDxtOtj0jZKnbI1Uwt8+Jsw1HHIA+Ib2UACCGNhQ/un2f8sIbTfLD1WuucNMOy8KZpQ==} + peerDependencies: + '@solana/web3.js': '*' + dependencies: + '@solana/wallet-standard-features': 1.2.0 + '@solana/web3.js': 1.91.8 + '@wallet-standard/base': 1.0.1 + bs58: 5.0.0 + eventemitter3: 5.0.1 + uuid: 9.0.1 + dev: false + + /@solflare-wallet/sdk@1.4.2(@solana/web3.js@1.91.1): + resolution: {integrity: sha512-jrseNWipwl9xXZgrzwZF3hhL0eIVxuEtoZOSLmuPuef7FgHjstuTtNJAeT4icA7pzdDV4hZvu54pI2r2f7SmrQ==} + peerDependencies: + '@solana/web3.js': '*' + dependencies: + '@solana/web3.js': 1.91.1 + bs58: 5.0.0 + eventemitter3: 5.0.1 + uuid: 9.0.1 + dev: false + + /@solflare-wallet/sdk@1.4.2(@solana/web3.js@1.91.8): + resolution: {integrity: sha512-jrseNWipwl9xXZgrzwZF3hhL0eIVxuEtoZOSLmuPuef7FgHjstuTtNJAeT4icA7pzdDV4hZvu54pI2r2f7SmrQ==} + peerDependencies: + '@solana/web3.js': '*' + dependencies: + '@solana/web3.js': 1.91.8 + bs58: 5.0.0 + eventemitter3: 5.0.1 + uuid: 9.0.1 + dev: false + + /@stablelib/aead@1.0.1: + resolution: {integrity: sha512-q39ik6sxGHewqtO0nP4BuSe3db5G1fEJE8ukvngS2gLkBXyy6E7pLubhbYgnkDFv6V8cWaxcE4Xn0t6LWcJkyg==} + dev: false + + /@stablelib/binary@1.0.1: + resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} + dependencies: + '@stablelib/int': 1.0.1 + dev: false + + /@stablelib/bytes@1.0.1: + resolution: {integrity: sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==} + dev: false + + /@stablelib/chacha20poly1305@1.0.1: + resolution: {integrity: sha512-MmViqnqHd1ymwjOQfghRKw2R/jMIGT3wySN7cthjXCBdO+qErNPUBnRzqNpnvIwg7JBCg3LdeCZZO4de/yEhVA==} + dependencies: + '@stablelib/aead': 1.0.1 + '@stablelib/binary': 1.0.1 + '@stablelib/chacha': 1.0.1 + '@stablelib/constant-time': 1.0.1 + '@stablelib/poly1305': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/chacha@1.0.1: + resolution: {integrity: sha512-Pmlrswzr0pBzDofdFuVe1q7KdsHKhhU24e8gkEwnTGOmlC7PADzLVxGdn2PoNVBBabdg0l/IfLKg6sHAbTQugg==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/constant-time@1.0.1: + resolution: {integrity: sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==} + dev: false + + /@stablelib/ed25519@1.0.3: + resolution: {integrity: sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==} + dependencies: + '@stablelib/random': 1.0.2 + '@stablelib/sha512': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/hash@1.0.1: + resolution: {integrity: sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==} + dev: false + + /@stablelib/hkdf@1.0.1: + resolution: {integrity: sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==} + dependencies: + '@stablelib/hash': 1.0.1 + '@stablelib/hmac': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/hmac@1.0.1: + resolution: {integrity: sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==} + dependencies: + '@stablelib/constant-time': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/int@1.0.1: + resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} + dev: false + + /@stablelib/keyagreement@1.0.1: + resolution: {integrity: sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==} + dependencies: + '@stablelib/bytes': 1.0.1 + dev: false + + /@stablelib/poly1305@1.0.1: + resolution: {integrity: sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==} + dependencies: + '@stablelib/constant-time': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/random@1.0.2: + resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/sha256@1.0.1: + resolution: {integrity: sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/sha512@1.0.1: + resolution: {integrity: sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==} + dependencies: + '@stablelib/binary': 1.0.1 + '@stablelib/hash': 1.0.1 + '@stablelib/wipe': 1.0.1 + dev: false + + /@stablelib/wipe@1.0.1: + resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} + dev: false + + /@stablelib/x25519@1.0.3: + resolution: {integrity: sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==} + dependencies: + '@stablelib/keyagreement': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/wipe': 1.0.1 + dev: false + + /@supercharge/promise-pool@3.2.0: + resolution: {integrity: sha512-pj0cAALblTZBPtMltWOlZTQSLT07jIaFNeM8TWoJD1cQMgDB9mcMlVMoetiB35OzNJpqQ2b+QEtwiR9f20mADg==} + engines: {node: '>=8'} + dev: false + + /@types/connect@3.4.38: + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + dependencies: + '@types/node': 20.12.7 + dev: false + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + dev: false + + /@types/node@11.11.6: + resolution: {integrity: sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==} + dev: false + + /@types/node@12.20.55: + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + dev: false + + /@types/node@20.12.7: + resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==} + dependencies: + undici-types: 5.26.5 + dev: false + + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: false + + /@types/ws@7.4.7: + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + dependencies: + '@types/node': 20.12.7 + dev: false + + /@types/ws@8.5.10: + resolution: {integrity: sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==} + dependencies: + '@types/node': 20.12.7 + dev: false + + /@wallet-standard/base@1.0.1: + resolution: {integrity: sha512-1To3ekMfzhYxe0Yhkpri+Fedq0SYcfrOfJi3vbLjMwF2qiKPjTGLwZkf2C9ftdQmxES+hmxhBzTwF4KgcOwf8w==} + engines: {node: '>=16'} + dev: false + + /@wallet-standard/features@1.0.3: + resolution: {integrity: sha512-m8475I6W5LTatTZuUz5JJNK42wFRgkJTB0I9tkruMwfqBF2UN2eomkYNVf9RbrsROelCRzSFmugqjKZBFaubsA==} + engines: {node: '>=16'} + dependencies: + '@wallet-standard/base': 1.0.1 + dev: false + + /@wallet-standard/wallet@1.0.1: + resolution: {integrity: sha512-qkhJeuQU2afQTZ02yMZE5SFc91Fo3hyFjFkpQglHudENNyiSG0oUKcIjky8X32xVSaumgTZSQUAzpXnCTWHzKQ==} + engines: {node: '>=16'} + dependencies: + '@wallet-standard/base': 1.0.1 + dev: false + + /@walletconnect/browser-utils@1.8.0: + resolution: {integrity: sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A==} + dependencies: + '@walletconnect/safe-json': 1.0.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-metadata': 1.0.0 + detect-browser: 5.2.0 + dev: false + + /@walletconnect/core@2.11.2: + resolution: {integrity: sha512-bB4SiXX8hX3/hyBfVPC5gwZCXCl+OPj+/EDVM71iAO3TDsh78KPbrVAbDnnsbHzZVHlsMohtXX3j5XVsheN3+g==} + dependencies: + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-provider': 1.0.13 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.14 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.10 + '@walletconnect/relay-auth': 1.0.4 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.11.2 + '@walletconnect/utils': 2.11.2 + events: 3.3.0 + isomorphic-unfetch: 3.1.0 + lodash.isequal: 4.5.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/core@2.13.0: + resolution: {integrity: sha512-blDuZxQenjeXcVJvHxPznTNl6c/2DO4VNrFnus+qHmO6OtT5lZRowdMtlCaCNb1q0OxzgrmBDcTOCbFcCpio/g==} + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.14 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.10 + '@walletconnect/relay-auth': 1.0.4 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.13.0 + '@walletconnect/utils': 2.13.0 + events: 3.3.0 + isomorphic-unfetch: 3.1.0 + lodash.isequal: 4.5.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/environment@1.0.1: + resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/events@1.0.1: + resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/heartbeat@1.2.1: + resolution: {integrity: sha512-yVzws616xsDLJxuG/28FqtZ5rzrTA4gUjdEMTbWB5Y8V1XHRmqq4efAxCw5ie7WjbXFSUyBHaWlMR+2/CpQC5Q==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + tslib: 1.14.1 + dev: false + + /@walletconnect/heartbeat@1.2.2: + resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + events: 3.3.0 + dev: false + + /@walletconnect/jsonrpc-http-connection@1.0.8: + resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + cross-fetch: 3.1.8 + events: 3.3.0 + transitivePeerDependencies: + - encoding + dev: false + + /@walletconnect/jsonrpc-provider@1.0.13: + resolution: {integrity: sha512-K73EpThqHnSR26gOyNEL+acEex3P7VWZe6KE12ZwKzAt2H4e5gldZHbjsu2QR9cLeJ8AXuO7kEMOIcRv1QEc7g==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-provider@1.0.14: + resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + dev: false + + /@walletconnect/jsonrpc-types@1.0.3: + resolution: {integrity: sha512-iIQ8hboBl3o5ufmJ8cuduGad0CQm3ZlsHtujv9Eu16xq89q+BG7Nh5VLxxUgmtpnrePgFkTwXirCTkwJH1v+Yw==} + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-types@1.0.4: + resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} + dependencies: + events: 3.3.0 + keyvaluestorage-interface: 1.0.0 + dev: false + + /@walletconnect/jsonrpc-utils@1.0.8: + resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} + dependencies: + '@walletconnect/environment': 1.0.1 + '@walletconnect/jsonrpc-types': 1.0.4 + tslib: 1.14.1 + dev: false + + /@walletconnect/jsonrpc-ws-connection@1.0.14: + resolution: {integrity: sha512-Jsl6fC55AYcbkNVkwNM6Jo+ufsuCQRqViOQ8ZBPH9pRREHH9welbBiszuTLqEJiQcO/6XfFDl6bzCJIkrEi8XA==} + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /@walletconnect/keyvaluestorage@1.1.1: + resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + peerDependencies: + '@react-native-async-storage/async-storage': 1.x + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true + dependencies: + '@walletconnect/safe-json': 1.0.2 + idb-keyval: 6.2.1 + unstorage: 1.10.2(idb-keyval@6.2.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/logger@2.1.2: + resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 7.11.0 + dev: false + + /@walletconnect/mobile-registry@1.4.0: + resolution: {integrity: sha512-ZtKRio4uCZ1JUF7LIdecmZt7FOLnX72RPSY7aUVu7mj7CSfxDwUn6gBuK6WGtH+NZCldBqDl5DenI5fFSvkKYw==} + deprecated: 'Deprecated in favor of dynamic registry available from: https://github.com/walletconnect/walletconnect-registry' + dev: false + + /@walletconnect/qrcode-modal@1.8.0: + resolution: {integrity: sha512-BueaFefaAi8mawE45eUtztg3ZFbsAH4DDXh1UNwdUlsvFMjqcYzLUG0xZvDd6z2eOpbgDg2N3bl6gF0KONj1dg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + dependencies: + '@walletconnect/browser-utils': 1.8.0 + '@walletconnect/mobile-registry': 1.4.0 + '@walletconnect/types': 1.8.0 + copy-to-clipboard: 3.3.3 + preact: 10.4.1 + qrcode: 1.4.4 + dev: false + + /@walletconnect/relay-api@1.0.10: + resolution: {integrity: sha512-tqrdd4zU9VBNqUaXXQASaexklv6A54yEyQQEXYOCr+Jz8Ket0dmPBDyg19LVSNUN2cipAghQc45/KVmfFJ0cYw==} + dependencies: + '@walletconnect/jsonrpc-types': 1.0.4 + dev: false + + /@walletconnect/relay-auth@1.0.4: + resolution: {integrity: sha512-kKJcS6+WxYq5kshpPaxGHdwf5y98ZwbfuS4EE/NkQzqrDFm5Cj+dP8LofzWvjrrLkZq7Afy7WrQMXdLy8Sx7HQ==} + dependencies: + '@stablelib/ed25519': 1.0.3 + '@stablelib/random': 1.0.2 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + tslib: 1.14.1 + uint8arrays: 3.1.0 + dev: false + + /@walletconnect/safe-json@1.0.0: + resolution: {integrity: sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==} + dev: false + + /@walletconnect/safe-json@1.0.2: + resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/sign-client@2.11.2: + resolution: {integrity: sha512-MfBcuSz2GmMH+P7MrCP46mVE5qhP0ZyWA0FyIH6/WuxQ6G+MgKsGfaITqakpRPsykWOJq8tXMs3XvUPDU413OQ==} + dependencies: + '@walletconnect/core': 2.11.2 + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.11.2 + '@walletconnect/utils': 2.11.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/sign-client@2.13.0: + resolution: {integrity: sha512-En7KSvNUlQFx20IsYGsFgkNJ2lpvDvRsSFOT5PTdGskwCkUfOpB33SQJ6nCrN19gyoKPNvWg80Cy6MJI0TjNYA==} + dependencies: + '@walletconnect/core': 2.13.0 + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.13.0 + '@walletconnect/utils': 2.13.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/time@1.0.2: + resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/types@1.8.0: + resolution: {integrity: sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + dev: false + + /@walletconnect/types@2.11.2: + resolution: {integrity: sha512-p632MFB+lJbip2cvtXPBQslpUdiw1sDtQ5y855bOlAGquay+6fZ4h1DcDePeKQDQM3P77ax2a9aNPZxV6y/h1Q==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/types@2.12.0: + resolution: {integrity: sha512-uhB3waGmujQVJcPgJvGOpB8RalgYSBT+HpmVbfl4Qe0xJyqpRUo4bPjQa0UYkrHaW20xIw94OuP4+FMLYdeemg==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.1 + '@walletconnect/jsonrpc-types': 1.0.3 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/types@2.13.0: + resolution: {integrity: sha512-MWaVT0FkZwzYbD3tvk8F+2qpPlz1LUSWHuqbINUtMXnSzJtXN49Y99fR7FuBhNFtDalfuWsEK17GrNA+KnAsPQ==} + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/universal-provider@2.11.2: + resolution: {integrity: sha512-cNtIn5AVoDxKAJ4PmB8m5adnf5mYQMUamEUPKMVvOPscfGtIMQEh9peKsh2AN5xcRVDbgluC01Id545evFyymw==} + dependencies: + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.13 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.11.2 + '@walletconnect/types': 2.11.2 + '@walletconnect/utils': 2.11.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@walletconnect/utils@2.11.2: + resolution: {integrity: sha512-LyfdmrnZY6dWqlF4eDrx5jpUwsB2bEPjoqR5Z6rXPiHJKUOdJt7az+mNOn5KTSOlRpd1DmozrBrWr+G9fFLYVw==} + dependencies: + '@stablelib/chacha20poly1305': 1.0.1 + '@stablelib/hkdf': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@walletconnect/relay-api': 1.0.10 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.11.2 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/utils@2.12.0: + resolution: {integrity: sha512-GIpfHUe1Bjp1Tjda0SkJEizKOT2biuv7VPFnKsOLT1T+8QxEP9NruC+K2UUEvijS1Qr/LKH9P5004RYNgrch+w==} + dependencies: + '@stablelib/chacha20poly1305': 1.0.1 + '@stablelib/hkdf': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@walletconnect/relay-api': 1.0.10 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.12.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/utils@2.13.0: + resolution: {integrity: sha512-q1eDCsRHj5iLe7fF8RroGoPZpdo2CYMZzQSrw1iqL+2+GOeqapxxuJ1vaJkmDUkwgklfB22ufqG6KQnz78sD4w==} + dependencies: + '@stablelib/chacha20poly1305': 1.0.1 + '@stablelib/hkdf': 1.0.1 + '@stablelib/random': 1.0.2 + '@stablelib/sha256': 1.0.1 + '@stablelib/x25519': 1.0.3 + '@walletconnect/relay-api': 1.0.10 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.13.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@walletconnect/window-getters@1.0.0: + resolution: {integrity: sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA==} + dev: false + + /@walletconnect/window-getters@1.0.1: + resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + dependencies: + tslib: 1.14.1 + dev: false + + /@walletconnect/window-metadata@1.0.0: + resolution: {integrity: sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA==} + dependencies: + '@walletconnect/window-getters': 1.0.1 + dev: false + + /@walletconnect/window-metadata@1.0.1: + resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} + dependencies: + '@walletconnect/window-getters': 1.0.1 + tslib: 1.14.1 + dev: false + + /@web3modal/common@4.2.1: + resolution: {integrity: sha512-RSx+MKCTr9x8ACTBSIren30goFqkAiplMe4098VNYsYriDjIRyz0mtE8JcM/padrqM+Xvc61xgVx81O15H5drQ==} + dependencies: + bignumber.js: 9.1.2 + dayjs: 1.11.10 + dev: false + + /@web3modal/core@4.2.1(react@18.3.1): + resolution: {integrity: sha512-2Meod0xYxwtnaq6fzZXZOFat2+KhPO/N3y8TBZmN2Xl5DF7/jY/KCFP6/MLdhBEcKXxU5umm3tZ0ASAF7dFzrA==} + dependencies: + '@web3modal/common': 4.2.1 + '@web3modal/wallet': 4.2.1 + valtio: 1.11.2(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - react + dev: false + + /@web3modal/polyfills@4.2.1: + resolution: {integrity: sha512-ejt4Z1kDILTl1h1SjCQbfp69QG5N8eHert0m6uJnjnRedQkGYBN92qzAKDCcGjScZDfH4HOAFznFoNpTJChvrg==} + dependencies: + buffer: 6.0.3 + dev: false + + /@web3modal/scaffold-react@4.2.1(react@18.3.1): + resolution: {integrity: sha512-z21kMB2GTeLFqwXQdJsgJHEGiCPmqDpNZ/v/Lirn4sji6H5PSdiRYo4xQrZsjJaPiM7nQbV3qcPeNtKapOXRCA==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + dependencies: + '@web3modal/scaffold': 4.2.1(react@18.3.1) + react: 18.3.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - uWebSockets.js + dev: false + + /@web3modal/scaffold-utils@4.2.1(react@18.3.1): + resolution: {integrity: sha512-icycRYtElH5Cj4nZamwfG7Z4V5l+z52saaWsUHf+ectj65I8zAKBvYr3qh4pJ/UoxUIg/wIsX7h1qKscL0poMQ==} + dependencies: + '@web3modal/core': 4.2.1(react@18.3.1) + '@web3modal/polyfills': 4.2.1 + valtio: 1.11.2(react@18.3.1) + transitivePeerDependencies: + - '@types/react' + - react + dev: false + + /@web3modal/scaffold-vue@4.2.1(react@18.3.1): + resolution: {integrity: sha512-p6e8UJDHKfeQiZqaCge4+b94aTE1nq2XlkcJ6nORnDWfT8Brkw/FzlJJTSwpAUWBZsqpSjv6hlaPgDVs2SVfXA==} + peerDependencies: + vue: '>=3' + peerDependenciesMeta: + vue: + optional: true + dependencies: + '@web3modal/scaffold': 4.2.1(react@18.3.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - react + - uWebSockets.js + dev: false + + /@web3modal/scaffold@4.2.1(react@18.3.1): + resolution: {integrity: sha512-onSjmPu1iTHJdQzVcBiad6MIwey04x5NnGBlz4BZgGcpsvpumNU+I41ELbCqD3+5qEGXGcTncFL6rxBnF/ZqXw==} + dependencies: + '@web3modal/common': 4.2.1 + '@web3modal/core': 4.2.1(react@18.3.1) + '@web3modal/siwe': 4.2.1(react@18.3.1) + '@web3modal/ui': 4.2.1 + '@web3modal/wallet': 4.2.1 + lit: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - react + - uWebSockets.js + dev: false + + /@web3modal/siwe@4.2.1(react@18.3.1): + resolution: {integrity: sha512-9/MYyQf7JdLPJOM4Yv3vJPAAm97ar2cJodatYgl9zB7gWOXI9U9OwoY7Xlds+AT6dTurY4l5qF+S9nBYeYNnXQ==} + dependencies: + '@walletconnect/utils': 2.12.0 + '@web3modal/core': 4.2.1(react@18.3.1) + '@web3modal/scaffold-utils': 4.2.1(react@18.3.1) + lit: 3.1.0 + valtio: 1.11.2(react@18.3.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - ioredis + - react + - uWebSockets.js + dev: false + + /@web3modal/solana@4.2.1(react@18.3.1): + resolution: {integrity: sha512-FvpajoY/HzYKMvzb/4ZTCkqdyUXnMH7ETw/xrM9tEWouSNkpNWg7pW7i7AVgFFz9eFox9JG9WKlE6RVL3vmsiQ==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + vue: '>=3' + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + vue: + optional: true + dependencies: + '@ethersproject/sha2': 5.7.0 + '@solana/wallet-adapter-backpack': 0.1.14(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-base': 0.9.23(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-phantom': 0.9.24(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-solflare': 0.6.28(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-trust': 0.1.13(@solana/web3.js@1.91.1) + '@solana/wallet-adapter-walletconnect': 0.1.16(@solana/web3.js@1.91.1) + '@solana/web3.js': 1.91.1 + '@walletconnect/universal-provider': 2.11.2 + '@web3modal/polyfills': 4.2.1 + '@web3modal/scaffold': 4.2.1(react@18.3.1) + '@web3modal/scaffold-react': 4.2.1(react@18.3.1) + '@web3modal/scaffold-utils': 4.2.1(react@18.3.1) + '@web3modal/scaffold-vue': 4.2.1(react@18.3.1) + bn.js: 5.2.1 + bs58: 5.0.0 + react: 18.3.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/kv' + - bufferutil + - encoding + - ioredis + - uWebSockets.js + - utf-8-validate + dev: false + + /@web3modal/ui@4.2.1: + resolution: {integrity: sha512-mBoSy8/q9LFw62vpPQDVBo6rcsKaNmp3U7hdzEjTdMsDd0icXxgeaFGtaNu5D6uM/TxKe4UllwcH9Up+7OGlpQ==} + dependencies: + lit: 3.1.0 + qrcode: 1.5.3 + dev: false + + /@web3modal/wallet@4.2.1: + resolution: {integrity: sha512-O6PAjAHcttdkfUGMp6FN5VAEYjjh/5RycJsqfxlnDcxNVzirYgENROR+xdRL/6auR2sbnofkgIjJBGegyshn2A==} + dependencies: + '@web3modal/polyfills': 4.2.1 + zod: 3.22.4 + dev: false + + /JSONStream@1.3.5: + resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} + hasBin: true + dependencies: + jsonparse: 1.3.1 + through: 2.3.8 + dev: false + + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: false + + /aes-js@3.0.0: + resolution: {integrity: sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==} + dev: false + + /agentkeepalive@4.5.0: + resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} + engines: {node: '>= 8.0.0'} + dependencies: + humanize-ms: 1.2.1 + dev: false + + /algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + dev: false + + /algosdk@1.24.1: + resolution: {integrity: sha512-9moZxdqeJ6GdE4N6fA/GlUP4LrbLZMYcYkt141J4Ss68OfEgH9qW0wBuZ3ZOKEx/xjc5bg7mLP2Gjg7nwrkmww==} + engines: {node: '>=14.0.0'} + dependencies: + algo-msgpack-with-bigint: 2.1.1 + buffer: 6.0.3 + cross-fetch: 3.1.8 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + transitivePeerDependencies: + - encoding + dev: false + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: false + + /ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + dev: false + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: false + + /ansicolors@0.3.2: + resolution: {integrity: sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==} + dev: false + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: false + + /aptos@1.8.5(debug@4.3.4): + resolution: {integrity: sha512-iQxliWesNHjGQ5YYXCyss9eg4+bDGQWqAZa73vprqGQ9tungK0cRjUI2fmnp63Ed6UG6rurHrL+b0ckbZAOZZQ==} + engines: {node: '>=11.0.0'} + dependencies: + '@noble/hashes': 1.1.3 + '@scure/bip39': 1.1.0 + axios: 0.27.2(debug@4.3.4) + form-data: 4.0.0 + tweetnacl: 1.0.3 + transitivePeerDependencies: + - debug + dev: false + + /arbundles@0.10.1(arweave@1.15.1)(debug@4.3.4): + resolution: {integrity: sha512-QYFepxessLCirvRkQK9iQmjxjHz+s50lMNGRwZwpyPWLohuf6ISyj1gkFXJHlMT+rNSrsHxb532glHnKbjwu3A==} + dependencies: + '@ethersproject/bytes': 5.7.0 + '@ethersproject/hash': 5.7.0 + '@ethersproject/providers': 5.7.2 + '@ethersproject/signing-key': 5.7.0 + '@ethersproject/transactions': 5.7.0 + '@ethersproject/wallet': 5.7.0 + '@irys/arweave': 0.0.2(debug@4.3.4) + '@noble/ed25519': 1.7.3 + base64url: 3.0.1 + bs58: 4.0.1 + keccak: 3.0.4 + secp256k1: 5.0.0 + optionalDependencies: + '@randlabs/myalgo-connect': 1.4.2 + algosdk: 1.24.1 + arweave-stream-tx: 1.2.2(arweave@1.15.1) + multistream: 4.1.0 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - arweave + - bufferutil + - debug + - encoding + - utf-8-validate + dev: false + + /arconnect@0.4.2: + resolution: {integrity: sha512-Jkpd4QL3TVqnd3U683gzXmZUVqBUy17DdJDuL/3D9rkysLgX6ymJ2e+sR+xyZF5Rh42CBqDXWNMmCjBXeP7Gbw==} + dependencies: + arweave: 1.15.1 + dev: false + optional: true + + /arweave-stream-tx@1.2.2(arweave@1.15.1): + resolution: {integrity: sha512-bNt9rj0hbAEzoUZEF2s6WJbIz8nasZlZpxIw03Xm8fzb9gRiiZlZGW3lxQLjfc9Z0VRUWDzwtqoYeEoB/JDToQ==} + requiresBuild: true + peerDependencies: + arweave: ^1.10.0 + dependencies: + arweave: 1.15.1 + exponential-backoff: 3.1.1 + dev: false + optional: true + + /arweave@1.15.1: + resolution: {integrity: sha512-rT7FOwqdudd5npqp4xOYdDT2035LtpcqePjwirh4wjRiEtVsz1FZkRiM2Yj+fOAwYzOm/hNG0GDOipDSaiEGGQ==} + engines: {node: '>=18'} + dependencies: + arconnect: 0.4.2 + asn1.js: 5.4.1 + base64-js: 1.5.1 + bignumber.js: 9.1.2 + dev: false + optional: true + + /asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /asn1.js@5.4.1: + resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==} + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + safer-buffer: 2.1.2 + dev: false + + /assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + dependencies: + call-bind: 1.0.7 + is-nan: 1.3.2 + object-is: 1.1.6 + object.assign: 4.1.5 + util: 0.12.5 + dev: false + + /async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + dependencies: + retry: 0.13.1 + dev: false + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: false + + /axios@0.27.2(debug@4.3.4): + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: false + + /axios@1.6.8(debug@4.3.4): + resolution: {integrity: sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==} + dependencies: + follow-redirects: 1.15.6(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /base-x@3.0.9: + resolution: {integrity: sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /base-x@4.0.0: + resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /base64url@3.0.1: + resolution: {integrity: sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==} + engines: {node: '>=6.0.0'} + dev: false + + /bech32@1.1.4: + resolution: {integrity: sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==} + dev: false + + /bigint-buffer@1.1.5: + resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} + engines: {node: '>= 10.0.0'} + requiresBuild: true + dependencies: + bindings: 1.5.0 + dev: false + + /bignumber.js@9.1.2: + resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} + dev: false + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + dev: false + + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 + dev: false + + /bip39-light@1.0.7: + resolution: {integrity: sha512-WDTmLRQUsiioBdTs9BmSEmkJza+8xfJmptsNJjxnoq3EydSa/ZBXT6rm66KoT3PJIRYMnhSKNR7S9YL1l7R40Q==} + dependencies: + create-hash: 1.2.0 + pbkdf2: 3.1.2 + dev: false + + /bip39@3.0.2: + resolution: {integrity: sha512-J4E1r2N0tUylTKt07ibXvhpT2c5pyAFgvuA5q1H9uDy6dEGpjV8jmymh3MTYJDLCNbIVClSB9FbND49I6N24MQ==} + dependencies: + '@types/node': 11.11.6 + create-hash: 1.2.0 + pbkdf2: 3.1.2 + randombytes: 2.1.0 + dev: false + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /bn.js@4.11.6: + resolution: {integrity: sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==} + dev: false + + /bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + dev: false + + /bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + dev: false + + /borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + dependencies: + bn.js: 5.2.1 + bs58: 4.0.1 + text-encoding-utf-8: 1.0.2 + dev: false + + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + dev: false + + /brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + dev: false + + /browser-resolve@2.0.0: + resolution: {integrity: sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==} + dependencies: + resolve: 1.22.8 + dev: false + + /browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + dev: false + + /browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /browserify-rsa@4.1.0: + resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + dev: false + + /browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.5.5 + hash-base: 3.0.4 + inherits: 2.0.4 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + dev: false + + /browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + dependencies: + pako: 1.0.11 + dev: false + + /bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + dependencies: + base-x: 3.0.9 + dev: false + + /bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + dependencies: + base-x: 4.0.0 + dev: false + + /buffer-alloc-unsafe@1.1.0: + resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} + dev: false + + /buffer-alloc@1.2.0: + resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} + dependencies: + buffer-alloc-unsafe: 1.1.0 + buffer-fill: 1.0.0 + dev: false + + /buffer-fill@1.0.0: + resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + dev: false + + /buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: false + + /buffer-layout@1.2.2: + resolution: {integrity: sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==} + engines: {node: '>=4.5'} + dev: false + + /buffer-reverse@1.0.1: + resolution: {integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==} + dev: false + + /buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + dev: false + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /bufferutil@4.0.8: + resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.8.1 + dev: false + + /builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + dev: false + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: false + + /camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + dev: false + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: false + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + + /chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: false + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: false + + /cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + dependencies: + consola: 3.2.3 + dev: false + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: false + + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + dev: false + + /cli-width@3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + dev: false + + /clipboardy@4.0.0: + resolution: {integrity: sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==} + engines: {node: '>=18'} + dependencies: + execa: 8.0.1 + is-wsl: 3.1.0 + is64bit: 2.0.0 + dev: false + + /cliui@5.0.0: + resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} + dependencies: + string-width: 3.1.0 + strip-ansi: 5.2.0 + wrap-ansi: 5.1.0 + dev: false + + /cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: false + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + dev: false + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: false + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + dev: false + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: false + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + + /commander@12.0.0: + resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} + engines: {node: '>=18'} + dev: false + + /commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + dev: false + + /commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + dev: false + + /confbox@0.1.7: + resolution: {integrity: sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==} + dev: false + + /consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: false + + /console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + dev: false + + /constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + dev: false + + /cookie-es@1.1.0: + resolution: {integrity: sha512-L2rLOcK0wzWSfSDA33YR+PUHDG10a8px7rUHKWbGLP4YfbsMed2KFUw5fczvDPbT98DDe3LEzviswl810apTEw==} + dev: false + + /copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + dependencies: + toggle-selection: 1.0.6 + dev: false + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false + + /create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + dependencies: + bn.js: 4.12.0 + elliptic: 6.5.5 + dev: false + + /create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + dev: false + + /create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: false + + /create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + dev: false + + /cross-fetch@3.1.8: + resolution: {integrity: sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==} + dependencies: + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + dev: false + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: false + + /crossws@0.2.4: + resolution: {integrity: sha512-DAxroI2uSOgUKLz00NX6A8U/8EE3SZHmIND+10jkVSaypvyt57J5JEOxAQOL6lQxyzi/wZbTIwssU1uy69h5Vg==} + peerDependencies: + uWebSockets.js: '*' + peerDependenciesMeta: + uWebSockets.js: + optional: true + dev: false + + /crypto-browserify@3.12.0: + resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.3 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + dev: false + + /crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + dev: false + + /csv-generate@3.4.3: + resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} + dev: false + + /csv-parse@4.16.3: + resolution: {integrity: sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg==} + dev: false + + /csv-stringify@5.6.5: + resolution: {integrity: sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A==} + dev: false + + /csv@5.5.3: + resolution: {integrity: sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g==} + engines: {node: '>= 0.1.90'} + dependencies: + csv-generate: 3.4.3 + csv-parse: 4.16.3 + csv-stringify: 5.6.5 + stream-transform: 2.1.3 + dev: false + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: false + + /debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + dev: false + + /decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + dev: false + + /decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + dev: false + + /defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + dependencies: + clone: 1.0.4 + dev: false + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + dev: false + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + dev: false + + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dev: false + + /delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} + engines: {node: '>=10'} + dev: false + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + + /depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + dev: false + + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + + /des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /destr@2.0.3: + resolution: {integrity: sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==} + dev: false + + /detect-browser@5.2.0: + resolution: {integrity: sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==} + dev: false + + /detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + dev: false + + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: false + + /diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + dev: false + + /dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + dev: false + + /domain-browser@4.23.0: + resolution: {integrity: sha512-ArzcM/II1wCCujdCNyQjXrAFwS4mrLh4C7DZWlaI8mdh7h3BfKdNd3bKXITfl2PT9FtfQqaGvhi1vPRQPimjGA==} + engines: {node: '>=10'} + dev: false + + /dotenv@10.0.0: + resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} + engines: {node: '>=10'} + dev: false + + /duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + dependencies: + end-of-stream: 1.4.4 + inherits: 2.0.4 + readable-stream: 3.6.2 + stream-shift: 1.0.3 + dev: false + + /elliptic@6.5.4: + resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /elliptic@6.5.5: + resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + dev: false + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + + /encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: false + + /es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + dev: false + + /es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + dependencies: + es6-promise: 4.2.8 + dev: false + + /esbuild@0.20.2: + resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.20.2 + '@esbuild/android-arm': 0.20.2 + '@esbuild/android-arm64': 0.20.2 + '@esbuild/android-x64': 0.20.2 + '@esbuild/darwin-arm64': 0.20.2 + '@esbuild/darwin-x64': 0.20.2 + '@esbuild/freebsd-arm64': 0.20.2 + '@esbuild/freebsd-x64': 0.20.2 + '@esbuild/linux-arm': 0.20.2 + '@esbuild/linux-arm64': 0.20.2 + '@esbuild/linux-ia32': 0.20.2 + '@esbuild/linux-loong64': 0.20.2 + '@esbuild/linux-mips64el': 0.20.2 + '@esbuild/linux-ppc64': 0.20.2 + '@esbuild/linux-riscv64': 0.20.2 + '@esbuild/linux-s390x': 0.20.2 + '@esbuild/linux-x64': 0.20.2 + '@esbuild/netbsd-x64': 0.20.2 + '@esbuild/openbsd-x64': 0.20.2 + '@esbuild/sunos-x64': 0.20.2 + '@esbuild/win32-arm64': 0.20.2 + '@esbuild/win32-ia32': 0.20.2 + '@esbuild/win32-x64': 0.20.2 + dev: false + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: false + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: false + + /ethereum-bloom-filters@1.1.0: + resolution: {integrity: sha512-J1gDRkLpuGNvWYzWslBQR9cDV4nd4kfvVTE/Wy4Kkm4yb3EYRSlyi0eB/inTsSTTVyA0+HyzHgbr95Fn/Z1fSw==} + dependencies: + '@noble/hashes': 1.4.0 + dev: false + + /ethereum-cryptography@2.1.3: + resolution: {integrity: sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==} + dependencies: + '@noble/curves': 1.3.0 + '@noble/hashes': 1.3.3 + '@scure/bip32': 1.3.3 + '@scure/bip39': 1.2.2 + dev: false + + /ethjs-unit@0.1.6: + resolution: {integrity: sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==} + engines: {node: '>=6.5.0', npm: '>=3'} + dependencies: + bn.js: 4.11.6 + number-to-bn: 1.7.0 + dev: false + + /eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + dev: false + + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + dev: false + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + dev: false + + /execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + dev: false + + /exponential-backoff@3.1.1: + resolution: {integrity: sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==} + requiresBuild: true + dev: false + optional: true + + /external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: false + + /eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} + dev: false + + /fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + dev: false + + /fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + dev: false + + /fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + dev: false + + /figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: false + + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: false + + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: false + + /filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} + dev: false + + /find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + dependencies: + locate-path: 3.0.0 + dev: false + + /find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + dev: false + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: false + + /follow-redirects@1.15.6(debug@4.3.4): + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4 + dev: false + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: false + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: false + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: false + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + dev: false + + /get-port-please@3.1.2: + resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==} + dev: false + + /get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: false + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /h3@1.11.1: + resolution: {integrity: sha512-AbaH6IDnZN6nmbnJOH72y3c5Wwh9P97soSVdGSBbcDACRdkC0FEWf25pzx4f/NuOCK6quHmW18yF2Wx+G4Zi1A==} + dependencies: + cookie-es: 1.1.0 + crossws: 0.2.4 + defu: 6.1.4 + destr: 2.0.3 + iron-webcrypto: 1.2.1 + ohash: 1.1.3 + radix3: 1.1.2 + ufo: 1.5.3 + uncrypto: 0.1.3 + unenv: 1.9.0 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + dev: false + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + dev: false + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: false + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false + + /hash-base@3.0.4: + resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /hash-base@3.1.0: + resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} + engines: {node: '>=4'} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + safe-buffer: 5.2.1 + dev: false + + /hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: false + + /hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + dev: false + + /hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + dev: false + + /http-errors@1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + dependencies: + depd: 1.1.2 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 1.5.0 + toidentifier: 1.0.1 + dev: false + + /http-shutdown@1.2.2: + resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + dev: false + + /https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + dev: false + + /human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + dev: false + + /humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + dependencies: + ms: 2.1.3 + dev: false + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /inquirer@8.2.6: + resolution: {integrity: sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==} + engines: {node: '>=12.0.0'} + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.8.1 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 6.2.0 + dev: false + + /iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + dev: false + + /is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: false + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + dev: false + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: false + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.2 + dev: false + + /is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + dev: false + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: false + + /is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + dev: false + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: false + + /is-hex-prefixed@1.0.0: + resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} + engines: {node: '>=6.5.0', npm: '>=3'} + dev: false + + /is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + dependencies: + is-docker: 3.0.0 + dev: false + + /is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: false + + /is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + dev: false + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: false + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + dev: false + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: false + + /is-wsl@3.1.0: + resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} + engines: {node: '>=16'} + dependencies: + is-inside-container: 1.0.0 + dev: false + + /is64bit@2.0.0: + resolution: {integrity: sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==} + engines: {node: '>=18'} + dependencies: + system-architecture: 0.1.0 + dev: false + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: false + + /isomorphic-timers-promises@1.0.1: + resolution: {integrity: sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==} + engines: {node: '>=10'} + dev: false + + /isomorphic-unfetch@3.1.0: + resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} + dependencies: + node-fetch: 2.7.0 + unfetch: 4.2.0 + transitivePeerDependencies: + - encoding + dev: false + + /isomorphic-ws@4.0.1(ws@7.5.9): + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' + dependencies: + ws: 7.5.9 + dev: false + + /jayson@4.1.0: + resolution: {integrity: sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==} + engines: {node: '>=8'} + hasBin: true + dependencies: + '@types/connect': 3.4.38 + '@types/node': 12.20.55 + '@types/ws': 7.4.7 + JSONStream: 1.3.5 + commander: 2.20.3 + delay: 5.0.0 + es6-promisify: 5.0.0 + eyes: 0.1.8 + isomorphic-ws: 4.0.1(ws@7.5.9) + json-stringify-safe: 5.0.1 + uuid: 8.3.2 + ws: 7.5.9 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /jiti@1.21.0: + resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} + hasBin: true + dev: false + + /js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + dev: false + + /js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + dev: false + + /js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: false + + /json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + dependencies: + bignumber.js: 9.1.2 + dev: false + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: false + + /jsonparse@1.3.1: + resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} + engines: {'0': node >= 0.2.0} + dev: false + + /keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} + requiresBuild: true + dependencies: + node-addon-api: 2.0.2 + node-gyp-build: 4.8.1 + readable-stream: 3.6.2 + dev: false + + /keyvaluestorage-interface@1.0.0: + resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + dev: false + + /listhen@1.7.2: + resolution: {integrity: sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g==} + hasBin: true + dependencies: + '@parcel/watcher': 2.4.1 + '@parcel/watcher-wasm': 2.4.1 + citty: 0.1.6 + clipboardy: 4.0.0 + consola: 3.2.3 + crossws: 0.2.4 + defu: 6.1.4 + get-port-please: 3.1.2 + h3: 1.11.1 + http-shutdown: 1.2.2 + jiti: 1.21.0 + mlly: 1.7.0 + node-forge: 1.3.1 + pathe: 1.1.2 + std-env: 3.7.0 + ufo: 1.5.3 + untun: 0.1.3 + uqr: 0.1.2 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /lit-element@4.0.5: + resolution: {integrity: sha512-iTWskWZEtn9SyEf4aBG6rKT8GABZMrTWop1+jopsEOgEcugcXJGKuX5bEbkq9qfzY+XB4MAgCaSPwnNpdsNQ3Q==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.2.0 + '@lit/reactive-element': 2.0.4 + lit-html: 3.1.3 + dev: false + + /lit-html@3.1.3: + resolution: {integrity: sha512-FwIbqDD8O/8lM4vUZ4KvQZjPPNx7V1VhT7vmRB8RBAO0AU6wuTVdoXiu2CivVjEGdugvcbPNBLtPE1y0ifplHA==} + dependencies: + '@types/trusted-types': 2.0.7 + dev: false + + /lit@3.1.0: + resolution: {integrity: sha512-rzo/hmUqX8zmOdamDAeydfjsGXbbdtAFqMhmocnh2j9aDYqbu0fjXygjCa0T99Od9VQ/2itwaGrjZz/ZELVl7w==} + dependencies: + '@lit/reactive-element': 2.0.4 + lit-element: 4.0.5 + lit-html: 3.1.3 + dev: false + + /locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + dev: false + + /locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + dependencies: + p-locate: 4.1.0 + dev: false + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: false + + /lodash.clonedeep@4.5.0: + resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + dev: false + + /lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: false + + /lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} + dev: false + + /magic-string@0.30.10: + resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + + /md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: false + + /merkletreejs@0.3.11: + resolution: {integrity: sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ==} + engines: {node: '>= 7.6.0'} + dependencies: + bignumber.js: 9.1.2 + buffer-reverse: 1.0.1 + crypto-js: 4.2.0 + treeify: 1.1.0 + web3-utils: 1.10.4 + dev: false + + /micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + dev: false + + /micromatch@4.0.6: + resolution: {integrity: sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 4.0.2 + dev: false + + /miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + dev: false + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: false + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: false + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: false + + /minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dev: false + + /minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + dev: false + + /mixme@0.5.10: + resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} + engines: {node: '>= 8.0.0'} + dev: false + + /mlly@1.7.0: + resolution: {integrity: sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==} + dependencies: + acorn: 8.11.3 + pathe: 1.1.2 + pkg-types: 1.1.1 + ufo: 1.5.3 + dev: false + + /mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + dev: false + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + + /multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + dev: false + + /multistream@4.1.0: + resolution: {integrity: sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==} + requiresBuild: true + dependencies: + once: 1.4.0 + readable-stream: 3.6.2 + dev: false + optional: true + + /mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + dev: false + + /mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + dev: false + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: false + + /napi-wasm@1.1.0: + resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==} + dev: false + + /near-hd-key@1.2.1: + resolution: {integrity: sha512-SIrthcL5Wc0sps+2e1xGj3zceEa68TgNZDLuCx0daxmfTP7sFTB3/mtE2pYhlFsCxWoMn+JfID5E1NlzvvbRJg==} + dependencies: + bip39: 3.0.2 + create-hmac: 1.1.7 + tweetnacl: 1.0.3 + dev: false + + /near-seed-phrase@0.2.0: + resolution: {integrity: sha512-NpmrnejpY1AdlRpDZ0schJQJtfBaoUheRfiYtQpcq9TkwPgqKZCRULV5L3hHmLc0ep7KRtikbPQ9R2ztN/3cyQ==} + dependencies: + bip39-light: 1.0.7 + bs58: 4.0.1 + near-hd-key: 1.2.1 + tweetnacl: 1.0.3 + dev: false + + /node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + dev: false + + /node-addon-api@5.1.0: + resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + dev: false + + /node-addon-api@7.1.0: + resolution: {integrity: sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==} + engines: {node: ^16 || ^18 || >= 20} + dev: false + + /node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + dev: false + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + + /node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: false + + /node-gyp-build@4.8.1: + resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} + hasBin: true + requiresBuild: true + dev: false + + /node-stdlib-browser@1.2.0: + resolution: {integrity: sha512-VSjFxUhRhkyed8AtLwSCkMrJRfQ3e2lGtG3sP6FEgaLKBBbxM/dLfjRe1+iLhjvyLFW3tBQ8+c0pcOtXGbAZJg==} + engines: {node: '>=10'} + dependencies: + assert: 2.1.0 + browser-resolve: 2.0.0 + browserify-zlib: 0.2.0 + buffer: 5.7.1 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + create-require: 1.1.1 + crypto-browserify: 3.12.0 + domain-browser: 4.23.0 + events: 3.3.0 + https-browserify: 1.0.0 + isomorphic-timers-promises: 1.0.1 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + pkg-dir: 5.0.0 + process: 0.11.10 + punycode: 1.4.1 + querystring-es3: 0.2.1 + readable-stream: 3.6.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.3 + util: 0.12.5 + vm-browserify: 1.1.2 + dev: false + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: false + + /npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + path-key: 4.0.0 + dev: false + + /number-to-bn@1.7.0: + resolution: {integrity: sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==} + engines: {node: '>=6.5.0', npm: '>=3'} + dependencies: + bn.js: 4.11.6 + strip-hex-prefix: 1.0.0 + dev: false + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: false + + /object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + dev: false + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: false + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: false + + /ofetch@1.3.4: + resolution: {integrity: sha512-KLIET85ik3vhEfS+3fDlc/BAZiAp+43QEC/yCo5zkNoY2YaKvNkOaFr/6wCFgFH1kuYQM5pMNi0Tg8koiIemtw==} + dependencies: + destr: 2.0.3 + node-fetch-native: 1.6.4 + ufo: 1.5.3 + dev: false + + /ohash@1.1.3: + resolution: {integrity: sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==} + dev: false + + /on-exit-leak-free@0.2.0: + resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + requiresBuild: true + dependencies: + wrappy: 1.0.2 + dev: false + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: false + + /onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + dependencies: + mimic-fn: 4.0.0 + dev: false + + /ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: false + + /os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + dev: false + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + dev: false + + /p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + dependencies: + p-try: 2.2.0 + dev: false + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: false + + /p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + dependencies: + p-limit: 2.3.0 + dev: false + + /p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + dependencies: + p-limit: 2.3.0 + dev: false + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: false + + /p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + dev: false + + /pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: false + + /parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} + dependencies: + asn1.js: 4.10.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + hash-base: 3.0.4 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 + dev: false + + /path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: false + + /path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: false + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: false + + /path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + dev: false + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: false + + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: false + + /pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + dev: false + + /picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + dev: false + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: false + + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: false + + /pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + dependencies: + duplexify: 4.1.3 + split2: 4.2.0 + dev: false + + /pino-std-serializers@4.0.0: + resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + dev: false + + /pino@7.11.0: + resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 0.2.0 + pino-abstract-transport: 0.5.0 + pino-std-serializers: 4.0.0 + process-warning: 1.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.1.0 + safe-stable-stringify: 2.4.3 + sonic-boom: 2.8.0 + thread-stream: 0.15.2 + dev: false + + /pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + dependencies: + find-up: 5.0.0 + dev: false + + /pkg-types@1.1.1: + resolution: {integrity: sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==} + dependencies: + confbox: 0.1.7 + mlly: 1.7.0 + pathe: 1.1.2 + dev: false + + /pngjs@3.4.0: + resolution: {integrity: sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==} + engines: {node: '>=4.0.0'} + dev: false + + /pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + dev: false + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: false + + /postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + dev: false + + /preact@10.4.1: + resolution: {integrity: sha512-WKrRpCSwL2t3tpOOGhf2WfTpcmbpxaWtDbdJdKdjd0aEiTkvOmS4NBkG6kzlaAHI9AkQ3iVqbFWM3Ei7mZ4o1Q==} + dev: false + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: false + + /process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + dev: false + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /proxy-compare@2.5.1: + resolution: {integrity: sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==} + dev: false + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.0 + create-hash: 1.2.0 + parse-asn1: 5.1.7 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: false + + /punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + dev: false + + /qrcode@1.4.4: + resolution: {integrity: sha512-oLzEC5+NKFou9P0bMj5+v6Z40evexeE29Z9cummZXZ9QXyMr3lphkURzxjXgPJC5azpxcshoDWV1xE46z+/c3Q==} + engines: {node: '>=4'} + hasBin: true + dependencies: + buffer: 5.7.1 + buffer-alloc: 1.2.0 + buffer-from: 1.1.2 + dijkstrajs: 1.0.3 + isarray: 2.0.5 + pngjs: 3.4.0 + yargs: 13.3.2 + dev: false + + /qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + dijkstrajs: 1.0.3 + encode-utf8: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + dev: false + + /qs@6.12.1: + resolution: {integrity: sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.6 + dev: false + + /query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + dependencies: + decode-uri-component: 0.2.2 + filter-obj: 1.1.0 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + dev: false + + /querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + dev: false + + /quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + + /radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + dev: false + + /randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + dev: false + + /react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: false + + /real-require@0.1.0: + resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + engines: {node: '>= 12.13.0'} + dev: false + + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: false + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: false + + /require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + dev: false + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + + /retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: false + + /ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + dependencies: + hash-base: 3.1.0 + inherits: 2.0.4 + dev: false + + /rollup@4.17.2: + resolution: {integrity: sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.17.2 + '@rollup/rollup-android-arm64': 4.17.2 + '@rollup/rollup-darwin-arm64': 4.17.2 + '@rollup/rollup-darwin-x64': 4.17.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.17.2 + '@rollup/rollup-linux-arm-musleabihf': 4.17.2 + '@rollup/rollup-linux-arm64-gnu': 4.17.2 + '@rollup/rollup-linux-arm64-musl': 4.17.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.17.2 + '@rollup/rollup-linux-riscv64-gnu': 4.17.2 + '@rollup/rollup-linux-s390x-gnu': 4.17.2 + '@rollup/rollup-linux-x64-gnu': 4.17.2 + '@rollup/rollup-linux-x64-musl': 4.17.2 + '@rollup/rollup-win32-arm64-msvc': 4.17.2 + '@rollup/rollup-win32-ia32-msvc': 4.17.2 + '@rollup/rollup-win32-x64-msvc': 4.17.2 + fsevents: 2.3.3 + dev: false + + /rpc-websockets@7.11.0: + resolution: {integrity: sha512-IkLYjayPv6Io8C/TdCL5gwgzd1hFz2vmBZrjMw/SPEXo51ETOhnzgS4Qy5GWi2JQN7HKHa66J3+2mv0fgNh/7w==} + dependencies: + eventemitter3: 4.0.7 + uuid: 8.3.2 + ws: 8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + dev: false + + /run-async@2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + dev: false + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.6.2 + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-stable-stringify@2.4.3: + resolution: {integrity: sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==} + engines: {node: '>=10'} + dev: false + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /scrypt-js@3.0.1: + resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} + dev: false + + /secp256k1@5.0.0: + resolution: {integrity: sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + elliptic: 6.5.5 + node-addon-api: 5.1.0 + node-gyp-build: 4.8.1 + dev: false + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + dev: false + + /setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: false + + /setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + dev: false + + /sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: false + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: false + + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.1 + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: false + + /sonic-boom@2.8.0: + resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + dev: false + + /split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} + dev: false + + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + + /statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + dev: false + + /std-env@3.7.0: + resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} + dev: false + + /stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + dev: false + + /stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + dev: false + + /stream-transform@2.1.3: + resolution: {integrity: sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ==} + dependencies: + mixme: 0.5.10 + dev: false + + /strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + dev: false + + /string-width@3.1.0: + resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} + engines: {node: '>=6'} + dependencies: + emoji-regex: 7.0.3 + is-fullwidth-code-point: 2.0.0 + strip-ansi: 5.2.0 + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + dependencies: + ansi-regex: 4.1.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + + /strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + dev: false + + /strip-hex-prefix@1.0.0: + resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} + engines: {node: '>=6.5.0', npm: '>=3'} + dependencies: + is-hex-prefixed: 1.0.0 + dev: false + + /superstruct@0.14.2: + resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} + dev: false + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: false + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: false + + /system-architecture@0.1.0: + resolution: {integrity: sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==} + engines: {node: '>=18'} + dev: false + + /text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + dev: false + + /thread-stream@0.15.2: + resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + dependencies: + real-require: 0.1.0 + dev: false + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: false + + /timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + dependencies: + setimmediate: 1.0.5 + dev: false + + /tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + requiresBuild: true + dependencies: + tmp: 0.2.3 + dev: false + optional: true + + /tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + dependencies: + os-tmpdir: 1.0.2 + dev: false + + /tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + requiresBuild: true + dev: false + optional: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: false + + /toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + dev: false + + /toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + dev: false + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false + + /treeify@1.1.0: + resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} + engines: {node: '>=0.6'} + dev: false + + /tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: false + + /tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + dev: false + + /tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + dev: false + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: false + + /typescript-collections@1.3.3: + resolution: {integrity: sha512-7sI4e/bZijOzyURng88oOFZCISQPTHozfE2sUu5AviFYk5QV7fYGb6YiDl+vKjF/pICA354JImBImL9XJWUvdQ==} + dev: false + + /ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + dev: false + + /uint8arrays@3.1.0: + resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + dependencies: + multiformats: 9.9.0 + dev: false + + /uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + dev: false + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: false + + /unenv@1.9.0: + resolution: {integrity: sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g==} + dependencies: + consola: 3.2.3 + defu: 6.1.4 + mime: 3.0.0 + node-fetch-native: 1.6.4 + pathe: 1.1.2 + dev: false + + /unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + dev: false + + /unstorage@1.10.2(idb-keyval@6.2.1): + resolution: {integrity: sha512-cULBcwDqrS8UhlIysUJs2Dk0Mmt8h7B0E6mtR+relW9nZvsf/u4SkAYyNliPiPW7XtFNb5u3IUMkxGxFTTRTgQ==} + peerDependencies: + '@azure/app-configuration': ^1.5.0 + '@azure/cosmos': ^4.0.0 + '@azure/data-tables': ^13.2.2 + '@azure/identity': ^4.0.1 + '@azure/keyvault-secrets': ^4.8.0 + '@azure/storage-blob': ^12.17.0 + '@capacitor/preferences': ^5.0.7 + '@netlify/blobs': ^6.5.0 || ^7.0.0 + '@planetscale/database': ^1.16.0 + '@upstash/redis': ^1.28.4 + '@vercel/kv': ^1.0.1 + idb-keyval: ^6.2.1 + ioredis: ^5.3.2 + peerDependenciesMeta: + '@azure/app-configuration': + optional: true + '@azure/cosmos': + optional: true + '@azure/data-tables': + optional: true + '@azure/identity': + optional: true + '@azure/keyvault-secrets': + optional: true + '@azure/storage-blob': + optional: true + '@capacitor/preferences': + optional: true + '@netlify/blobs': + optional: true + '@planetscale/database': + optional: true + '@upstash/redis': + optional: true + '@vercel/kv': + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + dependencies: + anymatch: 3.1.3 + chokidar: 3.6.0 + destr: 2.0.3 + h3: 1.11.1 + idb-keyval: 6.2.1 + listhen: 1.7.2 + lru-cache: 10.2.2 + mri: 1.2.0 + node-fetch-native: 1.6.4 + ofetch: 1.3.4 + ufo: 1.5.3 + transitivePeerDependencies: + - uWebSockets.js + dev: false + + /untun@0.1.3: + resolution: {integrity: sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==} + hasBin: true + dependencies: + citty: 0.1.6 + consola: 3.2.3 + pathe: 1.1.2 + dev: false + + /uqr@0.1.2: + resolution: {integrity: sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==} + dev: false + + /url@0.11.3: + resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + dependencies: + punycode: 1.4.1 + qs: 6.12.1 + dev: false + + /use-sync-external-store@1.2.0(react@18.3.1): + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.3.1 + dev: false + + /utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} + requiresBuild: true + dependencies: + node-gyp-build: 4.8.1 + dev: false + + /utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 + dev: false + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: false + + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + dev: false + + /valtio@1.11.2(react@18.3.1): + resolution: {integrity: sha512-1XfIxnUXzyswPAPXo1P3Pdx2mq/pIqZICkWN60Hby0d9Iqb+MEIpqgYVlbflvHdrp2YR/q3jyKWRPJJ100yxaw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=16.8' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + dependencies: + proxy-compare: 2.5.1 + react: 18.3.1 + use-sync-external-store: 1.2.0(react@18.3.1) + dev: false + + /vite-plugin-node-polyfills@0.21.0(vite@5.2.11): + resolution: {integrity: sha512-Sk4DiKnmxN8E0vhgEhzLudfJQfaT8k4/gJ25xvUPG54KjLJ6HAmDKbr4rzDD/QWEY+Lwg80KE85fGYBQihEPQA==} + peerDependencies: + vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + dependencies: + '@rollup/plugin-inject': 5.0.5 + node-stdlib-browser: 1.2.0 + vite: 5.2.11 + transitivePeerDependencies: + - rollup + dev: false + + /vite@5.2.11: + resolution: {integrity: sha512-HndV31LWW05i1BLPMUCE1B9E9GFbOu1MbenhS58FuK6owSO5qHm7GiCotrNY1YE5rMeQSFBGmT5ZaLEjFizgiQ==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.20.2 + postcss: 8.4.38 + rollup: 4.17.2 + optionalDependencies: + fsevents: 2.3.3 + dev: false + + /vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + dev: false + + /vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + dev: false + + /wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.4 + dev: false + + /web3-errors@1.1.4: + resolution: {integrity: sha512-WahtszSqILez+83AxGecVroyZsMuuRT+KmQp4Si5P4Rnqbczno1k748PCrZTS1J4UCPmXMG2/Vt+0Bz2zwXkwQ==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + web3-types: 1.5.0 + dev: false + + /web3-types@1.5.0: + resolution: {integrity: sha512-geWuMIeegQ8AedKAO6wO4G4j1gyQ1F/AyKLMw2vud4bsfZayyzWJgCMDZtjYMm5uo2a7i8j1W3/4QFmzlSy5cw==} + engines: {node: '>=14', npm: '>=6.12.0'} + dev: false + + /web3-utils@1.10.4: + resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} + engines: {node: '>=8.0.0'} + dependencies: + '@ethereumjs/util': 8.1.0 + bn.js: 5.2.1 + ethereum-bloom-filters: 1.1.0 + ethereum-cryptography: 2.1.3 + ethjs-unit: 0.1.6 + number-to-bn: 1.7.0 + randombytes: 2.1.0 + utf8: 3.0.0 + dev: false + + /web3-utils@4.2.1: + resolution: {integrity: sha512-Fk29BlEqD9Q9Cnw4pBkKw7czcXiRpsSco/BzEUl4ye0ZTSHANQFfjsfQmNm4t7uY11u6Ah+8F3tNjBeU4CA80A==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + ethereum-cryptography: 2.1.3 + eventemitter3: 5.0.1 + web3-errors: 1.1.4 + web3-types: 1.5.0 + web3-validator: 2.0.4 + dev: false + + /web3-validator@2.0.4: + resolution: {integrity: sha512-qRxVePwdW+SByOmTpDZFWHIUAa7PswvxNszrOua6BoGqAhERo5oJZBN+EbWtK/+O+ApNxt5FR3nCPmiZldiOQA==} + engines: {node: '>=14', npm: '>=6.12.0'} + dependencies: + ethereum-cryptography: 2.1.3 + util: 0.12.5 + web3-errors: 1.1.4 + web3-types: 1.5.0 + zod: 3.22.4 + dev: false + + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + + /which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + dev: false + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: false + + /wrap-ansi@5.1.0: + resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} + engines: {node: '>=6'} + dependencies: + ansi-styles: 3.2.1 + string-width: 3.1.0 + strip-ansi: 5.2.0 + dev: false + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + requiresBuild: true + dev: false + + /ws@7.4.6: + resolution: {integrity: sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /ws@7.5.9: + resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /ws@8.16.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + resolution: {integrity: sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + dev: false + + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + + /y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + dev: false + + /yargs-parser@13.1.2: + resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + + /yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + dev: false + + /yargs@13.3.2: + resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} + dependencies: + cliui: 5.0.0 + find-up: 3.0.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 3.1.0 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 13.1.2 + dev: false + + /yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + dev: false + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: false + + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + dev: false diff --git a/packages/networks/solana/src/assets/Coin.ts b/packages/networks/solana/src/assets/Coin.ts new file mode 100644 index 0000000..31b533e --- /dev/null +++ b/packages/networks/solana/src/assets/Coin.ts @@ -0,0 +1,84 @@ +import { Provider } from '../services/Provider.ts' +import { fromLamports, toLamports } from '../utils.ts' +import { PublicKey, SystemProgram, Transaction } from '@solana/web3.js' +import { ErrorTypeEnum, type CoinInterface } from '@multiplechain/types' +import { CoinTransactionSigner } from '../services/TransactionSigner.ts' + +export class Coin implements CoinInterface { + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {Provider} provider network provider + */ + constructor(provider?: Provider) { + this.provider = provider ?? Provider.instance + } + + /** + * @returns {string} Coin name + */ + getName(): string { + return 'Solana' + } + + /** + * @returns {string} Coin symbol + */ + getSymbol(): string { + return 'SOL' + } + + /** + * @returns {number} Decimal value of the coin + */ + getDecimals(): number { + return 9 + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of COIN + */ + async getBalance(owner: string): Promise { + return fromLamports(await this.provider.web3.getBalance(new PublicKey(owner))) + } + + /** + * @param {string} sender Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + amount: number + ): Promise { + if (amount < 0) { + throw new Error(ErrorTypeEnum.INVALID_AMOUNT) + } + + if (amount > (await this.getBalance(sender))) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + const lamports = toLamports(amount) + const senderPubKey = new PublicKey(sender) + const receiverPubKey = new PublicKey(receiver) + + const transaction = new Transaction().add( + SystemProgram.transfer({ + fromPubkey: senderPubKey, + toPubkey: receiverPubKey, + lamports + }) + ) + + transaction.feePayer = senderPubKey + + return new CoinTransactionSigner(transaction) + } +} diff --git a/packages/networks/solana/src/assets/Contract.ts b/packages/networks/solana/src/assets/Contract.ts new file mode 100644 index 0000000..f3e0c35 --- /dev/null +++ b/packages/networks/solana/src/assets/Contract.ts @@ -0,0 +1,61 @@ +import { PublicKey } from '@solana/web3.js' +import { Provider } from '../services/Provider.ts' +import type { ContractInterface } from '@multiplechain/types' + +export class Contract implements ContractInterface { + /** + * Contract address + */ + address: string + + pubKey: PublicKey + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {string} address Contract address + * @param {Provider} provider Blockchain network provider + */ + constructor(address: string, provider?: Provider) { + this.address = address + this.pubKey = new PublicKey(address) + this.provider = provider ?? Provider.instance + } + + /** + * @returns {string} Contract address + */ + getAddress(): string { + return this.address + } + + /** + * @param {string} _method Method name + * @param {any[]} _args Method parameters + * @returns {Promise} Method result + */ + async callMethod(_method: string, ..._args: any[]): Promise { + throw new Error('Method not implemented.') + } + + /** + * @param {string} _method Method name + * @param {any[]} _args Sender wallet address + * @returns {Promise} Encoded method data + */ + async getMethodData(_method: string, ..._args: any[]): Promise { + throw new Error('Method not implemented.') + } + + /** + * @param {string} _method Method name + * @param {string} _from Sender wallet address + * @param {any[]} _args Method parameters + * @returns {Promise} Encoded method data + */ + async createTransactionData(_method: string, _from: string, ..._args: any[]): Promise { + throw new Error('Method not implemented.') + } +} diff --git a/packages/networks/solana/src/assets/NFT.ts b/packages/networks/solana/src/assets/NFT.ts new file mode 100644 index 0000000..954a00c --- /dev/null +++ b/packages/networks/solana/src/assets/NFT.ts @@ -0,0 +1,249 @@ +import { Contract } from './Contract.ts' +import { Metaplex } from '@metaplex-foundation/js' +import { ErrorTypeEnum, type NftInterface } from '@multiplechain/types' +import { NftTransactionSigner } from '../services/TransactionSigner.ts' +import type { Sft, SftWithToken, Nft, NftWithToken } from '@metaplex-foundation/js' +import { + PublicKey, + Transaction, + type AccountInfo, + type ParsedAccountData, + type RpcResponseAndContext +} from '@solana/web3.js' +import { + TOKEN_PROGRAM_ID, + ASSOCIATED_TOKEN_PROGRAM_ID, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountInstruction, + createTransferInstruction, + createApproveInstruction +} from '@solana/spl-token' + +type Metadata = Sft | SftWithToken | Nft | NftWithToken + +export class NFT extends Contract implements NftInterface { + metadata: Metadata + + /** + * @param {PublicKey} pubKey + * @returns {Promise} Metadata of the NFT + */ + async getMetadata(pubKey?: PublicKey): Promise { + try { + // if metadata is already fetched and pubKey is not provided, return the metadata + if (this.metadata !== undefined && pubKey === undefined) { + return this.metadata + } + const metaplex = Metaplex.make(this.provider.web3) + return (this.metadata = await metaplex.nfts().findByMint({ + mintAddress: pubKey ?? this.pubKey + })) + } catch (error) { + return null + } + } + + /** + * @param {PublicKey} pubKey Program ID + * @returns {Promise} Program ID + * @throws {Error} If the program ID is not found + */ + async getProgramId(pubKey: PublicKey): Promise { + const accountInfo = await this.provider.web3.getAccountInfo(pubKey) + return accountInfo !== null ? accountInfo.owner : TOKEN_PROGRAM_ID + } + + /** + * @returns {Promise} NFT name + */ + async getName(): Promise { + return (await this.getMetadata())?.name ?? '' + } + + /** + * @returns {Promise} NFT symbol + */ + async getSymbol(): Promise { + return (await this.getMetadata())?.symbol ?? '' + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of NFT + */ + async getBalance(owner: string): Promise { + const metaplex = Metaplex.make(this.provider.web3) + const res = await metaplex.nfts().findAllByOwner({ owner: new PublicKey(owner) }) + return res.filter((nft) => { + if (nft.collection?.address === undefined) return false + return this.pubKey.equals(nft.collection?.address) + }).length + } + + /** + * @param {number | string} nftId NFT ID + * @returns {Promise} Wallet address of the owner of the NFT + */ + async getOwner(nftId: number | string): Promise { + const accounts = await this.provider.web3.getTokenLargestAccounts(new PublicKey(nftId)) + const accountInfo = (await this.provider.web3.getParsedAccountInfo( + accounts.value[0].address + )) as unknown as RpcResponseAndContext> + return accountInfo.value.data.parsed.info.owner + } + + /** + * @param {number | string} nftId NFT ID + * @returns {Promise} URI of the NFT + */ + async getTokenURI(nftId: number | string): Promise { + return (await this.getMetadata(new PublicKey(nftId)))?.uri ?? '' + } + + /** + * @param {number | string} nftId ID of the NFT that will be transferred + * @returns {Promise} Wallet address of the approved spender + */ + async getApproved(nftId: number | string): Promise { + const accounts = await this.provider.web3.getTokenLargestAccounts(new PublicKey(nftId)) + const accountInfo = (await this.provider.web3.getParsedAccountInfo( + accounts.value[0].address + )) as unknown as RpcResponseAndContext> + return accountInfo.value.data.parsed.info.delegate ?? null + } + + /** + * @param {string} sender Sender address + * @param {string} receiver Receiver address + * @param {number | string} nftId NFT ID + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + nftId: number | string + ): Promise { + return await this.transferFrom(sender, sender, receiver, nftId) + } + + /** + * @param {string} spender Spender address + * @param {string} owner Owner address + * @param {string} receiver Receiver address + * @param {number | string} nftId NFT ID + * @returns {Promise} Transaction signer + */ + async transferFrom( + spender: string, + owner: string, + receiver: string, + nftId: number | string + ): Promise { + // Check if tokens exist + const balance = await this.getBalance(owner) + + if (balance <= 0) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + // Check ownership + const originalOwner = await this.getOwner(nftId) + if (originalOwner !== owner) { + throw new Error(ErrorTypeEnum.UNAUTHORIZED_ADDRESS) + } + + // check if spender different from owner + if (spender !== owner) { + const approved = await this.getApproved(nftId) + if (approved !== spender) { + throw new Error(ErrorTypeEnum.UNAUTHORIZED_ADDRESS) + } + } + + const nftPubKey = new PublicKey(nftId) + const transaction = new Transaction() + const ownerPubKey = new PublicKey(owner) + const spenderPubKey = new PublicKey(spender) + const receiverPubKey = new PublicKey(receiver) + const programId = await this.getProgramId(nftPubKey) + + const ownerAccount = getAssociatedTokenAddressSync(nftPubKey, ownerPubKey, false, programId) + + const receiverAccount = getAssociatedTokenAddressSync( + nftPubKey, + receiverPubKey, + false, + programId + ) + // If the receiver does not have an associated token account, create one + if ((await this.provider.web3.getAccountInfo(receiverAccount)) === null) { + transaction.add( + createAssociatedTokenAccountInstruction( + spenderPubKey, + receiverAccount, + receiverPubKey, + nftPubKey, + programId, + ASSOCIATED_TOKEN_PROGRAM_ID + ) + ) + } + + transaction.add( + createTransferInstruction( + ownerAccount, + receiverAccount, + spenderPubKey, + 1, + [], + programId + ) + ) + + transaction.feePayer = spenderPubKey + + return new NftTransactionSigner(transaction) + } + + /** + * Gives permission to the spender to spend owner's tokens + * @param {string} owner Address of owner of the tokens that will be used + * @param {string} spender Address of the spender that will use the tokens of owner + * @param {number | string} nftId ID of the NFT that will be transferred + * @returns {Promise} Transaction signer + */ + async approve( + owner: string, + spender: string, + nftId: number | string + ): Promise { + // Check if tokens exist + const balance = await this.getBalance(owner) + + if (balance <= 0) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + // Check ownership + const originalOwner = await this.getOwner(nftId) + if (originalOwner !== owner) { + throw new Error(ErrorTypeEnum.UNAUTHORIZED_ADDRESS) + } + + const transaction = new Transaction() + const nftPubKey = new PublicKey(nftId) + const ownerPubKey = new PublicKey(owner) + const spenderPubKey = new PublicKey(spender) + const programId = await this.getProgramId(nftPubKey) + + const ownerAccount = getAssociatedTokenAddressSync(nftPubKey, ownerPubKey, false, programId) + + transaction.add( + createApproveInstruction(ownerAccount, spenderPubKey, ownerPubKey, 1, [], programId) + ) + + transaction.feePayer = ownerPubKey + + return new NftTransactionSigner(transaction) + } +} diff --git a/packages/networks/solana/src/assets/Token.ts b/packages/networks/solana/src/assets/Token.ts new file mode 100644 index 0000000..4ebe7af --- /dev/null +++ b/packages/networks/solana/src/assets/Token.ts @@ -0,0 +1,321 @@ +import { Contract } from './Contract.ts' +import { math } from '@multiplechain/utils' +import { Metaplex } from '@metaplex-foundation/js' +import { ErrorTypeEnum, type TokenInterface } from '@multiplechain/types' +import { TokenTransactionSigner } from '../services/TransactionSigner.ts' +import { + PublicKey, + Transaction, + type AccountInfo, + type ParsedAccountData, + type RpcResponseAndContext +} from '@solana/web3.js' +import { + TOKEN_PROGRAM_ID, + TOKEN_2022_PROGRAM_ID, + getTokenMetadata, + ASSOCIATED_TOKEN_PROGRAM_ID, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountInstruction, + createTransferInstruction, + createApproveInstruction +} from '@solana/spl-token' + +interface Metadata { + name: string + symbol: string + programId: string + decimals: number +} + +export class Token extends Contract implements TokenInterface { + metadata: Metadata + + /** + * Token metadata + */ + async getMetadata(): Promise { + if (this.metadata !== undefined) return this.metadata + + const accountInfo = (await this.provider.web3.getParsedAccountInfo( + this.pubKey + )) as unknown as RpcResponseAndContext> + + if (accountInfo?.value === null) return null + + const programId = accountInfo.value.owner + + if (TOKEN_2022_PROGRAM_ID.equals(programId)) { + const result = await getTokenMetadata( + this.provider.web3, + this.pubKey, + 'confirmed', + programId + ) + if (result === null) return null + return (this.metadata = { + name: result.name, + symbol: result.symbol, + programId: programId.toBase58(), + decimals: accountInfo.value.data.parsed.info.decimals + }) + } else { + const metaplex = Metaplex.make(this.provider.web3) + const data = await metaplex.nfts().findByMint({ mintAddress: this.pubKey }) + return (this.metadata = { + name: data.name, + symbol: data.symbol, + programId: programId.toBase58(), + decimals: accountInfo.value.data.parsed.info.decimals + }) + } + } + + async getProgramId(): Promise { + const accountInfo = await this.provider.web3.getAccountInfo(this.pubKey) + return accountInfo !== null ? accountInfo.owner : TOKEN_PROGRAM_ID + } + + /** + * @returns {Promise} Token name + */ + async getName(): Promise { + await this.getMetadata() + return this.metadata.name + } + + /** + * @returns {Promise} Token symbol + */ + async getSymbol(): Promise { + await this.getMetadata() + return this.metadata.symbol + } + + /** + * @returns {Promise} Decimal value of the token + */ + async getDecimals(): Promise { + await this.getMetadata() + return this.metadata.decimals + } + + /** + * @param {string} owner Wallet address + * @returns {Promise} Wallet balance as currency of TOKEN + */ + async getBalance(owner: string): Promise { + try { + const res = await this.provider.web3.getParsedTokenAccountsByOwner( + new PublicKey(owner), + { + mint: this.pubKey + } + ) + + return res.value[0] === undefined + ? 0 + : res.value[0].account.data.parsed.info.tokenAmount.uiAmount + } catch (error) { + return 0 + } + } + + /** + * @returns {Promise} Total supply of the token + */ + async getTotalSupply(): Promise { + return (await this.provider.web3.getTokenSupply(this.pubKey)).value.uiAmount ?? 0 + } + + /** + * @param {string} owner Address of owner of the tokens that is being used + * @param {string} spender Address of the spender that is using the tokens of owner + * @returns {Promise} Amount of tokens that the spender is allowed to spend + */ + async getAllowance(owner: string, spender?: string): Promise { + try { + const ownerResult = await this.provider.web3.getParsedTokenAccountsByOwner( + new PublicKey(owner), + { + mint: this.pubKey + } + ) + + if (ownerResult.value[0] === undefined) return 0 + + if (ownerResult.value[0].account.data.parsed.info.delegatedAmount === undefined) + return 0 + + if (spender !== undefined) { + if ( + ownerResult.value[0].account.data.parsed.info.delegate.toLowerCase() !== + spender.toLowerCase() + ) + return 0 + } + + return ownerResult.value[0].account.data.parsed.info.delegatedAmount.uiAmount + } catch (error) { + return 0 + } + } + + /** + * @param {number} amount Amount of tokens that will be transferred + * @returns {Promise} Formatted amount + */ + private async formatAmount(amount: number): Promise { + const decimals = await this.getDecimals() + return math.mul(amount, math.pow(10, decimals), decimals) + } + + /** + * transfer() method is the main method for processing transfers for fungible assets (TOKEN, COIN) + * @param {string} sender Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Transaction signer + */ + async transfer( + sender: string, + receiver: string, + amount: number + ): Promise { + return await this.transferFrom(sender, sender, receiver, amount) + } + + /** + * @param {string} spender Address of the spender of transaction + * @param {string} owner Sender wallet address + * @param {string} receiver Receiver wallet address + * @param {number} amount Amount of tokens that will be transferred + * @returns {Promise} Transaction signer + */ + async transferFrom( + spender: string, + owner: string, + receiver: string, + amount: number + ): Promise { + if (amount < 0) { + throw new Error(ErrorTypeEnum.INVALID_AMOUNT) + } + + const balance = await this.getBalance(owner) + + if (amount > balance) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + // check if spender different from owner + if (spender !== owner) { + const allowance = await this.getAllowance(owner, spender) + + if (allowance === 0) { + throw new Error(ErrorTypeEnum.UNAUTHORIZED_ADDRESS) + } + + if (amount > allowance) { + throw new Error(ErrorTypeEnum.INVALID_AMOUNT) + } + } + + const transaction = new Transaction() + const ownerPubKey = new PublicKey(owner) + const spenderPubKey = new PublicKey(spender) + const receiverPubKey = new PublicKey(receiver) + const programId = await this.getProgramId() + const transferAmount = await this.formatAmount(amount) + + const ownerAccount = getAssociatedTokenAddressSync( + this.pubKey, + ownerPubKey, + false, + programId + ) + + const receiverAccount = getAssociatedTokenAddressSync( + this.pubKey, + receiverPubKey, + false, + programId + ) + + // If the receiver does not have an associated token account, create one + if ((await this.provider.web3.getAccountInfo(receiverAccount)) === null) { + transaction.add( + createAssociatedTokenAccountInstruction( + spenderPubKey, + receiverAccount, + receiverPubKey, + this.pubKey, + programId, + ASSOCIATED_TOKEN_PROGRAM_ID + ) + ) + } + + transaction.add( + createTransferInstruction( + ownerAccount, + receiverAccount, + spenderPubKey, + transferAmount, + [], + programId + ) + ) + + transaction.feePayer = spenderPubKey + + return new TokenTransactionSigner(transaction) + } + + /** + * Gives permission to the spender to spend owner's tokens + * @param {string} owner Address of owner of the tokens that will be used + * @param {string} spender Address of the spender that will use the tokens of owner + * @param {number} amount Amount of the tokens that will be used + * @returns {Promise} Transaction signer + */ + async approve(owner: string, spender: string, amount: number): Promise { + if (amount < 0) { + throw new Error(ErrorTypeEnum.INVALID_AMOUNT) + } + + const balance = await this.getBalance(owner) + + if (amount > balance) { + throw new Error(ErrorTypeEnum.INSUFFICIENT_BALANCE) + } + + const transaction = new Transaction() + const ownerPubKey = new PublicKey(owner) + const spenderPubKey = new PublicKey(spender) + const programId = await this.getProgramId() + const approveAmount = await this.formatAmount(amount) + + const ownerAccount = getAssociatedTokenAddressSync( + this.pubKey, + ownerPubKey, + false, + programId + ) + + transaction.add( + createApproveInstruction( + ownerAccount, + spenderPubKey, + ownerPubKey, + approveAmount, + [], + programId + ) + ) + + transaction.feePayer = ownerPubKey + + return new TokenTransactionSigner(transaction) + } +} diff --git a/packages/networks/solana/src/assets/index.ts b/packages/networks/solana/src/assets/index.ts new file mode 100644 index 0000000..7ea522f --- /dev/null +++ b/packages/networks/solana/src/assets/index.ts @@ -0,0 +1,4 @@ +export * from './NFT.ts' +export * from './Coin.ts' +export * from './Token.ts' +export * from './Contract.ts' diff --git a/packages/networks/solana/src/browser/Wallet.ts b/packages/networks/solana/src/browser/Wallet.ts new file mode 100644 index 0000000..156d929 --- /dev/null +++ b/packages/networks/solana/src/browser/Wallet.ts @@ -0,0 +1,239 @@ +import { + type WalletInterface, + type WalletAdapterInterface, + type WalletPlatformEnum, + type TransactionSignerInterface, + type ProviderInterface, + ErrorTypeEnum +} from '@multiplechain/types' +import { Provider } from '../services/Provider.ts' +import type { + BaseMessageSignerWalletAdapter, + WalletAdapterEvents +} from '@solana/wallet-adapter-base' +import { base58Encode } from '@multiplechain/utils' +import type { TransactionSigner } from '../services/TransactionSigner.ts' + +const rejectMap = (error: any, reject: (a: any) => any): any => { + console.error('MultipleChain Solana Wallet Error:', error) + + const errorMessage = String(error.message ?? '') + + if (typeof error === 'object') { + if (errorMessage.includes('QR Code Modal Closed')) { + return reject(new Error(ErrorTypeEnum.CLOSED_WALLETCONNECT_MODAL)) + } + + if (error.name === 'WalletSendTransactionError') { + if ( + errorMessage.includes('Unexpected error') || + errorMessage.includes('Transaction simulation failed: Blockhash not found') || + errorMessage.includes( + 'Transaction results in an account (1) without insufficient funds for rent' + ) + ) { + return reject(error) + } + } + + if ( + [ + 'WalletConnectionError', + 'WalletWindowClosedError', + 'WalletAccountError', + 'WalletSendTransactionError', + 'WalletSignMessageError' + ].includes(String(error.name)) || + error.code === 4001 || + errorMessage === 'User rejected the request.' || + error.name === 'WalletSignTransactionError' || + errorMessage.includes('user reject this request') || + errorMessage.includes('Transaction rejected') || + errorMessage === 'User canceled request' + ) { + return reject(new Error(ErrorTypeEnum.WALLET_REQUEST_REJECTED)) + } else if (error.name === 'WalletTimeoutError') { + return reject(new Error(ErrorTypeEnum.WALLET_CONNECTION_TIMEOUT)) + } else if ( + (errorMessage.length > 0 && errorMessage.includes('403')) || + (errorMessage.length > 0 && errorMessage.includes('Access forbidden')) + ) { + return reject(new Error(ErrorTypeEnum.RPC_ACCESS_DENIED)) + } else if (error.name === 'WalletNotReadyError') { + return reject(new Error(ErrorTypeEnum.WALLET_CONNECTION_FAILED)) + } else if ( + (error.name === 'WalletSendTransactionError' && + errorMessage !== 'User rejected the request') || + errorMessage === 'User disapproved requested chains' + ) { + return reject(new Error(ErrorTypeEnum.UNACCEPTED_CHAIN)) + } + } + + return reject(error) +} + +export class Wallet implements WalletInterface { + adapter: WalletAdapterInterface + + walletProvider: BaseMessageSignerWalletAdapter + + networkProvider: Provider + + currentReject: (a: any) => any + + /** + * @param {WalletAdapterInterface} adapter + * @param {Provider} provider + */ + constructor(adapter: WalletAdapterInterface, provider?: Provider) { + this.adapter = adapter + this.networkProvider = provider ?? Provider.instance + } + + /** + * @returns {string} + */ + getId(): string { + return this.adapter.id + } + + /** + * @returns {string} + */ + getName(): string { + return this.adapter.name + } + + /** + * @returns {string} + */ + getIcon(): string { + return this.adapter.icon + } + + /** + * @returns {WalletPlatformEnum[]} + */ + getPlatforms(): WalletPlatformEnum[] { + return this.adapter.platforms + } + + /** + * @returns {string} + */ + getDownloadLink(): string | undefined { + return this.adapter.downloadLink + } + + /** + * @param {string} url + * @param {object} ops + * @returns {string} + */ + createDeepLink(url: string, ops?: object): string | null { + if (this.adapter.createDeepLink === undefined) { + return null + } + + return this.adapter.createDeepLink(url, ops) + } + + /** + * @param {ProviderInterface} provider + * @param {Object} ops + * @returns {Promise} + */ + async connect(provider?: ProviderInterface, ops?: object): Promise { + return await new Promise((resolve, reject) => { + this.currentReject = reject + this.adapter + .connect(provider, ops) + .then(async (provider) => { + this.walletProvider = provider as BaseMessageSignerWalletAdapter + this.on('error', (error) => rejectMap(error, this.currentReject)) + resolve(await this.getAddress()) + }) + .catch((error) => { + const customReject = (error: any): void => { + if (error.message === ErrorTypeEnum.WALLET_REQUEST_REJECTED) { + reject(new Error(ErrorTypeEnum.WALLET_CONNECT_REJECTED)) + } else { + reject(error) + } + } + rejectMap(error, customReject) + }) + }) + } + + /** + * @returns {boolean} + */ + async isDetected(): Promise { + return await this.adapter.isDetected() + } + + /** + * @returns {boolean} + */ + async isConnected(): Promise { + return await this.adapter.isConnected() + } + + /** + * @returns {Promise} + */ + async getAddress(): Promise { + return this.walletProvider.publicKey?.toBase58() ?? '' + } + + /** + * @param {string} message + */ + async signMessage(message: string): Promise { + return await new Promise((resolve, reject) => { + this.currentReject = reject + this.walletProvider + .signMessage(Buffer.from(message, 'utf8')) + .then((signature: Uint8Array) => { + resolve(base58Encode(signature)) + }) + .catch((error) => { + rejectMap(error, reject) + }) + }) + } + + /** + * @param {TransactionSignerInterface} transactionSigner + * @returns {Promise} + */ + async sendTransaction(_transactionSigner: TransactionSignerInterface): Promise { + const transactionSigner = _transactionSigner as TransactionSigner + return await new Promise((resolve, reject) => { + this.currentReject = reject + try { + void (async () => { + resolve( + await this.walletProvider.sendTransaction( + transactionSigner.getRawData(), + this.networkProvider.web3 + ) + ) + })() + } catch (error) { + rejectMap(error, reject) + } + }) + } + + /** + * @param {string} eventName + * @param {Function} callback + * @returns {void} + */ + on(eventName: string, callback: (...args: any[]) => void): void { + this.walletProvider.on(eventName as keyof WalletAdapterEvents, callback) + } +} diff --git a/packages/networks/solana/src/browser/adapters/BitgetWallet.ts b/packages/networks/solana/src/browser/adapters/BitgetWallet.ts new file mode 100644 index 0000000..be1dead --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/BitgetWallet.ts @@ -0,0 +1,31 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { BitgetWalletAdapter } from '@solana/wallet-adapter-bitkeep' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { WalletReadyState, type BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' + +const bitget = new BitgetWalletAdapter() + +const BitgetWallet: WalletAdapterInterface = { + id: 'bitgetwallet', + name: bitget.name, + icon: bitget.icon, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://web3.bitget.com/en/wallet-download?type=3', + createDeepLink(url: string, _ops?: object): string { + return `https://bkcode.vip?action=dapp&url=${url}` + }, + isDetected: () => bitget.readyState === WalletReadyState.Installed, + isConnected: async () => bitget.connected, + disconnect: async () => { + await bitget.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await bitget.connect() + return bitget as BaseMessageSignerWalletAdapter + } +} + +export default BitgetWallet diff --git a/packages/networks/solana/src/browser/adapters/CoinbaseWallet.ts b/packages/networks/solana/src/browser/adapters/CoinbaseWallet.ts new file mode 100644 index 0000000..a5205ac --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/CoinbaseWallet.ts @@ -0,0 +1,31 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { CoinbaseWalletAdapter } from '@solana/wallet-adapter-coinbase' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { WalletReadyState, type BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' + +const coinbase = new CoinbaseWalletAdapter() + +const CoinbaseWallet: WalletAdapterInterface = { + id: 'coinbasewallet', + name: coinbase.name, + icon: coinbase.icon, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://www.coinbase.com/wallet/downloads', + createDeepLink(url: string, _ops?: object): string { + return `https://go.cb-w.com/dapp?cb_url=${url}` + }, + isDetected: () => coinbase.readyState === WalletReadyState.Installed, + isConnected: async () => coinbase.connected, + disconnect: async () => { + await coinbase.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await coinbase.connect() + return coinbase + } +} + +export default CoinbaseWallet diff --git a/packages/networks/solana/src/browser/adapters/Phantom.ts b/packages/networks/solana/src/browser/adapters/Phantom.ts new file mode 100644 index 0000000..51a77ad --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/Phantom.ts @@ -0,0 +1,45 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { PhantomWalletAdapter } from '@solana/wallet-adapter-phantom' +import type { BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' + +const phantomAdapter = new PhantomWalletAdapter() + +declare global { + interface Window { + phantom?: { + connect?: () => Promise + solana?: { + isPhantom?: boolean + } + } + } +} + +const Phantom: WalletAdapterInterface = { + id: 'phantom', + name: phantomAdapter.name, + icon: phantomAdapter.icon, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://phantom.app/download', + createDeepLink(url: string, _ops?: object): string { + return `https://phantom.app/ul/browse/${url}?ref=${url}` + }, + isDetected: () => + Boolean( + window.phantom?.solana?.isPhantom !== undefined && window.phantom?.connect === undefined + ), + isConnected: async () => phantomAdapter.connected, + disconnect: async () => { + await phantomAdapter.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await phantomAdapter.connect() + return phantomAdapter + } +} + +export default Phantom diff --git a/packages/networks/solana/src/browser/adapters/Slope.ts b/packages/networks/solana/src/browser/adapters/Slope.ts new file mode 100644 index 0000000..1d7fbe6 --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/Slope.ts @@ -0,0 +1,28 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { SlopeWalletAdapter } from '@solana/wallet-adapter-slope' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { WalletReadyState, type BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' + +const slope = new SlopeWalletAdapter() + +const Slope: WalletAdapterInterface = { + id: 'slope', + name: slope.name, + icon: slope.icon, + platforms: [WalletPlatformEnum.BROWSER], + downloadLink: 'https://www.slope.finance/', + isDetected: () => slope.readyState === WalletReadyState.Installed, + isConnected: async () => slope.connected, + disconnect: async () => { + await slope.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await slope.connect() + return slope as BaseMessageSignerWalletAdapter + } +} + +export default Slope diff --git a/packages/networks/solana/src/browser/adapters/Solflare.ts b/packages/networks/solana/src/browser/adapters/Solflare.ts new file mode 100644 index 0000000..69b453a --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/Solflare.ts @@ -0,0 +1,49 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { SolflareWalletAdapter } from '@solana/wallet-adapter-solflare' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { + WalletReadyState, + WalletAdapterNetwork, + type BaseMessageSignerWalletAdapter +} from '@solana/wallet-adapter-base' + +const solflare = new SolflareWalletAdapter() + +declare global { + interface Window { + solflare?: { + isSolflare?: boolean + } + } +} + +const Solflare: WalletAdapterInterface = { + id: 'solflare', + name: solflare.name, + icon: solflare.icon, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://solflare.com/download#extension', + createDeepLink(url: string, _ops?: object): string { + return `https://solflare.com/ul/v1/browse/${url}?ref=${url}` + }, + isDetected: () => solflare.readyState === WalletReadyState.Installed, + isConnected: async () => solflare.connected, + disconnect: async () => { + await solflare.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + const solflare = new SolflareWalletAdapter({ + network: + _provider !== undefined && _provider?.isTestnet() + ? WalletAdapterNetwork.Devnet + : WalletAdapterNetwork.Mainnet + }) + await solflare.connect() + return solflare + } +} + +export default Solflare diff --git a/packages/networks/solana/src/browser/adapters/TokenPocket.ts b/packages/networks/solana/src/browser/adapters/TokenPocket.ts new file mode 100644 index 0000000..12725d6 --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/TokenPocket.ts @@ -0,0 +1,38 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { TokenPocketWalletAdapter } from '@solana/wallet-adapter-tokenpocket' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { WalletReadyState, type BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' + +const tokenPocket = new TokenPocketWalletAdapter() + +const TokenPocket: WalletAdapterInterface = { + id: 'tokenpocket', + name: tokenPocket.name, + icon: tokenPocket.icon, + platforms: [WalletPlatformEnum.MOBILE], + downloadLink: 'https://www.tokenpocket.pro/en/download/app', + createDeepLink(url: string, _ops?: object): string { + return ( + 'tpdapp://open?params=' + + JSON.stringify({ + url, + chain: 'Solana', + source: url + }) + ) + }, + isDetected: () => tokenPocket.readyState === WalletReadyState.Installed, + isConnected: async () => tokenPocket.connected, + disconnect: async () => { + await tokenPocket.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await tokenPocket.connect() + return tokenPocket as BaseMessageSignerWalletAdapter + } +} + +export default TokenPocket diff --git a/packages/networks/solana/src/browser/adapters/TrustWallet.ts b/packages/networks/solana/src/browser/adapters/TrustWallet.ts new file mode 100644 index 0000000..3ed7a93 --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/TrustWallet.ts @@ -0,0 +1,31 @@ +import { WalletPlatformEnum } from '@multiplechain/types' +import { TrustWalletAdapter } from '@solana/wallet-adapter-trust' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { WalletReadyState, type BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' + +const trustIcon = + 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTgiIGhlaWdodD0iNjUiIHZpZXdCb3g9IjAgMCA1OCA2NSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTAgOS4zODk0OUwyOC44OTA3IDBWNjUuMDA0MkM4LjI1NDUgNTYuMzM2OSAwIDM5LjcyNDggMCAzMC4zMzUzVjkuMzg5NDlaIiBmaWxsPSIjMDUwMEZGIi8+CjxwYXRoIGQ9Ik01Ny43ODIyIDkuMzg5NDlMMjguODkxNSAwVjY1LjAwNDJDNDkuNTI3NyA1Ni4zMzY5IDU3Ljc4MjIgMzkuNzI0OCA1Ny43ODIyIDMwLjMzNTNWOS4zODk0OVoiIGZpbGw9InVybCgjcGFpbnQwX2xpbmVhcl8yMjAxXzY5NDIpIi8+CjxkZWZzPgo8bGluZWFyR3JhZGllbnQgaWQ9InBhaW50MF9saW5lYXJfMjIwMV82OTQyIiB4MT0iNTEuMzYxNSIgeTE9Ii00LjE1MjkzIiB4Mj0iMjkuNTM4NCIgeTI9IjY0LjUxNDciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KPHN0b3Agb2Zmc2V0PSIwLjAyMTEyIiBzdG9wLWNvbG9yPSIjMDAwMEZGIi8+CjxzdG9wIG9mZnNldD0iMC4wNzYyNDIzIiBzdG9wLWNvbG9yPSIjMDA5NEZGIi8+CjxzdG9wIG9mZnNldD0iMC4xNjMwODkiIHN0b3AtY29sb3I9IiM0OEZGOTEiLz4KPHN0b3Agb2Zmc2V0PSIwLjQyMDA0OSIgc3RvcC1jb2xvcj0iIzAwOTRGRiIvPgo8c3RvcCBvZmZzZXQ9IjAuNjgyODg2IiBzdG9wLWNvbG9yPSIjMDAzOEZGIi8+CjxzdG9wIG9mZnNldD0iMC45MDI0NjUiIHN0b3AtY29sb3I9IiMwNTAwRkYiLz4KPC9saW5lYXJHcmFkaWVudD4KPC9kZWZzPgo8L3N2Zz4K' + +const trust = new TrustWalletAdapter() + +const TrustWallet: WalletAdapterInterface = { + id: 'trustwallet', + name: 'TrustWallet', + icon: trustIcon, + platforms: [WalletPlatformEnum.BROWSER, WalletPlatformEnum.MOBILE], + downloadLink: 'https://trustwallet.com/download', + isDetected: () => trust.readyState === WalletReadyState.Installed, + isConnected: async () => trust.connected, + disconnect: async () => { + await trust.disconnect() + }, + connect: async ( + _provider?: ProviderInterface, + _ops?: object + ): Promise => { + await trust.connect() + return trust as BaseMessageSignerWalletAdapter + } +} + +export default TrustWallet diff --git a/packages/networks/solana/src/browser/adapters/WalletConnect.ts b/packages/networks/solana/src/browser/adapters/WalletConnect.ts new file mode 100644 index 0000000..3b945ff --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/WalletConnect.ts @@ -0,0 +1,79 @@ +import { ErrorTypeEnum, WalletPlatformEnum } from '@multiplechain/types' +import WalletConnectWalletAdapter from '@multiplechain/solana-walletconnect' +import { + WalletAdapterNetwork, + type BaseMessageSignerWalletAdapter +} from '@solana/wallet-adapter-base' +import type { + ProviderInterface, + WalletAdapterInterface, + WalletConnectOps +} from '@multiplechain/types' + +const icon = + 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJiYXNpYyIgaWQ9IkxheWVyXzEiCgkgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCAzODcuNiAyMzcuNiIKCSB4bWw6c3BhY2U9InByZXNlcnZlIj4KPHBhdGggaWQ9IldhbGxldENvbm5lY3RfMDAwMDAwNzM3MDMwNjM0MzgyMjA2NDI3MzAwMDAwMDI5MTc3MTc1NTIyMzY0NzI0OTZfIiBmaWxsPSIjM0I5OUZDIiBkPSJNNzkuNCw0Ni40CgljNjMuMi02MS45LDE2NS43LTYxLjksMjI4LjksMGw3LjYsNy40YzMuMiwzLjEsMy4yLDguMSwwLDExLjJsLTI2LDI1LjVjLTEuNiwxLjUtNC4xLDEuNS01LjcsMGwtMTAuNS0xMC4zCgljLTQ0LjEtNDMuMi0xMTUuNi00My4yLTE1OS43LDBsLTExLjIsMTFjLTEuNiwxLjUtNC4xLDEuNS01LjcsMEw3MSw2NS44Yy0zLjItMy4xLTMuMi04LjEsMC0xMS4yTDc5LjQsNDYuNHogTTM2Mi4xLDk5LjFsMjMuMiwyMi43CgljMy4yLDMuMSwzLjIsOC4xLDAsMTEuMkwyODAuOCwyMzUuM2MtMy4yLDMuMS04LjMsMy4xLTExLjQsMGMwLDAsMCwwLDAsMGwtNzQuMS03Mi42Yy0wLjgtMC44LTIuMS0wLjgtMi45LDBjMCwwLDAsMCwwLDAKCWwtNzQuMSw3Mi42Yy0zLjIsMy4xLTguMywzLjEtMTEuNCwwYzAsMCwwLDAsMCwwTDIuNCwxMzNjLTMuMi0zLjEtMy4yLTguMSwwLTExLjJsMjMuMi0yMi43YzMuMi0zLjEsOC4zLTMuMSwxMS40LDBsNzQuMSw3Mi42CgljMC44LDAuOCwyLjEsMC44LDIuOSwwYzAsMCwwLDAsMCwwbDc0LjEtNzIuNmMzLjItMy4xLDguMy0zLjEsMTEuNCwwYzAsMCwwLDAsMCwwbDc0LjEsNzIuNmMwLjgsMC44LDIuMSwwLjgsMi45LDBsNzQuMS03Mi42CglDMzUzLjgsOTYsMzU4LjksOTYsMzYyLjEsOTkuMXoiLz4KPC9zdmc+' + +let isConnected = false + +const WalletConnect: WalletAdapterInterface = { + icon, + id: 'walletconnect', + name: 'WalletConnect', + platforms: [WalletPlatformEnum.UNIVERSAL], + isDetected: () => true, + isConnected: () => isConnected, + disconnect: async () => { + isConnected = false + Object.keys(localStorage) + .filter((x) => x.startsWith('wc@2')) + .forEach((x) => { + localStorage.removeItem(x) + }) + localStorage.removeItem('walletconnect') + localStorage.removeItem('WALLETCONNECT_DEEPLINK_CHOICE') + indexedDB.deleteDatabase('WALLET_CONNECT_V2_INDEXED_DB') + }, + connect: async ( + provider?: ProviderInterface, + _ops?: WalletConnectOps | object + ): Promise => { + const ops = _ops as WalletConnectOps + + if (provider === undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_REQUIRED) + } + + if (ops === undefined) { + throw new Error(ErrorTypeEnum.OPS_IS_REQUIRED) + } + + if (ops.projectId === undefined) { + throw new Error(ErrorTypeEnum.PROJECT_ID_IS_REQUIRED) + } + + const walletConnect = new WalletConnectWalletAdapter({ + network: provider.isTestnet() + ? WalletAdapterNetwork.Devnet + : WalletAdapterNetwork.Mainnet, + options: { + projectId: ops.projectId, + relayUrl: 'wss://relay.walletconnect.com', + qrcodeModalOptions: { + mobileLinks: ['trust'], + desktopLinks: [ + // 'zerion', + // 'ledger' + ] + } + } + }) + + await walletConnect.connect() + + isConnected = true + + return walletConnect + } +} + +export default WalletConnect diff --git a/packages/networks/solana/src/browser/adapters/Web3Modal.ts b/packages/networks/solana/src/browser/adapters/Web3Modal.ts new file mode 100644 index 0000000..c8dd207 --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/Web3Modal.ts @@ -0,0 +1,185 @@ +import type { Metadata } from '@web3modal/core' +import { solana, solanaDevnet } from '@web3modal/solana/chains' +import { ErrorTypeEnum, WalletPlatformEnum } from '@multiplechain/types' +import type { BaseMessageSignerWalletAdapter } from '@solana/wallet-adapter-base' +import type { ProviderInterface, WalletAdapterInterface } from '@multiplechain/types' +import { + createWeb3Modal, + defaultSolanaConfig, + type Web3ModalOptions, + type Web3Modal as Web3ModalType +} from '@web3modal/solana' + +const icon = + 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKIHdpZHRoPSI0MDAuMDAwMDAwcHQiIGhlaWdodD0iNDAwLjAwMDAwMHB0IiB2aWV3Qm94PSIwIDAgNDAwLjAwMDAwMCA0MDAuMDAwMDAwIgogcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQgbWVldCI+Cgo8ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLjAwMDAwMCw0MDAuMDAwMDAwKSBzY2FsZSgwLjEwMDAwMCwtMC4xMDAwMDApIgpmaWxsPSIjMDAwMDAwIiBzdHJva2U9Im5vbmUiPgo8cGF0aCBkPSJNMCAyMDAwIGwwIC0yMDAwIDIwMDAgMCAyMDAwIDAgMCAyMDAwIDAgMjAwMCAtMjAwMCAwIC0yMDAwIDAgMAotMjAwMHogbTIyNjQgNzM2IGMxMjQgLTMyIDI2MSAtOTggMzYzIC0xNzUgOTEgLTY5IDE3MyAtMTUzIDE3MyAtMTc4IDAgLTE3Ci0xODcgLTIwMiAtMjA1IC0yMDMgLTYgMCAtMzEgMjEgLTU1IDQ2IC0yMjcgMjM0IC01NjkgMjk5IC04NTcgMTY0IC03OSAtMzYKLTEzMSAtNzMgLTIxMyAtMTQ5IC0zNiAtMzMgLTcyIC02MCAtODAgLTYxIC0yMCAwIC0yMDAgMTgxIC0yMDAgMjAyIDAgMjQgNDkKNzggMTM2IDE0OCAxMzYgMTA5IDI4MSAxNzkgNDQxIDIxNSAxMDYgMjMgMTE5IDI0IDI2MyAyMCAxMDQgLTMgMTU4IC0xMCAyMzQKLTI5eiBtLTEyODQgLTYwMyBjMTQgLTkgMTMwIC0xMjAgMjU4IC0yNDYgbDIzMyAtMjMxIDU3IDU1IGMzMSAyOSAxNDUgMTQxCjI1MyAyNDYgMTEwIDEwOSAyMDMgMTkzIDIxMyAxOTMgMjAgMCAzOSAtMTggNTIyIC00OTAgMyAtMiA3OCA2OCAxNjcgMTU2IDI3MAoyNjYgMzQ0IDMzNCAzNjIgMzM0IDEwIDAgNTcgLTM5IDEwNiAtODcgNjcgLTY1IDg5IC05MyA4OSAtMTEzIDAgLTIxIC02NiAtOTAKLTM0MSAtMzYwIC0xODggLTE4NCAtMzUwIC0zMzkgLTM2MCAtMzQ0IC0xMSAtNSAtMjcgLTUgLTM4IDAgLTExIDUgLTEyOCAxMTYKLTI2MSAyNDcgLTEzMyAxMzEgLTI0NSAyMzYgLTI0OCAyMzIgLTEzNiAtMTM4IC00OTAgLTQ3MyAtNTA4IC00NzkgLTI4IC0xMQotMTYgLTIyIC00NTEgNDA2IC0yMDMgMTk5IC0yODMgMjg0IC0yODMgMzAwIDAgMjggMTcxIDE5OCAyMDAgMTk4IDMgMCAxNyAtNwozMCAtMTd6Ii8+CjwvZz4KPC9zdmc+Cg==' + +export interface Web3ModalOps extends Web3ModalOptions { + metadata: Metadata +} + +export interface Web3ModalAdapterInterface extends Omit { + connect: ( + provider?: ProviderInterface, + ops?: Web3ModalOps | object + ) => Promise +} + +interface Chain { + rpcUrl: string + explorerUrl: string + currency: string + name: string + chainId: string +} + +let modal: Web3ModalType +let currentNetwork: Chain +let clickedAnyWallet = false +let connectRejectMethod: (reason?: any) => void +let connectResolveMethod: ( + value: BaseMessageSignerWalletAdapter | PromiseLike +) => void + +const web3Modal = (ops: Web3ModalOps): Web3ModalType => { + if (modal !== undefined) { + return modal + } + + const chains = [solana, solanaDevnet] + + const solanaConfig = defaultSolanaConfig({ + chains, + projectId: ops.projectId, + metadata: ops.metadata + }) + + modal = createWeb3Modal({ + chains, + solanaConfig, + metadata: ops.metadata, + projectId: ops.projectId, + themeMode: ops.themeMode, + allowUnsupportedChain: true, + defaultChain: currentNetwork, + customWallets: ops.customWallets, + themeVariables: { + '--w3m-z-index': 999999999999 + } + }) + + modal.subscribeEvents(async (event) => { + if (event.data.event === 'SELECT_WALLET') { + clickedAnyWallet = true + } + if (event.data.event === 'MODAL_CLOSE') { + if (clickedAnyWallet) { + clickedAnyWallet = false + } else { + connectRejectMethod(new Error(ErrorTypeEnum.CLOSED_WALLETCONNECT_MODAL)) + } + } + }) + + modal.subscribeProvider(async (ctx) => { + if (ctx.provider === undefined) { + return + } + + if (`solana:${currentNetwork.chainId}` !== ctx.caipChainId) { + await modal + .switchNetwork({ + id: `solana:${currentNetwork.chainId}`, + name: currentNetwork.name + }) + .catch(() => { + connectRejectMethod(new Error(ErrorTypeEnum.WALLET_CONNECT_REJECTED)) + }) + } + + if (ctx.provider !== undefined && ctx.provider.on === undefined) { + ctx.provider.on = (_eventName: string, _callback: (...args: any[]) => void): void => { + // WalletConnectProvider does not have an on method + } + } + + // @ts-expect-error this provider methods enought for our needs + connectResolveMethod(ctx.provider as BaseMessageSignerWalletAdapter) + }) + + return modal +} + +const Web3Modal: Web3ModalAdapterInterface = { + icon, + id: 'web3modal', + name: 'Web3Modal', + platforms: [WalletPlatformEnum.UNIVERSAL], + isDetected: () => true, + isConnected: () => { + if (modal === undefined) { + return false + } + + return modal.getAddress() !== undefined + }, + disconnect: async () => { + Object.keys(localStorage) + .filter((x) => { + return ( + x.startsWith('wc@2') || + x.startsWith('@w3m') || + x.startsWith('W3M') || + x.startsWith('-walletlink') + ) + }) + .forEach((x) => { + localStorage.removeItem(x) + }) + + indexedDB.deleteDatabase('WALLET_CONNECT_V2_INDEXED_DB') + + if (modal?.disconnect !== undefined) { + modal.disconnect() + } + }, + connect: async ( + provider?: ProviderInterface, + _ops?: Web3ModalOps | object + ): Promise => { + const ops = _ops as Web3ModalOps + + if (provider === undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_REQUIRED) + } + + if (ops === undefined) { + throw new Error(ErrorTypeEnum.OPS_IS_REQUIRED) + } + + if (ops.projectId === undefined) { + throw new Error(ErrorTypeEnum.PROJECT_ID_IS_REQUIRED) + } + + if (ops.metadata === undefined) { + throw new Error(ErrorTypeEnum.METADATA_IS_REQUIRED) + } + + currentNetwork = provider.isTestnet() ? solanaDevnet : solana + + return await new Promise((resolve, reject) => { + try { + const modal = web3Modal(ops) + connectRejectMethod = async (reason) => { + modal.disconnect() + reject(reason) + } + connectResolveMethod = resolve + void modal.open({ view: 'Connect' }) + } catch (error) { + reject(error) + } + }) + } +} + +export default Web3Modal diff --git a/packages/networks/solana/src/browser/adapters/index.ts b/packages/networks/solana/src/browser/adapters/index.ts new file mode 100644 index 0000000..4afca6c --- /dev/null +++ b/packages/networks/solana/src/browser/adapters/index.ts @@ -0,0 +1,9 @@ +export { default as Slope } from './Slope.ts' +export { default as Phantom } from './Phantom.ts' +export { default as Solflare } from './Solflare.ts' +export { default as Web3Modal } from './Web3Modal.ts' +export { default as TrustWallet } from './TrustWallet.ts' +export { default as TokenPocket } from './TokenPocket.ts' +export { default as BitgetWallet } from './BitgetWallet.ts' +export { default as WalletConnect } from './WalletConnect.ts' +export { default as CoinbaseWallet } from './CoinbaseWallet.ts' diff --git a/packages/networks/solana/src/browser/index.ts b/packages/networks/solana/src/browser/index.ts new file mode 100644 index 0000000..787e9bd --- /dev/null +++ b/packages/networks/solana/src/browser/index.ts @@ -0,0 +1,25 @@ +import { Wallet } from './Wallet.ts' +import * as adapterList from './adapters/index.ts' +import type { + WalletAdapterListType, + WalletAdapterInterface, + RegisterWalletAdapterType +} from '@multiplechain/types' + +const adapters: WalletAdapterListType = {} + +const registerAdapter: RegisterWalletAdapterType = (adapter: WalletAdapterInterface): void => { + if (Object.values(adapters).find((a) => a.id === adapter.id) !== undefined) { + throw new Error(`Adapter with id ${adapter.id} already exists`) + } + + adapters[adapter.id] = adapter +} + +export * from '../index.ts' + +export const browser = { + Wallet, + registerAdapter, + adapters: Object.assign(adapters, adapterList) +} diff --git a/packages/networks/solana/src/index.ts b/packages/networks/solana/src/index.ts new file mode 100644 index 0000000..7b0e1cd --- /dev/null +++ b/packages/networks/solana/src/index.ts @@ -0,0 +1,8 @@ +export * from './services/Provider.ts' + +export * as assets from './assets/index.ts' +export * as models from './models/index.ts' +export * as services from './services/index.ts' + +export * as utils from './utils.ts' +export * as types from '@multiplechain/types' diff --git a/packages/networks/solana/src/models/CoinTransaction.ts b/packages/networks/solana/src/models/CoinTransaction.ts new file mode 100644 index 0000000..1adc260 --- /dev/null +++ b/packages/networks/solana/src/models/CoinTransaction.ts @@ -0,0 +1,96 @@ +import { fromLamports } from '../utils.ts' +import { Transaction } from './Transaction.ts' +import type { ParsedInstruction } from '@solana/web3.js' +import { TransactionStatusEnum } from '@multiplechain/types' +import { AssetDirectionEnum, type CoinTransactionInterface } from '@multiplechain/types' + +export class CoinTransaction extends Transaction implements CoinTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + findTransferInstruction(data: any): ParsedInstruction | null { + return ( + (data.transaction.message.instructions.find((instruction: any): boolean => { + return ( + instruction.parsed !== undefined && + (instruction.parsed.type === 'transfer' || + instruction.parsed.type === 'createAccount') + ) + }) as ParsedInstruction) ?? null + ) + } + + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + async getReceiver(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + const instruction = this.findTransferInstruction(data) + + return instruction?.parsed.info.destination ?? instruction?.parsed.info.newAccount ?? '' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + return this.findTransferInstruction(data)?.parsed.info.source ?? '' + } + + /** + * @returns {Promise} Amount of coin that will be transferred + */ + async getAmount(): Promise { + const data = await this.getData() + if (data === null) { + return 0 + } + + return fromLamports( + (this.findTransferInstruction(data)?.parsed.info.lamports as number) ?? 0 + ) + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (asset) + * @param {string} address - Wallet address of the receiver or sender of the transaction, dependant on direction + * @param {number} amount Amount of assets that will be transferred + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + amount: number + ): Promise { + const status = await this.getStatus() + + if (status === TransactionStatusEnum.PENDING) { + return TransactionStatusEnum.PENDING + } + + if ((await this.getAmount()) !== amount) { + return TransactionStatusEnum.FAILED + } + + if (direction === AssetDirectionEnum.INCOMING) { + if ((await this.getReceiver()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } else { + if ((await this.getSender()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } + + return TransactionStatusEnum.CONFIRMED + } +} diff --git a/packages/networks/solana/src/models/ContractTransaction.ts b/packages/networks/solana/src/models/ContractTransaction.ts new file mode 100644 index 0000000..4fd88e2 --- /dev/null +++ b/packages/networks/solana/src/models/ContractTransaction.ts @@ -0,0 +1,25 @@ +import { Transaction } from './Transaction.ts' +import type { ParsedInstruction } from '@solana/web3.js' +import type { ContractTransactionInterface } from '@multiplechain/types' + +export class ContractTransaction extends Transaction implements ContractTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + findTransferInstruction(data: any): ParsedInstruction | null { + const length = data.transaction.message.instructions.length + return data.transaction.message.instructions[length - 1] as ParsedInstruction + } + + /** + * @returns {Promise} Contract address of the transaction + */ + async getAddress(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + return this.findTransferInstruction(data)?.programId.toBase58() ?? '' + } +} diff --git a/packages/networks/solana/src/models/NftTransaction.ts b/packages/networks/solana/src/models/NftTransaction.ts new file mode 100644 index 0000000..31de29f --- /dev/null +++ b/packages/networks/solana/src/models/NftTransaction.ts @@ -0,0 +1,124 @@ +import type { ParsedInstruction } from '@solana/web3.js' +import { TransactionStatusEnum } from '@multiplechain/types' +import { ContractTransaction } from './ContractTransaction.ts' +import { type NftTransactionInterface, AssetDirectionEnum } from '@multiplechain/types' + +export class NftTransaction extends ContractTransaction implements NftTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + findTransferInstruction(data: any): ParsedInstruction | null { + return ( + (data.transaction.message.instructions.find((instruction: any): boolean => { + return ( + instruction.parsed !== undefined && + (instruction.parsed.type === 'transferChecked' || + instruction.parsed.type === 'transfer') + ) + }) as ParsedInstruction) ?? null + ) + } + + /** + * @returns {Promise} Contract address of the transaction + */ + async getAddress(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + const instruction = this.findTransferInstruction(data) + + if (instruction?.parsed?.info.mint !== undefined) { + return instruction.parsed.info.mint + } + + const postBalance = data.meta?.postTokenBalances?.find((balance: any): boolean => { + return balance.mint !== undefined + }) + + if (postBalance !== undefined) { + return postBalance.mint + } + + return await super.getAddress() + } + + /** + * @returns {Promise} Receiver wallet address + */ + async getReceiver(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + if (data.meta?.postTokenBalances?.length === undefined) { + return '' + } + + return data.meta.postTokenBalances[0].owner ?? '' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + const data = await this.getData() + + if (data === null) { + return '' + } + + return this.findTransferInstruction(data)?.parsed.info.authority + } + + /** + * @returns {Promise} NFT ID + */ + async getNftId(): Promise { + const data = await this.getData() + + if (data === null) { + return '' + } + + return this.findTransferInstruction(data)?.parsed.info.mint + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (nft) + * @param {string} address - Wallet address of the receiver or sender of the transaction, dependant on direction + * @param {string} nftId ID of the NFT that will be transferred + * @override verifyTransfer() in AssetTransactionInterface + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + nftId: string | number + ): Promise { + const status = await this.getStatus() + + if (status === TransactionStatusEnum.PENDING) { + return TransactionStatusEnum.PENDING + } + + if ((await this.getNftId()) !== nftId) { + return TransactionStatusEnum.FAILED + } + + if (direction === AssetDirectionEnum.INCOMING) { + if ((await this.getReceiver()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } else { + if ((await this.getSender()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } + + return TransactionStatusEnum.CONFIRMED + } +} diff --git a/packages/networks/solana/src/models/TokenTransaction.ts b/packages/networks/solana/src/models/TokenTransaction.ts new file mode 100644 index 0000000..d748020 --- /dev/null +++ b/packages/networks/solana/src/models/TokenTransaction.ts @@ -0,0 +1,138 @@ +import { PublicKey } from '@solana/web3.js' +import { math } from '@multiplechain/utils' +import { TransactionStatusEnum } from '@multiplechain/types' +import { ContractTransaction } from './ContractTransaction.ts' +import type { ParsedAccountData, ParsedInstruction } from '@solana/web3.js' +import { AssetDirectionEnum, type TokenTransactionInterface } from '@multiplechain/types' + +export class TokenTransaction extends ContractTransaction implements TokenTransactionInterface { + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + findTransferInstruction(data: any): ParsedInstruction | null { + return ( + (data.transaction.message.instructions.find((instruction: any): boolean => { + return ( + instruction.parsed !== undefined && + (instruction.parsed.type === 'transferChecked' || + instruction.parsed.type === 'transfer') + ) + }) as ParsedInstruction) ?? null + ) + } + + /** + * @returns {Promise} Contract address of the transaction + */ + async getAddress(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + const instruction = this.findTransferInstruction(data) + + if (instruction?.parsed?.info.mint !== undefined) { + return instruction.parsed.info.mint + } + + const postBalance = data.meta?.postTokenBalances?.find((balance: any): boolean => { + return balance.mint !== undefined + }) + + if (postBalance !== undefined) { + return postBalance.mint + } + + return await super.getAddress() + } + + /** + * @returns {Promise} Wallet address of the receiver of transaction + */ + async getReceiver(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + const instruction = this.findTransferInstruction(data) + const accountInfo = await this.provider.web3.getParsedAccountInfo( + new PublicKey(instruction?.parsed.info.destination as string) + ) + + return (accountInfo.value?.data as ParsedAccountData)?.parsed?.info?.owner ?? '' + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSender(): Promise { + const data = await this.getData() + if (data === null) { + return '' + } + + return this.findTransferInstruction(data)?.parsed.info.authority + } + + /** + * @returns {Promise} Amount of tokens that will be transferred + */ + async getAmount(): Promise { + const data = await this.getData() + if (data === null) { + return 0 + } + + const instruction = this.findTransferInstruction(data) + + if (instruction?.parsed?.info?.tokenAmount?.uiAmount !== undefined) { + return instruction.parsed.info.tokenAmount.uiAmount as number + } + + const amount = instruction?.parsed.info.amount as number + + const postBalance = data.meta?.postTokenBalances?.find((balance: any): boolean => { + return balance.mint !== undefined + }) + + const decimals = postBalance?.uiTokenAmount?.decimals ?? 0 + + return math.div(amount, math.pow(10, decimals), decimals) + } + + /** + * @param {AssetDirectionEnum} direction - Direction of the transaction (token) + * @param {string} address - Wallet address of the owner or spender of the transaction, dependant on direction + * @param {number} amount Amount of tokens that will be approved + * @returns {Promise} Status of the transaction + */ + async verifyTransfer( + direction: AssetDirectionEnum, + address: string, + amount: number + ): Promise { + const status = await this.getStatus() + + if (status === TransactionStatusEnum.PENDING) { + return TransactionStatusEnum.PENDING + } + + if ((await this.getAmount()) !== amount) { + return TransactionStatusEnum.FAILED + } + + if (direction === AssetDirectionEnum.INCOMING) { + if ((await this.getReceiver()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } else { + if ((await this.getSender()).toLowerCase() !== address.toLowerCase()) { + return TransactionStatusEnum.FAILED + } + } + + return TransactionStatusEnum.CONFIRMED + } +} diff --git a/packages/networks/solana/src/models/Transaction.ts b/packages/networks/solana/src/models/Transaction.ts new file mode 100644 index 0000000..6daa7cd --- /dev/null +++ b/packages/networks/solana/src/models/Transaction.ts @@ -0,0 +1,166 @@ +import { fromLamports } from '../utils.ts' +import { Provider } from '../services/Provider.ts' +import type { TransactionInterface } from '@multiplechain/types' +import type { ParsedTransactionWithMeta } from '@solana/web3.js' +import { ErrorTypeEnum, TransactionStatusEnum } from '@multiplechain/types' + +export class Transaction implements TransactionInterface { + /** + * Each transaction has its own unique ID defined by the user + */ + id: string + + /** + * Blockchain network provider + */ + provider: Provider + + data: ParsedTransactionWithMeta | null = null + + /** + * @param {string} id Transaction id + * @param {Provider} provider Blockchain network provider + */ + constructor(id: string, provider?: Provider) { + this.id = id + this.provider = provider ?? Provider.instance + } + + /** + * @returns {Promise} Transaction data + */ + async getData(): Promise { + if (this.data !== null) { + return this.data + } + try { + const data = await this.provider.web3.getParsedTransaction(this.id, { + commitment: 'confirmed' + }) + + if (data === null) { + return null + } + + return (this.data = data) + } catch (error) { + throw new Error(ErrorTypeEnum.RPC_REQUEST_ERROR) + } + } + + /** + * @param {number} ms - Milliseconds to wait for the transaction to be confirmed. Default is 4000ms + * @returns {Promise} Status of the transaction + */ + async wait(ms: number = 4000): Promise { + return await new Promise((resolve, reject) => { + const check = async (): Promise => { + try { + let status = await this.getStatus() + if (status === TransactionStatusEnum.PENDING) { + const latestBlockHash = await this.provider.web3.getLatestBlockhash() + await this.provider.web3.confirmTransaction( + { + signature: this.id, + blockhash: latestBlockHash.blockhash, + lastValidBlockHeight: latestBlockHash.lastValidBlockHeight + }, + 'finalized' + ) + status = await this.getStatus() + } + if (status === TransactionStatusEnum.CONFIRMED) { + resolve(TransactionStatusEnum.CONFIRMED) + return + } else if (status === TransactionStatusEnum.FAILED) { + reject(TransactionStatusEnum.FAILED) + return + } + setTimeout(check, ms) + } catch (error) { + reject(TransactionStatusEnum.FAILED) + } + } + void check() + }) + } + + /** + * @returns {string} Transaction ID + */ + getId(): string { + return this.id + } + + /** + * @returns {string} Transaction URL + */ + getUrl(): string { + const node = this.provider.node + let transactionUrl = this.provider.node.explorerUrl + 'tx/' + this.id + transactionUrl += node.cluster !== 'mainnet-beta' ? '?cluster=' + node.cluster : '' + return transactionUrl + } + + /** + * @returns {Promise} Wallet address of the sender of transaction + */ + async getSigner(): Promise { + const data = await this.getData() + return ( + data?.transaction?.message?.accountKeys + .find((account) => { + return account.signer + }) + ?.pubkey.toBase58() ?? '' + ) + } + + /** + * @returns {Promise} Transaction fee + */ + async getFee(): Promise { + const data = await this.getData() + return fromLamports(data?.meta?.fee ?? 0) + } + + /** + * @returns {Promise} Block number that transaction + */ + async getBlockNumber(): Promise { + const data = await this.getData() + return data?.slot ?? 0 + } + + /** + * @returns {Promise} Block timestamp that transaction + */ + async getBlockTimestamp(): Promise { + const data = await this.getData() + return data?.blockTime ?? 0 + } + + /** + * @returns {Promise} Confirmation count of the block + */ + async getBlockConfirmationCount(): Promise { + const data = await this.getData() + const currentSlot = await this.provider.web3.getSlot() + return currentSlot - (data?.slot ?? 0) + } + + /** + * @returns {Promise} Status of the transaction + */ + async getStatus(): Promise { + const data = await this.getData() + + if (data === null) { + return TransactionStatusEnum.PENDING + } + + return data.meta?.err !== null + ? TransactionStatusEnum.FAILED + : TransactionStatusEnum.CONFIRMED + } +} diff --git a/packages/networks/solana/src/models/index.ts b/packages/networks/solana/src/models/index.ts new file mode 100644 index 0000000..cc0a27c --- /dev/null +++ b/packages/networks/solana/src/models/index.ts @@ -0,0 +1,5 @@ +export * from './Transaction.ts' +export * from './NftTransaction.ts' +export * from './CoinTransaction.ts' +export * from './TokenTransaction.ts' +export * from './ContractTransaction.ts' diff --git a/packages/networks/solana/src/services/Provider.ts b/packages/networks/solana/src/services/Provider.ts new file mode 100644 index 0000000..717de6c --- /dev/null +++ b/packages/networks/solana/src/services/Provider.ts @@ -0,0 +1,150 @@ +import axios from 'axios' +import { + ErrorTypeEnum, + type NetworkConfigInterface, + type ProviderInterface +} from '@multiplechain/types' +import { Connection } from '@solana/web3.js' +import { checkWebSocket } from '@multiplechain/utils' + +export interface SolanaNodeInfoInterface { + name: string + cluster: string + wsUrl?: string + rpcUrl: string + explorerUrl: string +} + +export type SolanaNodeInfoListInterface = Record + +export class Provider implements ProviderInterface { + /** + * Network configuration of the provider + */ + network: NetworkConfigInterface + + /** + * Node list + */ + nodes: SolanaNodeInfoListInterface = { + mainnet: { + name: 'Mainnet', + cluster: 'mainnet-beta', + rpcUrl: 'https://api.mainnet-beta.solana.com/', + explorerUrl: 'https://solscan.io/' + }, + devnet: { + name: 'Devnet', + cluster: 'devnet', + rpcUrl: 'https://api.devnet.solana.com/', + explorerUrl: 'https://solscan.io/' + } + } + + /** + * Node information + */ + node: SolanaNodeInfoInterface + + /** + * Static instance of the provider + */ + private static _instance: Provider + + web3: Connection + + /** + * @param network - Network configuration of the provider + */ + constructor(network: NetworkConfigInterface) { + this.update(network) + } + + /** + * Get the static instance of the provider + * @returns {Provider} Provider + */ + static get instance(): Provider { + if (Provider._instance === undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_NOT_INITIALIZED) + } + return Provider._instance + } + + /** + * Initialize the static instance of the provider + * @param {NetworkConfigInterface} network - Network configuration of the provider + * @returns {void} + */ + static initialize(network: NetworkConfigInterface): void { + if (Provider._instance !== undefined) { + throw new Error(ErrorTypeEnum.PROVIDER_IS_ALREADY_INITIALIZED) + } + Provider._instance = new Provider(network) + } + + /** + * Check RPC connection + * @param {string} url - RPC URL + * @returns {Promise} + */ + async checkRpcConnection(url?: string): Promise { + try { + const response = await axios.post(url ?? this.node.rpcUrl, { + jsonrpc: '2.0', + id: 1, + method: 'getEpochInfo' + }) + + if (response.status !== 200) { + return new Error(response.statusText + ': ' + JSON.stringify(response.data)) + } + + return true + } catch (error) { + return error as any + } + } + + /** + * Check WS connection + * @param {string} url - Websocket URL + * @returns {Promise} + */ + async checkWsConnection(url?: string): Promise { + try { + const result: any = await checkWebSocket(url ?? this.node.wsUrl ?? '') + + if (result instanceof Error) { + return result + } + + return true + } catch (error) { + return error as Error + } + } + + /** + * Update network configuration of the provider + * @param network - Network configuration of the provider + */ + update(network: NetworkConfigInterface): void { + this.network = network + Provider._instance = this + this.node = this.nodes[network.testnet ?? false ? 'devnet' : 'mainnet'] + this.node.rpcUrl = this.network.rpcUrl ?? this.node.rpcUrl + this.node.wsUrl = this.network.wsUrl ?? this.node.wsUrl + this.web3 = new Connection(this.node.rpcUrl, { + wsEndpoint: this.node.wsUrl + }) + } + + /** + * Get the current network configuration is testnet or not + * @returns boolean + */ + isTestnet(): boolean { + return this.network?.testnet ?? false + } +} diff --git a/packages/networks/solana/src/services/TransactionListener.ts b/packages/networks/solana/src/services/TransactionListener.ts new file mode 100644 index 0000000..b3c1a7c --- /dev/null +++ b/packages/networks/solana/src/services/TransactionListener.ts @@ -0,0 +1,541 @@ +import { Provider } from './Provider.ts' +import { Transaction } from '../models/Transaction.ts' +import { objectsEqual } from '@multiplechain/utils' +import { NftTransaction } from '../models/NftTransaction.ts' +import { CoinTransaction } from '../models/CoinTransaction.ts' +import { TokenTransaction } from '../models/TokenTransaction.ts' +import { ContractTransaction } from '../models/ContractTransaction.ts' +import { getAssociatedTokenAddressSync } from '@solana/spl-token' +import { + PublicKey, + SystemProgram, + type Logs, + type LogsFilter, + type ParsedAccountData, + type ParsedInstruction, + type PartiallyDecodedInstruction +} from '@solana/web3.js' +import type { + DynamicTransactionType, + TransactionListenerInterface, + DynamicTransactionListenerFilterType +} from '@multiplechain/types' +import { + ErrorTypeEnum, + TransactionTypeEnum, + TransactionListenerProcessIndex +} from '@multiplechain/types' + +type TransactionListenerTriggerType = DynamicTransactionType< + T, + Transaction, + ContractTransaction, + CoinTransaction, + TokenTransaction, + NftTransaction +> + +type TransactionListenerCallbackType< + T extends TransactionTypeEnum, + Transaction = TransactionListenerTriggerType +> = (transaction: Transaction) => void + +export class TransactionListener< + T extends TransactionTypeEnum, + DTransaction extends TransactionListenerTriggerType, + CallBackType extends TransactionListenerCallbackType +> implements TransactionListenerInterface +{ + /** + * Transaction type + */ + type: T + + /** + * Transaction listener callback + */ + callbacks: CallBackType[] = [] + + /** + * Transaction listener filter + */ + filter?: DynamicTransactionListenerFilterType | Record + + /** + * Provider + */ + provider: Provider + + /** + * Listener status + */ + status: boolean = false + + /** + * Connected status + */ + connected: boolean = false + + /** + * Dynamic stop method + */ + dynamicStop: () => void = () => {} + + /** + * Triggered transactions + */ + triggeredTransactions: string[] = [] + + /** + * @param {T} type - Transaction type + * @param {DynamicTransactionListenerFilterType} filter - Transaction listener filter + * @param {Provider} provider - Provider + */ + constructor(type: T, filter?: DynamicTransactionListenerFilterType, provider?: Provider) { + this.type = type + this.filter = filter ?? {} + this.provider = provider ?? Provider.instance + } + + /** + * Close the listener + * @returns {void} + */ + stop(): void { + if (this.status) { + this.status = false + this.dynamicStop() + } + } + + /** + * Start the listener + * @returns {void} + */ + start(): void { + if (!this.status) { + this.status = true + // @ts-expect-error allow dynamic access + this[TransactionListenerProcessIndex[this.type]]() + } + } + + /** + * Get the listener status + * @returns {boolean} Listener status + */ + getStatus(): boolean { + return this.status + } + + /** + * Listen to the transaction events + * @param {CallBackType} callback - Transaction listener callback + * @returns {Promise} + */ + async on(callback: CallBackType): Promise { + if (!this.connected) { + if ((await this.provider.checkWsConnection()) instanceof Error) { + throw new Error(ErrorTypeEnum.WS_CONNECTION_FAILED) + } else { + this.connected = true + } + } + + this.start() + this.callbacks.push(callback) + + return true + } + + /** + * Trigger the event when a transaction is detected + * @param {TransactionListenerTriggerType} transaction - Transaction data + * @returns {void} + */ + trigger(transaction: TransactionListenerTriggerType): void { + if (!this.triggeredTransactions.includes(transaction.id)) { + this.triggeredTransactions.push(transaction.id) + this.callbacks.forEach((callback) => { + callback(transaction as unknown as DTransaction) + }) + } + } + + /** + * General transaction process + * @returns {void} + */ + generalProcess(): void { + let subscriptionId: number + + if (this.filter?.signer === undefined) { + subscriptionId = this.provider.web3.onLogs( + 'all', + (logs) => { + this.trigger(new Transaction(logs.signature)) + }, + 'recent' + ) + } else { + const signer = this.filter.signer + subscriptionId = this.provider.web3.onLogs( + new PublicKey(signer), + async (logs) => { + try { + const transaction = new Transaction(logs.signature) + const data = await transaction.getData() + + if (data === null) { + return + } + + if ( + signer.toLowerCase() !== (await transaction.getSigner()).toLowerCase() + ) { + return + } + + this.trigger(transaction) + } catch (error) { + // Maybe in future, we can add logging system + } + }, + 'confirmed' + ) + } + + this.dynamicStop = () => { + void this.provider.web3.removeOnLogsListener(subscriptionId) + } + } + + /** + * @param {(ParsedInstruction | PartiallyDecodedInstruction)[]} instructions + * @returns {boolean} + */ + private isSystemProgram( + instructions: Array + ): boolean { + return Boolean( + instructions.find((instruction) => { + return instruction.programId.equals(SystemProgram.programId) + }) + ) + } + + /** + * Contract transaction process + * @returns {void} + */ + contractProcess(): void { + const filter = this + .filter as DynamicTransactionListenerFilterType + + const callback = async (logs: Logs): Promise => { + try { + const transaction = new ContractTransaction(logs.signature) + const data = await transaction.getData() + + if (data === null) { + return + } + + if (this.isSystemProgram(data.transaction.message.instructions)) { + return + } + + interface ParamsType { + signer?: string + address?: string + } + + const expectedParams: ParamsType = {} + const receivedParams: ParamsType = {} + + if (filter.signer !== undefined) { + expectedParams.signer = filter.signer.toLowerCase() + receivedParams.signer = (await transaction.getSigner()).toLowerCase() + } + + if (filter.address !== undefined) { + expectedParams.address = filter.address.toLowerCase() + receivedParams.address = (await transaction.getAddress()).toLowerCase() + } + + if (!objectsEqual(expectedParams, receivedParams)) { + return + } + + this.trigger(transaction) + } catch (error) { + // Maybe in future, we can add logging system + } + } + + const address = filter.signer ?? filter.address + const parameter = address !== undefined ? new PublicKey(address) : 'all' + const subscriptionId = this.provider.web3.onLogs(parameter, callback, 'confirmed') + + this.dynamicStop = () => { + void this.provider.web3.removeOnLogsListener(subscriptionId) + } + } + + /** + * Coin transaction process + * @returns {void} + */ + coinProcess(): void { + const filter = this.filter as DynamicTransactionListenerFilterType + + const parameter = new PublicKey( + filter.signer ?? filter.sender ?? filter.receiver ?? SystemProgram.programId.toBase58() + ) + + const callback = async (logs: Logs): Promise => { + try { + const transaction = new CoinTransaction(logs.signature) + const data = await transaction.getData() + + if (data === null) { + return + } + + if (!this.isSystemProgram(data.transaction.message.instructions)) { + return + } + + interface ParamsType { + signer?: string + sender?: string + receiver?: string + amount?: number + } + + const expectedParams: ParamsType = {} + const receivedParams: ParamsType = {} + + if (filter.signer !== undefined) { + expectedParams.signer = filter.signer.toLowerCase() + receivedParams.signer = (await transaction.getSigner()).toLowerCase() + } + + if (filter.sender !== undefined) { + expectedParams.sender = filter.sender.toLowerCase() + receivedParams.sender = (await transaction.getSender()).toLowerCase() + } + + if (filter.receiver !== undefined) { + expectedParams.receiver = filter.receiver.toLowerCase() + receivedParams.receiver = (await transaction.getReceiver()).toLowerCase() + } + + if (filter.amount !== undefined) { + expectedParams.amount = filter.amount + receivedParams.amount = await transaction.getAmount() + } + + if (!objectsEqual(expectedParams, receivedParams)) { + return + } + + this.trigger(transaction) + } catch (error) { + // Maybe in future, we can add logging system + } + } + + const subscriptionId = this.provider.web3.onLogs(parameter, callback, 'confirmed') + + this.dynamicStop = () => { + void this.provider.web3.removeOnLogsListener(subscriptionId) + } + } + + private async tokenNftCondition( + _transaction: TokenTransaction | NftTransaction + ): Promise { + const filter = + this.type === TransactionTypeEnum.TOKEN + ? (this.filter as DynamicTransactionListenerFilterType) + : (this.filter as DynamicTransactionListenerFilterType) + + const transaction = + this.type === TransactionTypeEnum.TOKEN + ? (_transaction as TokenTransaction) + : (_transaction as NftTransaction) + + interface ParamsType { + signer?: string + sender?: string + receiver?: string + address?: string + amount?: number + nftId?: number | string + } + + const expectedParams: ParamsType = {} + const receivedParams: ParamsType = {} + + if (filter.signer !== undefined) { + expectedParams.signer = filter.signer.toLowerCase() + receivedParams.signer = (await transaction.getSigner()).toLowerCase() + } + + if (filter.sender !== undefined) { + expectedParams.sender = filter.sender.toLowerCase() + receivedParams.sender = (await transaction.getSender()).toLowerCase() + } + + if (filter.receiver !== undefined) { + expectedParams.receiver = filter.receiver.toLowerCase() + receivedParams.receiver = (await transaction.getReceiver()).toLowerCase() + } + + if (filter.address !== undefined) { + expectedParams.address = filter.address.toLowerCase() + receivedParams.address = (await transaction.getAddress()).toLowerCase() + } + + if (this.type === TransactionTypeEnum.TOKEN) { + const tFilter = + filter as DynamicTransactionListenerFilterType + const tTransaction = _transaction as TokenTransaction + if (tFilter.amount !== undefined) { + expectedParams.amount = tFilter.amount + receivedParams.amount = await tTransaction.getAmount() + } + } else { + const nFilter = filter as DynamicTransactionListenerFilterType + const nTransaction = _transaction as NftTransaction + if (nFilter.nftId !== undefined) { + expectedParams.nftId = nFilter.nftId + receivedParams.nftId = await nTransaction.getNftId() + } + } + + return objectsEqual(expectedParams, receivedParams) + } + + private async createTokenNftListenParameter(): Promise { + const filter = + this.type === TransactionTypeEnum.TOKEN + ? (this.filter as DynamicTransactionListenerFilterType) + : (this.filter as DynamicTransactionListenerFilterType) + + let parameter: LogsFilter = 'all' + + if (filter?.address !== undefined) { + const tokenMintAddress = new PublicKey(filter.address) + const accountInfo = await this.provider.web3.getParsedAccountInfo(tokenMintAddress) + + const result = accountInfo?.value + const data = (result?.data as ParsedAccountData) ?? null + const programId = ['spl-token', 'spl-token-2022'].includes(data?.program) + ? result?.owner + : null + + parameter = programId ?? tokenMintAddress ?? 'all' + const address = filter.sender ?? filter.receiver + + if (programId !== null && address !== undefined) { + const addressPubKey = new PublicKey(address) + const ownerAccount = getAssociatedTokenAddressSync( + tokenMintAddress, + addressPubKey, + false, + programId + ) + + parameter = ownerAccount + } + } + + return parameter + } + + /** + * Token transaction process + * @returns {Promise} + */ + async tokenProcess(): Promise { + const callback = async (logs: Logs): Promise => { + try { + const transaction = new TokenTransaction(logs.signature) + const data = await transaction.getData() + + if (data === null) { + return + } + + if (this.isSystemProgram(data.transaction.message.instructions)) { + return + } + + const instruction = transaction.findTransferInstruction(data) + + if (instruction === null || instruction.parsed?.info?.tokenAmount?.decimals === 0) { + return + } + + if (!(await this.tokenNftCondition(transaction))) { + return + } + + this.trigger(transaction) + } catch (error) { + // Maybe in future, we can add logging system + } + } + + const parameter = await this.createTokenNftListenParameter() + const subscriptionId = this.provider.web3.onLogs(parameter, callback, 'confirmed') + + this.dynamicStop = () => { + void this.provider.web3.removeOnLogsListener(subscriptionId) + } + } + + /** + * NFT transaction process + * @returns {Promise} + */ + async nftProcess(): Promise { + const callback = async (logs: Logs): Promise => { + try { + const transaction = new NftTransaction(logs.signature) + const data = await transaction.getData() + + if (data === null) { + return + } + + if (this.isSystemProgram(data.transaction.message.instructions)) { + return + } + + const instruction = transaction.findTransferInstruction(data) + + if (instruction === null || instruction.parsed?.info?.tokenAmount?.decimals !== 0) { + return + } + + if (!(await this.tokenNftCondition(transaction))) { + return + } + + this.trigger(transaction) + } catch (error) { + // Maybe in future, we can add logging system + } + } + + const parameter = await this.createTokenNftListenParameter() + const subscriptionId = this.provider.web3.onLogs(parameter, callback, 'confirmed') + + this.dynamicStop = () => { + void this.provider.web3.removeOnLogsListener(subscriptionId) + } + } +} diff --git a/packages/networks/solana/src/services/TransactionSigner.ts b/packages/networks/solana/src/services/TransactionSigner.ts new file mode 100644 index 0000000..5e01680 --- /dev/null +++ b/packages/networks/solana/src/services/TransactionSigner.ts @@ -0,0 +1,134 @@ +import { Provider } from '../services/Provider.ts' +import { base58Decode } from '@multiplechain/utils' +import { Transaction } from '../models/Transaction.ts' +import { NftTransaction } from '../models/NftTransaction.ts' +import { CoinTransaction } from '../models/CoinTransaction.ts' +import { TokenTransaction } from '../models/TokenTransaction.ts' +import type { TransactionSignerInterface } from '@multiplechain/types' +import { Keypair, VersionedTransaction, Transaction as RawTransaction } from '@solana/web3.js' + +type SignedTransaction = Buffer | Uint8Array + +export class TransactionSigner implements TransactionSignerInterface { + /** + * Transaction data from the blockchain network + */ + rawData: RawTransaction + + /** + * Signed transaction data + */ + signedData: SignedTransaction + + /** + * Blockchain network provider + */ + provider: Provider + + /** + * @param {RawTransaction} rawData - Transaction data + */ + constructor(rawData: RawTransaction, provider?: Provider) { + this.rawData = rawData + this.provider = provider ?? Provider.instance + } + + /** + * Sign the transaction + * @param {string} privateKey - Transaction data + * @returns {Promise} Signed transaction data + */ + async sign(privateKey: string): Promise { + this.rawData.recentBlockhash = ( + await this.provider.web3.getLatestBlockhash('finalized') + ).blockhash + + const serialized = this.rawData.serialize({ + requireAllSignatures: false, + verifySignatures: true + }) + + const feePayer = Keypair.fromSecretKey(base58Decode(privateKey)) + const transaction = this.getRawTransaction(serialized.toString('base64')) + + if (transaction instanceof VersionedTransaction) { + transaction.sign([feePayer]) + } else { + transaction.partialSign(feePayer) + } + + this.signedData = transaction.serialize() + + return this + } + + /** + * Get the raw transaction data + * @returns Transaction data + */ + private getRawTransaction(encodedTransaction: string): RawTransaction | VersionedTransaction { + let recoveredTransaction: RawTransaction | VersionedTransaction + try { + recoveredTransaction = RawTransaction.from(Buffer.from(encodedTransaction, 'base64')) + } catch (error) { + recoveredTransaction = VersionedTransaction.deserialize( + Buffer.from(encodedTransaction, 'base64') + ) + } + return recoveredTransaction + } + + /** + * Send the transaction to the blockchain network + * @returns {Promise} + */ + async send(): Promise { + return new Transaction(await this.provider.web3.sendRawTransaction(this.signedData)) + } + + /** + * Get the raw transaction data + * @returns Transaction data + */ + getRawData(): RawTransaction { + return this.rawData + } + + /** + * Get the signed transaction data + * @returns Signed transaction data + */ + getSignedData(): SignedTransaction { + return this.signedData + } +} + +export class CoinTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new CoinTransaction((await super.send()).getId()) + } +} + +export class TokenTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new TokenTransaction((await super.send()).getId()) + } +} + +export class NftTransactionSigner extends TransactionSigner { + /** + * Send the transaction to the blockchain network + * @returns {Promise} Transaction data + */ + async send(): Promise { + return new NftTransaction((await super.send()).getId()) + } +} diff --git a/packages/networks/solana/src/services/index.ts b/packages/networks/solana/src/services/index.ts new file mode 100644 index 0000000..549a382 --- /dev/null +++ b/packages/networks/solana/src/services/index.ts @@ -0,0 +1,2 @@ +export * from './TransactionSigner.ts' +export * from './TransactionListener.ts' diff --git a/packages/networks/solana/src/utils.ts b/packages/networks/solana/src/utils.ts new file mode 100644 index 0000000..83246b7 --- /dev/null +++ b/packages/networks/solana/src/utils.ts @@ -0,0 +1,11 @@ +import { math } from '@multiplechain/utils' + +export * from '@multiplechain/utils' + +export const fromLamports = (amount: number): number => { + return math.div(amount, 1000000000, 9) +} + +export const toLamports = (amount: number): number => { + return math.mul(amount, 1000000000, 9) +} diff --git a/packages/networks/solana/tests/assets.spec.ts b/packages/networks/solana/tests/assets.spec.ts new file mode 100644 index 0000000..680d8de --- /dev/null +++ b/packages/networks/solana/tests/assets.spec.ts @@ -0,0 +1,327 @@ +import { describe, it, expect, assert } from 'vitest' + +import { NFT } from '../src/assets/NFT.ts' +import { Coin } from '../src/assets/Coin.ts' +import { Token } from '../src/assets/Token.ts' +import { math } from '@multiplechain/utils' +import { Transaction } from '../src/models/Transaction.ts' +import { TransactionStatusEnum } from '@multiplechain/types' +import { TransactionSigner } from '../src/services/TransactionSigner.ts' + +const coinBalanceTestAmount = Number(process.env.SOL_COIN_BALANCE_TEST_AMOUNT) +const tokenBalanceTestAmount = Number(process.env.SOL_TOKEN_BALANCE_TEST_AMOUNT) +const nftBalanceTestAmount = Number(process.env.SOL_NFT_BALANCE_TEST_AMOUNT) +const transferTestAmount = Number(process.env.SOL_TRANSFER_TEST_AMOUNT) +const tokenTransferTestAmount = Number(process.env.SOL_TOKEN_TRANSFER_TEST_AMOUNT) +const tokenApproveTestAmount = Number(process.env.SOL_TOKEN_APPROVE_TEST_AMOUNT) +const nftTransferId = String(process.env.SOL_NFT_TRANSFER_ID) + +const coinTransferTestIsActive = Boolean(process.env.SOL_COIN_TRANSFER_TEST_IS_ACTIVE !== 'false') +const tokenTransferTestIsActive = Boolean(process.env.SOL_TOKEN_TRANSFER_TEST_IS_ACTIVE !== 'false') +const tokenApproveTestIsActive = Boolean(process.env.SOL_TOKEN_APPROVE_TEST_IS_ACTIVE !== 'false') +const nftTransactionTestIsActive = Boolean( + process.env.SOL_NFT_TRANSACTION_TEST_IS_ACTIVE !== 'false' +) +const tokenTransferFromTestIsActive = Boolean( + process.env.SOL_TOKEN_TRANSFER_FROM_TEST_IS_ACTIVE !== 'false' +) + +const balanceTestAddress = String(process.env.SOL_BALANCE_TEST_ADDRESS) +const senderPrivateKey = String(process.env.SOL_SENDER_PRIVATE_KEY) +const receiverPrivateKey = String(process.env.SOL_RECEIVER_PRIVATE_KEY) +const senderTestAddress = String(process.env.SOL_SENDER_TEST_ADDRESS) +const receiverTestAddress = String(process.env.SOL_RECEIVER_TEST_ADDRESS) +const tokenTestAddress = String(process.env.SOL_TOKEN_TEST_ADDRESS) +const token2022TestAddress = String(process.env.SOL_TOKEN_2022_TEST_ADDRESS) +const nftTestAddress = String(process.env.SOL_NFT_TEST_ADDRESS) + +const waitSecondsBeforeThanNewTx = async (seconds: number): Promise => { + return await new Promise((resolve) => setTimeout(resolve, seconds * 1000)) +} + +const checkSigner = async (signer: TransactionSigner, privateKey?: string): Promise => { + expect(signer).toBeInstanceOf(TransactionSigner) + + const rawData = signer.getRawData() + + assert.isObject(rawData) + + await signer.sign(privateKey ?? senderPrivateKey) + + expect(signer.getSignedData()).toBeInstanceOf(Buffer) +} + +const checkTx = async (transaction: Transaction): Promise => { + expect(transaction).toBeInstanceOf(Transaction) + const status = await transaction.wait(10 * 1000) + expect(status).toBe(TransactionStatusEnum.CONFIRMED) +} + +describe('Coin', () => { + const coin = new Coin() + it('Name and symbol', () => { + expect(coin.getName()).toBe('Solana') + expect(coin.getSymbol()).toBe('SOL') + }) + + it('Decimals', () => { + expect(coin.getDecimals()).toBe(9) + }) + + it('Balance', async () => { + const balance = await coin.getBalance(balanceTestAddress) + expect(balance).toBe(coinBalanceTestAmount) + }) + + it('Transfer', async () => { + const signer = await coin.transfer( + senderTestAddress, + receiverTestAddress, + transferTestAmount + ) + + await checkSigner(signer) + + if (!coinTransferTestIsActive) return + + const beforeBalance = await coin.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await coin.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, transferTestAmount)) + }) +}) + +describe('Token', async () => { + const token = new Token(tokenTestAddress) + const token2022 = new Token(token2022TestAddress) + + it('Name and symbol', async () => { + expect(await token.getName()).toBe('Example') + expect(await token.getSymbol()).toBe('EXM') + expect(await token2022.getName()).toBe('Example Token 2022') + expect(await token2022.getSymbol()).toBe('EXM2') + }) + + it('Decimals', async () => { + expect(await token.getDecimals()).toBe(8) + expect(await token2022.getDecimals()).toBe(9) + }) + + it('Balance', async () => { + expect(await token.getBalance(balanceTestAddress)).toBe(tokenBalanceTestAmount) + expect(await token2022.getBalance(balanceTestAddress)).toBe(tokenBalanceTestAmount) + }) + + it('Total supply', async () => { + expect(await token.getTotalSupply()).toBe(100000000000) + expect(await token2022.getTotalSupply()).toBe(10000000) + }) + + it('Transfer', async () => { + const signer = await token.transfer( + senderTestAddress, + receiverTestAddress, + tokenTransferTestAmount + ) + + await checkSigner(signer) + + if (!tokenTransferTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + const beforeBalance = await token.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await token.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, tokenTransferTestAmount)) + }) + + it('Transfer 2022', async () => { + const signer = await token2022.transfer( + senderTestAddress, + receiverTestAddress, + tokenTransferTestAmount + ) + + await checkSigner(signer) + + if (!tokenTransferTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + const beforeBalance = await token2022.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await token2022.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, tokenTransferTestAmount)) + }) + + it('Approve and Allowance', async () => { + const signer = await token.approve( + senderTestAddress, + receiverTestAddress, + tokenApproveTestAmount + ) + + await checkSigner(signer) + + if (!tokenApproveTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + await checkTx(await signer.send()) + + expect(await token.getAllowance(senderTestAddress, receiverTestAddress)).toBe( + tokenApproveTestAmount + ) + }) + + it('Approve and Allowance 2022', async () => { + const signer = await token2022.approve( + senderTestAddress, + receiverTestAddress, + tokenApproveTestAmount + ) + + await checkSigner(signer) + + if (!tokenApproveTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + await checkTx(await signer.send()) + + expect(await token.getAllowance(senderTestAddress, receiverTestAddress)).toBe( + tokenApproveTestAmount + ) + }) + + it('Transfer from', async () => { + const signer = await token.transferFrom( + receiverTestAddress, + senderTestAddress, + receiverTestAddress, + 2 + ) + + await checkSigner(signer, receiverPrivateKey) + + if (!tokenTransferFromTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + const beforeBalance = await token.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await token.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, 2)) + }) + + it('Transfer from 2022', async () => { + const signer = await token2022.transferFrom( + receiverTestAddress, + senderTestAddress, + receiverTestAddress, + 2 + ) + + await checkSigner(signer, receiverPrivateKey) + + if (!tokenTransferFromTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + const beforeBalance = await token2022.getBalance(receiverTestAddress) + + await checkTx(await signer.send()) + + const afterBalance = await token2022.getBalance(receiverTestAddress) + expect(afterBalance).toBe(math.add(beforeBalance, 2)) + }) +}) + +describe('Nft', async () => { + const nft = new NFT(nftTestAddress) + const id = 'F8kj1xPSG69amgDS7XfmkHgAAWgiJ391NFTkxJL2e5Di' + + it('Name and symbol', async () => { + expect(await nft.getName()).toBe('Test NFT Collection') + expect(await nft.getSymbol()).toBe('TNFT') + }) + + it('Balance', async () => { + const balance = await nft.getBalance(balanceTestAddress) + expect(balance).toBe(nftBalanceTestAmount) + }) + + it('Owner', async () => { + expect(await nft.getOwner(id)).toBe(balanceTestAddress) + }) + + it('Token URI', async () => { + expect(await nft.getTokenURI(id)).toBe( + 'https://arweave.net/8SvLYJ8CgpxzihKD2r-DKRmjPlyxa_WGeuA8ARI0ems' + ) + }) + + it('Approved', async () => { + expect(await nft.getApproved(id)).toBe(null) + }) + + it('Transfer', async () => { + const signer = await nft.transfer(senderTestAddress, receiverTestAddress, nftTransferId) + + await checkSigner(signer) + + if (!nftTransactionTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + await checkTx(await signer.send()) + + expect(await nft.getOwner(nftTransferId)).toBe(receiverTestAddress) + }) + + it('Approve', async () => { + const customOwner = nftTransactionTestIsActive ? receiverTestAddress : senderTestAddress + const customSpender = nftTransactionTestIsActive ? senderTestAddress : receiverTestAddress + const customPrivateKey = nftTransactionTestIsActive ? receiverPrivateKey : senderPrivateKey + + const signer = await nft.approve(customOwner, customSpender, nftTransferId) + + await checkSigner(signer, customPrivateKey) + + if (!nftTransactionTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + await checkTx(await signer.send()) + + expect(await nft.getApproved(nftTransferId)).toBe(senderTestAddress) + }) + + it('Transfer from', async () => { + if (!nftTransactionTestIsActive) return + + await waitSecondsBeforeThanNewTx(5) + + const signer = await nft.transferFrom( + senderTestAddress, + receiverTestAddress, + senderTestAddress, + nftTransferId + ) + + await checkSigner(signer) + + await checkTx(await signer.send()) + + expect(await nft.getOwner(nftTransferId)).toBe(senderTestAddress) + }) +}) diff --git a/packages/networks/solana/tests/models.spec.ts b/packages/networks/solana/tests/models.spec.ts new file mode 100644 index 0000000..7c47351 --- /dev/null +++ b/packages/networks/solana/tests/models.spec.ts @@ -0,0 +1,209 @@ +import { describe, it, expect } from 'vitest' + +import { Transaction } from '../src/models/Transaction.ts' +import { NftTransaction } from '../src/models/NftTransaction.ts' +import { CoinTransaction } from '../src/models/CoinTransaction.ts' +import { TokenTransaction } from '../src/models/TokenTransaction.ts' +import { AssetDirectionEnum, TransactionStatusEnum } from '@multiplechain/types' +import { ContractTransaction } from '../src/models/ContractTransaction.ts' + +const nftId = String(process.env.SOL_NFT_ID) +const tokenAmount = Number(process.env.SOL_TOKEN_AMOUNT) +const coinAmount = Number(process.env.SOL_COIN_AMOUNT) + +const solTransferTx = String(process.env.SOL_TRANSFER_TX) +const tokenTransferTx = String(process.env.SOL_TOKEN_TRANSFER_TX) +const token2022TransferTx = String(process.env.SOL_TOKEN_2022_TRANSFER_TX) +const nftTransferTx = String(process.env.SOL_NFT_TRANSFER_TX) + +const sender = String(process.env.SOL_MODEL_TEST_SENDER) +const receiver = String(process.env.SOL_MODEL_TEST_RECEIVER) + +const tokenTestAddress = String(process.env.SOL_TOKEN_TEST_ADDRESS) +const token2022TestAddress = String(process.env.SOL_TOKEN_2022_TEST_ADDRESS) + +describe('Transaction', () => { + const tx = new Transaction(solTransferTx) + it('Id', async () => { + expect(tx.getId()).toBe(solTransferTx) + }) + + it('Data', async () => { + expect(await tx.getData()).toBeTypeOf('object') + }) + + it('Wait', async () => { + expect(await tx.wait()).toBe(TransactionStatusEnum.CONFIRMED) + }) + + it('URL', async () => { + expect(tx.getUrl()).toBe( + 'https://solscan.io/tx/2RDU1otuPR6UtevwYCQWnngvvjPiTFuHFdyCnzwQVR8wyZ7niqACt2QBmfuyD5aXJbEXSEUcqFquiCEtcQZzkWif?cluster=devnet' + ) + }) + + it('Sender', async () => { + expect(await tx.getSigner()).toBe(sender) + }) + + it('Fee', async () => { + expect(await tx.getFee()).toBe(0.000065) + }) + + it('Block Number', async () => { + expect(await tx.getBlockNumber()).toBe(299257452) + }) + + it('Block Timestamp', async () => { + expect(await tx.getBlockTimestamp()).toBe(1715865360) + }) + + it('Block Confirmation Count', async () => { + expect(await tx.getBlockConfirmationCount()).toBeGreaterThan(4567) + }) + + it('Status', async () => { + expect(await tx.getStatus()).toBe(TransactionStatusEnum.CONFIRMED) + }) +}) + +describe('Coin Transaction', () => { + const tx = new CoinTransaction(solTransferTx) + + it('Receiver', async () => { + expect((await tx.getReceiver()).toLowerCase()).toBe(receiver.toLowerCase()) + }) + + it('Amount', async () => { + expect(await tx.getAmount()).toBe(coinAmount) + }) + + it('Verify Transfer', async () => { + expect(await tx.verifyTransfer(AssetDirectionEnum.INCOMING, receiver, coinAmount)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, sender, coinAmount)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, receiver, coinAmount)).toBe( + TransactionStatusEnum.FAILED + ) + }) +}) + +describe('Contract Transaction', () => { + const tx = new ContractTransaction( + '5pak57tjpTf4BfHweZryxtmJBWsJjeaU56N6CbuwuSuNyPtHwKsu6CZp6Y2L9dHqNJH33w6V895ZQLgRjANJJSR3' + ) + + it('Address', async () => { + expect((await tx.getAddress()).toLowerCase()).toBe( + 'HeXZiyduAmAaYABvrh4bU94TdzB2TkwFuNXfgi1PYFwS'.toLowerCase() + ) + }) +}) + +describe('Token Transaction', () => { + const tx = new TokenTransaction(tokenTransferTx) + const tx2022 = new TokenTransaction(token2022TransferTx) + + it('Receiver', async () => { + expect((await tx.getReceiver()).toLowerCase()).toBe(receiver.toLowerCase()) + }) + + it('Sender', async () => { + expect((await tx.getSender()).toLowerCase()).toBe(sender.toLowerCase()) + }) + + it('Program', async () => { + expect((await tx.getAddress()).toLowerCase()).toBe(tokenTestAddress.toLowerCase()) + }) + + it('Amount', async () => { + expect(await tx.getAmount()).toBe(tokenAmount) + }) + + it('Verify Transfer', async () => { + expect(await tx.verifyTransfer(AssetDirectionEnum.INCOMING, receiver, tokenAmount)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, sender, tokenAmount)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, receiver, tokenAmount)).toBe( + TransactionStatusEnum.FAILED + ) + }) + + it('Receiver', async () => { + expect((await tx2022.getReceiver()).toLowerCase()).toBe(receiver.toLowerCase()) + }) + + it('Sender', async () => { + expect((await tx2022.getSender()).toLowerCase()).toBe(sender.toLowerCase()) + }) + + it('Program', async () => { + expect((await tx2022.getAddress()).toLowerCase()).toBe(token2022TestAddress.toLowerCase()) + }) + + it('Amount', async () => { + expect(await tx2022.getAmount()).toBe(tokenAmount) + }) + + it('Verify Transfer', async () => { + expect( + await tx2022.verifyTransfer(AssetDirectionEnum.INCOMING, receiver, tokenAmount) + ).toBe(TransactionStatusEnum.CONFIRMED) + + expect(await tx2022.verifyTransfer(AssetDirectionEnum.OUTGOING, sender, tokenAmount)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect( + await tx2022.verifyTransfer(AssetDirectionEnum.OUTGOING, receiver, tokenAmount) + ).toBe(TransactionStatusEnum.FAILED) + }) +}) + +describe('NFT Transaction', () => { + const tx = new NftTransaction(nftTransferTx) + + it('Receiver', async () => { + expect((await tx.getReceiver()).toLowerCase()).toBe(receiver.toLowerCase()) + }) + + it('Signer', async () => { + expect((await tx.getSigner()).toLowerCase()).toBe(sender.toLowerCase()) + }) + + it('Program', async () => { + expect((await tx.getAddress()).toLowerCase()).toBe(nftId.toLowerCase()) + }) + + it('Sender', async () => { + expect((await tx.getSender()).toLowerCase()).toBe(sender.toLowerCase()) + }) + + it('NFT ID', async () => { + expect(await tx.getNftId()).toBe(nftId) + }) + + it('Verify Transfer', async () => { + expect(await tx.verifyTransfer(AssetDirectionEnum.INCOMING, receiver, nftId)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, sender, nftId)).toBe( + TransactionStatusEnum.CONFIRMED + ) + + expect(await tx.verifyTransfer(AssetDirectionEnum.OUTGOING, receiver, nftId)).toBe( + TransactionStatusEnum.FAILED + ) + }) +}) diff --git a/packages/networks/solana/tests/services.spec.ts b/packages/networks/solana/tests/services.spec.ts new file mode 100644 index 0000000..e7aa9f2 --- /dev/null +++ b/packages/networks/solana/tests/services.spec.ts @@ -0,0 +1,219 @@ +import { describe, it, expect } from 'vitest' + +import { provider } from './setup.ts' +import { Provider } from '../src/services/Provider.ts' + +import { NFT } from '../src/assets/NFT.ts' +import { Coin } from '../src/assets/Coin.ts' +import { Token } from '../src/assets/Token.ts' +import { sleep } from '@multiplechain/utils' +import { TransactionTypeEnum } from '@multiplechain/types' +import { Transaction } from '../src/models/Transaction.ts' +import { NftTransaction } from '../src/models/NftTransaction.ts' +import { CoinTransaction } from '../src/models/CoinTransaction.ts' +import { TokenTransaction } from '../src/models/TokenTransaction.ts' +import { ContractTransaction } from '../src/models/ContractTransaction.ts' +import { TransactionListener } from '../src/services/TransactionListener.ts' + +const senderPrivateKey = String(process.env.SOL_SENDER_PRIVATE_KEY) +const receiverPrivateKey = String(process.env.SOL_RECEIVER_PRIVATE_KEY) +const senderTestAddress = String(process.env.SOL_SENDER_TEST_ADDRESS) +const receiverTestAddress = String(process.env.SOL_RECEIVER_TEST_ADDRESS) +const tokenTestAddress = String(process.env.SOL_TOKEN_TEST_ADDRESS) +const tokenProgram = String(process.env.SOL_TOKEN_PROGRAM) +const nftTestAddress = String(process.env.SOL_NFT_TEST_ADDRESS) +const nftTestAddress2 = String(process.env.SOL_NFT_TRANSFER_ID2) + +const transactionListenerTestIsActive = Boolean( + process.env.SOL_TRANSACTION_LISTENER_TEST_IS_ACTIVE !== 'false' +) + +const waitSecondsBeforeThanNewTx = async (seconds: number): Promise => { + return await new Promise((resolve) => setTimeout(resolve, seconds * 1000)) +} + +describe('Provider', () => { + it('isTestnet', () => { + expect(provider.isTestnet()).toBe(true) + }) + + it('instance', () => { + expect(Provider.instance).toBe(provider) + }) + + it('checkRpcConnection', async () => { + expect(await provider.checkRpcConnection()).toBe(true) + }) + + it('checkWsConnection', async () => { + expect(await provider.checkWsConnection()).toBe(true) + }) +}) + +describe('Transaction Listener', () => { + if (!transactionListenerTestIsActive) { + it('No test is active', () => { + expect(true).toBe(true) + }) + return + } + + it('General', async () => { + const listener = new TransactionListener(TransactionTypeEnum.GENERAL, { + signer: senderTestAddress + }) + + const signer = await new Coin().transfer(senderTestAddress, receiverTestAddress, 0.0001) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + expect(await waitListenerEvent()).toBeInstanceOf(Transaction) + }) + + it('Contract', async () => { + await waitSecondsBeforeThanNewTx(10) + + const listener = new TransactionListener(TransactionTypeEnum.CONTRACT, { + signer: senderTestAddress, + address: tokenProgram + }) + + const signer = await new Token(tokenTestAddress).transfer( + senderTestAddress, + receiverTestAddress, + 0.01 + ) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + expect(await waitListenerEvent()).toBeInstanceOf(ContractTransaction) + }) + + it('Coin', async () => { + await waitSecondsBeforeThanNewTx(10) + + const listener = new TransactionListener(TransactionTypeEnum.COIN, { + signer: senderTestAddress, + receiver: receiverTestAddress + }) + + const signer = await new Coin().transfer(senderTestAddress, receiverTestAddress, 0.0001) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + expect(await waitListenerEvent()).toBeInstanceOf(CoinTransaction) + }) + + it('Token', async () => { + await waitSecondsBeforeThanNewTx(10) + + const listener = new TransactionListener(TransactionTypeEnum.TOKEN, { + signer: senderTestAddress, + receiver: receiverTestAddress, + address: tokenTestAddress + }) + + const signer = await new Token(tokenTestAddress).transfer( + senderTestAddress, + receiverTestAddress, + 0.01 + ) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + expect(await waitListenerEvent()).toBeInstanceOf(TokenTransaction) + }) + + it('NFT', async () => { + await waitSecondsBeforeThanNewTx(10) + + const listener = new TransactionListener(TransactionTypeEnum.NFT, { + signer: senderTestAddress, + receiver: receiverTestAddress, + address: nftTestAddress2 + }) + + const nft = new NFT(nftTestAddress) + const signer = await nft.transfer(senderTestAddress, receiverTestAddress, nftTestAddress2) + + const waitListenerEvent = async (): Promise => { + return await new Promise((resolve, reject) => { + void listener + .on((transaction) => { + listener.stop() + resolve(transaction) + }) + .then(async () => { + await sleep(2000) + void (await signer.sign(senderPrivateKey)).send() + }) + .catch(reject) + }) + } + + const transaction = await waitListenerEvent() + expect(transaction).toBeInstanceOf(NftTransaction) + await transaction.wait() + await waitSecondsBeforeThanNewTx(10) + + const newSigner = await nft.transfer( + receiverTestAddress, + senderTestAddress, + nftTestAddress2 + ) + + void (await newSigner.sign(receiverPrivateKey)).send() + }) +}) diff --git a/packages/networks/solana/tests/setup.ts b/packages/networks/solana/tests/setup.ts new file mode 100644 index 0000000..42e7f45 --- /dev/null +++ b/packages/networks/solana/tests/setup.ts @@ -0,0 +1,14 @@ +import { Provider } from '../src/services/Provider.ts' + +let provider: Provider + +try { + provider = Provider.instance +} catch (e) { + provider = new Provider({ + testnet: true, + wsUrl: 'wss://alien-wild-fire.solana-devnet.quiknode.pro/ad7c4490b11cd2134e022052f0b2779acb8998ad/' + }) +} + +export { provider } diff --git a/packages/networks/solana/tsconfig.json b/packages/networks/solana/tsconfig.json new file mode 100644 index 0000000..e40c547 --- /dev/null +++ b/packages/networks/solana/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "noEmit": true, + "composite": true, + "declaration": true, + "outDir": "./dist/esm", + "declarationDir": "./dist/types" + }, + "extends": "../../../tsconfig.json", + "include": [ + "src", + ".eslintrc.json", + "tests", + "vite.config.ts", + "esbuild.ts", + "vitest.config.ts", + "../../../esbuild.ts", + "../../../vite.config.ts", + "../../../vitest.config.ts", + ] +} diff --git a/packages/networks/solana/vite.config.ts b/packages/networks/solana/vite.config.ts new file mode 100644 index 0000000..b4b80b7 --- /dev/null +++ b/packages/networks/solana/vite.config.ts @@ -0,0 +1,10 @@ +import { mergeConfig } from 'vite' +import mainConfig from '../../../vite.config.ts' + +export default mergeConfig(mainConfig, { + build: { + lib: { + name: 'Solana' + } + } +}) diff --git a/packages/networks/solana/vite.svg b/packages/networks/solana/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/packages/networks/solana/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/networks/solana/vitest.config.ts b/packages/networks/solana/vitest.config.ts new file mode 100644 index 0000000..433e719 --- /dev/null +++ b/packages/networks/solana/vitest.config.ts @@ -0,0 +1,12 @@ +import { mergeConfig, defineConfig } from 'vitest/config' +import mainConfig from '../../../vite.config.ts' + +export default mergeConfig( + mainConfig, + defineConfig({ + test: { + testTimeout: 180000, + setupFiles: ['./tests/setup.ts'] + } + }) +) diff --git a/packages/networks/tron/index.html b/packages/networks/tron/index.html index 12a24de..4902d75 100644 --- a/packages/networks/tron/index.html +++ b/packages/networks/tron/index.html @@ -215,7 +215,7 @@