diff --git a/.gitmodules b/.gitmodules index 8bfcb16..a03cfb3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "public-gateway/lib/solmate"] path = public-gateway/lib/solmate url = https://github.com/transmissions11/solmate +[submodule "TNLS-Gateways/public-gateway/lib/openzeppelin-contracts"] + path = TNLS-Gateways/public-gateway/lib/openzeppelin-contracts + url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/TNLS-Clients/VRFDemo/.editorconfig b/TNLS-Clients/VRFDemo/.editorconfig new file mode 100644 index 0000000..a148ba8 --- /dev/null +++ b/TNLS-Clients/VRFDemo/.editorconfig @@ -0,0 +1,10 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +[*.{js,json,yml,ts}] +charset = utf-8 +indent_style = space +indent_size = 2 diff --git a/TNLS-Clients/VRFDemo/.gitignore b/TNLS-Clients/VRFDemo/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/TNLS-Clients/VRFDemo/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/TNLS-Clients/VRFDemo/index.html b/TNLS-Clients/VRFDemo/index.html new file mode 100644 index 0000000..5589ef6 --- /dev/null +++ b/TNLS-Clients/VRFDemo/index.html @@ -0,0 +1,17 @@ + + + + + + + Snakepath Demo + + +
+ +
+
+
+ + + diff --git a/TNLS-Clients/VRFDemo/package-lock.json b/TNLS-Clients/VRFDemo/package-lock.json new file mode 100644 index 0000000..fb09a65 --- /dev/null +++ b/TNLS-Clients/VRFDemo/package-lock.json @@ -0,0 +1,2325 @@ +{ + "name": "create-payload", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "create-payload", + "version": "0.1.0", + "dependencies": { + "buffer": "^6.0.3", + "ethers": "^5.6.9", + "secure-random": "^1.1.2" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.1.4", + "@types/node": "^16.11.47", + "@types/secure-random": "^1.1.0", + "eslint": "^8.21.0", + "eslint-plugin-vue": "^9.3.0", + "prettier": "^2.7.1", + "typescript": "^4.6.4", + "vite": "^3.1.0", + "vite-plugin-wasm": "^2" + }, + "engines": { + "node": "20.x" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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.0", + "@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.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "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" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.6.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "16.18.68", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/secure-random": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secure-random/node_modules/@types/node": { + "version": "20.10.4", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.11.2", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "license": "MIT" + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bech32": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "license": "MIT" + }, + "node_modules/boolbase": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "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", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.15.18", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.18", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.19.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.13", + "semver": "^7.5.4", + "vue-eslint-parser": "^9.3.1", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@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/contracts": "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/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.15.0", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.7", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.32", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "2.79.1", + "dev": true, + "license": "MIT", + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "license": "MIT" + }, + "node_modules/secure-random": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", + "integrity": "sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ==" + }, + "node_modules/semver": { + "version": "7.5.4", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/type-check": { + "version": "0.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.15.9", + "postcss": "^8.4.18", + "resolve": "^1.22.1", + "rollup": "^2.79.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-wasm": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "peerDependencies": { + "vite": "^3" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.4.6", + "license": "MIT", + "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/xml-name-validator": { + "version": "4.0.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/TNLS-Clients/VRFDemo/package.json b/TNLS-Clients/VRFDemo/package.json new file mode 100644 index 0000000..aec79c1 --- /dev/null +++ b/TNLS-Clients/VRFDemo/package.json @@ -0,0 +1,30 @@ +{ + "name": "create-payload", + "private": true, + "version": "0.1.0", + "type": "module", + "engines": { + "node": "20.x" + }, + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "buffer": "^6.0.3", + "ethers": "^5.6.9", + "secure-random": "^1.1.2" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.1.4", + "@types/node": "^16.11.47", + "@types/secure-random": "^1.1.0", + "eslint": "^8.21.0", + "eslint-plugin-vue": "^9.3.0", + "prettier": "^2.7.1", + "typescript": "^4.6.4", + "vite": "^3.1.0", + "vite-plugin-wasm": "^2" + } +} diff --git a/TNLS-Clients/VRFDemo/public/vite.svg b/TNLS-Clients/VRFDemo/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/TNLS-Clients/VRFDemo/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/TNLS-Clients/VRFDemo/src/connect.ts b/TNLS-Clients/VRFDemo/src/connect.ts new file mode 100644 index 0000000..e308f86 --- /dev/null +++ b/TNLS-Clients/VRFDemo/src/connect.ts @@ -0,0 +1,16 @@ +import { ethers } from 'ethers'; + +export function setupConnect(element: HTMLButtonElement) { + element.innerHTML = `Connect` + let myAddress : string + const connect = async () => { + // @ts-ignore + const provider = new ethers.providers.Web3Provider(window.ethereum); + [myAddress] = await provider.send("eth_requestAccounts", []); + element.innerHTML = `Connected` + document.querySelector('#account')!.innerHTML = ` +

Connected account: ${myAddress}

+ ` + } + element.addEventListener('click', () => connect()) +} \ No newline at end of file diff --git a/TNLS-Clients/VRFDemo/src/main.ts b/TNLS-Clients/VRFDemo/src/main.ts new file mode 100644 index 0000000..fa2a58f --- /dev/null +++ b/TNLS-Clients/VRFDemo/src/main.ts @@ -0,0 +1,48 @@ +import './style.css' +import { setupConnect } from './connect' +import { setupSubmit } from './submit' + +document.querySelector('#app')!.innerHTML = ` +
+

Atbash Labs

+ +
+
+

Sample Application: Random Number Generation using Secret VRF

+
+ +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+` +setupSubmit(document.querySelector('#submit')!) +setupConnect(document.querySelector('#connect')!) \ No newline at end of file diff --git a/TNLS-Clients/VRFDemo/src/style.css b/TNLS-Clients/VRFDemo/src/style.css new file mode 100644 index 0000000..c8d6da9 --- /dev/null +++ b/TNLS-Clients/VRFDemo/src/style.css @@ -0,0 +1,192 @@ +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +#links { + display: flex; + place-items: center; + justify-content: center; +} + +header h1 { + margin-bottom: 0; +} + +header .card { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.4em 1.2em; + width: 20ch; + margin: 1em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} + +header .card:hover { + border-color: #646cff; +} +header .card:focus, +header .card:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; + animation: fadeIn 2s; + -webkit-animation: fadeIn 2s; + -moz-animation: fadeIn 2s; + -o-animation: fadeIn 2s; + -ms-animation: fadeIn 2s; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.vanilla:hover { + filter: drop-shadow(0 0 2em #3178c6aa); +} + +.card { + padding: 2em; +} + +form { + display: inline-block; + align-items: center; + text-align: left; + max-width: 400px; +} + +#preview { + max-width: 800px; + text-align: left; +} +#wallet { + position: absolute; + top: 6%; + right: 5%; +} +#account { + display: inline-block; + position: absolute; + text-shadow: 2px 2px 5px #242424; + top: 0; + right: 5%; +} + +.read-the-docs { + color: #888; +} + +input { + width: 100%; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +#submit { + margin-top: 0.6em; + width:100%; +} + +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} + +@keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@-moz-keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@-webkit-keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@-o-keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} + +@-ms-keyframes fadeIn { + 0% { opacity: 0; } + 100% { opacity: 1; } +} \ No newline at end of file diff --git a/TNLS-Clients/VRFDemo/src/submit.ts b/TNLS-Clients/VRFDemo/src/submit.ts new file mode 100644 index 0000000..dd8d7f7 --- /dev/null +++ b/TNLS-Clients/VRFDemo/src/submit.ts @@ -0,0 +1,84 @@ +import { ethers } from "ethers"; +import { arrayify, hexlify, SigningKey, keccak256, recoverPublicKey, computeAddress, sha256 } from "ethers/lib/utils"; +import { Buffer } from "buffer"; +import secureRandom from "secure-random"; + +export function setupSubmit(element: HTMLButtonElement) { + + const publicClientAddress = '0x62A76e4fFB2fa4b4FecA249cD1646C7fD1469319' + const routing_contract = "secret1zash9uk88y3sr8sjf0jdrlfsdsyuk6szvj99k6" + const routing_code_hash = "d94d2cd7d22f0509c7ca0b80d6576ecfebf2618c6026204c30a35f6624cb3230" + + // @ts-ignore + const provider = new ethers.providers.Web3Provider(window.ethereum); + + element.addEventListener("click", async function(event: Event){ + event.preventDefault() + const [myAddress] = await provider.send("eth_requestAccounts", []); + + const data = JSON.stringify({ + numWords:20 + }) + + + // create the abi interface and encode the function data + const abi = [{"type":"constructor","inputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"callback","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_result","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"postExecution","inputs":[{"name":"_taskId","type":"uint256","internalType":"uint256"},{"name":"_sourceNetwork","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.PostExecutionInfo","components":[{"name":"payload_hash","type":"bytes32","internalType":"bytes32"},{"name":"result_hash","type":"bytes32","internalType":"bytes32"},{"name":"packet_hash","type":"bytes32","internalType":"bytes32"},{"name":"callback_address","type":"bytes20","internalType":"bytes20"},{"name":"callback_selector","type":"bytes4","internalType":"bytes4"},{"name":"callback_gas_limit","type":"bytes4","internalType":"bytes4"},{"name":"packet_signature","type":"bytes","internalType":"bytes"},{"name":"result_signature","type":"bytes","internalType":"bytes"},{"name":"result","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"requestRandomWords","inputs":[{"name":"_numWords","type":"uint32","internalType":"uint32"},{"name":"_callbackGasLimit","type":"uint32","internalType":"uint32"}],"outputs":[{"name":"requestId","type":"uint256","internalType":"uint256"}],"stateMutability":"payable"},{"type":"function","name":"send","inputs":[{"name":"_payloadHash","type":"bytes32","internalType":"bytes32"},{"name":"_userAddress","type":"address","internalType":"address"},{"name":"_routingInfo","type":"string","internalType":"string"},{"name":"_info","type":"tuple","internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setContractAddressAndCodeHash","inputs":[{"name":"_contractAddress","type":"string","internalType":"string"},{"name":"_contractCodeHash","type":"string","internalType":"string"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"setMasterVerificationAddress","inputs":[{"name":"_masterVerificationAddress","type":"address","internalType":"address"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"function","name":"updateRoute","inputs":[{"name":"_route","type":"string","internalType":"string"},{"name":"_verificationAddress","type":"address","internalType":"address"},{"name":"_signature","type":"bytes","internalType":"bytes"}],"outputs":[],"stateMutability":"nonpayable"},{"type":"event","name":"ComputedResult","inputs":[{"name":"taskId","type":"uint256","indexed":false,"internalType":"uint256"},{"name":"result","type":"bytes","indexed":false,"internalType":"bytes"}],"anonymous":false},{"type":"event","name":"logCompletedTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"result_hash","type":"bytes32","indexed":false,"internalType":"bytes32"}],"anonymous":false},{"type":"event","name":"logNewTask","inputs":[{"name":"task_id","type":"uint256","indexed":true,"internalType":"uint256"},{"name":"source_network","type":"string","indexed":false,"internalType":"string"},{"name":"user_address","type":"address","indexed":false,"internalType":"address"},{"name":"routing_info","type":"string","indexed":false,"internalType":"string"},{"name":"payload_hash","type":"bytes32","indexed":false,"internalType":"bytes32"},{"name":"info","type":"tuple","indexed":false,"internalType":"struct Gateway.ExecutionInfo","components":[{"name":"user_key","type":"bytes","internalType":"bytes"},{"name":"user_pubkey","type":"bytes","internalType":"bytes"},{"name":"routing_code_hash","type":"string","internalType":"string"},{"name":"handle","type":"string","internalType":"string"},{"name":"nonce","type":"bytes12","internalType":"bytes12"},{"name":"payload","type":"bytes","internalType":"bytes"},{"name":"payload_signature","type":"bytes","internalType":"bytes"}]}],"anonymous":false},{"type":"error","name":"CallbackError","inputs":[]},{"type":"error","name":"InvalidPacketSignature","inputs":[]},{"type":"error","name":"InvalidPayloadHash","inputs":[]},{"type":"error","name":"InvalidResultSignature","inputs":[]},{"type":"error","name":"InvalidSignature","inputs":[]},{"type":"error","name":"InvalidSignatureLength","inputs":[]},{"type":"error","name":"InvalidSignatureSValue","inputs":[]},{"type":"error","name":"TaskAlreadyCompleted","inputs":[]}] + const iface= new ethers.utils.Interface( abi ) + const FormatTypes = ethers.utils.FormatTypes; + console.log(iface.format(FormatTypes.full)) + + + const functionData = iface.encodeFunctionData("send", + [ + _payloadHash, + _userAddress, + _routingInfo, + _info, + ] + ) + console.log(functionData) + + const tx_params = [ + { + gas: '0x249F0', // 150000 + to: publicClientAddress, + from: myAddress, + value: '0x00', // 0 + data: functionData, // TODO figure out what this data is meant to be + }, + ]; + + const txHash = await provider.send("eth_sendTransaction", tx_params); + console.log(txHash) + + document.querySelector('#preview')!.innerHTML = ` +

Raw Payload

+

${thePayload}

+ +

TNLS Payload

+

${ciphertext.toString('base64')}

+ +

Payload Hash

+

${payloadHash}

+ +

Payload Signature

+

${payloadSignature}

+ +

Other Info

+

+ + Public key used during encryption: ${userPublicKey}
+ Nonce used during encryption: ${nonce}
+ +

+ +

Transaction Parameters

+

Tx Hash: ${txHash}

+

Gateway Address (to check the postExecution callback) ${publicClientAddress}

+

${JSON.stringify(tx_params)}

+ ` + }) +} +//

Tx Hash: ${txHash}

+//

Gateway Address (to check the postExecution callback) ${publicClientAddress}

+//

${JSON.stringify(tx_params)}

\ No newline at end of file diff --git a/TNLS-Clients/VRFDemo/src/vite-env.d.ts b/TNLS-Clients/VRFDemo/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/TNLS-Clients/VRFDemo/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/TNLS-Clients/VRFDemo/tsconfig.json b/TNLS-Clients/VRFDemo/tsconfig.json new file mode 100644 index 0000000..c82b46b --- /dev/null +++ b/TNLS-Clients/VRFDemo/tsconfig.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM"], + "moduleResolution": "Node", + "strict": true, + "sourceMap": true, + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "noEmit": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/TNLS-Clients/VRFDemo/vite.config.ts b/TNLS-Clients/VRFDemo/vite.config.ts new file mode 100644 index 0000000..13298e7 --- /dev/null +++ b/TNLS-Clients/VRFDemo/vite.config.ts @@ -0,0 +1,13 @@ +import { fileURLToPath, URL } from "node:url"; + +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, +}); diff --git a/TNLS-Clients/payload-encryption/package-lock.json b/TNLS-Clients/payload-encryption/package-lock.json index baf7d57..fb09a65 100644 --- a/TNLS-Clients/payload-encryption/package-lock.json +++ b/TNLS-Clients/payload-encryption/package-lock.json @@ -1059,7 +1059,8 @@ }, "node_modules/elliptic": { "version": "6.5.4", - "license": "MIT", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -2034,7 +2035,8 @@ }, "node_modules/secure-random": { "version": "1.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/secure-random/-/secure-random-1.1.2.tgz", + "integrity": "sha512-H2bdSKERKdBV1SwoqYm6C0y+9EA94v6SUBOWO8kDndc4NoUih7Dv6Tsgma7zO1lv27wIvjlD0ZpMQk7um5dheQ==" }, "node_modules/semver": { "version": "7.5.4", diff --git a/TNLS-Clients/payload-encryption/src/wasm/encrypt_payload_bg.wasm.gz b/TNLS-Clients/payload-encryption/src/wasm/encrypt_payload_bg.wasm.gz deleted file mode 100644 index 1b5e9f4..0000000 Binary files a/TNLS-Clients/payload-encryption/src/wasm/encrypt_payload_bg.wasm.gz and /dev/null differ diff --git a/TNLS-Gateways/public-gateway/lib/openzeppelin-contracts b/TNLS-Gateways/public-gateway/lib/openzeppelin-contracts new file mode 160000 index 0000000..01ef448 --- /dev/null +++ b/TNLS-Gateways/public-gateway/lib/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 01ef448981be9d20ca85f2faf6ebdf591ce409f3 diff --git a/TNLS-Gateways/public-gateway/script/DeployScript.s.sol b/TNLS-Gateways/public-gateway/script/DeployScript.s.sol index 939ce9a..02904f2 100644 --- a/TNLS-Gateways/public-gateway/script/DeployScript.s.sol +++ b/TNLS-Gateways/public-gateway/script/DeployScript.s.sol @@ -7,17 +7,23 @@ import "forge-std/console2.sol"; import "forge-std/Script.sol"; import {Gateway} from "../src/Gateway.sol"; import {RandomnessReciever} from "../src/RandomnessReciever.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + contract DeployScript is Script { function setUp() public {} - Gateway gatewayAddress; + address deployer; + ProxyAdmin proxyAdmin; + Gateway gatewayLogic; + TransparentUpgradeableProxy gatewayProxy; RandomnessReciever randomnessAddress; - + uint256 privKey = vm.envUint("ETH_PRIVATE_KEY"); - address deployer = vm.rememberKey(privKey); - /// @notice Get the encoded hash of the inputs for signing + + /// @notice Get the encoded hash of the inputs for signing /// @param _routeInput Route name /// @param _verificationAddressInput Address corresponding to the route function getRouteHash(string memory _routeInput, address _verificationAddressInput) public pure returns (bytes32) { @@ -35,24 +41,43 @@ contract DeployScript is Script { } function run() public { + deployer = vm.rememberKey(privKey); vm.startBroadcast(); - gatewayAddress = new Gateway(); - randomnessAddress = new RandomnessReciever(); + // Deploy ProxyAdmin + proxyAdmin = new ProxyAdmin(msg.sender); + + // Deploy Gateway Logic Contract + gatewayLogic = new Gateway(); - console2.logAddress(address(gatewayAddress)); + // Prepare initializer data for Gateway + bytes memory initializerData = abi.encodeWithSelector( + Gateway.initialize.selector + ); + + // Deploy TransparentUpgradeableProxy + gatewayProxy = new TransparentUpgradeableProxy( + address(gatewayLogic), + address(proxyAdmin), + initializerData + ); + + // Cast the proxy address to the Gateway interface + Gateway gateway = Gateway(address(gatewayProxy)); + + // Continue with your existing setup, but replace `gatewayAddress` with `gateway` + randomnessAddress = new RandomnessReciever(); + console2.logAddress(address(gateway)); console2.logAddress(deployer); - randomnessAddress.setGatewayAddress(address(gatewayAddress)); + randomnessAddress.setGatewayAddress(address(gateway)); + // Initialize master verification Address - gatewayAddress.setMasterVerificationAddress(deployer); - gatewayAddress.setContractAddressAndCodeHash("secret1u3zsgg680f0fmjv7w6qkhpe6sh78wngzevvlvd", - "866d57146b2d9cccde295b57d84f22995568ffb5dc31a795e73f351bbfb19dfb"); - address verificationAddress = 0xBC0951b2f849020027921e7286aE134C8e159203; - gatewayAddress.setChainidentifier("ethereum"); + gateway.setMasterVerificationAddress(deployer); // Replace gatewayAddress with gateway + address verificationAddress = 0x09362bF5bbA88948f8B9fCDbB5B56C8CdD2403ad; /// ------ Update Routes Param Setup ------- /// - string memory route = "secret"; + string memory route = "secret-4"; //address verificationAddress = vm.envAddress("SECRET_GATEWAY_ETH_ADDRESS"); // Update the route with with masterVerificationKey signature @@ -62,8 +87,8 @@ contract DeployScript is Script { (uint8 v, bytes32 r, bytes32 s) = vm.sign(privKey, ethSignedMessageHash); bytes memory sig = abi.encodePacked(r, s, v); - gatewayAddress.updateRoute(route, verificationAddress, sig); + gateway.updateRoute(route, verificationAddress, sig); vm.stopBroadcast(); } -} +} \ No newline at end of file diff --git a/TNLS-Gateways/public-gateway/src/Gateway.sol b/TNLS-Gateways/public-gateway/src/Gateway.sol index 8da7ed3..ed03b11 100644 --- a/TNLS-Gateways/public-gateway/src/Gateway.sol +++ b/TNLS-Gateways/public-gateway/src/Gateway.sol @@ -1,8 +1,26 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; -contract Gateway { +import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + + /*////////////////////////////////////////////////////////////// + Gateway Proxy + //////////////////////////////////////////////////////////////*/ +contract GatewayProxy is TransparentUpgradeableProxy { + constructor(address _logic, address admin_, bytes memory _data) TransparentUpgradeableProxy(_logic, admin_, _data) {} +} + + /*////////////////////////////////////////////////////////////// + Secret VRF Interface + //////////////////////////////////////////////////////////////*/ +interface IRandomness { + function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external; +} + +contract Gateway is Initializable { /*////////////////////////////////////////////////////////////// Structs //////////////////////////////////////////////////////////////*/ @@ -22,6 +40,13 @@ contract Gateway { bytes payload_signature; } + struct VRFSecretContract { + bytes32 contract_address_1; + bytes13 contract_address_2; + bytes32 contract_code_hash_1; + bytes32 contract_code_hash_2; + } + struct PostExecutionInfo { bytes32 payload_hash; bytes32 result_hash; @@ -34,6 +59,21 @@ contract Gateway { bytes result; } + /*////////////////////////////////////////////////////////////// + State Variables + //////////////////////////////////////////////////////////////*/ + + address public owner; + address public masterVerificationAddress; + uint256 public taskId; + + /// @dev Task ID ====> ReducedTask + mapping(uint256 => ReducedTask) public tasks; + + /// @dev mapping of chain name string to the verification address + mapping(string => address) public route; + + /*////////////////////////////////////////////////////////////// Errors //////////////////////////////////////////////////////////////*/ @@ -66,8 +106,11 @@ contract Gateway { Helpers //////////////////////////////////////////////////////////////*/ - /// @notice Splitting signature util for recovery - /// @param _sig The signature + /// @notice Splits a signature into its r, s, and v components + /// @param _sig The signature to split + /// @return r The r component of the signature + /// @return s The s component of the signature + /// @return v The recovery byte of the signature function splitSignature(bytes memory _sig) private pure returns (bytes32 r, bytes32 s, uint8 v) { require(_sig.length == 65, "invalid signature length"); @@ -81,19 +124,20 @@ contract Gateway { } } - /// @notice Recover the signer from message hash with a valid recovery ID - /// @param _signedMessageHash the signed message hash - /// @param _signature The signature that needs to be verified + /// @notice Recovers the signer address from a message hash and a signature + /// @param _signedMessageHash The hash of the signed message + /// @param _signature The signature + /// @return The address of the signer function recoverSigner(bytes32 _signedMessageHash, bytes memory _signature) private pure returns (address) { (bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature); - return ecrecover(_signedMessageHash, v, r, s); } - /// @notice Get the encoded hash of the inputs for signing - /// @param _routeInput Route name - /// @param _verificationAddressInput Address corresponding to the route + /// @notice Calculates the keccak256 hash of the route name and verification address + /// @param _routeInput The route name + /// @param _verificationAddressInput The verification address + /// @return The calculated hash function getRouteHash(string calldata _routeInput, address _verificationAddressInput) private pure returns (bytes32) { return keccak256(abi.encode(_routeInput, _verificationAddressInput)); } @@ -102,6 +146,77 @@ contract Gateway { return bytes31(data & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00); } + function encodeBase64(bytes memory data) private pure returns (string memory) { + if (data.length == 0) return ""; + string memory table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + string memory result = new string(4 * ((data.length + 2) / 3)); + /// @solidity memory-safe-assembly + assembly { + let tablePtr := add(table, 1) + let resultPtr := add(result, 32) + for { + let dataPtr := data + let endPtr := add(data, mload(data)) + } lt(dataPtr, endPtr) { + } { + dataPtr := add(dataPtr, 3) + let input := mload(dataPtr) + mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) + resultPtr := add(resultPtr, 1) + mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) + resultPtr := add(resultPtr, 1) + } + switch mod(mload(data), 3) + case 1 { + mstore8(sub(resultPtr, 1), 0x3d) + mstore8(sub(resultPtr, 2), 0x3d) + } + case 2 { + mstore8(sub(resultPtr, 1), 0x3d) + } + } + return result; + } + + function uint256toString(uint256 value) private pure returns (string memory ptr) { + assembly { + ptr := add(mload(0x40), 128) + mstore(0x40, ptr) + let end := ptr + for { + let temp := value + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + temp := div(temp, 10) + } temp { + temp := div(temp, 10) + } { + ptr := sub(ptr, 1) + mstore8(ptr, add(48, mod(temp, 10))) + } + let length := sub(end, ptr) + ptr := sub(ptr, 32) + mstore(ptr, length) + } + } + + function bytesToUint256Array(bytes memory data) public pure returns (uint256[] memory) { + require(data.length % 32 == 0, "Data length must be a multiple of 32 bytes"); + + uint256[] memory uintArray; + assembly { + // Cast the bytes array to a uint256[] array by setting the appropriate length + uintArray := data + mstore(uintArray, div(mload(data), 32)) + } + return uintArray; + } + + /*////////////////////////////////////////////////////////////// Events //////////////////////////////////////////////////////////////*/ @@ -121,58 +236,46 @@ contract Gateway { event ComputedResult(uint256 taskId, bytes result); /*////////////////////////////////////////////////////////////// - Constructor + Modifiers //////////////////////////////////////////////////////////////*/ - address private immutable owner; - string private chainIdentifier; - string private routing_info; - string private routing_code_hash; - - constructor() { - owner = msg.sender; - } - modifier onlyOwner() { require(msg.sender == owner, "UNAUTHORIZED"); _; } + /*////////////////////////////////////////////////////////////// + Initializer + //////////////////////////////////////////////////////////////*/ + + /// @notice Replaces the constructor for upgradeable contracts + function initialize() public initializer { + owner = msg.sender; + taskId = 1; + } + /*////////////////////////////////////////////////////////////// Initialization //////////////////////////////////////////////////////////////*/ - address private masterVerificationAddress; - /// @notice Initialize the verification address /// @param _masterVerificationAddress The input address function setMasterVerificationAddress(address _masterVerificationAddress) external onlyOwner { masterVerificationAddress = _masterVerificationAddress; } - function setContractAddressAndCodeHash(string calldata _contractAddress, string calldata _codeHash) external onlyOwner { - routing_info = _contractAddress; - routing_code_hash = _codeHash; - } - - function setChainidentifier(string calldata _chainIdentifier) external onlyOwner { - chainIdentifier = _chainIdentifier; - } - /*////////////////////////////////////////////////////////////// Update Routes //////////////////////////////////////////////////////////////*/ - /// @dev mapping of chain name string to the verification address - mapping(string => address) private route; - /// @notice Updating the route /// @param _route Route name /// @param _verificationAddress Address corresponding to the route /// @param _signature Signed hashed inputs(_route + _verificationAddress) + function updateRoute(string calldata _route, address _verificationAddress, bytes calldata _signature) external onlyOwner { bytes32 routeHash = getRouteHash(_route, _verificationAddress); - bytes32 ethSignedMessageHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", routeHash)); + bytes32 ethSignedMessageHash = keccak256(bytes.concat("\x19Ethereum Signed Message:\n32", routeHash)); if (recoverSigner(ethSignedMessageHash, _signature) != masterVerificationAddress) { revert InvalidSignature(); @@ -185,27 +288,26 @@ contract Gateway { Pre Execution //////////////////////////////////////////////////////////////*/ - uint256 private taskId = 1; - - /// @dev Task ID ====> Task - mapping(uint256 => ReducedTask) private tasks; - - /// @notice Send - /// @param _userAddress User address - /// @param _sourceNetwork Source network of msg - /// @param _routingInfo Routing info for computation - /// @param _payloadHash Payload hash - /// @param _info ExecutionInfo struct + /// @notice Creates a new task with provided execution info + /// @param _payloadHash Hash of the payload + /// @param _userAddress Address of the user + /// @param _routingInfo Routing information + /// @param _info Execution information function send( bytes32 _payloadHash, address _userAddress, - string calldata _sourceNetwork, string calldata _routingInfo, ExecutionInfo calldata _info) - external { + external payable { - // Payload hash signature verification + // Payload hash verification + + if (keccak256(bytes.concat("\x19Ethereum Signed Message:\n32", keccak256(_info.payload))) != _payloadHash) { + revert InvalidPayloadHash(); + } + + // Payload signature verification if (recoverSigner(_payloadHash, _info.payload_signature) != _userAddress) { revert InvalidSignature(); @@ -216,7 +318,7 @@ contract Gateway { emit logNewTask( taskId, - _sourceNetwork, + uint256toString(block.chainid), _userAddress, _routingInfo, _payloadHash, @@ -226,52 +328,62 @@ contract Gateway { taskId++; } - function requestRandomWords( + /// @notice Requests random words for VRF + /// @param _numWords The number of random words requested + /// @param _callbackGasLimit The gas limit for the callback + /// @return requestId The request ID for the random words + + function requestRandomness( uint32 _numWords, uint32 _callbackGasLimit ) external payable returns (uint256 requestId) { - require(_numWords <= 50, "Too many words requested"); + require(_numWords <= 2000, "Too many words requested"); - string memory callback_address = Encoders.encodeBase64(abi.encodePacked(msg.sender)); + string memory callback_address = encodeBase64(bytes.concat(bytes20(msg.sender))); - bytes memory payload = abi.encodePacked( + //use hard coded contract values instead of storage variables, saves around 8,500 in gas per TX. + //Since contract is upgradeable, we can update these values as well with it. + bytes memory _routing_info = "secret10hwq375veu49khx9dkcl6249n6fc2u5tft50jp"; + bytes memory _routing_code_hash = "d94d2cd7d22f0509c7ca0b80d6576ecfebf2618c6026204c30a35f6624cb3230"; + + bytes memory payload = bytes.concat( bytes23(0x7b2264617461223a227b5c226e756d576f7264735c223a), //bytes representation of '{"data":"{\"numWords\":' because solidity has problems with correct string escaping of numWords - Encoders.uint256toString(_numWords), - '}","routing_info": "',routing_info, - '","routing_code_hash": "',routing_code_hash, - '","user_address": "0x0000000000000000000000000000000000000000",', //unused user_address here - '"user_key": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",', // 33 bytes of zeros in base64 - '"callback_address": "', callback_address, + bytes(uint256toString(_numWords)), + '}","routing_info": "',_routing_info, + '","routing_code_hash": "',_routing_code_hash, + '","user_address": "0x0000000000000000000000000000000000000000","user_key": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",', //unused user_address here + + 33 bytes of zeros in base64 for user_key + '"callback_address": "', bytes(callback_address), '","callback_selector": "OLpGFA==",', // 0x38ba4614 hex value already converted into base64, callback_selector of the fullfillRandomWords function - '"callback_gas_limit": ', Encoders.uint256toString(_callbackGasLimit),'}' // Corrected function call + '"callback_gas_limit": ', bytes(uint256toString(_callbackGasLimit)),'}' ); - bytes32 payloadHash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",keccak256(payload))); + bytes32 payloadHash = keccak256(bytes.concat("\x19Ethereum Signed Message:\n32", keccak256(payload))); // ExecutionInfo struct ExecutionInfo memory executionInfo = ExecutionInfo({ user_key: new bytes(33), // equals AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA in base64 user_pubkey: new bytes(64), // Fill with 0 bytes - routing_code_hash: routing_code_hash, + routing_code_hash: string(_routing_code_hash), handle: "request_random", nonce: bytes12(0), - payload: payload, // Make sure payload is correctly formatted + payload: payload, payload_signature: new bytes(64) // empty signature, fill with 0 bytes }); + uint256 oldTaskId = taskId; // persisting the task - tasks[taskId] = ReducedTask(sliceLastByte(payloadHash), false); + tasks[oldTaskId] = ReducedTask(sliceLastByte(payloadHash), false); emit logNewTask( taskId, - chainIdentifier, + uint256toString(block.chainid), msg.sender, - routing_info, + string(_routing_info), payloadHash, executionInfo ); - uint256 oldTaskId = taskId; + taskId++; return oldTaskId; } @@ -280,158 +392,86 @@ contract Gateway { Post Execution //////////////////////////////////////////////////////////////*/ - /// @notice Post-Execution - /// @param _taskId Task Id of the executed message - /// @param _sourceNetwork Source network of the message - /// @param _info PostExecutionInfo struct + /// @notice Handles the post-execution logic of a task + /// @param _taskId The ID of the task + /// @param _sourceNetwork The source network of the task + /// @param _info Post execution information function postExecution(uint256 _taskId, string calldata _sourceNetwork, PostExecutionInfo calldata _info) external { - - ReducedTask storage task = tasks[_taskId]; + + ReducedTask storage task = tasks[_taskId]; - // Check if the task is already completed - if (task.completed) { - revert TaskAlreadyCompleted(); - } - - if (sliceLastByte(_info.payload_hash) != task.payload_hash_reduced) { - revert InvalidPayloadHash(); - } - - address checkerAddress = route[_sourceNetwork]; - - // Result signature verification - if (recoverSigner(_info.result_hash, _info.result_signature) != checkerAddress) { - revert InvalidResultSignature(); - } + // Check if the task is already completed + if (task.completed) { + revert TaskAlreadyCompleted(); + } - // Concatenate data elements - bytes memory data = bytes.concat( - bytes(_sourceNetwork), - bytes(chainIdentifier), - bytes32(_taskId), - bytes32(_info.payload_hash), - bytes(_info.result), - bytes32(_info.result_hash), - bytes20(_info.callback_address), - bytes4(_info.callback_selector)); - - // Perform Keccak256 + sha256 hash - bytes32 packetHash = sha256(abi.encodePacked(keccak256(data))); + if (sliceLastByte(_info.payload_hash) != task.payload_hash_reduced) { + revert InvalidPayloadHash(); + } - // Packet signature verification - if ((_info.packet_hash != packetHash) || recoverSigner(_info.packet_hash, _info.packet_signature) != checkerAddress) { - revert InvalidPacketSignature(); - } - - task.completed = true; + address checkerAddress = route[_sourceNetwork]; - emit logCompletedTask(_taskId, _info.payload_hash, _info.result_hash); + // Result signature verification + if (recoverSigner(_info.result_hash, _info.result_signature) != checkerAddress) { + revert InvalidResultSignature(); + } - // Continue with the function execution + // Concatenate data elements + bytes memory data = bytes.concat( + bytes(_sourceNetwork), + bytes(uint256toString(block.chainid)), + bytes32(_taskId), + _info.payload_hash, + _info.result, + _info.result_hash, + _info.callback_address, + _info.callback_selector); + + // Perform Keccak256 + sha256 hash + bytes32 packetHash = sha256(abi.encodePacked(keccak256(data))); + + // Packet signature verification + if ((_info.packet_hash != packetHash) || recoverSigner(_info.packet_hash, _info.packet_signature) != checkerAddress) { + revert InvalidPacketSignature(); + } + + task.completed = true; - // Additional conversion for Secret VRF into uint256[] if callback_selector matches the fullfillRandomWords selector. + emit logCompletedTask(_taskId, _info.payload_hash, _info.result_hash); - bool val; + // Continue with the function execution + // Additional conversion for Secret VRF into uint256[] if callback_selector matches the fullfillRandomWords selector. - if (_info.callback_selector == bytes4(0x38ba4614)) { - uint256[] memory randomWords = Encoders.bytesToUint256Array(_info.result); - (val, ) = address(_info.callback_address).call{gas: uint32(_info.callback_gas_limit)}( - abi.encodeWithSelector(_info.callback_selector, _taskId, randomWords) - ); - } - else { - (val, ) = address(_info.callback_address).call{gas: uint32(_info.callback_gas_limit)}( - abi.encodeWithSelector(_info.callback_selector, _taskId, _info.result) - ); - } - if (!val) { - revert CallbackError(); + if (_info.callback_selector == bytes4(0x38ba4614)) { + uint256[] memory randomWords = bytesToUint256Array(_info.result); + IRandomness randomness = IRandomness(address(_info.callback_address)); + randomness.fulfillRandomWords(_taskId, randomWords); + } + else { + bool val; + (val, ) = address(_info.callback_address).call{gas: uint32(_info.callback_gas_limit)}( + abi.encodeWithSelector(_info.callback_selector, _taskId, _info.result) + ); + if (!val) { + revert CallbackError(); + } + } } -} /*////////////////////////////////////////////////////////////// Callback //////////////////////////////////////////////////////////////*/ - /// @param _taskId Task Id of the computation - /// @param _result Privately computed result + /// @notice Emits an event with the result of a computation + /// @param _taskId The ID of the task + /// @param _result The result of the computation + function callback(uint256 _taskId, bytes calldata _result) external { emit ComputedResult(_taskId, _result); } -} -library Encoders { - - function encodeBase64(bytes memory data) internal pure returns (string memory) { - if (data.length == 0) return ""; - string memory table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - string memory result = new string(4 * ((data.length + 2) / 3)); - /// @solidity memory-safe-assembly - assembly { - let tablePtr := add(table, 1) - let resultPtr := add(result, 32) - for { - let dataPtr := data - let endPtr := add(data, mload(data)) - } lt(dataPtr, endPtr) { - } { - dataPtr := add(dataPtr, 3) - let input := mload(dataPtr) - mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) - resultPtr := add(resultPtr, 1) - mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) - resultPtr := add(resultPtr, 1) - mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) - resultPtr := add(resultPtr, 1) - mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) - resultPtr := add(resultPtr, 1) - } - switch mod(mload(data), 3) - case 1 { - mstore8(sub(resultPtr, 1), 0x3d) - mstore8(sub(resultPtr, 2), 0x3d) - } - case 2 { - mstore8(sub(resultPtr, 1), 0x3d) - } - } - return result; - } - - function uint256toString(uint256 value) external pure returns (string memory ptr) { - assembly { - ptr := add(mload(0x40), 128) - mstore(0x40, ptr) - let end := ptr - for { - let temp := value - ptr := sub(ptr, 1) - mstore8(ptr, add(48, mod(temp, 10))) - temp := div(temp, 10) - } temp { - temp := div(temp, 10) - } { - ptr := sub(ptr, 1) - mstore8(ptr, add(48, mod(temp, 10))) - } - let length := sub(end, ptr) - ptr := sub(ptr, 32) - mstore(ptr, length) - } - } - - function bytesToUint256Array(bytes memory data) internal pure returns (uint256[] memory) { - require(data.length % 32 == 0, "Data length must be a multiple of 32 bytes"); - uint256[] memory uintArray = new uint256[](data.length / 32); - uint256 dataLength = data.length; - assembly { - let dataPtr := add(data, 0x20) - let uintArrayPtr := add(uintArray, 0x20) - for { let i := 0 } lt(i, dataLength) { i := add(i, 32) } { - mstore(add(uintArrayPtr, i), mload(add(dataPtr, i))) - } - } - return uintArray; - } + /*////////////////////////////////////////////////////////////// + New Functions for Upgradeability + //////////////////////////////////////////////////////////////*/ } \ No newline at end of file diff --git a/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol b/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol index aa3f435..079831e 100644 --- a/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol +++ b/TNLS-Gateways/public-gateway/src/RandomnessReciever.sol @@ -1,10 +1,14 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.23; +interface ISecretVRF { + function requestRandomness(uint32 _numWords, uint32 _callbackGasLimit) external payable returns (uint256 requestId); +} + contract RandomnessReciever { - address private RNGGateway; - address private immutable owner; + address public VRFGateway; + address public immutable owner; constructor() { owner = msg.sender; @@ -15,34 +19,26 @@ contract RandomnessReciever { _; } - function setGatewayAddress(address _RNGGateway) external onlyOwner { - RNGGateway = _RNGGateway; + function setGatewayAddress(address _VRFGateway) external onlyOwner { + VRFGateway = _VRFGateway; } - function requestRandomWordsTest() external { - bool success; - bytes memory data; - uint256 requestId; - uint32 numWords = 50; // can be up to 50 words - uint32 callbackGasLimit = 1000000; - (success, data) = RNGGateway.call(abi.encodeWithSelector(bytes4(0x967b2017), numWords, callbackGasLimit)); - require(success, "External call failed"); - if (data.length == 32) { - assembly {requestId := mload(add(data, 32))} - } else { - revert("Data returned is too short"); - } + function requestRandomnessTest() external { + uint32 numWords = 2000; // can be up to 2000 words + uint32 callbackGasLimit = 2000000; + ISecretVRF vrfContract = ISecretVRF(VRFGateway); + uint256 requestId = vrfContract.requestRandomness(numWords, callbackGasLimit); } event fulfilledRandomWords(uint256 requestId, uint256[] randomWords); /*////////////////////////////////////////////////////////////// - Callback + fulfillRandomWords Callback //////////////////////////////////////////////////////////////*/ - function fulfillRandomWords(uint256 requestId, uint256[] memory randomWords) external { - require(msg.sender == address(RNGGateway), "only Secret Gateway can fulfill"); + function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) external { + require(msg.sender == address(VRFGateway), "only Secret Gateway can fulfill"); //do your custom stuff here. emit fulfilledRandomWords(requestId, randomWords); } diff --git a/TNLS-Gateways/public-gateway/test/Contract.t.sol b/TNLS-Gateways/public-gateway/test/Contract.t.sol index 8222191..26607c6 100644 --- a/TNLS-Gateways/public-gateway/test/Contract.t.sol +++ b/TNLS-Gateways/public-gateway/test/Contract.t.sol @@ -51,7 +51,6 @@ contract ContractTest is Test { require(_sig.length == 65, "invalid signature length"); assembly { - // first 32 bytes, after the length prefix r := mload(add(_sig, 32)) // second 32 bytes @@ -135,16 +134,12 @@ contract ContractTest is Test { Test Cases //////////////////////////////////////////////////////////////*/ - function test_CheckTheOwnerOfTheContract() public { - address owner = gateway.owner(); - assertEq(deployer, owner); - } function test_OwnerCanInitialize() public { vm.prank(deployer); address tempAddress = vm.addr(5); - gateway.initialize(tempAddress); + gateway.setMasterVerificationAddress(tempAddress); assertEq(tempAddress, gateway.masterVerificationAddress()); } @@ -152,7 +147,7 @@ contract ContractTest is Test { function testFail_NonOwnerCannotInitialize() public { vm.startPrank(notOwner); address tempAddress = vm.addr(5); - gateway.initialize(tempAddress); + gateway.setMasterVerificationAddress(tempAddress); vm.stopPrank(); } @@ -161,10 +156,10 @@ contract ContractTest is Test { vm.prank(deployer); address masterVerificationKey = vm.addr(2); - gateway.initialize(masterVerificationKey); + gateway.setMasterVerificationAddress(masterVerificationKey); address SampleVerificationAddress = vm.addr(6); - string memory sampleRoute = "secret"; + string memory sampleRoute = "secret-4"; // Update the route with with masterVerificationKey signature bytes32 routeHash = getRouteHash(sampleRoute, SampleVerificationAddress); @@ -176,7 +171,7 @@ contract ContractTest is Test { vm.prank(deployer); gateway.updateRoute(sampleRoute, SampleVerificationAddress, sig); - assertEq(gateway.route("secret"), SampleVerificationAddress); + assertEq(gateway.route("secret-4"), SampleVerificationAddress); } function testFail_OwnerCannotUpdateRouteWithoutValidSignature() public { @@ -184,7 +179,7 @@ contract ContractTest is Test { vm.prank(deployer); address masterVerificationKey = vm.addr(5); - gateway.initialize(masterVerificationKey); + gateway.setMasterVerificationAddress(masterVerificationKey); address SampleVerificationAddress = vm.addr(6); string memory sampleRoute = "secret"; @@ -207,7 +202,7 @@ contract ContractTest is Test { vm.prank(deployer); address masterVerificationKey = vm.addr(5); - gateway.initialize(masterVerificationKey); + gateway.setMasterVerificationAddress(masterVerificationKey); address SampleVerificationAddress = vm.addr(6); string memory sampleRoute = "secret"; @@ -227,7 +222,7 @@ contract ContractTest is Test { vm.prank(deployer); address masterVerificationKey = vm.addr(5); - gateway.initialize(masterVerificationKey); + gateway.setMasterVerificationAddress(masterVerificationKey); address SampleVerificationAddress = vm.addr(6); string memory sampleRoute = "secret"; @@ -272,16 +267,10 @@ contract ContractTest is Test { gateway.send(vm.addr(5), sourceNetwork,routingInfo, payloadHash, assembledInfo, vm.addr(7), callbackSelector, 300000 ); - (bytes32 tempPayloadHash,,,,) = gateway.tasks(1); + (bytes31 tempPayloadHash,,,,) = gateway.tasks(1); assertEq(tempPayloadHash, payloadHash, "payloadHash failed"); - (,address tempCallbackAddress,,,) = gateway.tasks(1); - assertEq(tempCallbackAddress, vm.addr(7), "tempCallbackAddress failed"); - - (,,bytes4 tempCallbackSelector,,) = gateway.tasks(1); - assertEq(tempCallbackSelector, callbackSelector, "callbackSelector failed"); - - (,,,, bool tempCompleted) = gateway.tasks(1); + (,bool tempCompleted) = gateway.tasks(1); assertEq(tempCompleted, false, "tempCompleted failed"); } @@ -435,7 +424,7 @@ contract ContractTest is Test { vm.prank(deployer); address masterVerificationKey = vm.addr(2); - gateway.initialize(masterVerificationKey); + gateway.setMasterVerificationAddress(masterVerificationKey); address SampleVerificationAddress = 0x49F7552065228e5abF44e144cc750aEA4F711Dc3; string memory sampleRoute = "secret"; diff --git a/TNLS-Gateways/secret/contract.wasm.gz b/TNLS-Gateways/secret/contract.wasm.gz index d8161bc..e746e6b 100644 Binary files a/TNLS-Gateways/secret/contract.wasm.gz and b/TNLS-Gateways/secret/contract.wasm.gz differ diff --git a/TNLS-Gateways/secret/src/contract.rs b/TNLS-Gateways/secret/src/contract.rs index 9b7cbbe..ba4e735 100644 --- a/TNLS-Gateways/secret/src/contract.rs +++ b/TNLS-Gateways/secret/src/contract.rs @@ -23,6 +23,7 @@ use sha3::{Digest, Keccak256}; /// pad handle responses and log attributes to blocks of 256 bytes to prevent leaking info based on /// response size pub const BLOCK_SIZE: usize = 256; +pub const CHAIN_ID: &str = "secret-4"; #[cfg(feature = "contract")] ////////////////////////////////////// Init /////////////////////////////////////// @@ -92,7 +93,7 @@ pub fn execute( match msg { ExecuteMsg::Input { inputs } => { pad_handle_result(pre_execution(deps, env, inputs), BLOCK_SIZE) - } + }, ExecuteMsg::Output { outputs } => post_execution(deps, env, outputs), } } @@ -320,7 +321,7 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult< // create hash of entire packet (used to verify the message wasn't modified in transit) let data = [ - "secret".as_bytes(), // source network + CHAIN_ID.as_bytes(), // source network routing_info.as_bytes(), // task_destination_network task_id_padded.as_slice(), //msg.task_id.to_be_bytes().as_slice(), // task ID // task_info.payload.as_slice(), // payload (original encrypted or unencrypted payload) @@ -422,7 +423,7 @@ fn post_execution(deps: DepsMut, _env: Env, msg: PostExecutionMsg) -> StdResult< let callback_gas_limit = format!("0x{}", task_info.callback_gas_limit.to_be_bytes().encode_hex::()); Ok(Response::new() - .add_attribute_plaintext("source_network", "secret") + .add_attribute_plaintext("source_network", CHAIN_ID) .add_attribute_plaintext("task_destination_network", routing_info) .add_attribute_plaintext("task_id", msg.task_id.to_string()) .add_attribute_plaintext("payload_hash", payload_hash) diff --git a/TNLS-Relayers/base_interface.py b/TNLS-Relayers/base_interface.py index da1677d..761f73e 100644 --- a/TNLS-Relayers/base_interface.py +++ b/TNLS-Relayers/base_interface.py @@ -16,8 +16,8 @@ } -task_keys_to_msg = {'ethereum': eth_task_keys_to_msg} -task_keys_in_order = {'ethereum': ['_taskId', '_sourceNetwork', '_info']} +task_keys_to_msg = {'11155111': eth_task_keys_to_msg} +task_keys_in_order = {'11155111': ['_taskId', '_sourceNetwork', '_info']} def to_dict(dict_to_parse, key_type=""): @@ -96,7 +96,7 @@ def __init__(self, task_dict): task_dict['routing_info'] = task_dict['routing_info'].split(':')[1] task_dict['task_destination_network'] = self.task_destination_network elif 'routing_info' in task_dict and 'secret' in task_dict['routing_info']: - self.task_destination_network = 'secret' + self.task_destination_network = 'secret-4' task_dict['task_destination_network'] = self.task_destination_network elif 'routing_info' in task_dict: self.task_destination_network = task_dict['routing_info'] @@ -117,7 +117,7 @@ def __str__(self): return json.dumps(new_task_list) return json.dumps(to_dict(new_task_dict, key_type=self.task_destination_network)) else: - if 'task_id' in self.task_data and self.task_destination_network == 'secret': + if 'task_id' in self.task_data and self.task_destination_network == 'secret-4': self.task_data['task_id'] = int(self.task_data['task_id']) return json.dumps(to_dict(self.task_data)) diff --git a/TNLS-Relayers/eth_interface.py b/TNLS-Relayers/eth_interface.py index 3546d74..c037b78 100644 --- a/TNLS-Relayers/eth_interface.py +++ b/TNLS-Relayers/eth_interface.py @@ -56,7 +56,7 @@ def create_transaction(self, contract_function, *args, **kwargs): if kwargs is {}: tx = contract_function(*args).build_transaction({ 'from': self.address, - 'gas': 1000000, + 'gas': 3000000, 'nonce': nonce, #'maxFeePerGas': self.provider.eth.max_priority_fee #'maxPriorityFeePerGas': self.provider.eth.max_priority_fee, @@ -64,14 +64,14 @@ def create_transaction(self, contract_function, *args, **kwargs): elif len(args) == 0: tx = contract_function(**kwargs).build_transaction({ 'from': self.address, - 'gas': 1000000, + 'gas': 3000000, 'nonce': nonce, #'maxPriorityFeePerGas': self.provider.eth.max_priority_fee, }) else: tx = contract_function(*args, **kwargs).build_transaction({ 'from': self.address, - 'gas': 1000000, + 'gas': 3000000, 'nonce': nonce, #'maxPriorityFeePerGas': self.provider.eth.max_priority_fee, }) diff --git a/TNLS-Relayers/relayer.py b/TNLS-Relayers/relayer.py index c916303..d066452 100644 --- a/TNLS-Relayers/relayer.py +++ b/TNLS-Relayers/relayer.py @@ -71,7 +71,7 @@ def __init__(self, # Setup keys dictionary keys_dict = { - 'secret': { + 'secret-4': { 'verification': verification_key, 'encryption': encryption_key } @@ -90,7 +90,7 @@ def __init__(self, scrt_tuple = (scrt_base_interface, scrt_contract_interface, 'wasm', 'inputs') # Create the dictionary and add the tuple - self.dict_of_names_to_interfaces = {'ethereum': eth_tuple,'secret': scrt_tuple} + self.dict_of_names_to_interfaces = {'11155111': eth_tuple,'secret-4': scrt_tuple} """ Args: @@ -136,11 +136,11 @@ def process_transaction(self, transaction, name, contract_interface, evt_name): def poll_for_transactions(self): for name, (chain_interface, contract_interface, evt_name, _) in self.dict_of_names_to_interfaces.items(): - if name == 'secret': + if name == 'secret-4' or name == 'pulsar-3': continue prev_height = self.dict_of_names_to_blocks[name] curr_height = chain_interface.get_last_block() - #curr_height = 5021399 + #curr_height = 5029638 if prev_height is None: prev_height = curr_height - 1 @@ -176,7 +176,7 @@ def route_transaction(self, task: Task): return contract_for_txn = self.dict_of_names_to_interfaces[task.task_destination_network][1] function_name = self.dict_of_names_to_interfaces[task.task_destination_network][3] - if task.task_destination_network == 'secret': + if task.task_destination_network == 'secret-4': ntasks, _ = contract_for_txn.call_function(function_name, str(task)) self.task_list.extend(ntasks) else: diff --git a/TNLS-Samples/RNG/contract.wasm.gz b/TNLS-Samples/RNG/contract.wasm.gz index 71db02e..bcdd186 100644 Binary files a/TNLS-Samples/RNG/contract.wasm.gz and b/TNLS-Samples/RNG/contract.wasm.gz differ diff --git a/TNLS-Samples/RNG/src/contract.rs b/TNLS-Samples/RNG/src/contract.rs index b5efd81..41f1895 100644 --- a/TNLS-Samples/RNG/src/contract.rs +++ b/TNLS-Samples/RNG/src/contract.rs @@ -37,8 +37,7 @@ pub fn instantiate( #[entry_point] pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> StdResult { let response = match msg { - ExecuteMsg::Input { message } => try_handle(deps, env, info, message), - ExecuteMsg::ReturnRandom {} => return_random(deps, env, info), + ExecuteMsg::Input { message } => try_handle(deps, env, info, message) }; pad_handle_result(response, BLOCK_SIZE) } @@ -46,7 +45,7 @@ pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> S #[entry_point] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { let response = match msg { - QueryMsg::Query {} => try_query(deps), + QueryMsg::Query {} => try_query(deps) }; pad_query_result(response, BLOCK_SIZE) } @@ -78,20 +77,6 @@ fn try_handle( } } -fn return_random( - _deps: DepsMut, - env: Env, - _info: MessageInfo, -) -> StdResult { - - let result = match env.block.random { - Some(random_value) => random_value.to_base64(), - None => return Err(StdError::generic_err("No random value available")), - }; - - Ok(Response::new().add_attribute("random", result)) -} - fn try_random( deps: DepsMut, env: Env, diff --git a/TNLS-Samples/RNG/src/msg.rs b/TNLS-Samples/RNG/src/msg.rs index 0143d22..112069a 100644 --- a/TNLS-Samples/RNG/src/msg.rs +++ b/TNLS-Samples/RNG/src/msg.rs @@ -15,14 +15,13 @@ pub struct InstantiateMsg { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum ExecuteMsg { - Input { message: PrivContractHandleMsg }, - ReturnRandom {}, + Input { message: PrivContractHandleMsg } } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] #[serde(rename_all = "snake_case")] pub enum QueryMsg { - Query {}, + Query {} } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] diff --git a/TNLS-Samples/RNG/tests/integration.ts b/TNLS-Samples/RNG/tests/integration.ts index 641072d..a1d1d1d 100644 --- a/TNLS-Samples/RNG/tests/integration.ts +++ b/TNLS-Samples/RNG/tests/integration.ts @@ -46,8 +46,6 @@ const initializeClient = async (endpoint: string, chainId: string) => { const initializeGateway = async ( client: SecretNetworkClient, contractPath: string, - scrtRngHash: string, - scrtRngAddress: string, ) => { const wasmCode = fs.readFileSync(contractPath); console.log("Uploading gateway contract..."); @@ -91,11 +89,7 @@ const initializeGateway = async ( { sender: client.address, code_id: codeId, - init_msg: { - entropy: "secret", - rng_hash: scrtRngHash, - rng_addr: scrtRngAddress, - }, + init_msg: {}, code_hash: contractCodeHash.code_hash, label: "My contract" + Math.ceil(Math.random() * 10000), // The label should be unique for every contract, add random string in order to maintain uniqueness }, @@ -170,7 +164,7 @@ const initializeScrtRng = async ( { sender: client.address, code_id: codeId, - init_msg: { initseed: "secret", prng_seed: "secret" }, + init_msg: {}, code_hash: contractCodeHash.code_hash, label: "My contract" + Math.ceil(Math.random() * 10000), // The label should be unique for every contract, add random string in order to maintain uniqueness },