From bef5bb0df8775d4d58e321fc0d985f37893c9ef1 Mon Sep 17 00:00:00 2001 From: SDargarh Date: Mon, 22 Jul 2024 17:40:39 +0530 Subject: [PATCH 1/9] Initial Solana Keyring Implementation --- .gitignore | 3 +- CHANGELOG.md | 8 + package-lock.json | 763 +++++++++++++++++++++++++++++++++++- package.json | 7 +- src/config/index.js | 21 + src/helper/account.js | 11 + src/helper/getHdPath.js | 10 + src/helper/getNetwork.js | 7 + src/helper/importAccount.js | 12 + src/helper/index.js | 11 + src/index.js | 73 ++++ test/constants.js | 19 + test/index.js | 27 ++ 13 files changed, 969 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 src/config/index.js create mode 100644 src/helper/account.js create mode 100644 src/helper/getHdPath.js create mode 100644 src/helper/getNetwork.js create mode 100644 src/helper/importAccount.js create mode 100644 src/helper/index.js create mode 100644 src/index.js create mode 100644 test/constants.js create mode 100644 test/index.js diff --git a/.gitignore b/.gitignore index b512c09..b788561 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -node_modules \ No newline at end of file +node_modules +test.js diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a1ea987 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,8 @@ +### 1.0.0 (2024-7-22) + +##### Solana Keyring Implementation + +- Implemented Keyring functionality to enable account generation and export keys +- Added getAccounts() method to fetch list of generated accounts +- Added importWallet() to import account using privateKey +- Added initial test \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d59bc19..e94cf59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,13 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@solana/web3.js": "^1.95.1", + "bip39": "^3.1.0", + "bs58": "^5.0.0", + "ed25519-hd-key": "^1.3.0", "mocha": "^10.7.0", - "nyc": "^17.0.0" + "nyc": "^17.0.0", + "obs-store": "^4.0.3" } }, "node_modules/@ampproject/remapping": { @@ -272,6 +277,17 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", + "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", @@ -384,6 +400,122 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.95.1", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.95.1.tgz", + "integrity": "sha512-mRX/AjV6QbiOXpWcy5Rz1ZWEH2lVkwO7T0pcv9t97ACpv3/i3tPiqXwk0JIZgSR3wOSTiT26JfygnJH2ulS6dQ==", + "dependencies": { + "@babel/runtime": "^7.24.8", + "@noble/curves": "^1.4.2", + "@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.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@solana/web3.js/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/@swc/helpers": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.12.tgz", + "integrity": "sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -464,6 +596,42 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -475,6 +643,53 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip39": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "dependencies": { + "@noble/hashes": "^1.2.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/borsh/node_modules/base-x": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", + "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/borsh/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/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -531,6 +746,50 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/caching-transform": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", @@ -608,6 +867,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -639,6 +907,11 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -654,6 +927,36 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -705,6 +1008,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", @@ -713,6 +1027,15 @@ "node": ">=0.3.1" } }, + "node_modules/ed25519-hd-key": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ed25519-hd-key/-/ed25519-hd-key-1.3.0.tgz", + "integrity": "sha512-IWwAyiiuJQhgu3L8NaHb68eJxTu2pgCwxIBdgpLJdKpYZM46+AXePSVTr7fkNKaUOfOL4IrjEUaQvyVRIDP7fg==", + "dependencies": { + "create-hmac": "1.1.7", + "tweetnacl": "1.0.3" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.832", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.832.tgz", @@ -728,6 +1051,19 @@ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", @@ -756,6 +1092,37 @@ "node": ">=4" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -928,6 +1295,32 @@ "node": ">=4" } }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -956,6 +1349,33 @@ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==" }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "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/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1076,11 +1496,24 @@ "node": ">=0.10.0" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -1202,6 +1635,31 @@ "node": ">=8" } }, + "node_modules/jayson": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.1.tgz", + "integrity": "sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w==", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "JSONStream": "^1.3.5", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1230,6 +1688,11 @@ "node": ">=4" } }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1241,6 +1704,29 @@ "node": ">=6" } }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, "node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -1366,6 +1852,16 @@ "semver": "bin/semver.js" } }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1654,6 +2150,36 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -1718,6 +2244,17 @@ "node": ">=18" } }, + "node_modules/obs-store": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/obs-store/-/obs-store-4.0.3.tgz", + "integrity": "sha512-+mm13kCRDv6IcvUDKTw0LIy5+dQhIktYaR/RwwZUFzOTi/fjMaNBnk42Adb94qZqJ00qWkjhQSZH7MXlKnTi8A==", + "dependencies": { + "readable-stream": "^2.2.2", + "safe-event-emitter": "^1.0.1", + "through2": "^2.0.3", + "xtend": "^4.0.1" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1835,6 +2372,11 @@ "node": ">=8" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -1854,6 +2396,25 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -1865,6 +2426,11 @@ "node": ">=8.10.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -1912,6 +2478,65 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rpc-websockets": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.0.2.tgz", + "integrity": "sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw==", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.5.11", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.11.tgz", + "integrity": "sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "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/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1931,6 +2556,15 @@ } ] }, + "node_modules/safe-event-emitter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz", + "integrity": "sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg==", + "deprecated": "Renamed to @metamask/safe-event-emitter", + "dependencies": { + "events": "^3.0.0" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -1955,6 +2589,18 @@ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2008,6 +2654,19 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -2051,6 +2710,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2075,6 +2742,25 @@ "node": ">=8" } }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2094,6 +2780,21 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -2139,6 +2840,24 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -2147,6 +2866,20 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2230,6 +2963,34 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "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 + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", diff --git a/package.json b/package.json index 8633c23..83661ea 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,12 @@ "author": "SDargarh", "license": "MIT", "dependencies": { + "@solana/web3.js": "^1.95.1", + "bip39": "^3.1.0", + "bs58": "^5.0.0", + "ed25519-hd-key": "^1.3.0", "mocha": "^10.7.0", - "nyc": "^17.0.0" + "nyc": "^17.0.0", + "obs-store": "^4.0.3" } } diff --git a/src/config/index.js b/src/config/index.js new file mode 100644 index 0000000..d89a48c --- /dev/null +++ b/src/config/index.js @@ -0,0 +1,21 @@ + +module.exports = { + solana: { + HD_PATH: `m/44'/501'/0'/0'`, + }, + solana_connection: { + MAINNET: { + NETWORK: "MAINNET", + URL: 'https://api.mainnet-beta.solana.com', + }, + + TESTNET: { + NETWORK: "TESTNET", + URL: 'https://api.testnet.solana.com', + }, + DEVNET: { + NETWORK: "DEVNET", + URL: 'https://api.devnet.solana.com' + } + } +} \ No newline at end of file diff --git a/src/helper/account.js b/src/helper/account.js new file mode 100644 index 0000000..aa56677 --- /dev/null +++ b/src/helper/account.js @@ -0,0 +1,11 @@ +const bip39 = require("bip39"); +const { Keypair } = require("@solana/web3.js"); +const { derivePath } = require("ed25519-hd-key"); + +function manageSeedandGetAccountDetails(mnemonic, hdPath) { + const seed = bip39.mnemonicToSeedSync(mnemonic, ""); // (mnemonic, password) + const keypair = Keypair.fromSeed(derivePath(hdPath, seed.toString("hex")).key); + return keypair; +} + +module.exports = manageSeedandGetAccountDetails; diff --git a/src/helper/getHdPath.js b/src/helper/getHdPath.js new file mode 100644 index 0000000..cc11036 --- /dev/null +++ b/src/helper/getHdPath.js @@ -0,0 +1,10 @@ +function getHDPath(idx) { + /** + * HD_PATH TO CHECK + * m/44'/501'/${idx}'/0' + * m/44'/501'/0'/${idx}' + */ + return `m/44'/501'/${idx}'/0'` +} + +module.exports = getHDPath \ No newline at end of file diff --git a/src/helper/getNetwork.js b/src/helper/getNetwork.js new file mode 100644 index 0000000..b72a33f --- /dev/null +++ b/src/helper/getNetwork.js @@ -0,0 +1,7 @@ +const { solana_connection: { MAINNET, TESTNET, DEVNET } } = require('../config/index') + +function getActiveNetwork(_network) { + return _network === TESTNET.NETWORK ? TESTNET.URL : _network === DEVNET.NETWORK ? DEVNET.URL : MAINNET.URL +} + +module.exports = getActiveNetwork \ No newline at end of file diff --git a/src/helper/importAccount.js b/src/helper/importAccount.js new file mode 100644 index 0000000..3fca0da --- /dev/null +++ b/src/helper/importAccount.js @@ -0,0 +1,12 @@ +const { Keypair } = require("@solana/web3.js"); +const bs58 = require("bs58"); + +function importAccount(privateKey) { + try { + return Keypair.fromSecretKey(bs58.decode(privateKey)); + } catch (e) { + return undefined; + } +} + +module.exports = importAccount; diff --git a/src/helper/index.js b/src/helper/index.js new file mode 100644 index 0000000..dde3a58 --- /dev/null +++ b/src/helper/index.js @@ -0,0 +1,11 @@ +const setupAccount = require('./account') +const getNetwork = require('./getNetwork') +const importAccount = require('./importAccount') +const getHDPath = require("./getHdPath") + +module.exports = { + setupAccount, + getNetwork, + importAccount, + getHDPath +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..e6ea0c5 --- /dev/null +++ b/src/index.js @@ -0,0 +1,73 @@ +const ObservableStore = require("obs-store"); +const bs58 = require("bs58"); +const helper = require("./helper"); + + +const { solana: { HD_PATH }, solana_connection: { MAINNET }} = require('./config') + +class KeyringController { + constructor(opts) { + this.store = new ObservableStore({ + mnemonic: opts.mnemonic, + hdPath: HD_PATH, + network: helper.getNetwork(opts.network), + networkType: opts.network ? opts.network : MAINNET.NETWORK, + wallet: null, + address: [], + }); + this.importedWallets = []; + } + + async addAccount() { + const { mnemonic, address } = this.store.getState(); + const keyPair = helper.setupAccount( + mnemonic, + helper.getHDPath(address.length) + ); + const _address = keyPair.publicKey.toBase58(); + this.persistAllAddress(_address); + return { address: _address }; + } + + async getAccounts() { + const { address } = this.store.getState(); + return address; + } + + async exportPrivateKey(_address) { + const { mnemonic, address } = this.store.getState(); + + const idx = address.indexOf(_address); + if (idx < 0) + throw "Invalid address, the address is not available in the wallet"; + + const accountDetails = helper.setupAccount(mnemonic, helper.getHDPath(idx)); + return { privateKey: bs58.encode(accountDetails.secretKey) }; + } + + async importWallet(_privateKey) { + try { + const address = helper.importAccount(_privateKey); + this.importedWallets.push(address.publicKey.toString()); + return address.publicKey.toString(); + } catch (e) { + return Promise.reject(e); + } + } + + persistAllAddress(_address) { + const { address } = this.store.getState(); + let newAdd = address; + newAdd.push(_address); + this.store.updateState({ address: newAdd }); + return true; + } + + updatePersistentStore(obj) { + this.store.updateState(obj); + return true; + } +} + + +module.exports = { KeyringController }; diff --git a/test/constants.js b/test/constants.js new file mode 100644 index 0000000..f768c00 --- /dev/null +++ b/test/constants.js @@ -0,0 +1,19 @@ +module.exports = { + HD_WALLET_12_MNEMONIC: 'affair entry detect broom axis crawl found valve bamboo taste broken hundred', + + SOLANA_NETWORK: { + MAINNET: { + NETWORK: "MAINNET", + URL: 'https://api.mainnet-beta.solana.com', + }, + + TESTNET: { + NETWORK: "TESTNET", + URL: 'https://api.testnet.solana.com', + }, + DEVNET: { + NETWORK: "DEVNET", + URL: 'https://api.devnet.solana.com' + } + }, +} \ No newline at end of file diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..dbf6d9e --- /dev/null +++ b/test/index.js @@ -0,0 +1,27 @@ +var assert = require('assert'); +const { KeyringController: Solana, getBalance } = require('../src/index') + +const { + HD_WALLET_12_MNEMONIC, + SOLANA_NETWORK: { + MAINNET, + DEVNET, + TESTNET + }, +} = require('./constants.js') +const opts = { + mnemonic: HD_WALLET_12_MNEMONIC, + network: DEVNET.NETWORK +} + +describe('Controller test', () => { + const solWallet = new Solana(opts) + + it("Should generate new address ", async () => { + const wallet = await solWallet.addAccount() + console.log("wallet, ", wallet) + const wallet2 = await solWallet.addAccount() + console.log("wallet2, ", wallet2) + }) + +}) \ No newline at end of file From c511e059c46a26c9dec2e55b627324ddee2cd119 Mon Sep 17 00:00:00 2001 From: SDargarh Date: Mon, 22 Jul 2024 17:49:15 +0530 Subject: [PATCH 2/9] Added functionality to sign message --- CHANGELOG.md | 3 ++- package-lock.json | 3 ++- package.json | 3 ++- src/index.js | 14 ++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a1ea987..6d16828 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,4 +5,5 @@ - Implemented Keyring functionality to enable account generation and export keys - Added getAccounts() method to fetch list of generated accounts - Added importWallet() to import account using privateKey -- Added initial test \ No newline at end of file +- Added initial test +- Added functionality to sign message \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e94cf59..634632b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,8 @@ "ed25519-hd-key": "^1.3.0", "mocha": "^10.7.0", "nyc": "^17.0.0", - "obs-store": "^4.0.3" + "obs-store": "^4.0.3", + "tweetnacl": "^1.0.3" } }, "node_modules/@ampproject/remapping": { diff --git a/package.json b/package.json index 83661ea..12dd9ee 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "ed25519-hd-key": "^1.3.0", "mocha": "^10.7.0", "nyc": "^17.0.0", - "obs-store": "^4.0.3" + "obs-store": "^4.0.3", + "tweetnacl": "^1.0.3" } } diff --git a/src/index.js b/src/index.js index e6ea0c5..6d39fb5 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ const ObservableStore = require("obs-store"); const bs58 = require("bs58"); const helper = require("./helper"); +const nacl = require('tweetnacl'); const { solana: { HD_PATH }, solana_connection: { MAINNET }} = require('./config') @@ -55,6 +56,19 @@ class KeyringController { } } + async signMessage(message, _address) { + const { mnemonic, address } = this.store.getState() + const idx = address.indexOf(_address); + + if (idx < 0) + throw "Invalid address, the address is not available in the wallet" + + const accountDetails = helper.setupAccount(mnemonic, helper.getHDPath(idx)) + const msg = Buffer.from(message) + + return { signedMessage: bs58.encode(nacl.sign.detached(msg, accountDetails.secretKey)) }; + } + persistAllAddress(_address) { const { address } = this.store.getState(); let newAdd = address; From 724badde0c86b83b3b371ec12b08d2d5fdb0f3cd Mon Sep 17 00:00:00 2001 From: SDargarh Date: Mon, 22 Jul 2024 18:21:00 +0530 Subject: [PATCH 3/9] Added get balance method to fetch SOL balance of an account --- CHANGELOG.md | 3 ++- src/index.js | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d16828..956ffa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,4 +6,5 @@ - Added getAccounts() method to fetch list of generated accounts - Added importWallet() to import account using privateKey - Added initial test -- Added functionality to sign message \ No newline at end of file +- Added functionality to sign message +- Added get balance method to fetch SOL balance of an account \ No newline at end of file diff --git a/src/index.js b/src/index.js index 6d39fb5..88286ba 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,8 @@ -const ObservableStore = require("obs-store"); const bs58 = require("bs58"); -const helper = require("./helper"); const nacl = require('tweetnacl'); +const helper = require("./helper"); +const ObservableStore = require("obs-store"); +const solanaWeb3 = require('@solana/web3.js'); const { solana: { HD_PATH }, solana_connection: { MAINNET }} = require('./config') @@ -83,5 +84,15 @@ class KeyringController { } } +const getBalance = async (address, network) => { + try { + const _network = helper.getNetwork(network) + const connection = new solanaWeb3.Connection(_network, "confirmed") + const accInfo = await connection.getAccountInfo(new solanaWeb3.PublicKey(address), 'confirmed') + return { balance: accInfo ? accInfo.lamports : 0 } + } catch (err) { + throw err + } +} -module.exports = { KeyringController }; +module.exports = { KeyringController, getBalance }; From bea20ed1e063b819f26d19e0e47f91fab392286d Mon Sep 17 00:00:00 2001 From: SDargarh Date: Tue, 23 Jul 2024 12:21:25 +0530 Subject: [PATCH 4/9] Added functionality to sign transactions --- .gitignore | 1 + CHANGELOG.md | 3 +- package-lock.json | 307 ++++++++++++++++++++++++ package.json | 1 + src/config/index.js | 4 + src/helper/generateTransactionObject.js | 54 +++++ src/helper/index.js | 6 +- src/helper/signTransaction.js | 16 ++ src/index.js | 44 +++- 9 files changed, 427 insertions(+), 9 deletions(-) create mode 100644 src/helper/generateTransactionObject.js create mode 100644 src/helper/signTransaction.js diff --git a/.gitignore b/.gitignore index b788561..b2a5049 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules test.js +.vscode/launch.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 956ffa8..55e08fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,4 +7,5 @@ - Added importWallet() to import account using privateKey - Added initial test - Added functionality to sign message -- Added get balance method to fetch SOL balance of an account \ No newline at end of file +- Added get balance method to fetch SOL balance of an account +- Added functionality to sign SOL and fungible tokens transfer transaction \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 634632b..5af3920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@solana/spl-token": "^0.4.8", "@solana/web3.js": "^1.95.1", "bip39": "^3.1.0", "bs58": "^5.0.0", @@ -434,6 +435,285 @@ "node": ">=5.10" } }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-preview.4.tgz", + "integrity": "sha512-gLMupqI4i+G4uPi2SGF/Tc1aXcviZF2ybC81x7Q/fARamNSgNOCUUoSCg9nWu1Gid6+UhA7LH80sWI8XjKaRog==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/codecs-data-structures": "2.0.0-preview.4", + "@solana/codecs-numbers": "2.0.0-preview.4", + "@solana/codecs-strings": "2.0.0-preview.4", + "@solana/options": "2.0.0-preview.4" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-preview.4.tgz", + "integrity": "sha512-A0VVuDDA5kNKZUinOqHxJQK32aKTucaVbvn31YenGzHX1gPqq+SOnFwgaEY6pq4XEopSmaK16w938ZQS8IvCnw==", + "dependencies": { + "@solana/errors": "2.0.0-preview.4" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.4.tgz", + "integrity": "sha512-nt2k2eTeyzlI/ccutPcG36M/J8NAYfxBPI9h/nQjgJ+M+IgOKi31JV8StDDlG/1XvY0zyqugV3I0r3KAbZRJpA==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/codecs-numbers": "2.0.0-preview.4", + "@solana/errors": "2.0.0-preview.4" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.4.tgz", + "integrity": "sha512-Q061rLtMadsO7uxpguT+Z7G4UHnjQ6moVIxAQxR58nLxDPCC7MB1Pk106/Z7NDhDLHTcd18uO6DZ7ajHZEn2XQ==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/errors": "2.0.0-preview.4" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.4.tgz", + "integrity": "sha512-YDbsQePRWm+xnrfS64losSGRg8Wb76cjK1K6qfR8LPmdwIC3787x9uW5/E4icl/k+9nwgbIRXZ65lpF+ucZUnw==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/codecs-numbers": "2.0.0-preview.4", + "@solana/errors": "2.0.0-preview.4" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5" + } + }, + "node_modules/@solana/errors": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-preview.4.tgz", + "integrity": "sha512-kadtlbRv2LCWr8A9V22On15Us7Nn8BvqNaOB4hXsTB3O0fU40D1ru2l+cReqLcRPij4znqlRzW9Xi0m6J5DIhA==", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/errors/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/errors/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/options": { + "version": "2.0.0-preview.4", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-preview.4.tgz", + "integrity": "sha512-tv2O/Frxql/wSe3jbzi5nVicIWIus/BftH+5ZR+r9r3FO0/htEllZS5Q9XdbmSboHu+St87584JXeDx3xm4jaA==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.4", + "@solana/codecs-data-structures": "2.0.0-preview.4", + "@solana/codecs-numbers": "2.0.0-preview.4", + "@solana/codecs-strings": "2.0.0-preview.4", + "@solana/errors": "2.0.0-preview.4" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.8.tgz", + "integrity": "sha512-RO0JD9vPRi4LsAbMUdNbDJ5/cv2z11MGhtAvFeRzT4+hAGE/FUzRi0tkkWtuCfSIU3twC6CtmAihRp/+XXjWsA==", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-group": "^0.0.5", + "@solana/spl-token-metadata": "^0.1.3", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.94.0" + } + }, + "node_modules/@solana/spl-token-group": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.5.tgz", + "integrity": "sha512-CLJnWEcdoUBpQJfx9WEbX3h6nTdNiUzswfFdkABUik7HVwSNA98u5AYvBVK2H93d9PGMOHAak2lHW9xr+zAJGQ==", + "dependencies": { + "@solana/codecs": "2.0.0-preview.4", + "@solana/spl-type-length-value": "0.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.94.0" + } + }, + "node_modules/@solana/spl-token-metadata": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.4.tgz", + "integrity": "sha512-N3gZ8DlW6NWDV28+vCCDJoTqaCZiF/jDUnk3o8GRkAFzHObiR60Bs1gXHBa8zCPdvOwiG6Z3dg5pg7+RW6XNsQ==", + "dependencies": { + "@solana/codecs": "2.0.0-preview.2", + "@solana/spl-type-length-value": "0.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.91.6" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/codecs": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-preview.2.tgz", + "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", + "@solana/options": "2.0.0-preview.2" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/codecs-core": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-preview.2.tgz", + "integrity": "sha512-gLhCJXieSCrAU7acUJjbXl+IbGnqovvxQLlimztPoGgfLQ1wFYu+XJswrEVQqknZYK1pgxpxH3rZ+OKFs0ndQg==", + "dependencies": { + "@solana/errors": "2.0.0-preview.2" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-preview.2.tgz", + "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" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/codecs-numbers": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-preview.2.tgz", + "integrity": "sha512-aLZnDTf43z4qOnpTcDsUVy1Ci9im1Md8thWipSWbE+WM9ojZAx528oAql+Cv8M8N+6ALKwgVRhPZkto6E59ARw==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.2", + "@solana/errors": "2.0.0-preview.2" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/codecs-strings": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-preview.2.tgz", + "integrity": "sha512-EgBwY+lIaHHgMJIqVOGHfIfpdmmUDNoNO/GAUGeFPf+q0dF+DtwhJPEMShhzh64X2MeCZcmSO6Kinx0Bvmmz2g==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.2", + "@solana/codecs-numbers": "2.0.0-preview.2", + "@solana/errors": "2.0.0-preview.2" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/errors": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-preview.2.tgz", + "integrity": "sha512-H2DZ1l3iYF5Rp5pPbJpmmtCauWeQXRJapkDg8epQ8BJ7cA2Ut/QEtC3CMmw/iMTcuS6uemFNLcWvlOfoQhvQuA==", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.0.0" + }, + "bin": { + "errors": "bin/cli.js" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/@solana/options": { + "version": "2.0.0-preview.2", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-preview.2.tgz", + "integrity": "sha512-FAHqEeH0cVsUOTzjl5OfUBw2cyT8d5Oekx4xcn5hn+NyPAfQJgM3CEThzgRD6Q/4mM5pVUnND3oK/Mt1RzSE/w==", + "dependencies": { + "@solana/codecs-core": "2.0.0-preview.2", + "@solana/codecs-numbers": "2.0.0-preview.2" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/spl-token-metadata/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/spl-type-length-value": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz", + "integrity": "sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==", + "dependencies": { + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@solana/web3.js": { "version": "1.95.1", "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.95.1.tgz", @@ -633,6 +913,14 @@ "node": ">= 10.0.0" } }, + "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/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -1119,6 +1407,12 @@ "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "peer": true + }, "node_modules/file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", @@ -2812,6 +3106,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", diff --git a/package.json b/package.json index 12dd9ee..3a3832b 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "author": "SDargarh", "license": "MIT", "dependencies": { + "@solana/spl-token": "^0.4.8", "@solana/web3.js": "^1.95.1", "bip39": "^3.1.0", "bs58": "^5.0.0", diff --git a/src/config/index.js b/src/config/index.js index d89a48c..041ed84 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -3,6 +3,10 @@ module.exports = { solana: { HD_PATH: `m/44'/501'/0'/0'`, }, + solana_transaction: { + NATIVE_TRANSFER: "NATIVE_TRANSFER", + TOKEN_TRANSFER: "TOKEN_TRANSFER", + }, solana_connection: { MAINNET: { NETWORK: "MAINNET", diff --git a/src/helper/generateTransactionObject.js b/src/helper/generateTransactionObject.js new file mode 100644 index 0000000..e3245e3 --- /dev/null +++ b/src/helper/generateTransactionObject.js @@ -0,0 +1,54 @@ +const solanaWeb3 = require('@solana/web3.js'); +const { getOrCreateAssociatedTokenAccount, createTransferInstruction} = require("@solana/spl-token"); + +const { solana_transaction: { NATIVE_TRANSFER, TOKEN_TRANSFER }} = require("../config"); + +async function generateTransactionObject(transaction, signer, connection) { + const { txnType } = transaction; + let rawTransaction = {}; + + if (txnType === NATIVE_TRANSFER) { + const { to, amount } = transaction; + const receiverPublicKey = new solanaWeb3.PublicKey(to); + rawTransaction = new solanaWeb3.Transaction().add( + solanaWeb3.SystemProgram.transfer({ + fromPubkey: signer.publicKey, + toPubkey: receiverPublicKey, + lamports: amount, + }) + ); + } + + if (txnType === TOKEN_TRANSFER) { + const { to, amount, token } = transaction; + const receiverPublicKey = new solanaWeb3.PublicKey(to); + const tokenPublicKey = new solanaWeb3.PublicKey(token); + + let sourceAccount = await getOrCreateAssociatedTokenAccount( + connection, + signer, + tokenPublicKey, + signer.publicKey + ); + + const toTokenAccount = await getOrCreateAssociatedTokenAccount( + connection, + signer, + tokenPublicKey, + receiverPublicKey + ); + + rawTransaction = new solanaWeb3.Transaction().add( + createTransferInstruction( + sourceAccount.address, + toTokenAccount.address, + signer.publicKey, + amount + ) + ); + } + + return rawTransaction; +} + +module.exports = generateTransactionObject; diff --git a/src/helper/index.js b/src/helper/index.js index dde3a58..22f8b26 100644 --- a/src/helper/index.js +++ b/src/helper/index.js @@ -2,10 +2,14 @@ const setupAccount = require('./account') const getNetwork = require('./getNetwork') const importAccount = require('./importAccount') const getHDPath = require("./getHdPath") +const signTransaction = require('./signTransaction') +const generateTransactionObject = require('./generateTransactionObject') module.exports = { setupAccount, getNetwork, importAccount, - getHDPath + getHDPath, + signTransaction, + generateTransactionObject } \ No newline at end of file diff --git a/src/helper/signTransaction.js b/src/helper/signTransaction.js new file mode 100644 index 0000000..f0c35f7 --- /dev/null +++ b/src/helper/signTransaction.js @@ -0,0 +1,16 @@ +async function sign(transaction, signer, connection, otherSigners) { + + transaction.recentBlockhash = ( + await connection.getRecentBlockhash('max') + ).blockhash; + + transaction.sign(signer) + if (otherSigners.length > 0) { + transaction.partialSign(...otherSigners); + } + + const rawTransaction = transaction.serialize(); + return rawTransaction; +} + +module.exports = sign \ No newline at end of file diff --git a/src/index.js b/src/index.js index 88286ba..558b5b0 100644 --- a/src/index.js +++ b/src/index.js @@ -5,7 +5,10 @@ const ObservableStore = require("obs-store"); const solanaWeb3 = require('@solana/web3.js'); -const { solana: { HD_PATH }, solana_connection: { MAINNET }} = require('./config') +const { + solana: { HD_PATH }, + solana_connection: { MAINNET }, +} = require("./config"); class KeyringController { constructor(opts) { @@ -62,12 +65,39 @@ class KeyringController { const idx = address.indexOf(_address); if (idx < 0) - throw "Invalid address, the address is not available in the wallet" - - const accountDetails = helper.setupAccount(mnemonic, helper.getHDPath(idx)) - const msg = Buffer.from(message) - - return { signedMessage: bs58.encode(nacl.sign.detached(msg, accountDetails.secretKey)) }; + throw "Invalid address, the address is not available in the wallet"; + + const accountDetails = helper.setupAccount(mnemonic, helper.getHDPath(idx)); + const msg = Buffer.from(message); + + return { + signedMessage: bs58.encode( + nacl.sign.detached(msg, accountDetails.secretKey) + ), + }; + } + + async signTransaction(transaction) { + const { mnemonic, address, network, networkType } = this.store.getState(); + + const { from } = transaction; + const idx = address.indexOf(from); + if (idx < 0) + throw "Invalid address, the address is not available in the wallet"; + + try { + const signer = helper.setupAccount(mnemonic, helper.getHDPath(idx)); + + const connection = new solanaWeb3.Connection(network, "confirmed"); + + const rawTx = await helper.generateTransactionObject(transaction, signer, connection); + const rawSignedTxn = await helper.signTransaction(rawTx, signer, connection, []); + + const signedTxn = rawSignedTxn.toString("hex"); + return { signedTransaction: signedTxn }; + } catch (err) { + throw err; + } } persistAllAddress(_address) { From d9a0408783a0a614ec8b3f4dafc404f88ea4ad95 Mon Sep 17 00:00:00 2001 From: SDargarh Date: Tue, 23 Jul 2024 12:33:12 +0530 Subject: [PATCH 5/9] Added functionality to broadcast a signed transaction --- CHANGELOG.md | 3 ++- src/index.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55e08fe..78e434e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,4 +8,5 @@ - Added initial test - Added functionality to sign message - Added get balance method to fetch SOL balance of an account -- Added functionality to sign SOL and fungible tokens transfer transaction \ No newline at end of file +- Added functionality to sign SOL and fungible tokens transfer transaction +- Added functionality to broadcast a signed transaction \ No newline at end of file diff --git a/src/index.js b/src/index.js index 558b5b0..332148c 100644 --- a/src/index.js +++ b/src/index.js @@ -100,6 +100,22 @@ class KeyringController { } } + async sendTransaction(rawTransaction) { + + try { + const { network } = this.store.getState() + const stringBuff = Buffer.from(rawTransaction, 'hex') + + const connection = new solanaWeb3.Connection(network, "confirmed") + const transactionDetails = await connection.sendRawTransaction(stringBuff) + return { transactionDetails: transactionDetails } + + } catch (err) { + console.log(err); + throw err + } + } + persistAllAddress(_address) { const { address } = this.store.getState(); let newAdd = address; From 3556e39604a98fafcf02c1c5828f9dfbc15aa5fa Mon Sep 17 00:00:00 2001 From: SDargarh Date: Tue, 23 Jul 2024 15:57:46 +0530 Subject: [PATCH 6/9] Added functionality to get estimated fee for a transaction --- CHANGELOG.md | 3 ++- src/helper/signTransaction.js | 5 +++-- src/index.js | 28 ++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78e434e..2627ffe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,4 +9,5 @@ - Added functionality to sign message - Added get balance method to fetch SOL balance of an account - Added functionality to sign SOL and fungible tokens transfer transaction -- Added functionality to broadcast a signed transaction \ No newline at end of file +- Added functionality to broadcast a signed transaction +- Added functionality to get estimated fee for a transaction \ No newline at end of file diff --git a/src/helper/signTransaction.js b/src/helper/signTransaction.js index f0c35f7..6bfcc80 100644 --- a/src/helper/signTransaction.js +++ b/src/helper/signTransaction.js @@ -4,13 +4,14 @@ async function sign(transaction, signer, connection, otherSigners) { await connection.getRecentBlockhash('max') ).blockhash; + transaction.feePayer = signer.publicKey; + transaction.sign(signer) if (otherSigners.length > 0) { transaction.partialSign(...otherSigners); } - const rawTransaction = transaction.serialize(); - return rawTransaction; + return transaction; } module.exports = sign \ No newline at end of file diff --git a/src/index.js b/src/index.js index 332148c..689e877 100644 --- a/src/index.js +++ b/src/index.js @@ -78,7 +78,7 @@ class KeyringController { } async signTransaction(transaction) { - const { mnemonic, address, network, networkType } = this.store.getState(); + const { mnemonic, address, network } = this.store.getState(); const { from } = transaction; const idx = address.indexOf(from); @@ -91,9 +91,11 @@ class KeyringController { const connection = new solanaWeb3.Connection(network, "confirmed"); const rawTx = await helper.generateTransactionObject(transaction, signer, connection); + const rawSignedTxn = await helper.signTransaction(rawTx, signer, connection, []); - const signedTxn = rawSignedTxn.toString("hex"); + const signedTxn = rawSignedTxn.serialize().toString("hex"); + return { signedTransaction: signedTxn }; } catch (err) { throw err; @@ -116,6 +118,28 @@ class KeyringController { } } + async getFees(rawTransaction) { + const { mnemonic, address, network } = this.store.getState(); + + const { from } = rawTransaction; + const idx = address.indexOf(from); + if (idx < 0) + throw "Invalid address, the address is not available in the wallet"; + + const signer = helper.setupAccount(mnemonic, helper.getHDPath(idx)); + + const connection = new solanaWeb3.Connection(network, "confirmed"); + + const rawTx = await helper.generateTransactionObject(rawTransaction, signer, connection); + + const rawSignedTxn = await helper.signTransaction(rawTx, signer, connection, []); + + const fees = await connection.getFeeForMessage(rawSignedTxn.compileMessage()); + + return { fees: fees.value }; + + } + persistAllAddress(_address) { const { address } = this.store.getState(); let newAdd = address; From 2e31237a9eab425d1bd30a98e77c22dc17de685a Mon Sep 17 00:00:00 2001 From: SDargarh Date: Tue, 23 Jul 2024 19:22:58 +0530 Subject: [PATCH 7/9] Added functionality to accept priority fee for a transaction --- CHANGELOG.md | 3 ++- src/helper/generateTransactionObject.js | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2627ffe..466793c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,4 +10,5 @@ - Added get balance method to fetch SOL balance of an account - Added functionality to sign SOL and fungible tokens transfer transaction - Added functionality to broadcast a signed transaction -- Added functionality to get estimated fee for a transaction \ No newline at end of file +- Added functionality to get estimated fee for a transaction +- Added functionality to accept priority fee for a transaction \ No newline at end of file diff --git a/src/helper/generateTransactionObject.js b/src/helper/generateTransactionObject.js index e3245e3..f4809d7 100644 --- a/src/helper/generateTransactionObject.js +++ b/src/helper/generateTransactionObject.js @@ -48,6 +48,15 @@ async function generateTransactionObject(transaction, signer, connection) { ); } + // set the desired priority fee in microLamport + if(transaction?.priorityFee && transaction?.priorityFee > 0) { + const addPriorityFee = solanaWeb3.ComputeBudgetProgram.setComputeUnitPrice({ + microLamports: transaction.priorityFee, + }); + + rawTransaction.add(addPriorityFee); + } + return rawTransaction; } From f15c96fe55b0279ee787ae64ec9080a1edd6b747 Mon Sep 17 00:00:00 2001 From: SDargarh Date: Wed, 24 Jul 2024 15:49:00 +0530 Subject: [PATCH 8/9] Added test cases --- CHANGELOG.md | 3 +- test/constants.js | 19 ++++++++++++ test/index.js | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 466793c..6f1de8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,4 +11,5 @@ - Added functionality to sign SOL and fungible tokens transfer transaction - Added functionality to broadcast a signed transaction - Added functionality to get estimated fee for a transaction -- Added functionality to accept priority fee for a transaction \ No newline at end of file +- Added functionality to accept priority fee for a transaction +- Added test cases \ No newline at end of file diff --git a/test/constants.js b/test/constants.js index f768c00..dfdc4a7 100644 --- a/test/constants.js +++ b/test/constants.js @@ -1,5 +1,10 @@ module.exports = { HD_WALLET_12_MNEMONIC: 'affair entry detect broom axis crawl found valve bamboo taste broken hundred', + + TEST_ADDRESS_1: 'FwHMHCWLZDDoFU3e9fngmX5KtGZ2dyvTQfqZxPcEX2Zi', + PRIVATE_KEY_1: '59gSMJ78dCitP5Yw328BGL7fyG4qeT2ovE1bxkRXwfPkzPEMsAP3CGHmbE4r1eFqwcQH4H7AY5CzAsEr5t2cfVBz', + TEST_ADDRESS_2: '71H3rBodCbkMSNDg4vzoH7tmdQmpY8h8SEe4UY6ZujYS', + TEST_ADDRESS_3: '2JUYPMzwdFvrJWcRweyXzFWHQodCgK93EhEB9yF91FUW', SOLANA_NETWORK: { MAINNET: { @@ -16,4 +21,18 @@ module.exports = { URL: 'https://api.devnet.solana.com' } }, + + TRANSACTION_TYPE: { + NATIVE_TRANSFER: "NATIVE_TRANSFER", + TOKEN_TRANSFER: "TOKEN_TRANSFER" + }, + + TRANSFER_SOL: { + SOL_RECEIVER: '71H3rBodCbkMSNDg4vzoH7tmdQmpY8h8SEe4UY6ZujYS', + SOL_AMOUNT: 100000000 + }, + + TESTING_MESSAGE_1: "ThisMessageOneIsForTesting", + TESTING_MESSAGE_2: "This_message_two_is_for_testing", + TESTING_MESSAGE_3: "This message three is for testing" } \ No newline at end of file diff --git a/test/index.js b/test/index.js index dbf6d9e..c2185a2 100644 --- a/test/index.js +++ b/test/index.js @@ -3,25 +3,102 @@ const { KeyringController: Solana, getBalance } = require('../src/index') const { HD_WALLET_12_MNEMONIC, + TEST_ADDRESS_1, + TEST_ADDRESS_2, + PRIVATE_KEY_1, SOLANA_NETWORK: { MAINNET, DEVNET, TESTNET }, + TRANSACTION_TYPE: { + NATIVE_TRANSFER, + TOKEN_TRANSFER + }, + TRANSFER_SOL: { + SOL_RECEIVER, + SOL_AMOUNT + }, + TESTING_MESSAGE_1, + TESTING_MESSAGE_2, + TESTING_MESSAGE_3, } = require('./constants.js') + const opts = { mnemonic: HD_WALLET_12_MNEMONIC, network: DEVNET.NETWORK } +const SOL_TXN_PARAM = { + to: SOL_RECEIVER, + amount: SOL_AMOUNT, + txnType: NATIVE_TRANSFER, +} + describe('Controller test', () => { const solWallet = new Solana(opts) it("Should generate new address ", async () => { const wallet = await solWallet.addAccount() + assert(wallet.address === TEST_ADDRESS_1, "Added address should be " + TEST_ADDRESS_1) console.log("wallet, ", wallet) const wallet2 = await solWallet.addAccount() console.log("wallet2, ", wallet2) + assert(wallet2.address === TEST_ADDRESS_2, "Added address should be " + TEST_ADDRESS_2) + }) + + it("Should get accounts", async () => { + const acc = await solWallet.getAccounts() + console.log("acc ", acc) + assert(acc.length === 2, "Should have 2 addresses") + }) + + it("Should get privateKey ", async () => { + const acc = await solWallet.getAccounts() + const privateKey = await solWallet.exportPrivateKey(acc[0]) + console.log("privateKey, ", privateKey) + assert(privateKey.privateKey === PRIVATE_KEY_1, "Private key should be " + PRIVATE_KEY_1) + }) + + it("Should import new account ", async () => { + const acc = await solWallet.getAccounts() + const { privateKey } = await solWallet.exportPrivateKey(acc[0]) + const account = await solWallet.importWallet(privateKey) + console.log("account, ", account) + assert(account === acc[0], "Should be the zeroth account") + }) + + it("Should get balance of the address ", async () => { + const acc = await solWallet.getAccounts() + const balance = await getBalance(acc[0], opts.network) + console.log("balance ", balance) + assert(balance.balance > 0, "Balance should be greater than 0") + }) + + it("Should sign SOL transfer transaction ", async () => { + assert(solWallet.address !== null) + const acc = await solWallet.getAccounts() + SOL_TXN_PARAM['from'] = acc[0] + + const wallet = await solWallet.signTransaction(SOL_TXN_PARAM) + + console.log("SOL Transfer signed transaction ", wallet.signedTransaction) + }) + + it("Sign message", async () => { + const acc = await solWallet.getAccounts() + + const signedMessage1 = await solWallet.signMessage(TESTING_MESSAGE_1, acc[0]) + console.log("Signed message 1: ", signedMessage1) + assert(signedMessage1.signedMessage, "Message not signed successfully") + + const signedMessage2 = await solWallet.signMessage(TESTING_MESSAGE_2, acc[0]) + console.log("Signed message 2: ", signedMessage2) + assert(signedMessage2.signedMessage, "Message not signed successfully") + + const signedMessage3 = await solWallet.signMessage(TESTING_MESSAGE_3, acc[0]) + console.log("Signed message 3: ", signedMessage3) + assert(signedMessage3.signedMessage, "Message not signed successfully") }) }) \ No newline at end of file From 4eedafd9018885661b0a6e351e2c17c1c4854b7f Mon Sep 17 00:00:00 2001 From: SDargarh Date: Thu, 25 Jul 2024 11:43:05 +0530 Subject: [PATCH 9/9] Added readme --- CHANGELOG.md | 3 +- README.MD | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 README.MD diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f1de8c..ba90764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,4 +12,5 @@ - Added functionality to broadcast a signed transaction - Added functionality to get estimated fee for a transaction - Added functionality to accept priority fee for a transaction -- Added test cases \ No newline at end of file +- Added test cases +- Added readme \ No newline at end of file diff --git a/README.MD b/README.MD new file mode 100644 index 0000000..a2f42be --- /dev/null +++ b/README.MD @@ -0,0 +1,79 @@ +# vault-SOL-controller + +[![npm version](https://badge.fury.io/js/@getsafle%2Fvault-sol-controller.svg)](https://badge.fury.io/js/@getsafle%2Fvault-sol-controller) Static Badge [![Discussions][discussions-badge]][discussions-link] + Static Badge + + + +## Install + +`npm install --save @getsafle/vault-sol-controller` + +## Initialize the solana Controller class + +``` +const { KeyringController, getBalance } = require('@getsafle/vault-sol-controller'); + +const solController = new KeyringController({ + // 12 words mnemonic to create wallet + mnemonic: string, + // network - type of network [TESTNET|MAINNET] + // default is MAINNET even if no network is passed + network: string (TESTNET | MAINNET) +}); +``` + +## Methods + +### add new account + +``` +const keyringState = await solController.addAccount(); +``` + +### Export the private key of an address present in the keyring + +``` +const privateKey = await solController.exportPrivateKey(address); +``` + +### Get all accounts in the keyring + +``` +const privateKey = await solController.getAccounts(); +``` + +### Sign a transaction + +``` +const signedTx = await solController.signTransaction(solTx); + +STX transfer transaction: +solTx: {from, to, amount, txnType} + +Token transfer transaction: +solTx: {from, to, amount, txnType, token} + +transactionType = 'NATIVE_TRANSFER' || 'TOKEN_TRANSFER' +``` + +### Sign a message + +``` +const signedMsg = await solController.signMessage(msgString, address); +``` + +### Get fees + +``` +const fees = await solController.getFees(rawTransaction); +``` + +### Get balance + +``` +const balance = await getBalance(address, network); // if network !== TESTNET then it will fetch mainnet balance +``` + +[discussions-badge]: https://img.shields.io/badge/Code_Quality-passing-rgba +[discussions-link]: https://github.com/getsafle/vault-sol-controller/actions