diff --git a/.gitignore b/.gitignore index 4750380a5..e147248c7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,6 @@ transpiled/ *.log ganache_account_keys.txt deployedAddresses.json -yarn.lock .idea/ dist/ +.env diff --git a/packages/hebao_v2/yarn.lock b/packages/hebao_v2/yarn.lock new file mode 100644 index 000000000..3cabb68f5 --- /dev/null +++ b/packages/hebao_v2/yarn.lock @@ -0,0 +1,8971 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@ensdomains/ens@^0.4.4": + version "0.4.5" + resolved "https://registry.npmmirror.com/@ensdomains/ens/-/ens-0.4.5.tgz#e0aebc005afdc066447c6e22feb4eda89a5edbfc" + integrity sha512-JSvpj1iNMFjK6K+uVl4unqMoa9rf5jopb8cya5UGBWz23Nw8hSNT7efgUx4BTlAPAgpNlEioUfeTyQ6J9ZvTVw== + dependencies: + bluebird "^3.5.2" + eth-ens-namehash "^2.0.8" + solc "^0.4.20" + testrpc "0.0.1" + web3-utils "^1.0.0-beta.31" + +"@ensdomains/resolver@^0.2.4": + version "0.2.4" + resolved "https://registry.npmmirror.com/@ensdomains/resolver/-/resolver-0.2.4.tgz#c10fe28bf5efbf49bff4666d909aed0265efbc89" + integrity sha512-bvaTH34PMCbv6anRa9I/0zjLJgY4EuznbEMgbV77JBCQ9KNC46rzi0avuxpOfu+xDjPEtSFGqVEOr5GlUSGudA== + +"@ethereum-waffle/chai@^3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/@ethereum-waffle/chai/-/chai-3.4.4.tgz#16c4cc877df31b035d6d92486dfdf983df9138ff" + integrity sha512-/K8czydBtXXkcM9X6q29EqEkc5dN3oYenyH2a9hF7rGAApAJUpH8QBtojxOY/xQ2up5W332jqgxwp0yPiYug1g== + dependencies: + "@ethereum-waffle/provider" "^3.4.4" + ethers "^5.5.2" + +"@ethereum-waffle/compiler@^3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/@ethereum-waffle/compiler/-/compiler-3.4.4.tgz#d568ee0f6029e68b5c645506079fbf67d0dfcf19" + integrity sha512-RUK3axJ8IkD5xpWjWoJgyHclOeEzDLQFga6gKpeGxiS/zBu+HB0W2FvsrrLalTFIaPw/CGYACRBSIxqiCqwqTQ== + dependencies: + "@resolver-engine/imports" "^0.3.3" + "@resolver-engine/imports-fs" "^0.3.3" + "@typechain/ethers-v5" "^2.0.0" + "@types/mkdirp" "^0.5.2" + "@types/node-fetch" "^2.5.5" + ethers "^5.0.1" + mkdirp "^0.5.1" + node-fetch "^2.6.1" + solc "^0.6.3" + ts-generator "^0.1.1" + typechain "^3.0.0" + +"@ethereum-waffle/ens@^3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/@ethereum-waffle/ens/-/ens-3.4.4.tgz#db97ea2c9decbb70b9205d53de2ccbd6f3182ba1" + integrity sha512-0m4NdwWxliy3heBYva1Wr4WbJKLnwXizmy5FfSSr5PMbjI7SIGCdCB59U7/ZzY773/hY3bLnzLwvG5mggVjJWg== + dependencies: + "@ensdomains/ens" "^0.4.4" + "@ensdomains/resolver" "^0.2.4" + ethers "^5.5.2" + +"@ethereum-waffle/mock-contract@^3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/@ethereum-waffle/mock-contract/-/mock-contract-3.4.4.tgz#fc6ffa18813546f4950a69f5892d4dd54b2c685a" + integrity sha512-Mp0iB2YNWYGUV+VMl5tjPsaXKbKo8MDH9wSJ702l9EBjdxFf/vBvnMBAC1Fub1lLtmD0JHtp1pq+mWzg/xlLnA== + dependencies: + "@ethersproject/abi" "^5.5.0" + ethers "^5.5.2" + +"@ethereum-waffle/provider@^3.4.4": + version "3.4.4" + resolved "https://registry.npmmirror.com/@ethereum-waffle/provider/-/provider-3.4.4.tgz#398fc1f7eb91cc2df7d011272eacba8af0c7fffb" + integrity sha512-GK8oKJAM8+PKy2nK08yDgl4A80mFuI8zBkE0C9GqTRYQqvuxIyXoLmJ5NZU9lIwyWVv5/KsoA11BgAv2jXE82g== + dependencies: + "@ethereum-waffle/ens" "^3.4.4" + ethers "^5.5.2" + ganache-core "^2.13.2" + patch-package "^6.2.2" + postinstall-postinstall "^2.1.0" + +"@ethersproject/abi@5.0.0-beta.153": + version "5.0.0-beta.153" + resolved "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.0.0-beta.153.tgz#43a37172b33794e4562999f6e2d555b7599a8eee" + integrity sha512-aXweZ1Z7vMNzJdLpR1CZUAIgnwjrZeUSvN9syCwlBaEBUFJmFY+HHnfuTI5vIhVs/mRkfJVrbEyl51JZQqyjAg== + dependencies: + "@ethersproject/address" ">=5.0.0-beta.128" + "@ethersproject/bignumber" ">=5.0.0-beta.130" + "@ethersproject/bytes" ">=5.0.0-beta.129" + "@ethersproject/constants" ">=5.0.0-beta.128" + "@ethersproject/hash" ">=5.0.0-beta.128" + "@ethersproject/keccak256" ">=5.0.0-beta.127" + "@ethersproject/logger" ">=5.0.0-beta.129" + "@ethersproject/properties" ">=5.0.0-beta.131" + "@ethersproject/strings" ">=5.0.0-beta.130" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.0-beta.146", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.5.0", "@ethersproject/abi@^5.6.3", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + 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" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@>=5.0.0-beta.128", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@>=5.0.0-beta.130", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@>=5.0.0-beta.129", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@>=5.0.0-beta.128", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@>=5.0.0-beta.128", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@>=5.0.0-beta.127", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@>=5.0.0-beta.129", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@>=5.0.0-beta.131", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.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" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + 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" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@>=5.0.0-beta.130", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.0" + resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.14" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@metamask/eth-sig-util@^4.0.0": + version "4.0.1" + resolved "https://registry.npmmirror.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" + integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== + dependencies: + ethereumjs-abi "^0.6.8" + ethereumjs-util "^6.2.1" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== + +"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": + version "1.7.1" + resolved "https://registry.npmmirror.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + +"@nomicfoundation/ethereumjs-block@4.2.2", "@nomicfoundation/ethereumjs-block@^4.0.0": + version "4.2.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-4.2.2.tgz#f317078c810a54381c682d0c12e1e81acfc11599" + integrity sha512-atjpt4gc6ZGZUPHBAQaUJsm1l/VCo7FmyQ780tMGO8QStjLdhz09dXynmhwVTy5YbRr0FOh/uX3QaEM0yIB2Zg== + dependencies: + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-trie" "5.0.5" + "@nomicfoundation/ethereumjs-tx" "4.1.2" + "@nomicfoundation/ethereumjs-util" "8.0.6" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-blockchain@6.2.2", "@nomicfoundation/ethereumjs-blockchain@^6.0.0": + version "6.2.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-6.2.2.tgz#9f79dd2b3dc73f5d5a220f7d8a734330c4c26320" + integrity sha512-6AIB2MoTEPZJLl6IRKcbd8mUmaBAQ/NMe3O7OsAOIiDjMNPPH5KaUQiLfbVlegT4wKIg/GOsFH7XlH2KDVoJNg== + dependencies: + "@nomicfoundation/ethereumjs-block" "4.2.2" + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-ethash" "2.0.5" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-trie" "5.0.5" + "@nomicfoundation/ethereumjs-util" "8.0.6" + abstract-level "^1.0.3" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + level "^8.0.0" + lru-cache "^5.1.1" + memory-level "^1.0.0" + +"@nomicfoundation/ethereumjs-common@3.1.2", "@nomicfoundation/ethereumjs-common@^3.0.0": + version "3.1.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-3.1.2.tgz#041086da66ed40f2bf2a2116a1f2f0fcf33fb80d" + integrity sha512-JAEBpIua62dyObHM9KI2b4wHZcRQYYge9gxiygTWa3lNCr2zo+K0TbypDpgiNij5MCGNWP1eboNfNfx1a3vkvA== + dependencies: + "@nomicfoundation/ethereumjs-util" "8.0.6" + crc-32 "^1.2.0" + +"@nomicfoundation/ethereumjs-ethash@2.0.5": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-2.0.5.tgz#0c605812f6f4589a9f6d597db537bbf3b86469db" + integrity sha512-xlLdcICGgAYyYmnI3r1t0R5fKGBJNDQSOQxXNjVO99JmxJIdXR5MgPo5CSJO1RpyzKOgzi3uIFn8agv564dZEQ== + dependencies: + "@nomicfoundation/ethereumjs-block" "4.2.2" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-util" "8.0.6" + abstract-level "^1.0.3" + bigint-crypto-utils "^3.0.23" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-evm@1.3.2", "@nomicfoundation/ethereumjs-evm@^1.0.0": + version "1.3.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-1.3.2.tgz#f9d6bafd5c23d07ab75b8649d589af1a43b60bfc" + integrity sha512-I00d4MwXuobyoqdPe/12dxUQxTYzX8OckSaWsMcWAfQhgVDvBx6ffPyP/w1aL0NW7MjyerySPcSVfDJAMHjilw== + dependencies: + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-util" "8.0.6" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/ethereumjs-rlp@4.0.3", "@nomicfoundation/ethereumjs-rlp@^4.0.0": + version "4.0.3" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-4.0.3.tgz#8d9147fbd0d49e8f4c5ce729d226694a8fe03eb8" + integrity sha512-DZMzB/lqPK78T6MluyXqtlRmOMcsZbTTbbEyAjo0ncaff2mqu/k8a79PBcyvpgAhWD/R59Fjq/x3ro5Lof0AtA== + +"@nomicfoundation/ethereumjs-statemanager@1.0.5", "@nomicfoundation/ethereumjs-statemanager@^1.0.0": + version "1.0.5" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-1.0.5.tgz#951cc9ff2c421d40233d2e9d0fe033db2391ee44" + integrity sha512-CAhzpzTR5toh/qOJIZUUOnWekUXuRqkkzaGAQrVcF457VhtCmr+ddZjjK50KNZ524c1XP8cISguEVNqJ6ij1sA== + dependencies: + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-trie" "5.0.5" + "@nomicfoundation/ethereumjs-util" "8.0.6" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + +"@nomicfoundation/ethereumjs-trie@5.0.5", "@nomicfoundation/ethereumjs-trie@^5.0.0": + version "5.0.5" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-5.0.5.tgz#bf31c9306dcbba2007fad668e96109ddb147040c" + integrity sha512-+8sNZrXkzvA1NH5F4kz5RSYl1I6iaRz7mAZRsyxOm0IVY4UaP43Ofvfp/TwOalFunurQrYB5pRO40+8FBcxFMA== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-util" "8.0.6" + ethereum-cryptography "0.1.3" + readable-stream "^3.6.0" + +"@nomicfoundation/ethereumjs-tx@4.1.2", "@nomicfoundation/ethereumjs-tx@^4.0.0": + version "4.1.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-4.1.2.tgz#8659fad7f9094b7eb82aa6cc3c8097cb1c42ff31" + integrity sha512-emJBJZpmTdUa09cqxQqHaysbBI9Od353ZazeH7WgPb35miMgNY6mb7/3vBA98N5lUW/rgkiItjX0KZfIzihSoQ== + dependencies: + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-util" "8.0.6" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-util@8.0.6", "@nomicfoundation/ethereumjs-util@^8.0.0": + version "8.0.6" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-8.0.6.tgz#dbce5d258b017b37aa58b3a7c330ad59d10ccf0b" + integrity sha512-jOQfF44laa7xRfbfLXojdlcpkvxeHrE2Xu7tSeITsWFgoII163MzjOwFEzSNozHYieFysyoEMhCdP+NY5ikstw== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-vm@^6.0.0": + version "6.4.2" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-6.4.2.tgz#af1cf62e6c0054bc2b7febc8556d032433d1b18c" + integrity sha512-PRTyxZMP6kx+OdAzBhuH1LD2Yw+hrSpaytftvaK//thDy2OI07S0nrTdbrdk7b8ZVPAc9H9oTwFBl3/wJ3w15g== + dependencies: + "@nomicfoundation/ethereumjs-block" "4.2.2" + "@nomicfoundation/ethereumjs-blockchain" "6.2.2" + "@nomicfoundation/ethereumjs-common" "3.1.2" + "@nomicfoundation/ethereumjs-evm" "1.3.2" + "@nomicfoundation/ethereumjs-rlp" "4.0.3" + "@nomicfoundation/ethereumjs-statemanager" "1.0.5" + "@nomicfoundation/ethereumjs-trie" "5.0.5" + "@nomicfoundation/ethereumjs-tx" "4.1.2" + "@nomicfoundation/ethereumjs-util" "8.0.6" + "@types/async-eventemitter" "^0.2.1" + async-eventemitter "^0.2.4" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + functional-red-black-tree "^1.0.1" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz#4c858096b1c17fe58a474fe81b46815f93645c15" + integrity sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w== + +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz#6e25ccdf6e2d22389c35553b64fe6f3fdaec432c" + integrity sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA== + +"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz#0a224ea50317139caeebcdedd435c28a039d169c" + integrity sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA== + +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz#dfa085d9ffab9efb2e7b383aed3f557f7687ac2b" + integrity sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg== + +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz#c9e06b5d513dd3ab02a7ac069c160051675889a4" + integrity sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w== + +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz#8d328d16839e52571f72f2998c81e46bf320f893" + integrity sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA== + +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz#9b49d0634b5976bb5ed1604a1e1b736f390959bb" + integrity sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w== + +"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz#e2867af7264ebbcc3131ef837878955dd6a3676f" + integrity sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg== + +"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz#0685f78608dd516c8cdfb4896ed451317e559585" + integrity sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ== + +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz#c9a44f7108646f083b82e851486e0f6aeb785836" + integrity sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw== + +"@nomicfoundation/solidity-analyzer@^0.1.0": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz#f5f4d36d3f66752f59a57e7208cd856f3ddf6f2d" + integrity sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg== + optionalDependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.1" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.1" + "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1" + +"@nomiclabs/hardhat-ethers@^2.0.1": + version "2.2.2" + resolved "https://registry.npmmirror.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.2.tgz#812d48929c3bf8fe840ec29eab4b613693467679" + integrity sha512-NLDlDFL2us07C0jB/9wzvR0kuLivChJWCXTKcj3yqjZqMoYp7g7wwS157F70VHx/+9gHIBGzak5pKDwG8gEefA== + +"@nomiclabs/hardhat-etherscan@^2.1.4": + version "2.1.8" + resolved "https://registry.npmmirror.com/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-2.1.8.tgz#e206275e96962cd15e5ba9148b44388bc922d8c2" + integrity sha512-0+rj0SsZotVOcTLyDOxnOc3Gulo8upo0rsw/h+gBPcmtj91YqYJNhdARHoBxOhhE8z+5IUQPx+Dii04lXT14PA== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^5.0.2" + debug "^4.1.1" + fs-extra "^7.0.1" + node-fetch "^2.6.0" + semver "^6.3.0" + +"@nomiclabs/hardhat-waffle@^2.0.1": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nomiclabs/hardhat-waffle/-/hardhat-waffle-2.0.5.tgz#97c217f1db795395c04404291937edb528f3f218" + integrity sha512-U1RH9OQ1mWYQfb+moX5aTgGjpVVlOcpiFI47wwnaGG4kLhcTy90cNiapoqZenxcRAITVbr0/+QSduINL5EsUIQ== + +"@resolver-engine/core@^0.3.3": + version "0.3.3" + resolved "https://registry.npmmirror.com/@resolver-engine/core/-/core-0.3.3.tgz#590f77d85d45bc7ecc4e06c654f41345db6ca967" + integrity sha512-eB8nEbKDJJBi5p5SrvrvILn4a0h42bKtbCTri3ZxCGt6UvoQyp7HnGOfki944bUjBSHKK3RvgfViHn+kqdXtnQ== + dependencies: + debug "^3.1.0" + is-url "^1.2.4" + request "^2.85.0" + +"@resolver-engine/fs@^0.3.3": + version "0.3.3" + resolved "https://registry.npmmirror.com/@resolver-engine/fs/-/fs-0.3.3.tgz#fbf83fa0c4f60154a82c817d2fe3f3b0c049a973" + integrity sha512-wQ9RhPUcny02Wm0IuJwYMyAG8fXVeKdmhm8xizNByD4ryZlx6PP6kRen+t/haF43cMfmaV7T3Cx6ChOdHEhFUQ== + dependencies: + "@resolver-engine/core" "^0.3.3" + debug "^3.1.0" + +"@resolver-engine/imports-fs@^0.3.3": + version "0.3.3" + resolved "https://registry.npmmirror.com/@resolver-engine/imports-fs/-/imports-fs-0.3.3.tgz#4085db4b8d3c03feb7a425fbfcf5325c0d1e6c1b" + integrity sha512-7Pjg/ZAZtxpeyCFlZR5zqYkz+Wdo84ugB5LApwriT8XFeQoLwGUj4tZFFvvCuxaNCcqZzCYbonJgmGObYBzyCA== + dependencies: + "@resolver-engine/fs" "^0.3.3" + "@resolver-engine/imports" "^0.3.3" + debug "^3.1.0" + +"@resolver-engine/imports@^0.3.3": + version "0.3.3" + resolved "https://registry.npmmirror.com/@resolver-engine/imports/-/imports-0.3.3.tgz#badfb513bb3ff3c1ee9fd56073e3144245588bcc" + integrity sha512-anHpS4wN4sRMwsAbMXhMfOD/y4a4Oo0Cw/5+rue7hSwGWsDOQaAU1ClK1OxjUC35/peazxEl8JaSRRS+Xb8t3Q== + dependencies: + "@resolver-engine/core" "^0.3.3" + debug "^3.1.0" + hosted-git-info "^2.6.0" + path-browserify "^1.0.0" + url "^0.11.0" + +"@scure/base@~1.1.0": + version "1.1.1" + resolved "https://registry.npmmirror.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" + integrity sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA== + +"@scure/bip32@1.1.5": + version "1.1.5" + resolved "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" + integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== + dependencies: + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== + dependencies: + "@noble/hashes" "~1.2.0" + "@scure/base" "~1.1.0" + +"@sentry/core@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" + integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/hub@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" + integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== + dependencies: + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/minimal@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" + integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sentry/node@^5.18.1": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" + integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== + dependencies: + "@sentry/core" "5.30.0" + "@sentry/hub" "5.30.0" + "@sentry/tracing" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" + integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/types@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" + integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== + +"@sentry/utils@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" + integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== + dependencies: + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.npmmirror.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + +"@sindresorhus/is@^4.0.0": + version "4.6.0" + resolved "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@solidity-parser/parser@^0.14.0": + version "0.14.5" + resolved "https://registry.npmmirror.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" + integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + +"@szmarczak/http-timer@^4.0.5": + version "4.0.6" + resolved "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807" + integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w== + dependencies: + defer-to-connect "^2.0.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + +"@typechain/ethers-v5@^2.0.0": + version "2.0.0" + resolved "https://registry.npmmirror.com/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz#cd3ca1590240d587ca301f4c029b67bfccd08810" + integrity sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw== + dependencies: + ethers "^5.0.2" + +"@types/async-eventemitter@^0.2.1": + version "0.2.1" + resolved "https://registry.npmmirror.com/@types/async-eventemitter/-/async-eventemitter-0.2.1.tgz#f8e6280e87e8c60b2b938624b0a3530fb3e24712" + integrity sha512-M2P4Ng26QbAeITiH7w1d7OxtldgfAe0wobpyJzVK/XOb0cUGKU2R4pfAhqcJBXAe2ife5ZOhSv4wk7p+ffURtg== + +"@types/bn.js@^4.11.3", "@types/bn.js@^4.11.5": + version "4.11.6" + resolved "https://registry.npmmirror.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + +"@types/bn.js@^5.1.0": + version "5.1.1" + resolved "https://registry.npmmirror.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + +"@types/cacheable-request@^6.0.1": + version "6.0.3" + resolved "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" + integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw== + dependencies: + "@types/http-cache-semantics" "*" + "@types/keyv" "^3.1.4" + "@types/node" "*" + "@types/responselike" "^1.0.0" + +"@types/chai@^4.2.14": + version "4.3.4" + resolved "https://registry.npmmirror.com/@types/chai/-/chai-4.3.4.tgz#e913e8175db8307d78b4e8fa690408ba6b65dee4" + integrity sha512-KnRanxnpfpjUTqTCXslZSEdLfXExwgNxYPdiO2WGUj8+HDjFi8R3k5RVKPeSCzLjCcshCAtVO2QBbVuAV4kTnw== + +"@types/concat-stream@^1.6.0": + version "1.6.1" + resolved "https://registry.npmmirror.com/@types/concat-stream/-/concat-stream-1.6.1.tgz#24bcfc101ecf68e886aaedce60dfd74b632a1b74" + integrity sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA== + dependencies: + "@types/node" "*" + +"@types/form-data@0.0.33": + version "0.0.33" + resolved "https://registry.npmmirror.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" + integrity sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw== + dependencies: + "@types/node" "*" + +"@types/http-cache-semantics@*": + version "4.0.1" + resolved "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" + integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== + +"@types/keyv@^3.1.4": + version "3.1.4" + resolved "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6" + integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg== + dependencies: + "@types/node" "*" + +"@types/lru-cache@^5.1.0": + version "5.1.1" + resolved "https://registry.npmmirror.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" + integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== + +"@types/mkdirp@^0.5.2": + version "0.5.2" + resolved "https://registry.npmmirror.com/@types/mkdirp/-/mkdirp-0.5.2.tgz#503aacfe5cc2703d5484326b1b27efa67a339c1f" + integrity sha512-U5icWpv7YnZYGsN4/cmh3WD2onMY0aJIiTE6+51TwJCttdHvtCYmkBNOobHlXwrJRL0nkH9jH4kD+1FAdMN4Tg== + dependencies: + "@types/node" "*" + +"@types/mocha@^8.2.0": + version "8.2.3" + resolved "https://registry.npmmirror.com/@types/mocha/-/mocha-8.2.3.tgz#bbeb55fbc73f28ea6de601fbfa4613f58d785323" + integrity sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw== + +"@types/node-fetch@^2.5.5": + version "2.6.2" + resolved "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node@*": + version "18.15.3" + resolved "https://registry.npmmirror.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" + integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== + +"@types/node@^10.0.3": + version "10.17.60" + resolved "https://registry.npmmirror.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== + +"@types/node@^12.12.6": + version "12.20.55" + resolved "https://registry.npmmirror.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/node@^8.0.0": + version "8.10.66" + resolved "https://registry.npmmirror.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" + integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== + +"@types/pbkdf2@^3.0.0": + version "3.1.0" + resolved "https://registry.npmmirror.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" + integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== + dependencies: + "@types/node" "*" + +"@types/prettier@^2.1.1": + version "2.7.2" + resolved "https://registry.npmmirror.com/@types/prettier/-/prettier-2.7.2.tgz#6c2324641cc4ba050a8c710b2b251b377581fbf0" + integrity sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg== + +"@types/qs@^6.2.31": + version "6.9.7" + resolved "https://registry.npmmirror.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/resolve@^0.0.8": + version "0.0.8" + resolved "https://registry.npmmirror.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" + integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== + dependencies: + "@types/node" "*" + +"@types/responselike@^1.0.0": + version "1.0.0" + resolved "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29" + integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA== + dependencies: + "@types/node" "*" + +"@types/secp256k1@^4.0.1": + version "4.0.3" + resolved "https://registry.npmmirror.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" + integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.npmmirror.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.npmmirror.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" + integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" + +abstract-leveldown@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/abstract-leveldown/-/abstract-leveldown-3.0.0.tgz#5cb89f958a44f526779d740d1440e743e0c30a57" + integrity sha512-KUWx9UWGQD12zsmLNj64/pndaz4iJh/Pj7nopgkfDG6RlCcbMZvT6+9l7dchK4idog2Is8VdC/PvNbFuFmalIQ== + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^2.4.1, abstract-leveldown@~2.7.1: + version "2.7.2" + resolved "https://registry.npmmirror.com/abstract-leveldown/-/abstract-leveldown-2.7.2.tgz#87a44d7ebebc341d59665204834c8b7e0932cc93" + integrity sha512-+OVvxH2rHVEhWLdbudP6p0+dNMXu8JA1CbhP19T8paTYAcX7oJ4OVjT+ZUVpv7mITxXHqDMej+GdqXBmXkw09w== + dependencies: + xtend "~4.0.0" + +abstract-leveldown@^5.0.0, abstract-leveldown@~5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/abstract-leveldown/-/abstract-leveldown-5.0.0.tgz#f7128e1f86ccabf7d2893077ce5d06d798e386c6" + integrity sha512-5mU5P1gXtsMIXg65/rsYGsi93+MlogXZ9FA8JnwKurHQg64bfXwGYVdVdijNTVNOlAsuIiOwHdvFFD5JqCJQ7A== + dependencies: + xtend "~4.0.0" + +abstract-leveldown@~2.6.0: + version "2.6.3" + resolved "https://registry.npmmirror.com/abstract-leveldown/-/abstract-leveldown-2.6.3.tgz#1c5e8c6a5ef965ae8c35dfb3a8770c476b82c4b8" + integrity sha512-2++wDf/DYqkPR3o5tbfdhF96EfMApo1GpPfzOsR/ZYXdkSmELlvOOEAl9iKkRsktMPHdGjO4rtkBpf2I7TiTeA== + dependencies: + xtend "~4.0.0" + +accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.2" + resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.npmmirror.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + +aes-js@^3.1.1: + version "3.1.2" + resolved "https://registry.npmmirror.com/aes-js/-/aes-js-3.1.2.tgz#db9aabde85d5caabbfc0d4f2a4446960f627146a" + integrity sha512-e5pEa2kBnBOgR4Y/p20pskXI74UEz7de8ZGVo58asOtvSVG5YAbJeELPZxOmt+Bnz3rX753YKhfIn4X4l1PPRQ== + +agent-base@6: + version "6.0.2" + resolved "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.3: + version "6.12.6" + resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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" + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + +ansi-regex@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.npmmirror.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +anymatch@~3.1.1, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== + +array-back@^1.0.3, array-back@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/array-back/-/array-back-1.0.4.tgz#644ba7f095f7ffcf7c43b5f0dc39d3c1f03c063b" + integrity sha512-1WxbZvrmyhkNoeYcizokbmh5oiOCIfyvGtcqbK3Ls1v1fKcquzxnQSceOx6tzq7jmai2kFLWIpGND2cLhH6TPw== + dependencies: + typical "^2.6.0" + +array-back@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/array-back/-/array-back-2.0.0.tgz#6877471d51ecc9c9bfa6136fb6c7d5fe69748022" + integrity sha512-eJv4pLLufP3g5kcZry0j6WXpIbzYw9GUB4mVJZno9wfwiBxbizTnHCw3VJb07cBihbFX48Y7oSrW9y+gt4glyw== + dependencies: + typical "^2.6.1" + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-uniq@1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.npmmirror.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== + +array.prototype.reduce@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/array.prototype.reduce/-/array.prototype.reduce-1.0.5.tgz#6b20b0daa9d9734dd6bc7ea66b5bbce395471eac" + integrity sha512-kDdugMl7id9COE8R7MHF5jWk7Dqt/fs4Pv+JXoICnYwqpjjjbUurz6w5fT5IG6brLdJhv6/VoHB0H7oyIBXd+Q== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + es-array-method-boxes-properly "^1.0.0" + is-string "^1.0.7" + +asap@~2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.npmmirror.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== + +async-eventemitter@^0.2.2, async-eventemitter@^0.2.4: + version "0.2.4" + resolved "https://registry.npmmirror.com/async-eventemitter/-/async-eventemitter-0.2.4.tgz#f5e7c8ca7d3e46aab9ec40a292baf686a0bafaca" + integrity sha512-pd20BwL7Yt1zwDFy+8MX8F1+WCT8aQeKj0kQnTrH9WaeRETlRamVhD0JtRPmrV4GfOJ2F9CvdQkZeZhnh2TuHw== + dependencies: + async "^2.4.0" + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@2.6.2: + version "2.6.2" + resolved "https://registry.npmmirror.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" + integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== + dependencies: + lodash "^4.17.11" + +async@^1.4.2: + version "1.5.2" + resolved "https://registry.npmmirror.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== + +async@^2.0.1, async@^2.1.2, async@^2.4.0, async@^2.5.0, async@^2.6.1: + version "2.6.4" + resolved "https://registry.npmmirror.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.npmmirror.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.12.0" + resolved "https://registry.npmmirror.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" + integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== + +babel-code-frame@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" + integrity sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g== + dependencies: + chalk "^1.1.3" + esutils "^2.0.2" + js-tokens "^3.0.2" + +babel-core@^6.0.14, babel-core@^6.26.0: + version "6.26.3" + resolved "https://registry.npmmirror.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" + integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== + dependencies: + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.1" + debug "^2.6.9" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.8" + slash "^1.0.0" + source-map "^0.5.7" + +babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.npmmirror.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" + integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.17.4" + source-map "^0.5.7" + trim-right "^1.0.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + integrity sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q== + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + integrity sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ== + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz#a5f56dab41a25f97ecb498c7ebaca9819f95be5f" + integrity sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA== + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + integrity sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ== + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + integrity sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q== + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + integrity sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + integrity sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + integrity sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz#325c59f902f82f24b74faceed0363954f6495e72" + integrity sha512-VlPiWmqmGJp0x0oK27Out1D+71nVVCTSdlbhIVoaBAj2lUgrNjBCRR9+llO4lTSb2O4r7PJg+RobRkhBrf6ofg== + dependencies: + babel-runtime "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + integrity sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg== + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + integrity sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw== + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + integrity sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ== + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.npmmirror.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + integrity sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + integrity sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.npmmirror.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + integrity sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw== + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.npmmirror.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + integrity sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ== + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + integrity sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ== + +babel-plugin-transform-async-to-generator@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + integrity sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw== + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + integrity sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + integrity sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz#d70f5299c1308d05c12f463813b0a09e73b1895f" + integrity sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw== + dependencies: + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + lodash "^4.17.4" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + integrity sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag== + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + integrity sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw== + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + integrity sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + integrity sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + integrity sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + integrity sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg== + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + integrity sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + integrity sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA== + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.26.2" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz#58a793863a9e7ca870bdc5a881117ffac27db6f3" + integrity sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q== + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-types "^6.26.0" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + integrity sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg== + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + integrity sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw== + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + integrity sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA== + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + integrity sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ== + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + integrity sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + integrity sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + integrity sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ== + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + integrity sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + integrity sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw== + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + integrity sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ== + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + integrity sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ== + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz#e0703696fbde27f0a3efcacf8b4dca2f7b3a8f2f" + integrity sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg== + dependencies: + regenerator-transform "^0.10.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.npmmirror.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + integrity sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw== + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.7.0: + version "1.7.0" + resolved "https://registry.npmmirror.com/babel-preset-env/-/babel-preset-env-1.7.0.tgz#dea79fa4ebeb883cd35dab07e260c1c9c04df77a" + integrity sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg== + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^3.2.6" + invariant "^2.2.2" + semver "^5.3.0" + +babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + integrity sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A== + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" + integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.11.0" + +babel-template@^6.24.1, babel-template@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" + integrity sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg== + dependencies: + babel-runtime "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + lodash "^4.17.4" + +babel-traverse@^6.24.1, babel-traverse@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" + integrity sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA== + dependencies: + babel-code-frame "^6.26.0" + babel-messages "^6.23.0" + babel-runtime "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + debug "^2.6.8" + globals "^9.18.0" + invariant "^2.2.2" + lodash "^4.17.4" + +babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: + version "6.26.0" + resolved "https://registry.npmmirror.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" + integrity sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g== + dependencies: + babel-runtime "^6.26.0" + esutils "^2.0.2" + lodash "^4.17.4" + to-fast-properties "^1.0.3" + +babelify@^7.3.0: + version "7.3.0" + resolved "https://registry.npmmirror.com/babelify/-/babelify-7.3.0.tgz#aa56aede7067fd7bd549666ee16dc285087e88e5" + integrity sha512-vID8Fz6pPN5pJMdlUnNFSfrlcx5MUule4k9aKs/zbZPyXxMTcRrB0M4Tarw22L8afr8eYSWxDPYCob3TdrqtlA== + dependencies: + babel-core "^6.0.14" + object-assign "^4.0.0" + +babylon@^6.18.0: + version "6.18.0" + resolved "https://registry.npmmirror.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" + integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== + +backoff@^2.5.0: + version "2.5.0" + resolved "https://registry.npmmirror.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f" + integrity sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA== + dependencies: + precond "0.2" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2, base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.npmmirror.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.npmmirror.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bigint-crypto-utils@^3.0.23: + version "3.1.8" + resolved "https://registry.npmmirror.com/bigint-crypto-utils/-/bigint-crypto-utils-3.1.8.tgz#e2e0f40cf45488f9d7f0e32ff84152aa73819d5d" + integrity sha512-+VMV9Laq8pXLBKKKK49nOoq9bfR3j7NNQAtbA617a4nw9bVLo8rsqkKMBgM2AJWlNX9fEIyYaYX+d0laqYV4tw== + dependencies: + bigint-mod-arith "^3.1.0" + +bigint-mod-arith@^3.1.0: + version "3.1.2" + resolved "https://registry.npmmirror.com/bigint-mod-arith/-/bigint-mod-arith-3.1.2.tgz#658e416bc593a463d97b59766226d0a3021a76b1" + integrity sha512-nx8J8bBeiRR+NlsROFH9jHswW5HO8mgfOSqW0AmjicMMvaONDa8AO+5ViKDUUNytBPWiwfvZP4/Bj4Y3lUfvgQ== + +bignumber.js@^9.0.0, bignumber.js@^9.0.1: + version "9.1.1" + resolved "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bip39@2.5.0: + version "2.5.0" + resolved "https://registry.npmmirror.com/bip39/-/bip39-2.5.0.tgz#51cbd5179460504a63ea3c000db3f787ca051235" + integrity sha512-xwIx/8JKoT2+IPJpFEfXoWdYwP7UVAoUxxLNfGCfVowaJE7yg1Y5B1BVPqlUNsBq5/nGwmFkwRJ8xDW4sX8OdA== + dependencies: + create-hash "^1.1.0" + pbkdf2 "^3.0.9" + randombytes "^2.0.1" + safe-buffer "^5.0.1" + unorm "^1.3.3" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.npmmirror.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bluebird@^3.5.0, bluebird@^3.5.2: + version "3.7.2" + resolved "https://registry.npmmirror.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.8.0: + version "4.12.0" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +body-parser@^1.16.0: + version "1.20.2" + resolved "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.npmmirror.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.npmmirror.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.npmmirror.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserslist@^3.2.6: + version "3.2.8" + resolved "https://registry.npmmirror.com/browserslist/-/browserslist-3.2.8.tgz#b0005361d6471f0f5952797a76fc985f1f978fc6" + integrity sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ== + dependencies: + caniuse-lite "^1.0.30000844" + electron-to-chromium "^1.3.47" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.npmmirror.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer-xor@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/buffer-xor/-/buffer-xor-2.0.2.tgz#34f7c64f04c777a1f8aac5e661273bb9dd320289" + integrity sha512-eHslX0bin3GB+Lx2p7lEYRShRewuNZL3fUl4qlVJGGiwoPGftmt8JQgk2Y9Ji5/01TnVDo33E5b5O3vUB1HdqQ== + dependencies: + safe-buffer "^5.1.1" + +buffer@^5.0.5, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bufferutil@^4.0.1: + version "4.0.7" + resolved "https://registry.npmmirror.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" + integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== + dependencies: + node-gyp-build "^4.3.0" + +busboy@^1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== + dependencies: + streamsearch "^1.1.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +bytewise-core@^1.2.2: + version "1.2.3" + resolved "https://registry.npmmirror.com/bytewise-core/-/bytewise-core-1.2.3.tgz#3fb410c7e91558eb1ab22a82834577aa6bd61d42" + integrity sha512-nZD//kc78OOxeYtRlVk8/zXqTB4gf/nlguL1ggWA8FuchMyOxcyHR4QPQZMUmA7czC+YnaBrPUCubqAWe50DaA== + dependencies: + typewise-core "^1.2" + +bytewise@~1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/bytewise/-/bytewise-1.1.0.tgz#1d13cbff717ae7158094aa881b35d081b387253e" + integrity sha512-rHuuseJ9iQ0na6UDhnrRVDh8YnWVlU6xM3VH6q/+yHDeUH2zIhUzP+2/h3LIrhLDBtTqzWpE3p3tP/boefskKQ== + dependencies: + bytewise-core "^1.2.2" + typewise "^1.0.3" + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +cacheable-lookup@^5.0.3: + version "5.0.4" + resolved "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" + integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== + +cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^4.0.0" + lowercase-keys "^2.0.0" + normalize-url "^6.0.1" + responselike "^2.0.0" + +cachedown@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/cachedown/-/cachedown-1.0.0.tgz#d43f036e4510696b31246d7db31ebf0f7ac32d15" + integrity sha512-t+yVk82vQWCJF3PsWHMld+jhhjkkWjcAzz8NbFx1iULOXWl8Tm/FdM4smZNVw3MRr0X+lVTx9PKzvEn4Ng19RQ== + dependencies: + abstract-leveldown "^2.4.1" + lru-cache "^3.2.0" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg== + +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30000844: + version "1.0.30001467" + resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001467.tgz#1afc9c16ed61f50dd87139da87ca43a3e0051c77" + integrity sha512-cEdN/5e+RPikvl9AHm4uuLXxeCNq8rFsQ+lPHTfe/OtypP3WwnVVbjn+6uBV7PaFL6xUFzTh+sSCOz1rKhcO+Q== + +caseless@^0.12.0, caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + +cbor@^5.0.2: + version "5.2.0" + resolved "https://registry.npmmirror.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" + integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== + dependencies: + bignumber.js "^9.0.1" + nofilter "^1.0.4" + +chai@^4.2.0: + version "4.3.7" + resolved "https://registry.npmmirror.com/chai/-/chai-4.3.7.tgz#ec63f6df01829088e8bf55fca839bcd464a8ec51" + integrity sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.2" + deep-eql "^4.1.2" + get-func-name "^2.0.0" + loupe "^2.3.1" + pathval "^1.1.1" + type-detect "^4.0.5" + +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.4.1, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +"charenc@>= 0.0.1": + version "0.0.2" + resolved "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + +check-error@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" + integrity sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA== + +checkpoint-store@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06" + integrity sha512-J/NdY2WvIx654cc6LWSq/IYFFCUf75fFTgwzFnmbqyORH4MwgiQCgswLLKBGzmsyTI5V7i5bp/So6sMbDWhedg== + dependencies: + functional-red-black-tree "^1.0.1" + +chokidar@3.3.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.3.0.tgz#12c0714668c55800f659e262d4962a97faf554a6" + integrity sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.2.0" + optionalDependencies: + fsevents "~2.1.1" + +chokidar@3.5.1: + version "3.5.1" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" + integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.3.1" + +chokidar@3.5.3, chokidar@^3.4.0: + version "3.5.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.npmmirror.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.npmmirror.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +classic-level@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/classic-level/-/classic-level-1.2.0.tgz#2d52bdec8e7a27f534e67fdeb890abef3e643c27" + integrity sha512-qw5B31ANxSluWz9xBzklRWTUAJ1SXIdaVKTVS7HcTGKOAmExx65Wo5BUICW+YGORe2FOUaDghoI9ZDxj82QcFg== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "~2.0.0" + node-gyp-build "^4.3.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.npmmirror.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha512-0yayqDxWQbqk3ojkYqUKqaAQ6AfNKeKWRNA8kR0WXzAsdHpP4BIaOmMAG87JGuO6qcobyW4GjxHd9PmhEd+T9w== + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-response@^1.0.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3" + integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA== + dependencies: + mimic-response "^1.0.0" + +clone@2.1.2, clone@^2.0.0: + version "2.1.2" + resolved "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.4.0, colors@^1.1.2: + version "1.4.0" + resolved "https://registry.npmmirror.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.npmmirror.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + +command-line-args@^4.0.7: + version "4.0.7" + resolved "https://registry.npmmirror.com/command-line-args/-/command-line-args-4.0.7.tgz#f8d1916ecb90e9e121eda6428e41300bfb64cc46" + integrity sha512-aUdPvQRAyBvQd2n7jXcsMDz68ckBJELXNzBybCHOibUWEg0mWTnaYCSRU8h9R+aNRSvDihJtssSRCiDRpLaezA== + dependencies: + array-back "^2.0.0" + find-replace "^1.0.3" + typical "^2.6.1" + +commander@3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@^1.6.2: + version "1.6.2" + resolved "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.npmmirror.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^1.5.1: + version "1.9.0" + resolved "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" + integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +cookie@^0.4.1: + version "0.4.2" + resolved "https://registry.npmmirror.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +cookiejar@^2.1.1: + version "2.1.4" + resolved "https://registry.npmmirror.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" + integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.npmmirror.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== + +core-js-pure@^3.0.1: + version "3.29.1" + resolved "https://registry.npmmirror.com/core-js-pure/-/core-js-pure-3.29.1.tgz#1be6ca2b8772f6b4df7fc4621743286e676c6162" + integrity sha512-4En6zYVi0i0XlXHVz/bi6l1XDjCqkKRq765NXuX+SnaIatlE96Odt5lMLjdxUiNI1v9OXI5DSLWYPlmTfkTktg== + +core-js@^2.4.0, core-js@^2.5.0: + version "2.6.12" + resolved "https://registry.npmmirror.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.1: + version "2.8.5" + resolved "https://registry.npmmirror.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.npmmirror.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmmirror.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@^2.1.0, cross-fetch@^2.1.1: + version "2.2.6" + resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-2.2.6.tgz#2ef0bb39a24ac034787965c457368a28730e220a" + integrity sha512-9JZz+vXCmfKUZ68zAptS7k4Nu8e2qcibe7WVZYps7sAgk5R8GYTc+T1WR0v1rlP9HxgARmOX1UTIJZFytajpNA== + dependencies: + node-fetch "^2.6.7" + whatwg-fetch "^2.0.4" + +cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +"crypt@>= 0.0.1": + version "0.0.2" + resolved "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + +crypto-browserify@3.12.0: + version "3.12.0" + resolved "https://registry.npmmirror.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.npmmirror.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@3.2.6: + version "3.2.6" + resolved "https://registry.npmmirror.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.3: + version "4.3.4" + resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@4.3.1: + version "4.3.1" + resolved "https://registry.npmmirror.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== + dependencies: + ms "2.1.2" + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize@^1.1.1, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decode-uri-component@^0.2.0: + version "0.2.2" + resolved "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-eql@^4.1.2: + version "4.1.3" + resolved "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + +deep-equal@~1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + +defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + +defer-to-connect@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +deferred-leveldown@~1.2.1: + version "1.2.2" + resolved "https://registry.npmmirror.com/deferred-leveldown/-/deferred-leveldown-1.2.2.tgz#3acd2e0b75d1669924bc0a4b642851131173e1eb" + integrity sha512-uukrWD2bguRtXilKt6cAWKyoXrTSMo5m7crUdLfWQmu8kIm88w3QZoUL+6nhpfKVmhHANER6Re3sKoNoZ3IKMA== + dependencies: + abstract-leveldown "~2.6.0" + +deferred-leveldown@~4.0.0: + version "4.0.2" + resolved "https://registry.npmmirror.com/deferred-leveldown/-/deferred-leveldown-4.0.2.tgz#0b0570087827bf480a23494b398f04c128c19a20" + integrity sha512-5fMC8ek8alH16QiV0lTCis610D1Zt1+LA4MS4d63JgS32lrCjTFDUFz2ao09/j2I4Bqb5jL4FZYwu7Jz0XO1ww== + dependencies: + abstract-leveldown "~5.0.0" + inherits "^2.0.3" + +define-properties@^1.1.2, define-properties@^1.1.3, define-properties@^1.1.4: + version "1.2.0" + resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" + integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== + dependencies: + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.npmmirror.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@~1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf" + integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + integrity sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A== + dependencies: + repeating "^2.0.0" + +diff@3.5.0: + version "3.5.0" + resolved "https://registry.npmmirror.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmmirror.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.npmmirror.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.npmmirror.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +dotignore@~0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/dotignore/-/dotignore-0.1.2.tgz#f942f2200d28c3a76fbdd6f0ee9f3257c8a2e905" + integrity sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw== + dependencies: + minimatch "^3.0.4" + +duplexer3@^0.1.4: + version "0.1.5" + resolved "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz#0b5e4d7bad5de8901ea4440624c8e1d20099217e" + integrity sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.npmmirror.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.3.47: + version "1.4.333" + resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.333.tgz#ebb21f860f8a29923717b06ec0cb54e77ed34c04" + integrity sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ== + +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.2, elliptic@^6.5.3, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + 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" + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding-down@5.0.4, encoding-down@~5.0.0: + version "5.0.4" + resolved "https://registry.npmmirror.com/encoding-down/-/encoding-down-5.0.4.tgz#1e477da8e9e9d0f7c8293d320044f8b2cd8e9614" + integrity sha512-8CIZLDcSKxgzT+zX8ZVfgNbu8Md2wq/iqa1Y7zyVR18QBEAc0Nmzuvj/N5ykSKpfGzjM8qxbaFntLPwnVoUhZw== + dependencies: + abstract-leveldown "^5.0.0" + inherits "^2.0.3" + level-codec "^9.0.0" + level-errors "^2.0.0" + xtend "^4.0.1" + +encoding@^0.1.11: + version "0.1.13" + resolved "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.0: + version "2.3.6" + resolved "https://registry.npmmirror.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +errno@~0.1.1: + version "0.1.8" + resolved "https://registry.npmmirror.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.1" + +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.0, es-abstract@^1.20.4: + version "1.21.2" + resolved "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.21.2.tgz#a56b9695322c8a185dc25975aa3b8ec31d0e7eff" + integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== + dependencies: + array-buffer-byte-length "^1.0.0" + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.5" + get-intrinsic "^1.2.0" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has "^1.0.3" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.10" + is-weakref "^1.0.2" + object-inspect "^1.12.3" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.4.3" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.7" + string.prototype.trimend "^1.0.6" + string.prototype.trimstart "^1.0.6" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.9" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-set-tostringtag@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" + integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== + dependencies: + get-intrinsic "^1.1.3" + has "^1.0.3" + has-tostringtag "^1.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.62" + resolved "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eth-block-tracker@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/eth-block-tracker/-/eth-block-tracker-3.0.1.tgz#95cd5e763c7293e0b1b2790a2a39ac2ac188a5e1" + integrity sha512-WUVxWLuhMmsfenfZvFO5sbl1qFY2IqUlw/FPVmjjdElpqLsZtSG+wPe9Dz7W/sB6e80HgFKknOmKk2eNlznHug== + dependencies: + eth-query "^2.1.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.3" + ethjs-util "^0.1.3" + json-rpc-engine "^3.6.0" + pify "^2.3.0" + tape "^4.6.3" + +eth-ens-namehash@2.0.8, eth-ens-namehash@^2.0.8: + version "2.0.8" + resolved "https://registry.npmmirror.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw== + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-gas-reporter@^0.2.25: + version "0.2.25" + resolved "https://registry.npmmirror.com/eth-gas-reporter/-/eth-gas-reporter-0.2.25.tgz#546dfa946c1acee93cb1a94c2a1162292d6ff566" + integrity sha512-1fRgyE4xUB8SoqLgN3eDfpDfwEfRxh2Sz1b7wzFbyQA+9TekMmvSjjoRu9SKcSVyK+vLkLIsVbJDsTWjw195OQ== + dependencies: + "@ethersproject/abi" "^5.0.0-beta.146" + "@solidity-parser/parser" "^0.14.0" + cli-table3 "^0.5.0" + colors "1.4.0" + ethereum-cryptography "^1.0.3" + ethers "^4.0.40" + fs-readdir-recursive "^1.1.0" + lodash "^4.17.14" + markdown-table "^1.1.3" + mocha "^7.1.1" + req-cwd "^2.0.0" + request "^2.88.0" + request-promise-native "^1.0.5" + sha1 "^1.1.1" + sync-request "^6.0.0" + +eth-json-rpc-infura@^3.1.0: + version "3.2.1" + resolved "https://registry.npmmirror.com/eth-json-rpc-infura/-/eth-json-rpc-infura-3.2.1.tgz#26702a821067862b72d979c016fd611502c6057f" + integrity sha512-W7zR4DZvyTn23Bxc0EWsq4XGDdD63+XPUCEhV2zQvQGavDVC4ZpFDK4k99qN7bd7/fjj37+rxmuBOBeIqCA5Mw== + dependencies: + cross-fetch "^2.1.1" + eth-json-rpc-middleware "^1.5.0" + json-rpc-engine "^3.4.0" + json-rpc-error "^2.0.0" + +eth-json-rpc-middleware@^1.5.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/eth-json-rpc-middleware/-/eth-json-rpc-middleware-1.6.0.tgz#5c9d4c28f745ccb01630f0300ba945f4bef9593f" + integrity sha512-tDVCTlrUvdqHKqivYMjtFZsdD7TtpNLBCfKAcOpaVs7orBMS/A8HWro6dIzNtTZIR05FAbJ3bioFOnZpuCew9Q== + dependencies: + async "^2.5.0" + eth-query "^2.1.2" + eth-tx-summary "^3.1.2" + ethereumjs-block "^1.6.0" + ethereumjs-tx "^1.3.3" + ethereumjs-util "^5.1.2" + ethereumjs-vm "^2.1.0" + fetch-ponyfill "^4.0.0" + json-rpc-engine "^3.6.0" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + tape "^4.6.3" + +eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.npmmirror.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +eth-lib@^0.1.26: + version "0.1.29" + resolved "https://registry.npmmirror.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" + integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + +eth-query@^2.0.2, eth-query@^2.1.0, eth-query@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/eth-query/-/eth-query-2.1.2.tgz#d6741d9000106b51510c72db92d6365456a6da5e" + integrity sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA== + dependencies: + json-rpc-random-id "^1.0.0" + xtend "^4.0.1" + +eth-sig-util@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/eth-sig-util/-/eth-sig-util-3.0.0.tgz#75133b3d7c20a5731af0690c385e184ab942b97e" + integrity sha512-4eFkMOhpGbTxBQ3AMzVf0haUX2uTur7DpWiHzWyTURa28BVJJtOkcb9Ok5TV0YvEPG61DODPW7ZUATbJTslioQ== + dependencies: + buffer "^5.2.1" + elliptic "^6.4.0" + ethereumjs-abi "0.6.5" + ethereumjs-util "^5.1.1" + tweetnacl "^1.0.0" + tweetnacl-util "^0.15.0" + +eth-sig-util@^1.4.2: + version "1.4.2" + resolved "https://registry.npmmirror.com/eth-sig-util/-/eth-sig-util-1.4.2.tgz#8d958202c7edbaae839707fba6f09ff327606210" + integrity sha512-iNZ576iTOGcfllftB73cPB5AN+XUQAT/T8xzsILsghXC1o8gJUqe3RHlcDqagu+biFpYQ61KQrZZJza8eRSYqw== + dependencies: + ethereumjs-abi "git+https://github.com/ethereumjs/ethereumjs-abi.git" + ethereumjs-util "^5.1.1" + +eth-tx-summary@^3.1.2: + version "3.2.4" + resolved "https://registry.npmmirror.com/eth-tx-summary/-/eth-tx-summary-3.2.4.tgz#e10eb95eb57cdfe549bf29f97f1e4f1db679035c" + integrity sha512-NtlDnaVZah146Rm8HMRUNMgIwG/ED4jiqk0TME9zFheMl1jOp6jL1m0NKGjJwehXQ6ZKCPr16MTr+qspKpEXNg== + dependencies: + async "^2.1.2" + clone "^2.0.0" + concat-stream "^1.5.1" + end-of-stream "^1.1.0" + eth-query "^2.0.2" + ethereumjs-block "^1.4.1" + ethereumjs-tx "^1.1.1" + ethereumjs-util "^5.0.1" + ethereumjs-vm "^2.6.0" + through2 "^2.0.3" + +ethashjs@~0.0.7: + version "0.0.8" + resolved "https://registry.npmmirror.com/ethashjs/-/ethashjs-0.0.8.tgz#227442f1bdee409a548fb04136e24c874f3aa6f9" + integrity sha512-/MSbf/r2/Ld8o0l15AymjOTlPqpN8Cr4ByUEA9GtR4x0yAh3TdtDzEg29zMjXCNPI7u6E5fOQdj/Cf9Tc7oVNw== + dependencies: + async "^2.1.2" + buffer-xor "^2.0.1" + ethereumjs-util "^7.0.2" + miller-rabin "^4.0.0" + +ethereum-bloom-filters@^1.0.6: + version "1.0.10" + resolved "https://registry.npmmirror.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" + integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + dependencies: + js-sha3 "^0.8.0" + +ethereum-common@0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/ethereum-common/-/ethereum-common-0.2.0.tgz#13bf966131cce1eeade62a1b434249bb4cb120ca" + integrity sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA== + +ethereum-common@^0.0.18: + version "0.0.18" + resolved "https://registry.npmmirror.com/ethereum-common/-/ethereum-common-0.0.18.tgz#2fdc3576f232903358976eb39da783213ff9523f" + integrity sha512-EoltVQTRNg2Uy4o84qpa2aXymXDJhxm7eos/ACOg0DG4baAbMjhbdAEsx9GeE8sC3XCxnYvrrzZDH8D8MtA2iQ== + +ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereum-cryptography@^1.0.3: + version "1.2.0" + resolved "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" + integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== + dependencies: + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/bip32" "1.1.5" + "@scure/bip39" "1.1.1" + +ethereum-waffle@^3.2.1: + version "3.4.4" + resolved "https://registry.npmmirror.com/ethereum-waffle/-/ethereum-waffle-3.4.4.tgz#1378b72040697857b7f5e8f473ca8f97a37b5840" + integrity sha512-PA9+jCjw4WC3Oc5ocSMBj5sXvueWQeAbvCA+hUlb6oFgwwKyq5ka3bWQ7QZcjzIX+TdFkxP4IbFmoY2D8Dkj9Q== + dependencies: + "@ethereum-waffle/chai" "^3.4.4" + "@ethereum-waffle/compiler" "^3.4.4" + "@ethereum-waffle/mock-contract" "^3.4.4" + "@ethereum-waffle/provider" "^3.4.4" + ethers "^5.0.1" + +ethereumjs-abi@0.6.5: + version "0.6.5" + resolved "https://registry.npmmirror.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241" + integrity sha512-rCjJZ/AE96c/AAZc6O3kaog4FhOsAViaysBxqJNy2+LHP0ttH0zkZ7nXdVHOAyt6lFwLO0nlCwWszysG/ao1+g== + dependencies: + bn.js "^4.10.0" + ethereumjs-util "^4.3.0" + +ethereumjs-abi@0.6.8, ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.npmmirror.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" + integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git": + version "0.6.8" + resolved "git+https://github.com/ethereumjs/ethereumjs-abi.git#ee3994657fa7a427238e6ba92a84d0b529bbcde0" + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-account@3.0.0, ethereumjs-account@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/ethereumjs-account/-/ethereumjs-account-3.0.0.tgz#728f060c8e0c6e87f1e987f751d3da25422570a9" + integrity sha512-WP6BdscjiiPkQfF9PVfMcwx/rDvfZTjFKY0Uwc09zSQr9JfIVH87dYIJu0gNhBhpmovV4yq295fdllS925fnBA== + dependencies: + ethereumjs-util "^6.0.0" + rlp "^2.2.1" + safe-buffer "^5.1.1" + +ethereumjs-account@^2.0.3: + version "2.0.5" + resolved "https://registry.npmmirror.com/ethereumjs-account/-/ethereumjs-account-2.0.5.tgz#eeafc62de544cb07b0ee44b10f572c9c49e00a84" + integrity sha512-bgDojnXGjhMwo6eXQC0bY6UK2liSFUSMwwylOmQvZbSl/D7NXQ3+vrGO46ZeOgjGfxXmgIeVNDIiHw7fNZM4VA== + dependencies: + ethereumjs-util "^5.0.0" + rlp "^2.0.0" + safe-buffer "^5.1.1" + +ethereumjs-block@2.2.2, ethereumjs-block@^2.2.2, ethereumjs-block@~2.2.0, ethereumjs-block@~2.2.2: + version "2.2.2" + resolved "https://registry.npmmirror.com/ethereumjs-block/-/ethereumjs-block-2.2.2.tgz#c7654be7e22df489fda206139ecd63e2e9c04965" + integrity sha512-2p49ifhek3h2zeg/+da6XpdFR3GlqY3BIEiqxGF8j9aSRIgkb7M1Ky+yULBKJOu8PAZxfhsYA+HxUk2aCQp3vg== + dependencies: + async "^2.0.1" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.1" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-block@^1.2.2, ethereumjs-block@^1.4.1, ethereumjs-block@^1.6.0: + version "1.7.1" + resolved "https://registry.npmmirror.com/ethereumjs-block/-/ethereumjs-block-1.7.1.tgz#78b88e6cc56de29a6b4884ee75379b6860333c3f" + integrity sha512-B+sSdtqm78fmKkBq78/QLKJbu/4Ts4P2KFISdgcuZUPDm9x+N7qgBPIIFUGbaakQh8bzuquiRVbdmvPKqbILRg== + dependencies: + async "^2.0.1" + ethereum-common "0.2.0" + ethereumjs-tx "^1.2.2" + ethereumjs-util "^5.0.0" + merkle-patricia-tree "^2.1.2" + +ethereumjs-blockchain@^4.0.3: + version "4.0.4" + resolved "https://registry.npmmirror.com/ethereumjs-blockchain/-/ethereumjs-blockchain-4.0.4.tgz#30f2228dc35f6dcf94423692a6902604ae34960f" + integrity sha512-zCxaRMUOzzjvX78DTGiKjA+4h2/sF0OYL1QuPux0DHpyq8XiNoF5GYHtb++GUxVlMsMfZV7AVyzbtgcRdIcEPQ== + dependencies: + async "^2.6.1" + ethashjs "~0.0.7" + ethereumjs-block "~2.2.2" + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.1.0" + flow-stoplight "^1.0.0" + level-mem "^3.0.1" + lru-cache "^5.1.1" + rlp "^2.2.2" + semaphore "^1.1.0" + +ethereumjs-common@1.5.0: + version "1.5.0" + resolved "https://registry.npmmirror.com/ethereumjs-common/-/ethereumjs-common-1.5.0.tgz#d3e82fc7c47c0cef95047f431a99485abc9bb1cd" + integrity sha512-SZOjgK1356hIY7MRj3/ma5qtfr/4B5BL+G4rP/XSMYr2z1H5el4RX5GReYCKmQmYI/nSBmRnwrZ17IfHuG0viQ== + +ethereumjs-common@^1.1.0, ethereumjs-common@^1.3.2, ethereumjs-common@^1.5.0: + version "1.5.2" + resolved "https://registry.npmmirror.com/ethereumjs-common/-/ethereumjs-common-1.5.2.tgz#2065dbe9214e850f2e955a80e650cb6999066979" + integrity sha512-hTfZjwGX52GS2jcVO6E2sx4YuFnf0Fhp5ylo4pEPhEffNln7vS59Hr5sLnp3/QCazFLluuBZ+FZ6J5HTp0EqCA== + +ethereumjs-tx@2.1.2, ethereumjs-tx@^2.1.1, ethereumjs-tx@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ethereumjs-tx/-/ethereumjs-tx-2.1.2.tgz#5dfe7688bf177b45c9a23f86cf9104d47ea35fed" + integrity sha512-zZEK1onCeiORb0wyCXUvg94Ve5It/K6GD1K+26KfFKodiBiS6d9lfCXlUKGBBdQ+bv7Day+JK0tj1K+BeNFRAw== + dependencies: + ethereumjs-common "^1.5.0" + ethereumjs-util "^6.0.0" + +ethereumjs-tx@^1.1.1, ethereumjs-tx@^1.2.0, ethereumjs-tx@^1.2.2, ethereumjs-tx@^1.3.3: + version "1.3.7" + resolved "https://registry.npmmirror.com/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz#88323a2d875b10549b8347e09f4862b546f3d89a" + integrity sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA== + dependencies: + ethereum-common "^0.0.18" + ethereumjs-util "^5.0.0" + +ethereumjs-util@6.2.1, ethereumjs-util@^6.0.0, ethereumjs-util@^6.1.0, ethereumjs-util@^6.2.0, ethereumjs-util@^6.2.1: + version "6.2.1" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethereumjs-util@^4.3.0: + version "4.5.1" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-4.5.1.tgz#f4bf9b3b515a484e3cc8781d61d9d980f7c83bd0" + integrity sha512-WrckOZ7uBnei4+AKimpuF1B3Fv25OmoRgmYCpGsP7u8PFxXAmAgiJSYT2kRWnt6fVIlKaQlZvuwXp7PIrmn3/w== + dependencies: + bn.js "^4.8.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + rlp "^2.0.0" + +ethereumjs-util@^5.0.0, ethereumjs-util@^5.0.1, ethereumjs-util@^5.1.1, ethereumjs-util@^5.1.2, ethereumjs-util@^5.1.3, ethereumjs-util@^5.1.5, ethereumjs-util@^5.2.0: + version "5.2.1" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz#a833f0e5fca7e5b361384dc76301a721f537bf65" + integrity sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ== + dependencies: + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "^0.1.3" + rlp "^2.0.0" + safe-buffer "^5.1.1" + +ethereumjs-util@^7.0.2, ethereumjs-util@^7.1.0: + version "7.1.5" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethereumjs-vm@4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/ethereumjs-vm/-/ethereumjs-vm-4.2.0.tgz#e885e861424e373dbc556278f7259ff3fca5edab" + integrity sha512-X6qqZbsY33p5FTuZqCnQ4+lo957iUJMM6Mpa6bL4UW0dxM6WmDSHuI4j/zOp1E2TDKImBGCJA9QPfc08PaNubA== + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + core-js-pure "^3.0.1" + ethereumjs-account "^3.0.0" + ethereumjs-block "^2.2.2" + ethereumjs-blockchain "^4.0.3" + ethereumjs-common "^1.5.0" + ethereumjs-tx "^2.1.2" + ethereumjs-util "^6.2.0" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.3.2" + rustbn.js "~0.2.0" + safe-buffer "^5.1.1" + util.promisify "^1.0.0" + +ethereumjs-vm@^2.1.0, ethereumjs-vm@^2.3.4, ethereumjs-vm@^2.6.0: + version "2.6.0" + resolved "https://registry.npmmirror.com/ethereumjs-vm/-/ethereumjs-vm-2.6.0.tgz#76243ed8de031b408793ac33907fb3407fe400c6" + integrity sha512-r/XIUik/ynGbxS3y+mvGnbOKnuLo40V5Mj1J25+HEO63aWYREIqvWeRO/hnROlMBE5WoniQmPmhiaN0ctiHaXw== + dependencies: + async "^2.1.2" + async-eventemitter "^0.2.2" + ethereumjs-account "^2.0.3" + ethereumjs-block "~2.2.0" + ethereumjs-common "^1.1.0" + ethereumjs-util "^6.0.0" + fake-merkle-patricia-tree "^1.0.1" + functional-red-black-tree "^1.0.1" + merkle-patricia-tree "^2.3.2" + rustbn.js "~0.2.0" + safe-buffer "^5.1.1" + +ethereumjs-wallet@0.6.5: + version "0.6.5" + resolved "https://registry.npmmirror.com/ethereumjs-wallet/-/ethereumjs-wallet-0.6.5.tgz#685e9091645cee230ad125c007658833991ed474" + integrity sha512-MDwjwB9VQVnpp/Dc1XzA6J1a3wgHQ4hSvA1uWNatdpOrtCbPVuQSKSyRnjLvS0a+KKMw2pvQ9Ybqpb3+eW8oNA== + dependencies: + aes-js "^3.1.1" + bs58check "^2.1.2" + ethereum-cryptography "^0.1.3" + ethereumjs-util "^6.0.0" + randombytes "^2.0.6" + safe-buffer "^5.1.2" + scryptsy "^1.2.1" + utf8 "^3.0.0" + uuid "^3.3.2" + +ethers@^4.0.40: + version "4.0.49" + resolved "https://registry.npmmirror.com/ethers/-/ethers-4.0.49.tgz#0eb0e9161a0c8b4761be547396bbe2fb121a8894" + integrity sha512-kPltTvWiyu+OktYy1IStSO16i2e7cS9D9OxZ81q2UUaiNPVrm/RTcbxamCXF9VUSKzJIdJV68EAIhTEVBalRWg== + dependencies: + aes-js "3.0.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.3" + js-sha3 "0.5.7" + scrypt-js "2.0.4" + setimmediate "1.0.4" + uuid "2.0.1" + xmlhttprequest "1.8.0" + +ethers@^5.0.1, ethers@^5.0.2, ethers@^5.0.24, ethers@^5.5.2: + version "5.7.2" + resolved "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + 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" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethjs-util@0.1.6, ethjs-util@^0.1.3, ethjs-util@^0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + +events@^3.0.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.npmmirror.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +express@^4.14.0: + version "4.18.2" + resolved "https://registry.npmmirror.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +fake-merkle-patricia-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/fake-merkle-patricia-tree/-/fake-merkle-patricia-tree-1.0.1.tgz#4b8c3acfb520afadf9860b1f14cd8ce3402cddd3" + integrity sha512-Tgq37lkc9pUIgIKw5uitNUKcgcYL3R6JvXtKQbOf/ZSavXbidsksgp/pAY6p//uhw0I4yoMsvTSovvVIsk/qxA== + dependencies: + checkpoint-store "^1.1.0" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fetch-ponyfill@^4.0.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" + integrity sha512-knK9sGskIg2T7OnYLdZ2hZXn0CtDrAIBxYQLpmEf0BqfdWnwmM1weccUl5+4EdA44tzNSFAuxITPbXtPehUB3g== + dependencies: + node-fetch "~1.7.1" + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-replace@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/find-replace/-/find-replace-1.0.3.tgz#b88e7364d2d9c959559f388c66670d6130441fa0" + integrity sha512-KrUnjzDCD9426YnCP56zGYy/eieTnhtK6Vn++j+JJzmlsWWwEkDnsyVF575spT6HJ6Ow9tlbT3TQTDsa+O4UWA== + dependencies: + array-back "^1.0.4" + test-value "^2.1.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA== + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + +find-yarn-workspace-root@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" + integrity sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q== + dependencies: + fs-extra "^4.0.3" + micromatch "^3.1.4" + +find-yarn-workspace-root@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" + integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== + dependencies: + micromatch "^4.0.2" + +flat@^4.1.0: + version "4.1.1" + resolved "https://registry.npmmirror.com/flat/-/flat-4.1.1.tgz#a392059cc382881ff98642f5da4dde0a959f309b" + integrity sha512-FmTtBsHskrU6FJ2VxCnsDb84wu9zhmO3cUX2kGFb5tuwhfXxGciiT0oRY+cck35QmG+NmGh5eLz6lLCpWTqwpA== + dependencies: + is-buffer "~2.0.3" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flow-stoplight@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/flow-stoplight/-/flow-stoplight-1.0.0.tgz#4a292c5bcff8b39fa6cc0cb1a853d86f27eeff7b" + integrity sha512-rDjbZUKpN8OYhB0IE/vY/I8UWO/602IIJEU/76Tv4LvYnwHCk0BCsvz4eRr9n+FQcri7L5cyaXOo0+/Kh4HisA== + +follow-redirects@^1.12.1: + version "1.15.2" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +for-each@^0.3.3, for-each@~0.3.3: + version "0.3.3" + resolved "https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.npmmirror.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@^2.2.0: + version "2.5.1" + resolved "https://registry.npmmirror.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fp-ts@1.19.3: + version "1.19.3" + resolved "https://registry.npmmirror.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" + integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== + +fp-ts@^1.0.0: + version "1.19.5" + resolved "https://registry.npmmirror.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" + integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^4.0.2, fs-extra@^4.0.3: + version "4.0.3" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.0.0: + version "9.1.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== + +fsevents@~2.3.1, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +function.prototype.name@^1.1.5: + version "1.1.5" + resolved "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" + integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + functions-have-names "^1.2.2" + +functional-red-black-tree@^1.0.1, functional-red-black-tree@~1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.2: + version "1.2.3" + resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +ganache-core@^2.13.2: + version "2.13.2" + resolved "https://registry.npmmirror.com/ganache-core/-/ganache-core-2.13.2.tgz#27e6fc5417c10e6e76e2e646671869d7665814a3" + integrity sha512-tIF5cR+ANQz0+3pHWxHjIwHqFXcVo0Mb+kcsNhglNFALcYo49aQpnS9dqHartqPfMFjiHh/qFoD3mYK0d/qGgw== + dependencies: + abstract-leveldown "3.0.0" + async "2.6.2" + bip39 "2.5.0" + cachedown "1.0.0" + clone "2.1.2" + debug "3.2.6" + encoding-down "5.0.4" + eth-sig-util "3.0.0" + ethereumjs-abi "0.6.8" + ethereumjs-account "3.0.0" + ethereumjs-block "2.2.2" + ethereumjs-common "1.5.0" + ethereumjs-tx "2.1.2" + ethereumjs-util "6.2.1" + ethereumjs-vm "4.2.0" + heap "0.2.6" + keccak "3.0.1" + level-sublevel "6.6.4" + levelup "3.1.1" + lodash "4.17.20" + lru-cache "5.1.1" + merkle-patricia-tree "3.0.0" + patch-package "6.2.2" + seedrandom "3.0.1" + source-map-support "0.5.12" + tmp "0.1.0" + web3-provider-engine "14.2.1" + websocket "1.0.32" + optionalDependencies: + ethereumjs-wallet "0.6.5" + web3 "1.2.11" + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" + integrity sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" + integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.3" + +get-port@^3.1.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== + +get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + +glob-parent@~5.1.0, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.1.6: + version "7.1.6" + resolved "https://registry.npmmirror.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.2.3: + version "7.2.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +global@~4.4.0: + version "4.4.0" + resolved "https://registry.npmmirror.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^9.18.0: + version "9.18.0" + resolved "https://registry.npmmirror.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" + integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +got@9.6.0: + version "9.6.0" + resolved "https://registry.npmmirror.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + +got@^11.8.5: + version "11.8.6" + resolved "https://registry.npmmirror.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.npmmirror.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.npmmirror.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +hardhat-gas-reporter@^1.0.4: + version "1.0.9" + resolved "https://registry.npmmirror.com/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz#9a2afb354bc3b6346aab55b1c02ca556d0e16450" + integrity sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg== + dependencies: + array-uniq "1.0.3" + eth-gas-reporter "^0.2.25" + sha1 "^1.1.1" + +hardhat@^2.0.7: + version "2.13.0" + resolved "https://registry.npmmirror.com/hardhat/-/hardhat-2.13.0.tgz#d52a0ec9b733a651687e5b1c1b0ee9a11a30f3d0" + integrity sha512-ZlzBOLML1QGlm6JWyVAG8lVTEAoOaVm1in/RU2zoGAnYEoD1Rp4T+ZMvrLNhHaaeS9hfjJ1gJUBfiDr4cx+htQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/ethereumjs-block" "^4.0.0" + "@nomicfoundation/ethereumjs-blockchain" "^6.0.0" + "@nomicfoundation/ethereumjs-common" "^3.0.0" + "@nomicfoundation/ethereumjs-evm" "^1.0.0" + "@nomicfoundation/ethereumjs-rlp" "^4.0.0" + "@nomicfoundation/ethereumjs-statemanager" "^1.0.0" + "@nomicfoundation/ethereumjs-trie" "^5.0.0" + "@nomicfoundation/ethereumjs-tx" "^4.0.0" + "@nomicfoundation/ethereumjs-util" "^8.0.0" + "@nomicfoundation/ethereumjs-vm" "^6.0.0" + "@nomicfoundation/solidity-analyzer" "^0.1.0" + "@sentry/node" "^5.18.1" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + abort-controller "^3.0.0" + adm-zip "^0.4.16" + aggregate-error "^3.0.0" + ansi-escapes "^4.3.0" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + ethereum-cryptography "^1.0.3" + ethereumjs-abi "^0.6.8" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "7.2.0" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + keccak "^3.0.2" + lodash "^4.17.11" + mnemonist "^0.38.0" + mocha "^10.0.0" + p-map "^4.0.0" + qs "^6.7.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + solc "0.7.3" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + tsort "0.0.1" + undici "^5.14.0" + uuid "^8.3.2" + ws "^7.4.6" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== + dependencies: + ansi-regex "^2.0.0" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.0, has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.npmmirror.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.npmmirror.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3, has@~1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + integrity sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +heap@0.2.6: + version "0.2.6" + resolved "https://registry.npmmirror.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" + integrity sha512-MzzWcnfB1e4EG2vHi3dXHoBupmuXNZzx6pY6HldVS55JKKBoq3xOyzfSaZRkJp37HIhEYC78knabHff3zc4dQQ== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + integrity sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4, hosted-git-info@^2.6.0: + version "2.8.9" + resolved "https://registry.npmmirror.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +http-basic@^8.1.1: + version "8.1.3" + resolved "https://registry.npmmirror.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf" + integrity sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw== + dependencies: + caseless "^0.12.0" + concat-stream "^1.6.2" + http-response-object "^3.0.1" + parse-cache-control "^1.0.1" + +http-cache-semantics@^4.0.0: + version "4.1.1" + resolved "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== + +http-response-object@^3.0.1: + version "3.0.2" + resolved "https://registry.npmmirror.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" + integrity sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA== + dependencies: + "@types/node" "^10.0.3" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +http2-wrapper@^1.0.0-beta.5.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" + integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.0.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +immediate@^3.2.3: + version "3.3.0" + resolved "https://registry.npmmirror.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + +immediate@~3.2.3: + version "3.2.3" + resolved "https://registry.npmmirror.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" + integrity sha512-RrGCXRm/fRVqMIhqXrGEX9rRADavPiDFSoMb/k64i9XMk8uH4r/Omi5Ctierj6XzNecwDbO4WuFbDD1zmpl3Tg== + +immutable@^4.0.0-rc.12: + version "4.3.0" + resolved "https://registry.npmmirror.com/immutable/-/immutable-4.3.0.tgz#eb1738f14ffb39fd068b1dbe1296117484dd34be" + integrity sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.5.tgz#f2a2ee21f668f8627a4667f309dc0f4fb6674986" + integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== + dependencies: + get-intrinsic "^1.2.0" + has "^1.0.3" + side-channel "^1.0.4" + +invariant@^2.2.2: + version "2.2.4" + resolved "https://registry.npmmirror.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ== + +io-ts@1.10.4: + version "1.10.4" + resolved "https://registry.npmmirror.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" + integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== + dependencies: + fp-ts "^1.0.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha512-e1BM1qnDbMRG3ll2U9dSK0UMHuWOs3pY3AtcFsmvwPtKL3MML/Q86i+GilLfvqEs4GW+ExB91tQ3Ig9noDIZ+A== + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.5, is-buffer@~2.0.3: + version "2.0.5" + resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.9.0: + version "2.11.0" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" + integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.npmmirror.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha512-+w9D5ulSoBNlmw9OHn3U2v51SyoCd0he+bB3xMl62oijhrspxowjU+AIcDY0N3iEJbUEkB15IlMASQsxYigvXg== + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0: + version "2.2.1" + resolved "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.npmmirror.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== + +is-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-fn/-/is-fn-1.0.0.tgz#9543d5de7bcf5b08a22ec8a20bae6e286d510d8c" + integrity sha512-XoFPJQmsAShb3jEQRfzf2rqXavq7fIqF/jOekp308JlThqrODnMpweVSGilKTCXELfLhltGP2AGgbQGVP8F1dg== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== + dependencies: + kind-of "^3.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-regex@^1.0.4, is-regex@^1.1.4, is-regex@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.npmmirror.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.9: + version "1.1.10" + resolved "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" + integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-url@^1.2.4: + version "1.2.4" + resolved "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" + integrity sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww== + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.npmmirror.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^2.1.1: + version "2.2.0" + resolved "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +js-sha3@0.5.7, js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-tokens@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" + integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" + integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== + dependencies: + argparse "^2.0.1" + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + integrity sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.npmmirror.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: + version "3.8.0" + resolved "https://registry.npmmirror.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" + integrity sha512-6QNcvm2gFuuK4TKU1uwfH0Qd/cOSb9c1lls0gbnIhciktIUQJwz6NQNAW4B1KiGPenv7IKu97V222Yo1bNhGuA== + dependencies: + async "^2.0.1" + babel-preset-env "^1.7.0" + babelify "^7.3.0" + json-rpc-error "^2.0.0" + promise-to-callback "^1.0.0" + safe-event-emitter "^1.0.1" + +json-rpc-error@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/json-rpc-error/-/json-rpc-error-2.0.0.tgz#a7af9c202838b5e905c7250e547f1aff77258a02" + integrity sha512-EwUeWP+KgAZ/xqFpaP6YDAXMtCJi+o/QQpCQFIYyxr01AdADi2y413eM8hSqJcoQym9WMePAJWoaODEJufC4Ug== + dependencies: + inherits "^2.0.1" + +json-rpc-random-id@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/json-rpc-random-id/-/json-rpc-random-id-1.0.1.tgz#ba49d96aded1444dbb8da3d203748acbbcdec8c8" + integrity sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stable-stringify@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz#e06f23128e0bbe342dc996ed5a19e28b57b580e0" + integrity sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g== + dependencies: + jsonify "^0.0.1" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^0.5.1: + version "0.5.1" + resolved "https://registry.npmmirror.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw== + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + +jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.npmmirror.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +keccak@3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/keccak/-/keccak-3.0.1.tgz#ae30a0e94dbe43414f741375cff6d64c8bea0bff" + integrity sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +keccak@^3.0.0, keccak@^3.0.2: + version "3.0.3" + resolved "https://registry.npmmirror.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" + integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + +keyv@^4.0.0: + version "4.5.2" + resolved "https://registry.npmmirror.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56" + integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g== + dependencies: + json-buffer "3.0.1" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.npmmirror.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== + optionalDependencies: + graceful-fs "^4.1.9" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha512-YiGkH6EnGrDGqLMITnGjXtGmNtjoXw9SVUzcaos8RBi7Ps0VBylkq+vOcY9QE5poLasPCR849ucFUkl0UzUyOw== + dependencies: + invert-kv "^1.0.0" + +level-codec@^9.0.0: + version "9.0.2" + resolved "https://registry.npmmirror.com/level-codec/-/level-codec-9.0.2.tgz#fd60df8c64786a80d44e63423096ffead63d8cbc" + integrity sha512-UyIwNb1lJBChJnGfjmO0OR+ezh2iVu1Kas3nvBS/BzGnx79dv6g7unpKIDNPMhfdTEGoc7mC8uAu51XEtX+FHQ== + dependencies: + buffer "^5.6.0" + +level-codec@~7.0.0: + version "7.0.1" + resolved "https://registry.npmmirror.com/level-codec/-/level-codec-7.0.1.tgz#341f22f907ce0f16763f24bddd681e395a0fb8a7" + integrity sha512-Ua/R9B9r3RasXdRmOtd+t9TCOEIIlts+TN/7XTT2unhDaL6sJn83S3rUyljbr6lVtw49N3/yA0HHjpV6Kzb2aQ== + +level-errors@^1.0.3: + version "1.1.2" + resolved "https://registry.npmmirror.com/level-errors/-/level-errors-1.1.2.tgz#4399c2f3d3ab87d0625f7e3676e2d807deff404d" + integrity sha512-Sw/IJwWbPKF5Ai4Wz60B52yj0zYeqzObLh8k1Tk88jVmD51cJSKWSYpRyhVIvFzZdvsPqlH5wfhp/yxdsaQH4w== + dependencies: + errno "~0.1.1" + +level-errors@^2.0.0, level-errors@~2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/level-errors/-/level-errors-2.0.1.tgz#2132a677bf4e679ce029f517c2f17432800c05c8" + integrity sha512-UVprBJXite4gPS+3VznfgDSU8PTRuVX0NXwoWW50KLxd2yw4Y1t2JUR5In1itQnudZqRMT9DlAM3Q//9NCjCFw== + dependencies: + errno "~0.1.1" + +level-errors@~1.0.3: + version "1.0.5" + resolved "https://registry.npmmirror.com/level-errors/-/level-errors-1.0.5.tgz#83dbfb12f0b8a2516bdc9a31c4876038e227b859" + integrity sha512-/cLUpQduF6bNrWuAC4pwtUKA5t669pCsCi2XbmojG2tFeOr9j6ShtdDCtFFQO1DRt+EVZhx9gPzP9G2bUaG4ig== + dependencies: + errno "~0.1.1" + +level-iterator-stream@^2.0.3: + version "2.0.3" + resolved "https://registry.npmmirror.com/level-iterator-stream/-/level-iterator-stream-2.0.3.tgz#ccfff7c046dcf47955ae9a86f46dfa06a31688b4" + integrity sha512-I6Heg70nfF+e5Y3/qfthJFexhRw/Gi3bIymCoXAlijZdAcLaPuWSJs3KXyTYf23ID6g0o2QF62Yh+grOXY3Rig== + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.5" + xtend "^4.0.0" + +level-iterator-stream@~1.3.0: + version "1.3.1" + resolved "https://registry.npmmirror.com/level-iterator-stream/-/level-iterator-stream-1.3.1.tgz#e43b78b1a8143e6fa97a4f485eb8ea530352f2ed" + integrity sha512-1qua0RHNtr4nrZBgYlpV0qHHeHpcRRWTxEZJ8xsemoHAXNL5tbooh4tPEEqIqsbWCAJBmUmkwYK/sW5OrFjWWw== + dependencies: + inherits "^2.0.1" + level-errors "^1.0.3" + readable-stream "^1.0.33" + xtend "^4.0.0" + +level-iterator-stream@~3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/level-iterator-stream/-/level-iterator-stream-3.0.1.tgz#2c98a4f8820d87cdacab3132506815419077c730" + integrity sha512-nEIQvxEED9yRThxvOrq8Aqziy4EGzrxSZK+QzEFAVuJvQ8glfyZ96GB6BoI4sBbLfjMXm2w4vu3Tkcm9obcY0g== + dependencies: + inherits "^2.0.1" + readable-stream "^2.3.6" + xtend "^4.0.0" + +level-mem@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/level-mem/-/level-mem-3.0.1.tgz#7ce8cf256eac40f716eb6489654726247f5a89e5" + integrity sha512-LbtfK9+3Ug1UmvvhR2DqLqXiPW1OJ5jEh0a3m9ZgAipiwpSxGj/qaVVy54RG5vAQN1nCuXqjvprCuKSCxcJHBg== + dependencies: + level-packager "~4.0.0" + memdown "~3.0.0" + +level-packager@~4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/level-packager/-/level-packager-4.0.1.tgz#7e7d3016af005be0869bc5fa8de93d2a7f56ffe6" + integrity sha512-svCRKfYLn9/4CoFfi+d8krOtrp6RoX8+xm0Na5cgXMqSyRru0AnDYdLl+YI8u1FyS6gGZ94ILLZDE5dh2but3Q== + dependencies: + encoding-down "~5.0.0" + levelup "^3.0.0" + +level-post@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/level-post/-/level-post-1.0.7.tgz#19ccca9441a7cc527879a0635000f06d5e8f27d0" + integrity sha512-PWYqG4Q00asOrLhX7BejSajByB4EmG2GaKHfj3h5UmmZ2duciXLPGYWIjBzLECFWUGOZWlm5B20h/n3Gs3HKew== + dependencies: + ltgt "^2.1.2" + +level-sublevel@6.6.4: + version "6.6.4" + resolved "https://registry.npmmirror.com/level-sublevel/-/level-sublevel-6.6.4.tgz#f7844ae893919cd9d69ae19d7159499afd5352ba" + integrity sha512-pcCrTUOiO48+Kp6F1+UAzF/OtWqLcQVTVF39HLdZ3RO8XBoXt+XVPKZO1vVr1aUoxHZA9OtD2e1v7G+3S5KFDA== + dependencies: + bytewise "~1.1.0" + level-codec "^9.0.0" + level-errors "^2.0.0" + level-iterator-stream "^2.0.3" + ltgt "~2.1.1" + pull-defer "^0.2.2" + pull-level "^2.0.3" + pull-stream "^3.6.8" + typewiselite "~1.0.0" + xtend "~4.0.0" + +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== + dependencies: + buffer "^6.0.3" + module-error "^1.0.1" + +level-ws@0.0.0: + version "0.0.0" + resolved "https://registry.npmmirror.com/level-ws/-/level-ws-0.0.0.tgz#372e512177924a00424b0b43aef2bb42496d228b" + integrity sha512-XUTaO/+Db51Uiyp/t7fCMGVFOTdtLS/NIACxE/GHsij15mKzxksZifKVjlXDF41JMUP/oM1Oc4YNGdKnc3dVLw== + dependencies: + readable-stream "~1.0.15" + xtend "~2.1.1" + +level-ws@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/level-ws/-/level-ws-1.0.0.tgz#19a22d2d4ac57b18cc7c6ecc4bd23d899d8f603b" + integrity sha512-RXEfCmkd6WWFlArh3X8ONvQPm8jNpfA0s/36M4QzLqrLEIt1iJE9WBHLZ5vZJK6haMjJPJGJCQWfjMNnRcq/9Q== + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.8" + xtend "^4.0.1" + +level@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" + integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== + dependencies: + browser-level "^1.0.1" + classic-level "^1.2.0" + +levelup@3.1.1, levelup@^3.0.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/levelup/-/levelup-3.1.1.tgz#c2c0b3be2b4dc316647c53b42e2f559e232d2189" + integrity sha512-9N10xRkUU4dShSRRFTBdNaBxofz+PGaIZO962ckboJZiNmLuhVT6FZ6ZKAsICKfUBO76ySaYU6fJWX/jnj3Lcg== + dependencies: + deferred-leveldown "~4.0.0" + level-errors "~2.0.0" + level-iterator-stream "~3.0.0" + xtend "~4.0.0" + +levelup@^1.2.1: + version "1.3.9" + resolved "https://registry.npmmirror.com/levelup/-/levelup-1.3.9.tgz#2dbcae845b2bb2b6bea84df334c475533bbd82ab" + integrity sha512-VVGHfKIlmw8w1XqpGOAGwq6sZm2WwWLmlDcULkKWQXEA5EopA8OBNJ2Ck2v6bdk8HeEZSbCSEgzXadyQFm76sQ== + dependencies: + deferred-leveldown "~1.2.1" + level-codec "~7.0.0" + level-errors "~1.0.3" + level-iterator-stream "~1.3.0" + prr "~1.0.1" + semver "~5.4.1" + xtend "~4.0.0" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A== + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.assign@^4.0.3, lodash.assign@^4.0.6: + version "4.2.0" + resolved "https://registry.npmmirror.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + integrity sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw== + +lodash@4.17.20: + version "4.17.20" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + +log-symbols@4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" + integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== + dependencies: + chalk "^4.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +looper@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/looper/-/looper-2.0.0.tgz#66cd0c774af3d4fedac53794f742db56da8f09ec" + integrity sha512-6DzMHJcjbQX/UPHc1rRCBfKlLwDkvuGZ715cIR36wSdYqWXFT35uLXq5P/2orl3tz+t+VOVPxw4yPinQlUDGDQ== + +looper@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/looper/-/looper-3.0.0.tgz#2efa54c3b1cbaba9b94aee2e5914b0be57fbb749" + integrity sha512-LJ9wplN/uSn72oJRsXTx+snxPet5c8XiZmOKCm906NVYu+ag6SB6vUcnJcWxgnl2NfbIyeobAn7Bwv6xRj2XJg== + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loupe@^2.3.1: + version "2.3.6" + resolved "https://registry.npmmirror.com/loupe/-/loupe-2.3.6.tgz#76e4af498103c532d1ecc9be102036a21f787b53" + integrity sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA== + dependencies: + get-func-name "^2.0.0" + +lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + +lru-cache@5.1.1, lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + integrity sha512-91gyOKTc2k66UG6kHiH4h3S2eltcPwE1STVfMYC/NG+nZwf8IIuiamfmpGZjpbbxzSyEJaLC0tNSmhjlQUTJow== + dependencies: + pseudomap "^1.0.1" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.npmmirror.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +ltgt@^2.1.2, ltgt@~2.2.0: + version "2.2.1" + resolved "https://registry.npmmirror.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha512-AI2r85+4MquTw9ZYqabu4nMwy9Oftlfa/e/52t9IjtfG+mGBbTNdAoZ3RQKLHR6r0wQnwZnPIEh/Ya6XTWAKNA== + +ltgt@~2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/ltgt/-/ltgt-2.1.3.tgz#10851a06d9964b971178441c23c9e52698eece34" + integrity sha512-5VjHC5GsENtIi5rbJd+feEpDKhfr7j0odoUR2Uh978g+2p93nd5o34cTjQWohXsPsCZeqoDnIqEf88mPCe0Pfw== + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.npmmirror.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== + dependencies: + object-visit "^1.0.0" + +markdown-table@^1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" + integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== + +mcl-wasm@^0.7.1: + version "0.7.9" + resolved "https://registry.npmmirror.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" + integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmmirror.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memdown@^1.0.0: + version "1.4.1" + resolved "https://registry.npmmirror.com/memdown/-/memdown-1.4.1.tgz#b4e4e192174664ffbae41361aa500f3119efe215" + integrity sha512-iVrGHZB8i4OQfM155xx8akvG9FIj+ht14DX5CQkCTG4EHzZ3d3sgckIf/Lm9ivZalEsFuEVnWv2B2WZvbrro2w== + dependencies: + abstract-leveldown "~2.7.1" + functional-red-black-tree "^1.0.1" + immediate "^3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + +memdown@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/memdown/-/memdown-3.0.0.tgz#93aca055d743b20efc37492e9e399784f2958309" + integrity sha512-tbV02LfZMWLcHcq4tw++NuqMO+FZX8tNJEiD2aNRm48ZZusVg5N8NART+dmBkepJVye986oixErf7jfXboMGMA== + dependencies: + abstract-leveldown "~5.0.0" + functional-red-black-tree "~1.0.1" + immediate "~3.2.3" + inherits "~2.0.1" + ltgt "~2.2.0" + safe-buffer "~5.1.1" + +memory-level@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" + integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== + dependencies: + abstract-level "^1.0.0" + functional-red-black-tree "^1.0.1" + module-error "^1.0.1" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merkle-patricia-tree@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/merkle-patricia-tree/-/merkle-patricia-tree-3.0.0.tgz#448d85415565df72febc33ca362b8b614f5a58f8" + integrity sha512-soRaMuNf/ILmw3KWbybaCjhx86EYeBbD8ph0edQCTed0JN/rxDt1EBN52Ajre3VyGo+91f8+/rfPIRQnnGMqmQ== + dependencies: + async "^2.6.1" + ethereumjs-util "^5.2.0" + level-mem "^3.0.1" + level-ws "^1.0.0" + readable-stream "^3.0.6" + rlp "^2.0.0" + semaphore ">=1.0.1" + +merkle-patricia-tree@^2.1.2, merkle-patricia-tree@^2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.2.tgz#982ca1b5a0fde00eed2f6aeed1f9152860b8208a" + integrity sha512-81PW5m8oz/pz3GvsAwbauj7Y00rqm81Tzad77tHBwU7pIAtN+TJnMSOJhxBKflSVYhptMMb9RskhqHqrSm1V+g== + dependencies: + async "^1.4.2" + ethereumjs-util "^5.0.0" + level-ws "0.0.0" + levelup "^1.2.1" + memdown "^1.0.0" + readable-stream "^2.0.0" + rlp "^2.0.0" + semaphore ">=1.0.1" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.5" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.npmmirror.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@3.0.4: + version "3.0.4" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@~1.2.7: + version "1.2.8" + resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.npmmirror.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.npmmirror.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.npmmirror.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + integrity sha512-Hepn5kb1lJPtVW84RFT40YG1OddBNTOVUZR2bzQUHc+Z03en8/3uX0+060JDhcEzyO08HmipsN9DcnFMxhIL9w== + dependencies: + mkdirp "*" + +mkdirp@*: + version "2.1.5" + resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-2.1.5.tgz#78d7eaf15e069ba7b6b47d76dd94cfadf7a4062f" + integrity sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w== + +mkdirp@0.5.5: + version "0.5.5" + resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^0.5.1, mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mnemonist@^0.38.0: + version "0.38.5" + resolved "https://registry.npmmirror.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" + integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== + dependencies: + obliterator "^2.0.0" + +mocha@^10.0.0: + version "10.2.0" + resolved "https://registry.npmmirror.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +mocha@^7.1.1: + version "7.2.0" + resolved "https://registry.npmmirror.com/mocha/-/mocha-7.2.0.tgz#01cc227b00d875ab1eed03a75106689cfed5a604" + integrity sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ== + dependencies: + ansi-colors "3.2.3" + browser-stdout "1.3.1" + chokidar "3.3.0" + debug "3.2.6" + diff "3.5.0" + escape-string-regexp "1.0.5" + find-up "3.0.0" + glob "7.1.3" + growl "1.10.5" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "3.0.0" + minimatch "3.0.4" + mkdirp "0.5.5" + ms "2.1.1" + node-environment-flags "1.0.6" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.3.2" + yargs-parser "13.1.2" + yargs-unparser "1.6.0" + +mocha@^8.2.1: + version "8.4.0" + resolved "https://registry.npmmirror.com/mocha/-/mocha-8.4.0.tgz#677be88bf15980a3cae03a73e10a0fc3997f0cff" + integrity sha512-hJaO0mwDXmZS4ghXsvPVriOhsxQ7ofcpQdm8dE+jISUOKopitvnXFQmpRR7jd2K6VBG6E26gU3IAbXXGIbu4sQ== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.1" + debug "4.3.1" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.1.6" + growl "1.10.5" + he "1.2.0" + js-yaml "4.0.0" + log-symbols "4.0.0" + minimatch "3.0.4" + ms "2.1.3" + nanoid "3.1.20" + serialize-javascript "5.0.1" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + wide-align "1.1.3" + workerpool "6.1.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +mock-fs@^4.1.0: + version "4.14.0" + resolved "https://registry.npmmirror.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== + +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.npmmirror.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.npmmirror.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.npmmirror.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== + dependencies: + varint "^5.0.0" + +multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.npmmirror.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + +multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.npmmirror.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + +nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + integrity sha512-9MqxMH/BSJC7dnLsEMPyfN5Dvoo49IsPFYMcHw3Bcfc2kN0lpHRBSzlMSVx4HGyJ7s9B31CyBTVehWJoQ8Ctew== + +nanoid@3.1.20: + version "3.1.20" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" + integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.npmmirror.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +napi-macros@~2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/napi-macros/-/napi-macros-2.0.0.tgz#2b6bae421e7b96eb687aa6c77a7858640670001b" + integrity sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-environment-flags@1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: + version "2.6.9" + resolved "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" + integrity sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg== + dependencies: + whatwg-url "^5.0.0" + +node-fetch@~1.7.1: + version "1.7.3" + resolved "https://registry.npmmirror.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef" + integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ== + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.npmmirror.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +nofilter@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" + integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== + +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.npmmirror.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.npmmirror.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.npmmirror.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.0, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.12.3, object-inspect@^1.9.0, object-inspect@~1.12.3: + version "1.12.3" + resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.npmmirror.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + integrity sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +object-keys@^1.0.11, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + integrity sha512-ncrLw+X55z7bkl5PnUvHwFK9FcGuFYo9gtjws2XtSzL+aZ8tm830P60WJ0dSmFVaSalWieW5MD7kEdnXda9yJw== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== + dependencies: + isobject "^3.0.0" + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.assign@^4.1.4: + version "4.1.4" + resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" + integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.1: + version "2.1.5" + resolved "https://registry.npmmirror.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.5.tgz#db5a9002489b64eef903df81d6623c07e5b4b4d3" + integrity sha512-yDNzckpM6ntyQiGTik1fKV1DcVDRS+w8bvpWNCBanvH5LfRX9O8WTHqQzG4RZwRAM4I0oU7TV11Lj5v0g20ibw== + dependencies: + array.prototype.reduce "^1.0.5" + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== + dependencies: + isobject "^3.0.1" + +obliterator@^2.0.0: + version "2.0.4" + resolved "https://registry.npmmirror.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" + integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== + +oboe@2.1.4: + version "2.1.4" + resolved "https://registry.npmmirror.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" + integrity sha512-ymBJ4xSC6GBXLT9Y7lirj+xbqBLa+jADGJldGEYG7u8sZbS9GyG+u1Xk9c5cbriKwSpCg41qUhPjvU5xOpvIyQ== + dependencies: + http-https "^1.0.0" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +open@^7.4.2: + version "7.4.2" + resolved "https://registry.npmmirror.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" + integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha512-PRT7ZORmwu2MEFt4/fv3Q+mEfN4zetKxufQrkShY2oGvUms9r8otu5HfdyIFHkYXjO7laNsoVGmM2MANfuTA8g== + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + +p-cancelable@^2.0.0: + version "2.1.1" + resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" + integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== + dependencies: + p-limit "^1.1.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.npmmirror.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-cache-control@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== + +parse-headers@^2.0.0: + version "2.0.5" + resolved "https://registry.npmmirror.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" + integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ== + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.npmmirror.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== + +patch-package@6.2.2: + version "6.2.2" + resolved "https://registry.npmmirror.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" + integrity sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^2.4.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^1.2.1" + fs-extra "^7.0.1" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.0" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + +patch-package@^6.2.2: + version "6.5.1" + resolved "https://registry.npmmirror.com/patch-package/-/patch-package-6.5.1.tgz#3e5d00c16997e6160291fee06a521c42ac99b621" + integrity sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA== + dependencies: + "@yarnpkg/lockfile" "^1.1.0" + chalk "^4.1.2" + cross-spawn "^6.0.5" + find-yarn-workspace-root "^2.0.0" + fs-extra "^9.0.0" + is-ci "^2.0.0" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^5.6.0" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^1.10.2" + +path-browserify@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ== + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== + +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg== + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: + version "3.1.2" + resolved "https://registry.npmmirror.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.npmmirror.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.npmmirror.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== + +postinstall-postinstall@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" + integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== + +precond@0.2: + version "0.2.3" + resolved "https://registry.npmmirror.com/precond/-/precond-0.2.3.tgz#aa9591bcaa24923f1e0f4849d240f47efc1075ac" + integrity sha512-QCYG84SgGyGzqJ/vlMsxeXd/pgL/I94ixdNFyh1PusWmTCyVfPJjZ1K1jvHtsbfnXQs2TSkEP2fR7QiMZAnKFQ== + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== + +prettier@^2.1.2: + version "2.8.4" + resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3" + integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw== + +private@^0.1.6, private@^0.1.8: + version "0.1.8" + resolved "https://registry.npmmirror.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.npmmirror.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +promise-to-callback@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/promise-to-callback/-/promise-to-callback-1.0.0.tgz#5d2a749010bfb67d963598fcd3960746a68feef7" + integrity sha512-uhMIZmKM5ZteDMfLgJnoSq9GCwsNKrYau73Awf1jIy6/eUcuuZ3P+CD9zUv0kJsIUbU+x6uLNIhXhLHDs1pNPA== + dependencies: + is-fn "^1.0.0" + set-immediate-shim "^1.0.1" + +promise@^8.0.0: + version "8.3.0" + resolved "https://registry.npmmirror.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" + integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== + dependencies: + asap "~2.0.6" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== + +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.npmmirror.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.npmmirror.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pull-cat@^1.1.9: + version "1.1.11" + resolved "https://registry.npmmirror.com/pull-cat/-/pull-cat-1.1.11.tgz#b642dd1255da376a706b6db4fa962f5fdb74c31b" + integrity sha512-i3w+xZ3DCtTVz8S62hBOuNLRHqVDsHMNZmgrZsjPnsxXUgbWtXEee84lo1XswE7W2a3WHyqsNuDJTjVLAQR8xg== + +pull-defer@^0.2.2: + version "0.2.3" + resolved "https://registry.npmmirror.com/pull-defer/-/pull-defer-0.2.3.tgz#4ee09c6d9e227bede9938db80391c3dac489d113" + integrity sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA== + +pull-level@^2.0.3: + version "2.0.4" + resolved "https://registry.npmmirror.com/pull-level/-/pull-level-2.0.4.tgz#4822e61757c10bdcc7cf4a03af04c92734c9afac" + integrity sha512-fW6pljDeUThpq5KXwKbRG3X7Ogk3vc75d5OQU/TvXXui65ykm+Bn+fiktg+MOx2jJ85cd+sheufPL+rw9QSVZg== + dependencies: + level-post "^1.0.7" + pull-cat "^1.1.9" + pull-live "^1.0.1" + pull-pushable "^2.0.0" + pull-stream "^3.4.0" + pull-window "^2.1.4" + stream-to-pull-stream "^1.7.1" + +pull-live@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/pull-live/-/pull-live-1.0.1.tgz#a4ecee01e330155e9124bbbcf4761f21b38f51f5" + integrity sha512-tkNz1QT5gId8aPhV5+dmwoIiA1nmfDOzJDlOOUpU5DNusj6neNd3EePybJ5+sITr2FwyCs/FVpx74YMCfc8YeA== + dependencies: + pull-cat "^1.1.9" + pull-stream "^3.4.0" + +pull-pushable@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/pull-pushable/-/pull-pushable-2.2.0.tgz#5f2f3aed47ad86919f01b12a2e99d6f1bd776581" + integrity sha512-M7dp95enQ2kaHvfCt2+DJfyzgCSpWVR2h2kWYnVsW6ZpxQBx5wOu0QWOvQPVoPnBLUZYitYP2y7HyHkLQNeGXg== + +pull-stream@^3.2.3, pull-stream@^3.4.0, pull-stream@^3.6.8: + version "3.7.0" + resolved "https://registry.npmmirror.com/pull-stream/-/pull-stream-3.7.0.tgz#85de0e44ff38a4d2ad08cc43fc458e1922f9bf0b" + integrity sha512-Eco+/R004UaCK2qEDE8vGklcTG2OeZSVm1kTUQNrykEjDwcFXDZhygFDsW49DbXyJMEhHeRL3z5cRVqPAhXlIw== + +pull-window@^2.1.4: + version "2.1.4" + resolved "https://registry.npmmirror.com/pull-window/-/pull-window-2.1.4.tgz#fc3b86feebd1920c7ae297691e23f705f88552f0" + integrity sha512-cbDzN76BMlcGG46OImrgpkMf/VkCnupj8JhsrpBw3aWBM9ye345aYnqitmZCgauBkc0HbbRRn9hCnsa3k2FNUg== + dependencies: + looper "^2.0.0" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.npmmirror.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +qs@^6.4.0, qs@^6.7.0: + version "6.11.1" + resolved "https://registry.npmmirror.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" + integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ== + dependencies: + side-channel "^1.0.4" + +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + +queue-microtask@^1.2.2, queue-microtask@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.0.6, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@2.5.2, raw-body@^2.4.1: + version "2.5.2" + resolved "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A== + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ== + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@^1.0.33: + version "1.1.14" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.2.2, readable-stream@^2.2.8, readable-stream@^2.2.9, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.0.15: + version "1.0.34" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@~3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.2.0.tgz#c30c33352b12c96dfb4b895421a49fd5a9593839" + integrity sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ== + dependencies: + picomatch "^2.0.4" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerate@^1.2.1: + version "1.4.2" + resolved "https://registry.npmmirror.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.11.0: + version "0.11.1" + resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== + +regenerator-transform@^0.10.0: + version "0.10.1" + resolved "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" + integrity sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q== + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3: + version "1.4.3" + resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz#87cab30f80f66660181a3bb7bf5981a872b367ac" + integrity sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + functions-have-names "^1.2.2" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + integrity sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ== + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + integrity sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g== + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.npmmirror.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + integrity sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw== + dependencies: + jsesc "~0.5.0" + +repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.npmmirror.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.npmmirror.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== + dependencies: + is-finite "^1.0.0" + +req-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" + integrity sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ== + dependencies: + req-from "^2.0.0" + +req-from@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/req-from/-/req-from-2.0.0.tgz#d74188e47f93796f4aa71df6ee35ae689f3e0e70" + integrity sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA== + dependencies: + resolve-from "^3.0.0" + +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== + dependencies: + lodash "^4.17.19" + +request-promise-native@^1.0.5: + version "1.0.9" + resolved "https://registry.npmmirror.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== + dependencies: + request-promise-core "1.1.4" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.79.0, request@^2.85.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.npmmirror.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + integrity sha512-H7AkJWMobeskkttHyhTVtS0fxpFLjxhbfMa6Bk3wimP7sdPRGL3EyCg3sAQenFfAe+xQ+oAc85Nmtvq0ROM83Q== + +require-from-string@^2.0.0: + version "2.0.2" + resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha512-IqSUtOVP4ksd1C/ej5zeEh/BIP2ajqpn8c5x+q99gvcIG/Qf0cud5raVnE/Dwd0ua9TXYDoDc0RE5hBSdz22Ug== + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-alpn@^1.0.0: + version "1.2.1" + resolved "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== + +resolve@1.17.0: + version "1.17.0" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +resolve@^1.10.0, resolve@^1.8.1, resolve@~1.22.1: + version "1.22.1" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" + integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== + dependencies: + is-core-module "^2.9.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ== + dependencies: + lowercase-keys "^1.0.0" + +responselike@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" + integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw== + dependencies: + lowercase-keys "^2.0.0" + +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.npmmirror.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + integrity sha512-Fn9X8rX8yYF4m81rZCK/5VmrmsSbqS/i3rDLl6ZZHAXgC2nTAx3dhwG8q8odP/RmdLa2YrybDJaAMg+X1ajY3w== + dependencies: + through "~2.3.4" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.npmmirror.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.2.8, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3, rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.npmmirror.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + +rustbn.js@~0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" + integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-event-emitter@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/safe-event-emitter/-/safe-event-emitter-1.0.1.tgz#5b692ef22329ed8f69fdce607e50ca734f6f20af" + integrity sha512-e1wFe99A91XYYxoQbcq2ZJUWurxEyP8vfz7A7vuUe1s95q8r5ebraVaA1BukYJcpM6V16ugWoD9vngi8Ccu5fg== + dependencies: + events "^3.0.0" + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +scrypt-js@2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-2.0.4.tgz#32f8c5149f0797672e551c07e230f834b6af5f16" + integrity sha512-4KsaGcPnuhtCZQCxFxN3GVYIhKFPTdLd8PLC552XwbMndtD0cjRFAhDuuydXQ0h08ZfPgzqe6EKHozpuH74iDw== + +scrypt-js@3.0.1, scrypt-js@^3.0.0, scrypt-js@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +scryptsy@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/scryptsy/-/scryptsy-1.2.1.tgz#a3225fa4b2524f802700761e2855bdf3b2d92163" + integrity sha512-aldIRgMozSJ/Gl6K6qmJZysRP82lz83Wb42vl4PWN8SaLFHIaOzLPc9nUUW2jQN88CuGm5q5HefJ9jZ3nWSmTw== + dependencies: + pbkdf2 "^3.0.3" + +secp256k1@^4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +seedrandom@3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/seedrandom/-/seedrandom-3.0.1.tgz#eb3dde015bcf55df05a233514e5df44ef9dce083" + integrity sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg== + +semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" + integrity sha512-O4OZEaNtkMd/K0i6js9SL+gqy0ZCBMgUvlSqHKi4IBdjhe7wB8pwztUk1BbZ1fmrvpwFrPbHzqd2w5pTcJH6LA== + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: + version "5.7.1" + resolved "https://registry.npmmirror.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.npmmirror.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@~5.4.1: + version "5.4.1" + resolved "https://registry.npmmirror.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== + +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmmirror.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" + integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== + dependencies: + randombytes "^2.1.0" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmmirror.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +servify@^0.1.12: + version "0.1.12" + resolved "https://registry.npmmirror.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + integrity sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ== + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setimmediate@1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.4.tgz#20e81de622d4a02588ce0c8da8973cbcf1d3138f" + integrity sha512-/TjEmXQVEzdod/FFskf3o7oOAsGhHf2j1dZqRFbDzq4F3mvvxflIIi4Hd3bLQE9y/CpwqfSQam5JakI/mi3Pog== + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.npmmirror.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha1@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/sha1/-/sha1-1.1.1.tgz#addaa7a93168f393f19eb2b15091618e2700f848" + integrity sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA== + dependencies: + charenc ">= 0.0.1" + crypt ">= 0.0.1" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^2.7.0: + version "2.8.2" + resolved "https://registry.npmmirror.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== + +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.npmmirror.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +solc@0.7.3: + version "0.7.3" + resolved "https://registry.npmmirror.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" + integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +solc@^0.4.20: + version "0.4.26" + resolved "https://registry.npmmirror.com/solc/-/solc-0.4.26.tgz#5390a62a99f40806b86258c737c1cf653cc35cb5" + integrity sha512-o+c6FpkiHd+HPjmjEVpQgH7fqZ14tJpXhho+/bQXlXbliLIS/xjXb42Vxh+qQY1WCSTMQ0+a5vR9vi0MfhU6mA== + dependencies: + fs-extra "^0.30.0" + memorystream "^0.3.1" + require-from-string "^1.1.0" + semver "^5.3.0" + yargs "^4.7.1" + +solc@^0.6.3: + version "0.6.12" + resolved "https://registry.npmmirror.com/solc/-/solc-0.6.12.tgz#48ac854e0c729361b22a7483645077f58cba080e" + integrity sha512-Lm0Ql2G9Qc7yPP2Ba+WNmzw2jwsrd3u4PobHYlSOxaut3TtUbj9+5ZrT6f4DUpNPEoBaFUOEg9Op9C0mk7ge9g== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.npmmirror.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@0.5.12: + version "0.5.12" + resolved "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" + integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.4.15: + version "0.4.18" + resolved "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map-support@^0.5.13: + version "0.5.21" + resolved "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.npmmirror.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdx-correct@^3.0.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c" + integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.13" + resolved "https://registry.npmmirror.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" + integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +sshpk@^1.7.0: + version "1.17.0" + resolved "https://registry.npmmirror.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.npmmirror.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.npmmirror.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== + +stream-to-pull-stream@^1.7.1: + version "1.7.3" + resolved "https://registry.npmmirror.com/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz#4161aa2d2eb9964de60bfa1af7feaf917e874ece" + integrity sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg== + dependencies: + looper "^3.0.0" + pull-stream "^3.2.3" + +streamsearch@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trim@^1.2.7, string.prototype.trim@~1.2.7: + version "1.2.7" + resolved "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" + integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimend@^1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" + integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string.prototype.trimstart@^1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" + integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.4" + es-abstract "^1.20.4" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== + dependencies: + is-utf8 "^0.2.0" + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== + dependencies: + has-flag "^3.0.0" + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +swarm-js@^0.1.40: + version "0.1.42" + resolved "https://registry.npmmirror.com/swarm-js/-/swarm-js-0.1.42.tgz#497995c62df6696f6e22372f457120e43e727979" + integrity sha512-BV7c/dVlA3R6ya1lMlSSNPLYrntt0LUq4YMgy3iwpCIc6rZnS5W2wUoctarZ5pXlpKtxDDf9hNziEkcfrxdhqQ== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^11.8.5" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + +sync-request@^6.0.0: + version "6.1.0" + resolved "https://registry.npmmirror.com/sync-request/-/sync-request-6.1.0.tgz#e96217565b5e50bbffe179868ba75532fb597e68" + integrity sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw== + dependencies: + http-response-object "^3.0.1" + sync-rpc "^1.2.1" + then-request "^6.0.0" + +sync-rpc@^1.2.1: + version "1.3.6" + resolved "https://registry.npmmirror.com/sync-rpc/-/sync-rpc-1.3.6.tgz#b2e8b2550a12ccbc71df8644810529deb68665a7" + integrity sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw== + dependencies: + get-port "^3.1.0" + +tape@^4.6.3: + version "4.16.2" + resolved "https://registry.npmmirror.com/tape/-/tape-4.16.2.tgz#7565e6af20426565557266e9dda7215869b297b6" + integrity sha512-TUChV+q0GxBBCEbfCYkGLkv8hDJYjMdSWdE0/Lr331sB389dsvFUHNV9ph5iQqKzt8Ss9drzcda/YeexclBFqg== + dependencies: + call-bind "~1.0.2" + deep-equal "~1.1.1" + defined "~1.0.1" + dotignore "~0.1.2" + for-each "~0.3.3" + glob "~7.2.3" + has "~1.0.3" + inherits "~2.0.4" + is-regex "~1.1.4" + minimist "~1.2.7" + object-inspect "~1.12.3" + resolve "~1.22.1" + resumer "~0.0.0" + string.prototype.trim "~1.2.7" + through "~2.3.8" + +tar@^4.0.2: + version "4.4.19" + resolved "https://registry.npmmirror.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + +test-value@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/test-value/-/test-value-2.1.0.tgz#11da6ff670f3471a73b625ca4f3fdcf7bb748291" + integrity sha512-+1epbAxtKeXttkGFMTX9H42oqzOTufR1ceCF+GYA5aOmvaPq9wd4PUS8329fn2RRLGNeUkgRLnVpycjx8DsO2w== + dependencies: + array-back "^1.0.3" + typical "^2.6.0" + +testrpc@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/testrpc/-/testrpc-0.0.1.tgz#83e2195b1f5873aec7be1af8cbe6dcf39edb7aed" + integrity sha512-afH1hO+SQ/VPlmaLUFj2636QMeDvPCeQMc/9RBMW0IfjNe9gFD9Ra3ShqYkB7py0do1ZcCna/9acHyzTJ+GcNA== + +then-request@^6.0.0: + version "6.0.2" + resolved "https://registry.npmmirror.com/then-request/-/then-request-6.0.2.tgz#ec18dd8b5ca43aaee5cb92f7e4c1630e950d4f0c" + integrity sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA== + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/form-data" "0.0.33" + "@types/node" "^8.0.0" + "@types/qs" "^6.2.31" + caseless "~0.12.0" + concat-stream "^1.6.0" + form-data "^2.2.0" + http-basic "^8.1.1" + http-response-object "^3.0.1" + promise "^8.0.0" + qs "^6.4.0" + +through2@^2.0.3: + version "2.0.5" + resolved "https://registry.npmmirror.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@~2.3.4, through@~2.3.8: + version "2.3.8" + resolved "https://registry.npmmirror.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== + +tmp@0.0.33, tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmp@0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/tmp/-/tmp-0.1.0.tgz#ee434a4e22543082e294ba6201dcc6eafefa2877" + integrity sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw== + dependencies: + rimraf "^2.6.3" + +to-fast-properties@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== + dependencies: + kind-of "^3.0.2" + +to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@^2.3.3, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== + +ts-essentials@^1.0.0: + version "1.0.4" + resolved "https://registry.npmmirror.com/ts-essentials/-/ts-essentials-1.0.4.tgz#ce3b5dade5f5d97cf69889c11bf7d2da8555b15a" + integrity sha512-q3N1xS4vZpRouhYHDPwO0bDW3EZ6SK9CrrDHxi/D6BPReSjpVgWIOpLS2o0gSBZm+7q/wyKp6RVM1AeeW7uyfQ== + +ts-essentials@^6.0.3: + version "6.0.7" + resolved "https://registry.npmmirror.com/ts-essentials/-/ts-essentials-6.0.7.tgz#5f4880911b7581a873783740ce8b94da163d18a6" + integrity sha512-2E4HIIj4tQJlIHuATRHayv0EfMGK3ris/GRk1E3CFnsZzeNV+hUmelbaTZHLtXaZppM5oLhHRtO04gINC4Jusw== + +ts-generator@^0.1.1: + version "0.1.1" + resolved "https://registry.npmmirror.com/ts-generator/-/ts-generator-0.1.1.tgz#af46f2fb88a6db1f9785977e9590e7bcd79220ab" + integrity sha512-N+ahhZxTLYu1HNTQetwWcx3so8hcYbkKBHTr4b4/YgObFTIKkOSSsaa+nal12w8mfrJAyzJfETXawbNjSfP2gQ== + dependencies: + "@types/mkdirp" "^0.5.2" + "@types/prettier" "^2.1.1" + "@types/resolve" "^0.0.8" + chalk "^2.4.1" + glob "^7.1.2" + mkdirp "^0.5.1" + prettier "^2.1.2" + resolve "^1.8.1" + ts-essentials "^1.0.0" + +ts-node@^10.0.0: + version "10.9.1" + resolved "https://registry.npmmirror.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl-util@^0.15.0, tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.npmmirror.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +tweetnacl@^1.0.0, tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-detect@^4.0.0, type-detect@^4.0.5: + version "4.0.8" + resolved "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.npmmirror.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.npmmirror.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + +typechain@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/typechain/-/typechain-3.0.0.tgz#d5a47700831f238e43f7429b987b4bb54849b92e" + integrity sha512-ft4KVmiN3zH4JUFu2WJBrwfHeDf772Tt2d8bssDTo/YcckKW2D+OwFrHXRC6hJvO3mHjFQTihoMV6fJOi0Hngg== + dependencies: + command-line-args "^4.0.7" + debug "^4.1.1" + fs-extra "^7.0.0" + js-sha3 "^0.8.0" + lodash "^4.17.15" + ts-essentials "^6.0.3" + ts-generator "^0.1.1" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.npmmirror.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + +typescript@^4.1.3: + version "4.9.5" + resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +typewise-core@^1.2, typewise-core@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/typewise-core/-/typewise-core-1.2.0.tgz#97eb91805c7f55d2f941748fa50d315d991ef195" + integrity sha512-2SCC/WLzj2SbUwzFOzqMCkz5amXLlxtJqDKTICqg30x+2DZxcfZN2MvQZmGfXWKNWaKK9pBPsvkcwv8bF/gxKg== + +typewise@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/typewise/-/typewise-1.0.3.tgz#1067936540af97937cc5dcf9922486e9fa284651" + integrity sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ== + dependencies: + typewise-core "^1.2.0" + +typewiselite@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/typewiselite/-/typewiselite-1.0.0.tgz#c8882fa1bb1092c06005a97f34ef5c8508e3664e" + integrity sha512-J9alhjVHupW3Wfz6qFRGgQw0N3gr8hOkw6zm7FZ6UR1Cse/oD9/JVok7DNE9TT9IbciDHX2Ex9+ksE6cRmtymw== + +typical@^2.6.0, typical@^2.6.1: + version "2.6.1" + resolved "https://registry.npmmirror.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" + integrity sha512-ofhi8kjIje6npGozTip9Fr8iecmYfEbS06i0JnIg+rh51KakryWF4+jX8lLKZVhy6N+ID45WYSFCxPOdTWCzNg== + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +underscore@1.9.1: + version "1.9.1" + resolved "https://registry.npmmirror.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" + integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== + +undici@^5.14.0: + version "5.21.0" + resolved "https://registry.npmmirror.com/undici/-/undici-5.21.0.tgz#b00dfc381f202565ab7f52023222ab862bb2494f" + integrity sha512-HOjK8l6a57b2ZGXOcUsI5NLfoTrfmbOl90ixJDl0AEFG4wgHNDQxtZy15/ZQp7HhjkpaGlp/eneMgtsu1dIlUA== + dependencies: + busboy "^1.6.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unorm@^1.3.3: + version "1.6.0" + resolved "https://registry.npmmirror.com/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af" + integrity sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ== + dependencies: + prepend-http "^2.0.0" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.npmmirror.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.npmmirror.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +utf8@3.0.0, utf8@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util.promisify@^1.0.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" + integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + for-each "^0.3.3" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.1" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/uuid/-/uuid-2.0.1.tgz#c2a30dedb3e535d72ccf82e343941a50ba8533ac" + integrity sha512-nWg9+Oa3qD2CQzHIP4qKUqwNfzKn8P0LtFhotaCTFchsV7ZfDhAybeip/HZVeMIpZi9JgY1E3nUlwaCmZT1sEg== + +uuid@3.3.2: + version "3.3.2" + resolved "https://registry.npmmirror.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.npmmirror.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.npmmirror.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +varint@^5.0.0: + version "5.0.2" + resolved "https://registry.npmmirror.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +web3-bzz@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-bzz/-/web3-bzz-1.2.11.tgz#41bc19a77444bd5365744596d778b811880f707f" + integrity sha512-XGpWUEElGypBjeFyUhTkiPXFbDVD6Nr/S5jznE3t8cWUA0FxRf1n3n/NuIZeb0H9RkN2Ctd/jNma/k8XGa3YKg== + dependencies: + "@types/node" "^12.12.6" + got "9.6.0" + swarm-js "^0.1.40" + underscore "1.9.1" + +web3-core-helpers@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core-helpers/-/web3-core-helpers-1.2.11.tgz#84c681ed0b942c0203f3b324a245a127e8c67a99" + integrity sha512-PEPoAoZd5ME7UfbnCZBdzIerpe74GEvlwT4AjOmHeCVZoIFk7EqvOZDejJHt+feJA6kMVTdd0xzRNN295UhC1A== + dependencies: + underscore "1.9.1" + web3-eth-iban "1.2.11" + web3-utils "1.2.11" + +web3-core-method@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core-method/-/web3-core-method-1.2.11.tgz#f880137d1507a0124912bf052534f168b8d8fbb6" + integrity sha512-ff0q76Cde94HAxLDZ6DbdmKniYCQVtvuaYh+rtOUMB6kssa5FX0q3vPmixi7NPooFnbKmmZCM6NvXg4IreTPIw== + dependencies: + "@ethersproject/transactions" "^5.0.0-beta.135" + underscore "1.9.1" + web3-core-helpers "1.2.11" + web3-core-promievent "1.2.11" + web3-core-subscriptions "1.2.11" + web3-utils "1.2.11" + +web3-core-promievent@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core-promievent/-/web3-core-promievent-1.2.11.tgz#51fe97ca0ddec2f99bf8c3306a7a8e4b094ea3cf" + integrity sha512-il4McoDa/Ox9Agh4kyfQ8Ak/9ABYpnF8poBLL33R/EnxLsJOGQG2nZhkJa3I067hocrPSjEdlPt/0bHXsln4qA== + dependencies: + eventemitter3 "4.0.4" + +web3-core-requestmanager@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core-requestmanager/-/web3-core-requestmanager-1.2.11.tgz#fe6eb603fbaee18530293a91f8cf26d8ae28c45a" + integrity sha512-oFhBtLfOiIbmfl6T6gYjjj9igOvtyxJ+fjS+byRxiwFJyJ5BQOz4/9/17gWR1Cq74paTlI7vDGxYfuvfE/mKvA== + dependencies: + underscore "1.9.1" + web3-core-helpers "1.2.11" + web3-providers-http "1.2.11" + web3-providers-ipc "1.2.11" + web3-providers-ws "1.2.11" + +web3-core-subscriptions@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core-subscriptions/-/web3-core-subscriptions-1.2.11.tgz#beca908fbfcb050c16f45f3f0f4c205e8505accd" + integrity sha512-qEF/OVqkCvQ7MPs1JylIZCZkin0aKK9lDxpAtQ1F8niEDGFqn7DT8E/vzbIa0GsOjL2fZjDhWJsaW+BSoAW1gg== + dependencies: + eventemitter3 "4.0.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + +web3-core@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-core/-/web3-core-1.2.11.tgz#1043cacc1becb80638453cc5b2a14be9050288a7" + integrity sha512-CN7MEYOY5ryo5iVleIWRE3a3cZqVaLlIbIzDPsvQRUfzYnvzZQRZBm9Mq+ttDi2STOOzc1MKylspz/o3yq/LjQ== + dependencies: + "@types/bn.js" "^4.11.5" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-requestmanager "1.2.11" + web3-utils "1.2.11" + +web3-eth-abi@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-abi/-/web3-eth-abi-1.2.11.tgz#a887494e5d447c2926d557a3834edd66e17af9b0" + integrity sha512-PkRYc0+MjuLSgg03QVWqWlQivJqRwKItKtEpRUaxUAeLE7i/uU39gmzm2keHGcQXo3POXAbOnMqkDvOep89Crg== + dependencies: + "@ethersproject/abi" "5.0.0-beta.153" + underscore "1.9.1" + web3-utils "1.2.11" + +web3-eth-abi@^1.3.4: + version "1.8.2" + resolved "https://registry.npmmirror.com/web3-eth-abi/-/web3-eth-abi-1.8.2.tgz#16e1e9be40e2527404f041a4745111211488f31a" + integrity sha512-Om9g3kaRNjqiNPAgKwGT16y+ZwtBzRe4ZJFGjLiSs6v5I7TPNF+rRMWuKnR6jq0azQZDj6rblvKFMA49/k48Og== + dependencies: + "@ethersproject/abi" "^5.6.3" + web3-utils "1.8.2" + +web3-eth-accounts@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-accounts/-/web3-eth-accounts-1.2.11.tgz#a9e3044da442d31903a7ce035a86d8fa33f90520" + integrity sha512-6FwPqEpCfKIh3nSSGeo3uBm2iFSnFJDfwL3oS9pyegRBXNsGRVpgiW63yhNzL0796StsvjHWwQnQHsZNxWAkGw== + dependencies: + crypto-browserify "3.12.0" + eth-lib "0.2.8" + ethereumjs-common "^1.3.2" + ethereumjs-tx "^2.1.1" + scrypt-js "^3.0.1" + underscore "1.9.1" + uuid "3.3.2" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-utils "1.2.11" + +web3-eth-contract@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-contract/-/web3-eth-contract-1.2.11.tgz#917065902bc27ce89da9a1da26e62ef663663b90" + integrity sha512-MzYuI/Rq2o6gn7vCGcnQgco63isPNK5lMAan2E51AJLknjSLnOxwNY3gM8BcKoy4Z+v5Dv00a03Xuk78JowFow== + dependencies: + "@types/bn.js" "^4.11.5" + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-promievent "1.2.11" + web3-core-subscriptions "1.2.11" + web3-eth-abi "1.2.11" + web3-utils "1.2.11" + +web3-eth-ens@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-ens/-/web3-eth-ens-1.2.11.tgz#26d4d7f16d6cbcfff918e39832b939edc3162532" + integrity sha512-dbW7dXP6HqT1EAPvnniZVnmw6TmQEKF6/1KgAxbo8iBBYrVTMDGFQUUnZ+C4VETGrwwaqtX4L9d/FrQhZ6SUiA== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-promievent "1.2.11" + web3-eth-abi "1.2.11" + web3-eth-contract "1.2.11" + web3-utils "1.2.11" + +web3-eth-iban@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-iban/-/web3-eth-iban-1.2.11.tgz#f5f73298305bc7392e2f188bf38a7362b42144ef" + integrity sha512-ozuVlZ5jwFC2hJY4+fH9pIcuH1xP0HEFhtWsR69u9uDIANHLPQQtWYmdj7xQ3p2YT4bQLq/axKhZi7EZVetmxQ== + dependencies: + bn.js "^4.11.9" + web3-utils "1.2.11" + +web3-eth-personal@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth-personal/-/web3-eth-personal-1.2.11.tgz#a38b3942a1d87a62070ce0622a941553c3d5aa70" + integrity sha512-42IzUtKq9iHZ8K9VN0vAI50iSU9tOA1V7XU2BhF/tb7We2iKBVdkley2fg26TxlOcKNEHm7o6HRtiiFsVK4Ifw== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-net "1.2.11" + web3-utils "1.2.11" + +web3-eth@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-eth/-/web3-eth-1.2.11.tgz#4c81fcb6285b8caf544058fba3ae802968fdc793" + integrity sha512-REvxW1wJ58AgHPcXPJOL49d1K/dPmuw4LjPLBPStOVkQjzDTVmJEIsiLwn2YeuNDd4pfakBwT8L3bz1G1/wVsQ== + dependencies: + underscore "1.9.1" + web3-core "1.2.11" + web3-core-helpers "1.2.11" + web3-core-method "1.2.11" + web3-core-subscriptions "1.2.11" + web3-eth-abi "1.2.11" + web3-eth-accounts "1.2.11" + web3-eth-contract "1.2.11" + web3-eth-ens "1.2.11" + web3-eth-iban "1.2.11" + web3-eth-personal "1.2.11" + web3-net "1.2.11" + web3-utils "1.2.11" + +web3-net@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-net/-/web3-net-1.2.11.tgz#eda68ef25e5cdb64c96c39085cdb74669aabbe1b" + integrity sha512-sjrSDj0pTfZouR5BSTItCuZ5K/oZPVdVciPQ6981PPPIwJJkCMeVjD7I4zO3qDPCnBjBSbWvVnLdwqUBPtHxyg== + dependencies: + web3-core "1.2.11" + web3-core-method "1.2.11" + web3-utils "1.2.11" + +web3-provider-engine@14.2.1: + version "14.2.1" + resolved "https://registry.npmmirror.com/web3-provider-engine/-/web3-provider-engine-14.2.1.tgz#ef351578797bf170e08d529cb5b02f8751329b95" + integrity sha512-iSv31h2qXkr9vrL6UZDm4leZMc32SjWJFGOp/D92JXfcEboCqraZyuExDkpxKw8ziTufXieNM7LSXNHzszYdJw== + dependencies: + async "^2.5.0" + backoff "^2.5.0" + clone "^2.0.0" + cross-fetch "^2.1.0" + eth-block-tracker "^3.0.0" + eth-json-rpc-infura "^3.1.0" + eth-sig-util "^1.4.2" + ethereumjs-block "^1.2.2" + ethereumjs-tx "^1.2.0" + ethereumjs-util "^5.1.5" + ethereumjs-vm "^2.3.4" + json-rpc-error "^2.0.0" + json-stable-stringify "^1.0.1" + promise-to-callback "^1.0.0" + readable-stream "^2.2.9" + request "^2.85.0" + semaphore "^1.0.3" + ws "^5.1.1" + xhr "^2.2.0" + xtend "^4.0.1" + +web3-providers-http@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-providers-http/-/web3-providers-http-1.2.11.tgz#1cd03442c61670572d40e4dcdf1faff8bd91e7c6" + integrity sha512-psh4hYGb1+ijWywfwpB2cvvOIMISlR44F/rJtYkRmQ5jMvG4FOCPlQJPiHQZo+2cc3HbktvvSJzIhkWQJdmvrA== + dependencies: + web3-core-helpers "1.2.11" + xhr2-cookies "1.1.0" + +web3-providers-ipc@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-providers-ipc/-/web3-providers-ipc-1.2.11.tgz#d16d6c9be1be6e0b4f4536c4acc16b0f4f27ef21" + integrity sha512-yhc7Y/k8hBV/KlELxynWjJDzmgDEDjIjBzXK+e0rHBsYEhdCNdIH5Psa456c+l0qTEU2YzycF8VAjYpWfPnBpQ== + dependencies: + oboe "2.1.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + +web3-providers-ws@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-providers-ws/-/web3-providers-ws-1.2.11.tgz#a1dfd6d9778d840561d9ec13dd453046451a96bb" + integrity sha512-ZxnjIY1Er8Ty+cE4migzr43zA/+72AF1myzsLaU5eVgdsfV7Jqx7Dix1hbevNZDKFlSoEyq/3j/jYalh3So1Zg== + dependencies: + eventemitter3 "4.0.4" + underscore "1.9.1" + web3-core-helpers "1.2.11" + websocket "^1.0.31" + +web3-shh@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-shh/-/web3-shh-1.2.11.tgz#f5d086f9621c9a47e98d438010385b5f059fd88f" + integrity sha512-B3OrO3oG1L+bv3E1sTwCx66injW1A8hhwpknDUbV+sw3fehFazA06z9SGXUefuFI1kVs4q2vRi0n4oCcI4dZDg== + dependencies: + web3-core "1.2.11" + web3-core-method "1.2.11" + web3-core-subscriptions "1.2.11" + web3-net "1.2.11" + +web3-utils@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3-utils/-/web3-utils-1.2.11.tgz#af1942aead3fb166ae851a985bed8ef2c2d95a82" + integrity sha512-3Tq09izhD+ThqHEaWYX4VOT7dNPdZiO+c/1QMA0s5X2lDFKK/xHJb7cyTRRVzN2LvlHbR7baS1tmQhSua51TcQ== + dependencies: + bn.js "^4.11.9" + eth-lib "0.2.8" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + underscore "1.9.1" + utf8 "3.0.0" + +web3-utils@1.8.2, web3-utils@^1.0.0-beta.31: + version "1.8.2" + resolved "https://registry.npmmirror.com/web3-utils/-/web3-utils-1.8.2.tgz#c32dec5e9b955acbab220eefd7715bc540b75cc9" + integrity sha512-v7j6xhfLQfY7xQDrUP0BKbaNrmZ2/+egbqP9q3KYmOiPpnvAfol+32slgL0WX/5n8VPvKCK5EZ1HGrAVICSToA== + dependencies: + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + +web3@1.2.11: + version "1.2.11" + resolved "https://registry.npmmirror.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975" + integrity sha512-mjQ8HeU41G6hgOYm1pmeH0mRAeNKJGnJEUzDMoerkpw7QUQT4exVREgF1MYPvL/z6vAshOXei25LE/t/Bxl8yQ== + dependencies: + web3-bzz "1.2.11" + web3-core "1.2.11" + web3-eth "1.2.11" + web3-eth-personal "1.2.11" + web3-net "1.2.11" + web3-shh "1.2.11" + web3-utils "1.2.11" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +websocket@1.0.32: + version "1.0.32" + resolved "https://registry.npmmirror.com/websocket/-/websocket-1.0.32.tgz#1f16ddab3a21a2d929dec1687ab21cfdc6d3dbb1" + integrity sha512-i4yhcllSP4wrpoPMU2N0TQ/q0O94LRG/eUQjEAamRltjQ1oT1PFFKOG4i877OlJgCG8rw6LrrowJp+TYCEWF7Q== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +websocket@^1.0.31: + version "1.0.34" + resolved "https://registry.npmmirror.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-fetch@^2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f" + integrity sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha512-F6+WgncZi/mJDrammbTuHe1q0R5hOXv/mBaiNA2TCNT/LTHusX0V+CJnj9XT8ki5ln2UZyyddDgHfCzyrOH7MQ== + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q== + +which-typed-array@^1.1.9: + version "1.1.9" + resolved "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" + integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.10" + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.npmmirror.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha512-UD7d8HFA2+PZsbKyaOCEy8gMh1oDtHgJh1LfgjQ4zVXmYjAT/kvz3PueITKuqDiIXQe7yzpPnxX3lNc+AhQMyw== + +workerpool@6.1.0: + version "6.1.0" + resolved "https://registry.npmmirror.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" + integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.npmmirror.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw== + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@^3.0.0: + version "3.3.3" + resolved "https://registry.npmmirror.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@^5.1.1: + version "5.2.3" + resolved "https://registry.npmmirror.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" + integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== + dependencies: + async-limiter "~1.0.0" + +ws@^7.4.6: + version "7.5.9" + resolved "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.npmmirror.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== + dependencies: + xhr-request "^1.1.0" + +xhr-request@^1.0.1, xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + integrity sha512-hjXUA6q+jl/bd8ADHcVfFsSPIf+tyLIjuO9TwJC9WI6JP2zKcS7C+p56I9kCLLsaCiNT035iYvEUUzdEFj/8+g== + dependencies: + cookiejar "^2.1.1" + +xhr@^2.0.4, xhr@^2.2.0, xhr@^2.3.3: + version "2.6.0" + resolved "https://registry.npmmirror.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xmlhttprequest@1.8.0: + version "1.8.0" + resolved "https://registry.npmmirror.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + integrity sha512-58Im/U0mlVBLM38NdZjHyhuMtCqa61469k2YP/AaPbvCoV9aQGUpbJBj1QRm2ytRiVQBD/fsw7L2bJGDVQswBA== + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.npmmirror.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + integrity sha512-vMNKzr2rHP9Dp/e1NQFnLQlwlhp9L/LfvnsVdHxN1f+uggyVI3i08uD14GPvCToPkdsRfyPqIyYGmIk58V98ZQ== + dependencies: + object-keys "~0.4.0" + +y18n@^3.2.1: + version "3.2.2" + resolved "https://registry.npmmirror.com/y18n/-/y18n-3.2.2.tgz#85c901bd6470ce71fc4bb723ad209b70f7f28696" + integrity sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.npmmirror.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== + +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yargs-parser@13.1.2, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^2.4.1: + version "2.4.1" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-2.4.1.tgz#85568de3cf150ff49fa51825f03a8c880ddcc5c4" + integrity sha512-9pIKIJhnI5tonzG6OnCFlz/yln8xHYcGl+pn3xR0Vzff0vzN1PbNRaelgfgRUwZ3s4i3jvxT9WhmUGL4whnasA== + dependencies: + camelcase "^3.0.0" + lodash.assign "^4.0.6" + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" + integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== + dependencies: + flat "^4.1.0" + lodash "^4.17.15" + yargs "^13.3.0" + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@13.3.2, yargs@^13.3.0: + version "13.3.2" + resolved "https://registry.npmmirror.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^4.7.1: + version "4.8.1" + resolved "https://registry.npmmirror.com/yargs/-/yargs-4.8.1.tgz#c0c42924ca4aaa6b0e6da1739dfb216439f9ddc0" + integrity sha512-LqodLrnIDM3IFT+Hf/5sxBnEGECrfdC1uIbgZeJmESCSo4HoCAaKEus8MylXHAkdacGc0ye+Qa+dpkuom8uVYA== + dependencies: + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + lodash.assign "^4.0.3" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.1" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^2.4.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/packages/hebao_v3/.env.example b/packages/hebao_v3/.env.example new file mode 100644 index 000000000..6762492f6 --- /dev/null +++ b/packages/hebao_v3/.env.example @@ -0,0 +1,6 @@ +PRIVATE_KEY= +TEST_ACCOUNT_PRIVATE_KEY= +PAYMASTER_OWNER_PRIVATE_KEY= +BLANK_OWNER= +ETHERSCAN_API_KEY= +INFURA_API_KEY= diff --git a/packages/hebao_v3/.eslintignore b/packages/hebao_v3/.eslintignore new file mode 100644 index 000000000..7d92b8d13 --- /dev/null +++ b/packages/hebao_v3/.eslintignore @@ -0,0 +1,5 @@ +node_modules +artifacts +cache +coverage +typechain-types diff --git a/packages/hebao_v3/.eslintrc.js b/packages/hebao_v3/.eslintrc.js new file mode 100644 index 000000000..8ebf39957 --- /dev/null +++ b/packages/hebao_v3/.eslintrc.js @@ -0,0 +1,67 @@ +module.exports = { + env: { + browser: true, + es6: true, + jest: true, + mocha: true, + node: true + }, + globals: { + artifacts: false, + assert: false, + contract: false, + web3: false + }, + extends: ['standard-with-typescript', 'prettier'], + // This is needed to add configuration to rules with type information + parser: '@typescript-eslint/parser', + parserOptions: { + project: ['./tsconfig.json'] + }, + ignorePatterns: [ + '.eslintrc.js', + 'coverage', + 'dist/', + 'typechain-types' + ], + rules: { + 'no-console': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/return-await': 'off', + '@typescript-eslint/no-unnecessary-type-assertion': 'off', + '@typescript-eslint/require-array-sort-compare': [ + 'error', + { + ignoreStringArrays: true + } + ] + }, + overrides: [ + { + files: '*', + rules: { + '@typescript-eslint/naming-convention': 'off', + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/restrict-template-expressions': 'off' + } + }, + { + files: ['**/test/**/*.ts'], + rules: { + 'no-unused-expressions': 'off', + // chai assertions trigger this rule + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-non-null-assertion': 'off' + } + }, + { + // otherwise it will raise an error in every JavaScript file + files: ['*.ts'], + rules: { + '@typescript-eslint/prefer-ts-expect-error': 'off', + // allow using '${val}' with numbers, bool and null types + '@typescript-eslint/restrict-template-expressions': ['error'] + } + } + ] +} diff --git a/packages/hebao_v3/.gitignore b/packages/hebao_v3/.gitignore new file mode 100644 index 000000000..43af850e2 --- /dev/null +++ b/packages/hebao_v3/.gitignore @@ -0,0 +1,13 @@ +# Packages +node_modules/ + +# Hardhat build outputs +artifacts/ +cache/ +build/ +ABI/ +typechain-types/ +libraries.js +.env +/coverage +/coverage.json diff --git a/packages/hebao_v3/.nvmrc b/packages/hebao_v3/.nvmrc new file mode 100644 index 000000000..3f430af82 --- /dev/null +++ b/packages/hebao_v3/.nvmrc @@ -0,0 +1 @@ +v18 diff --git a/packages/hebao_v3/.prettierignore b/packages/hebao_v3/.prettierignore new file mode 100644 index 000000000..f4a106358 --- /dev/null +++ b/packages/hebao_v3/.prettierignore @@ -0,0 +1,7 @@ +node_modules +artifacts +cache +coverage* +gasReporterOutput.json +typechain-types +contracts/account-abstraction diff --git a/packages/hebao_v3/.prettierrc.json b/packages/hebao_v3/.prettierrc.json new file mode 100644 index 000000000..284133ed3 --- /dev/null +++ b/packages/hebao_v3/.prettierrc.json @@ -0,0 +1,20 @@ +{ + "semi": false, + "trailingComma": "none", + "singleQuote": true, + "printWidth": 70, + "plugins": ["prettier-plugin-solidity"], + "overrides": [ + { + "files": "*.sol", + "options": { + "parser": "solidity-parse", + "printWidth": 80, + "tabWidth": 4, + "useTabs": false, + "singleQuote": false, + "bracketSpacing": false + } + } + ] +} diff --git a/packages/hebao_v3/.solcover.js b/packages/hebao_v3/.solcover.js new file mode 100644 index 000000000..8bb7e9e7a --- /dev/null +++ b/packages/hebao_v3/.solcover.js @@ -0,0 +1,4 @@ +module.exports = { + skipFiles: ['account-abstraction', 'test', 'thirdparty'], + configureYulOptimizer: true +} diff --git a/packages/hebao_v3/.solhint.json b/packages/hebao_v3/.solhint.json new file mode 100644 index 000000000..eeca9894c --- /dev/null +++ b/packages/hebao_v3/.solhint.json @@ -0,0 +1,12 @@ +{ + "extends": "solhint:recommended", + "plugins": ["prettier"], + "rules": { + "prettier/prettier": "warning", + "compiler-version": ["error", "^0.8.12"], + "func-visibility": ["warn", { "ignoreConstructors": true }], + "no-global-import": "off", + "no-empty-blocks": ["off", { "ignoreConstructors": true }], + "not-rely-on-time": "off" + } +} diff --git a/packages/hebao_v3/.solhintignore b/packages/hebao_v3/.solhintignore new file mode 100644 index 000000000..65e5bb0fc --- /dev/null +++ b/packages/hebao_v3/.solhintignore @@ -0,0 +1,4 @@ +node_modules +account-abstraction +test +BytesUtil.sol diff --git a/packages/hebao_v3/LICENSE b/packages/hebao_v3/LICENSE new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/packages/hebao_v3/LICENSE @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/packages/hebao_v3/README.md b/packages/hebao_v3/README.md new file mode 100644 index 000000000..25986f59d --- /dev/null +++ b/packages/hebao_v3/README.md @@ -0,0 +1,22 @@ +# Hebao Smart Wallet Contracts + +_[hebao]_(荷包)means wallet in China -- see https://www.pinterest.com/pin/373376625330954965 for examples. + +# Build + +``` +yarn install +yarn compile +``` + +# Run test + +``` +yarn test +``` + +# Deploy contract to arbitrum: + +``` +npx hardhat run --network arbitrum scripts/deploy-arbitrum.ts +``` diff --git a/packages/hebao_v3/contracts/account-abstraction/core/BaseAccount.sol b/packages/hebao_v3/contracts/account-abstraction/core/BaseAccount.sol new file mode 100644 index 000000000..95b263991 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/BaseAccount.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable no-empty-blocks */ + +import "../interfaces/IAccount.sol"; +import "../interfaces/IEntryPoint.sol"; +import "./Helpers.sol"; + +/** + * Basic account implementation. + * this contract provides the basic logic for implementing the IAccount interface - validateUserOp + * specific account implementation should inherit it and provide the account-specific logic + */ +abstract contract BaseAccount is IAccount { + using UserOperationLib for UserOperation; + + //return value in case of signature failure, with no time-range. + // equivalent to _packValidationData(true,0,0); + uint256 constant internal SIG_VALIDATION_FAILED = 1; + + /** + * Return the account nonce. + * This method returns the next sequential nonce. + * For a nonce of a specific key, use `entrypoint.getNonce(account, key)` + */ + function getNonce() public view virtual returns (uint256) { + return entryPoint().getNonce(address(this), 0); + } + + /** + * return the entryPoint used by this account. + * subclass should return the current entryPoint used by this account. + */ + function entryPoint() public view virtual returns (IEntryPoint); + + /** + * Validate user's signature and nonce. + * subclass doesn't need to override this method. Instead, it should override the specific internal validation methods. + */ + function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) + external override virtual returns (uint256 validationData) { + _requireFromEntryPoint(); + validationData = _validateSignature(userOp, userOpHash); + _validateNonce(userOp.nonce); + _payPrefund(missingAccountFunds); + } + + /** + * ensure the request comes from the known entrypoint. + */ + function _requireFromEntryPoint() internal virtual view { + require(msg.sender == address(entryPoint()), "account: not from EntryPoint"); + } + + /** + * validate the signature is valid for this message. + * @param userOp validate the userOp.signature field + * @param userOpHash convenient field: the hash of the request, to check the signature against + * (also hashes the entrypoint and chain id) + * @return validationData signature and time-range of this operation + * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, + * otherwise, an address of an "authorizer" contract. + * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" + * <6-byte> validAfter - first timestamp this operation is valid + * If the account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure. + * Note that the validation code cannot use block.timestamp (or block.number) directly. + */ + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal virtual returns (uint256 validationData); + + /** + * Validate the nonce of the UserOperation. + * This method may validate the nonce requirement of this account. + * e.g. + * To limit the nonce to use sequenced UserOps only (no "out of order" UserOps): + * `require(nonce < type(uint64).max)` + * For a hypothetical account that *requires* the nonce to be out-of-order: + * `require(nonce & type(uint64).max == 0)` + * + * The actual nonce uniqueness is managed by the EntryPoint, and thus no other + * action is needed by the account itself. + * + * @param nonce to validate + * + * solhint-disable-next-line no-empty-blocks + */ + function _validateNonce(uint256 nonce) internal view virtual { + } + + /** + * sends to the entrypoint (msg.sender) the missing funds for this transaction. + * subclass MAY override this method for better funds management + * (e.g. send to the entryPoint more than the minimum required, so that in future transactions + * it will not be required to send again) + * @param missingAccountFunds the minimum value this method should send the entrypoint. + * this value MAY be zero, in case there is enough deposit, or the userOp has a paymaster. + */ + function _payPrefund(uint256 missingAccountFunds) internal virtual { + if (missingAccountFunds != 0) { + (bool success,) = payable(msg.sender).call{value : missingAccountFunds, gas : type(uint256).max}(""); + (success); + //ignore failure (its EntryPoint's job to verify, not account.) + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/core/BasePaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/core/BasePaymaster.sol new file mode 100644 index 000000000..1ae3c81c1 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/BasePaymaster.sol @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + + +/* solhint-disable reason-string */ + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "../interfaces/IPaymaster.sol"; +import "../interfaces/IEntryPoint.sol"; +import "./Helpers.sol"; + +/** + * Helper class for creating a paymaster. + * provides helper methods for staking. + * validates that the postOp is called only by the entryPoint + */ +abstract contract BasePaymaster is IPaymaster, Ownable { + + IEntryPoint immutable public entryPoint; + + constructor(IEntryPoint _entryPoint) { + entryPoint = _entryPoint; + } + + /// @inheritdoc IPaymaster + function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + external override returns (bytes memory context, uint256 validationData) { + _requireFromEntryPoint(); + return _validatePaymasterUserOp(userOp, userOpHash, maxCost); + } + + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + internal virtual returns (bytes memory context, uint256 validationData); + + /// @inheritdoc IPaymaster + function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external override { + _requireFromEntryPoint(); + _postOp(mode, context, actualGasCost); + } + + /** + * post-operation handler. + * (verified to be called only through the entryPoint) + * @dev if subclass returns a non-empty context from validatePaymasterUserOp, it must also implement this method. + * @param mode enum with the following options: + * opSucceeded - user operation succeeded. + * opReverted - user op reverted. still has to pay for gas. + * postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert. + * Now this is the 2nd call, after user's op was deliberately reverted. + * @param context - the context value returned by validatePaymasterUserOp + * @param actualGasCost - actual gas used so far (without this postOp call). + */ + function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal virtual { + + (mode,context,actualGasCost); // unused params + // subclass must override this method if validatePaymasterUserOp returns a context + revert("must override"); + } + + /** + * add a deposit for this paymaster, used for paying for transaction fees + */ + function deposit() public payable { + entryPoint.depositTo{value : msg.value}(address(this)); + } + + /** + * withdraw value from the deposit + * @param withdrawAddress target to send to + * @param amount to withdraw + */ + function withdrawTo(address payable withdrawAddress, uint256 amount) public onlyOwner { + entryPoint.withdrawTo(withdrawAddress, amount); + } + /** + * add stake for this paymaster. + * This method can also carry eth value to add to the current stake. + * @param unstakeDelaySec - the unstake delay for this paymaster. Can only be increased. + */ + function addStake(uint32 unstakeDelaySec) external payable onlyOwner { + entryPoint.addStake{value : msg.value}(unstakeDelaySec); + } + + /** + * return current paymaster's deposit on the entryPoint. + */ + function getDeposit() public view returns (uint256) { + return entryPoint.balanceOf(address(this)); + } + + /** + * unlock the stake, in order to withdraw it. + * The paymaster can't serve requests once unlocked, until it calls addStake again + */ + function unlockStake() external onlyOwner { + entryPoint.unlockStake(); + } + + /** + * withdraw the entire paymaster's stake. + * stake must be unlocked first (and then wait for the unstakeDelay to be over) + * @param withdrawAddress the address to send withdrawn value. + */ + function withdrawStake(address payable withdrawAddress) external onlyOwner { + entryPoint.withdrawStake(withdrawAddress); + } + + /// validate the call is made from a valid entrypoint + function _requireFromEntryPoint() internal virtual { + require(msg.sender == address(entryPoint), "Sender not EntryPoint"); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/core/EntryPoint.sol b/packages/hebao_v3/contracts/account-abstraction/core/EntryPoint.sol new file mode 100644 index 000000000..b5473a5e6 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/EntryPoint.sol @@ -0,0 +1,631 @@ +/** + ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. + ** Only one instance required on each chain. + **/ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable no-inline-assembly */ + +import "../interfaces/IAccount.sol"; +import "../interfaces/IPaymaster.sol"; +import "../interfaces/IEntryPoint.sol"; + +import "../utils/Exec.sol"; +import "./StakeManager.sol"; +import "./SenderCreator.sol"; +import "./Helpers.sol"; +import "./NonceManager.sol"; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; + +contract EntryPoint is IEntryPoint, StakeManager, NonceManager, ReentrancyGuard { + + using UserOperationLib for UserOperation; + + SenderCreator private immutable senderCreator = new SenderCreator(); + + // internal value used during simulation: need to query aggregator. + address private constant SIMULATE_FIND_AGGREGATOR = address(1); + + // marker for inner call revert on out of gas + bytes32 private constant INNER_OUT_OF_GAS = hex'deaddead'; + + uint256 private constant REVERT_REASON_MAX_LEN = 2048; + + /** + * for simulation purposes, validateUserOp (and validatePaymasterUserOp) must return this value + * in case of signature failure, instead of revert. + */ + uint256 public constant SIG_VALIDATION_FAILED = 1; + + /** + * compensate the caller's beneficiary address with the collected fees of all UserOperations. + * @param beneficiary the address to receive the fees + * @param amount amount to transfer. + */ + function _compensate(address payable beneficiary, uint256 amount) internal { + require(beneficiary != address(0), "AA90 invalid beneficiary"); + (bool success,) = beneficiary.call{value : amount}(""); + require(success, "AA91 failed send to beneficiary"); + } + + /** + * execute a user op + * @param opIndex index into the opInfo array + * @param userOp the userOp to execute + * @param opInfo the opInfo filled by validatePrepayment for this userOp. + * @return collected the total amount this userOp paid. + */ + function _executeUserOp(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory opInfo) private returns (uint256 collected) { + uint256 preGas = gasleft(); + bytes memory context = getMemoryBytesFromOffset(opInfo.contextOffset); + + try this.innerHandleOp(userOp.callData, opInfo, context) returns (uint256 _actualGasCost) { + collected = _actualGasCost; + } catch { + bytes32 innerRevertCode; + assembly { + returndatacopy(0, 0, 32) + innerRevertCode := mload(0) + } + // handleOps was called with gas limit too low. abort entire bundle. + if (innerRevertCode == INNER_OUT_OF_GAS) { + //report paymaster, since if it is not deliberately caused by the bundler, + // it must be a revert caused by paymaster. + revert FailedOp(opIndex, "AA95 out of gas"); + } + + uint256 actualGas = preGas - gasleft() + opInfo.preOpGas; + collected = _handlePostOp(opIndex, IPaymaster.PostOpMode.postOpReverted, opInfo, context, actualGas); + } + } + + /** + * Execute a batch of UserOperations. + * no signature aggregator is used. + * if any account requires an aggregator (that is, it returned an aggregator when + * performing simulateValidation), then handleAggregatedOps() must be used instead. + * @param ops the operations to execute + * @param beneficiary the address to receive the fees + */ + function handleOps(UserOperation[] calldata ops, address payable beneficiary) public nonReentrant { + + uint256 opslen = ops.length; + UserOpInfo[] memory opInfos = new UserOpInfo[](opslen); + + unchecked { + for (uint256 i = 0; i < opslen; i++) { + UserOpInfo memory opInfo = opInfos[i]; + (uint256 validationData, uint256 pmValidationData) = _validatePrepayment(i, ops[i], opInfo); + _validateAccountAndPaymasterValidationData(i, validationData, pmValidationData, address(0)); + } + + uint256 collected = 0; + emit BeforeExecution(); + + for (uint256 i = 0; i < opslen; i++) { + collected += _executeUserOp(i, ops[i], opInfos[i]); + } + + _compensate(beneficiary, collected); + } //unchecked + } + + /** + * Execute a batch of UserOperation with Aggregators + * @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts) + * @param beneficiary the address to receive the fees + */ + function handleAggregatedOps( + UserOpsPerAggregator[] calldata opsPerAggregator, + address payable beneficiary + ) public nonReentrant { + + uint256 opasLen = opsPerAggregator.length; + uint256 totalOps = 0; + for (uint256 i = 0; i < opasLen; i++) { + UserOpsPerAggregator calldata opa = opsPerAggregator[i]; + UserOperation[] calldata ops = opa.userOps; + IAggregator aggregator = opa.aggregator; + + //address(1) is special marker of "signature error" + require(address(aggregator) != address(1), "AA96 invalid aggregator"); + + if (address(aggregator) != address(0)) { + // solhint-disable-next-line no-empty-blocks + try aggregator.validateSignatures(ops, opa.signature) {} + catch { + revert SignatureValidationFailed(address(aggregator)); + } + } + + totalOps += ops.length; + } + + UserOpInfo[] memory opInfos = new UserOpInfo[](totalOps); + + emit BeforeExecution(); + + uint256 opIndex = 0; + for (uint256 a = 0; a < opasLen; a++) { + UserOpsPerAggregator calldata opa = opsPerAggregator[a]; + UserOperation[] calldata ops = opa.userOps; + IAggregator aggregator = opa.aggregator; + + uint256 opslen = ops.length; + for (uint256 i = 0; i < opslen; i++) { + UserOpInfo memory opInfo = opInfos[opIndex]; + (uint256 validationData, uint256 paymasterValidationData) = _validatePrepayment(opIndex, ops[i], opInfo); + _validateAccountAndPaymasterValidationData(i, validationData, paymasterValidationData, address(aggregator)); + opIndex++; + } + } + + uint256 collected = 0; + opIndex = 0; + for (uint256 a = 0; a < opasLen; a++) { + UserOpsPerAggregator calldata opa = opsPerAggregator[a]; + emit SignatureAggregatorChanged(address(opa.aggregator)); + UserOperation[] calldata ops = opa.userOps; + uint256 opslen = ops.length; + + for (uint256 i = 0; i < opslen; i++) { + collected += _executeUserOp(opIndex, ops[i], opInfos[opIndex]); + opIndex++; + } + } + emit SignatureAggregatorChanged(address(0)); + + _compensate(beneficiary, collected); + } + + /// @inheritdoc IEntryPoint + function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external override { + + UserOpInfo memory opInfo; + _simulationOnlyValidations(op); + (uint256 validationData, uint256 paymasterValidationData) = _validatePrepayment(0, op, opInfo); + ValidationData memory data = _intersectTimeRange(validationData, paymasterValidationData); + + numberMarker(); + uint256 paid = _executeUserOp(0, op, opInfo); + numberMarker(); + bool targetSuccess; + bytes memory targetResult; + if (target != address(0)) { + (targetSuccess, targetResult) = target.call(targetCallData); + } + revert ExecutionResult(opInfo.preOpGas, paid, data.validAfter, data.validUntil, targetSuccess, targetResult); + } + + + // A memory copy of UserOp static fields only. + // Excluding: callData, initCode and signature. Replacing paymasterAndData with paymaster. + struct MemoryUserOp { + address sender; + uint256 nonce; + uint256 callGasLimit; + uint256 verificationGasLimit; + uint256 preVerificationGas; + address paymaster; + uint256 maxFeePerGas; + uint256 maxPriorityFeePerGas; + } + + struct UserOpInfo { + MemoryUserOp mUserOp; + bytes32 userOpHash; + uint256 prefund; + uint256 contextOffset; + uint256 preOpGas; + } + + /** + * inner function to handle a UserOperation. + * Must be declared "external" to open a call context, but it can only be called by handleOps. + */ + function innerHandleOp(bytes memory callData, UserOpInfo memory opInfo, bytes calldata context) external returns (uint256 actualGasCost) { + uint256 preGas = gasleft(); + require(msg.sender == address(this), "AA92 internal call only"); + MemoryUserOp memory mUserOp = opInfo.mUserOp; + + uint callGasLimit = mUserOp.callGasLimit; + unchecked { + // handleOps was called with gas limit too low. abort entire bundle. + if (gasleft() < callGasLimit + mUserOp.verificationGasLimit + 5000) { + assembly { + mstore(0, INNER_OUT_OF_GAS) + revert(0, 32) + } + } + } + + IPaymaster.PostOpMode mode = IPaymaster.PostOpMode.opSucceeded; + if (callData.length > 0) { + bool success = Exec.call(mUserOp.sender, 0, callData, callGasLimit); + if (!success) { + bytes memory result = Exec.getReturnData(REVERT_REASON_MAX_LEN); + if (result.length > 0) { + emit UserOperationRevertReason(opInfo.userOpHash, mUserOp.sender, mUserOp.nonce, result); + } + mode = IPaymaster.PostOpMode.opReverted; + } + } + + unchecked { + uint256 actualGas = preGas - gasleft() + opInfo.preOpGas; + //note: opIndex is ignored (relevant only if mode==postOpReverted, which is only possible outside of innerHandleOp) + return _handlePostOp(0, mode, opInfo, context, actualGas); + } + } + + /** + * generate a request Id - unique identifier for this request. + * the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. + */ + function getUserOpHash(UserOperation calldata userOp) public view returns (bytes32) { + return keccak256(abi.encode(userOp.hash(), address(this), block.chainid)); + } + + /** + * copy general fields from userOp into the memory opInfo structure. + */ + function _copyUserOpToMemory(UserOperation calldata userOp, MemoryUserOp memory mUserOp) internal pure { + mUserOp.sender = userOp.sender; + mUserOp.nonce = userOp.nonce; + mUserOp.callGasLimit = userOp.callGasLimit; + mUserOp.verificationGasLimit = userOp.verificationGasLimit; + mUserOp.preVerificationGas = userOp.preVerificationGas; + mUserOp.maxFeePerGas = userOp.maxFeePerGas; + mUserOp.maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; + bytes calldata paymasterAndData = userOp.paymasterAndData; + if (paymasterAndData.length > 0) { + require(paymasterAndData.length >= 20, "AA93 invalid paymasterAndData"); + mUserOp.paymaster = address(bytes20(paymasterAndData[: 20])); + } else { + mUserOp.paymaster = address(0); + } + } + + /** + * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp. + * @dev this method always revert. Successful result is ValidationResult error. other errors are failures. + * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data. + * @param userOp the user operation to validate. + */ + function simulateValidation(UserOperation calldata userOp) external { + UserOpInfo memory outOpInfo; + + _simulationOnlyValidations(userOp); + (uint256 validationData, uint256 paymasterValidationData) = _validatePrepayment(0, userOp, outOpInfo); + StakeInfo memory paymasterInfo = _getStakeInfo(outOpInfo.mUserOp.paymaster); + StakeInfo memory senderInfo = _getStakeInfo(outOpInfo.mUserOp.sender); + StakeInfo memory factoryInfo; + { + bytes calldata initCode = userOp.initCode; + address factory = initCode.length >= 20 ? address(bytes20(initCode[0 : 20])) : address(0); + factoryInfo = _getStakeInfo(factory); + } + + ValidationData memory data = _intersectTimeRange(validationData, paymasterValidationData); + address aggregator = data.aggregator; + bool sigFailed = aggregator == address(1); + ReturnInfo memory returnInfo = ReturnInfo(outOpInfo.preOpGas, outOpInfo.prefund, + sigFailed, data.validAfter, data.validUntil, getMemoryBytesFromOffset(outOpInfo.contextOffset)); + + if (aggregator != address(0) && aggregator != address(1)) { + AggregatorStakeInfo memory aggregatorInfo = AggregatorStakeInfo(aggregator, _getStakeInfo(aggregator)); + revert ValidationResultWithAggregation(returnInfo, senderInfo, factoryInfo, paymasterInfo, aggregatorInfo); + } + revert ValidationResult(returnInfo, senderInfo, factoryInfo, paymasterInfo); + + } + + function _getRequiredPrefund(MemoryUserOp memory mUserOp) internal pure returns (uint256 requiredPrefund) { + unchecked { + //when using a Paymaster, the verificationGasLimit is used also to as a limit for the postOp call. + // our security model might call postOp eventually twice + uint256 mul = mUserOp.paymaster != address(0) ? 3 : 1; + uint256 requiredGas = mUserOp.callGasLimit + mUserOp.verificationGasLimit * mul + mUserOp.preVerificationGas; + + requiredPrefund = requiredGas * mUserOp.maxFeePerGas; + } + } + + // create the sender's contract if needed. + function _createSenderIfNeeded(uint256 opIndex, UserOpInfo memory opInfo, bytes calldata initCode) internal { + if (initCode.length != 0) { + address sender = opInfo.mUserOp.sender; + if (sender.code.length != 0) revert FailedOp(opIndex, "AA10 sender already constructed"); + address sender1 = senderCreator.createSender{gas : opInfo.mUserOp.verificationGasLimit}(initCode); + if (sender1 == address(0)) revert FailedOp(opIndex, "AA13 initCode failed or OOG"); + if (sender1 != sender) revert FailedOp(opIndex, "AA14 initCode must return sender"); + if (sender1.code.length == 0) revert FailedOp(opIndex, "AA15 initCode must create sender"); + address factory = address(bytes20(initCode[0 : 20])); + emit AccountDeployed(opInfo.userOpHash, sender, factory, opInfo.mUserOp.paymaster); + } + } + + /** + * Get counterfactual sender address. + * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. + * this method always revert, and returns the address in SenderAddressResult error + * @param initCode the constructor code to be passed into the UserOperation. + */ + function getSenderAddress(bytes calldata initCode) public { + address sender = senderCreator.createSender(initCode); + revert SenderAddressResult(sender); + } + + function _simulationOnlyValidations(UserOperation calldata userOp) internal view { + // solhint-disable-next-line no-empty-blocks + try this._validateSenderAndPaymaster(userOp.initCode, userOp.sender, userOp.paymasterAndData) {} + catch Error(string memory revertReason) { + if (bytes(revertReason).length != 0) { + revert FailedOp(0, revertReason); + } + } + } + + /** + * Called only during simulation. + * This function always reverts to prevent warm/cold storage differentiation in simulation vs execution. + */ + function _validateSenderAndPaymaster(bytes calldata initCode, address sender, bytes calldata paymasterAndData) external view { + if (initCode.length == 0 && sender.code.length == 0) { + // it would revert anyway. but give a meaningful message + revert("AA20 account not deployed"); + } + if (paymasterAndData.length >= 20) { + address paymaster = address(bytes20(paymasterAndData[0 : 20])); + if (paymaster.code.length == 0) { + // it would revert anyway. but give a meaningful message + revert("AA30 paymaster not deployed"); + } + } + // always revert + revert(""); + } + + /** + * call account.validateUserOp. + * revert (with FailedOp) in case validateUserOp reverts, or account didn't send required prefund. + * decrement account's deposit if needed + */ + function _validateAccountPrepayment(uint256 opIndex, UserOperation calldata op, UserOpInfo memory opInfo, uint256 requiredPrefund) + internal returns (uint256 gasUsedByValidateAccountPrepayment, uint256 validationData) { + unchecked { + uint256 preGas = gasleft(); + MemoryUserOp memory mUserOp = opInfo.mUserOp; + address sender = mUserOp.sender; + _createSenderIfNeeded(opIndex, opInfo, op.initCode); + address paymaster = mUserOp.paymaster; + numberMarker(); + uint256 missingAccountFunds = 0; + if (paymaster == address(0)) { + uint256 bal = balanceOf(sender); + missingAccountFunds = bal > requiredPrefund ? 0 : requiredPrefund - bal; + } + try IAccount(sender).validateUserOp{gas : mUserOp.verificationGasLimit}(op, opInfo.userOpHash, missingAccountFunds) + returns (uint256 _validationData) { + validationData = _validationData; + } catch Error(string memory revertReason) { + revert FailedOp(opIndex, string.concat("AA23 reverted: ", revertReason)); + } catch { + revert FailedOp(opIndex, "AA23 reverted (or OOG)"); + } + if (paymaster == address(0)) { + DepositInfo storage senderInfo = deposits[sender]; + uint256 deposit = senderInfo.deposit; + if (requiredPrefund > deposit) { + revert FailedOp(opIndex, "AA21 didn't pay prefund"); + } + senderInfo.deposit = uint112(deposit - requiredPrefund); + } + gasUsedByValidateAccountPrepayment = preGas - gasleft(); + } + } + + /** + * In case the request has a paymaster: + * Validate paymaster has enough deposit. + * Call paymaster.validatePaymasterUserOp. + * Revert with proper FailedOp in case paymaster reverts. + * Decrement paymaster's deposit + */ + function _validatePaymasterPrepayment(uint256 opIndex, UserOperation calldata op, UserOpInfo memory opInfo, uint256 requiredPreFund, uint256 gasUsedByValidateAccountPrepayment) + internal returns (bytes memory context, uint256 validationData) { + unchecked { + MemoryUserOp memory mUserOp = opInfo.mUserOp; + uint256 verificationGasLimit = mUserOp.verificationGasLimit; + require(verificationGasLimit > gasUsedByValidateAccountPrepayment, "AA41 too little verificationGas"); + uint256 gas = verificationGasLimit - gasUsedByValidateAccountPrepayment; + + address paymaster = mUserOp.paymaster; + DepositInfo storage paymasterInfo = deposits[paymaster]; + uint256 deposit = paymasterInfo.deposit; + if (deposit < requiredPreFund) { + revert FailedOp(opIndex, "AA31 paymaster deposit too low"); + } + paymasterInfo.deposit = uint112(deposit - requiredPreFund); + try IPaymaster(paymaster).validatePaymasterUserOp{gas : gas}(op, opInfo.userOpHash, requiredPreFund) returns (bytes memory _context, uint256 _validationData){ + context = _context; + validationData = _validationData; + } catch Error(string memory revertReason) { + revert FailedOp(opIndex, string.concat("AA33 reverted: ", revertReason)); + } catch { + revert FailedOp(opIndex, "AA33 reverted (or OOG)"); + } + } + } + + /** + * revert if either account validationData or paymaster validationData is expired + */ + function _validateAccountAndPaymasterValidationData(uint256 opIndex, uint256 validationData, uint256 paymasterValidationData, address expectedAggregator) internal view { + (address aggregator, bool outOfTimeRange) = _getValidationData(validationData); + if (expectedAggregator != aggregator) { + revert FailedOp(opIndex, "AA24 signature error"); + } + if (outOfTimeRange) { + revert FailedOp(opIndex, "AA22 expired or not due"); + } + //pmAggregator is not a real signature aggregator: we don't have logic to handle it as address. + // non-zero address means that the paymaster fails due to some signature check (which is ok only during estimation) + address pmAggregator; + (pmAggregator, outOfTimeRange) = _getValidationData(paymasterValidationData); + if (pmAggregator != address(0)) { + revert FailedOp(opIndex, "AA34 signature error"); + } + if (outOfTimeRange) { + revert FailedOp(opIndex, "AA32 paymaster expired or not due"); + } + } + + function _getValidationData(uint256 validationData) internal view returns (address aggregator, bool outOfTimeRange) { + if (validationData == 0) { + return (address(0), false); + } + ValidationData memory data = _parseValidationData(validationData); + // solhint-disable-next-line not-rely-on-time + outOfTimeRange = block.timestamp > data.validUntil || block.timestamp < data.validAfter; + aggregator = data.aggregator; + } + + /** + * validate account and paymaster (if defined). + * also make sure total validation doesn't exceed verificationGasLimit + * this method is called off-chain (simulateValidation()) and on-chain (from handleOps) + * @param opIndex the index of this userOp into the "opInfos" array + * @param userOp the userOp to validate + */ + function _validatePrepayment(uint256 opIndex, UserOperation calldata userOp, UserOpInfo memory outOpInfo) + private returns (uint256 validationData, uint256 paymasterValidationData) { + + uint256 preGas = gasleft(); + MemoryUserOp memory mUserOp = outOpInfo.mUserOp; + _copyUserOpToMemory(userOp, mUserOp); + outOpInfo.userOpHash = getUserOpHash(userOp); + + // validate all numeric values in userOp are well below 128 bit, so they can safely be added + // and multiplied without causing overflow + uint256 maxGasValues = mUserOp.preVerificationGas | mUserOp.verificationGasLimit | mUserOp.callGasLimit | + userOp.maxFeePerGas | userOp.maxPriorityFeePerGas; + require(maxGasValues <= type(uint120).max, "AA94 gas values overflow"); + + uint256 gasUsedByValidateAccountPrepayment; + (uint256 requiredPreFund) = _getRequiredPrefund(mUserOp); + (gasUsedByValidateAccountPrepayment, validationData) = _validateAccountPrepayment(opIndex, userOp, outOpInfo, requiredPreFund); + + if (!_validateAndUpdateNonce(mUserOp.sender, mUserOp.nonce)) { + revert FailedOp(opIndex, "AA25 invalid account nonce"); + } + + //a "marker" where account opcode validation is done and paymaster opcode validation is about to start + // (used only by off-chain simulateValidation) + numberMarker(); + + bytes memory context; + if (mUserOp.paymaster != address(0)) { + (context, paymasterValidationData) = _validatePaymasterPrepayment(opIndex, userOp, outOpInfo, requiredPreFund, gasUsedByValidateAccountPrepayment); + } + unchecked { + uint256 gasUsed = preGas - gasleft(); + + if (userOp.verificationGasLimit < gasUsed) { + revert FailedOp(opIndex, "AA40 over verificationGasLimit"); + } + outOpInfo.prefund = requiredPreFund; + outOpInfo.contextOffset = getOffsetOfMemoryBytes(context); + outOpInfo.preOpGas = preGas - gasleft() + userOp.preVerificationGas; + } + } + + /** + * process post-operation. + * called just after the callData is executed. + * if a paymaster is defined and its validation returned a non-empty context, its postOp is called. + * the excess amount is refunded to the account (or paymaster - if it was used in the request) + * @param opIndex index in the batch + * @param mode - whether is called from innerHandleOp, or outside (postOpReverted) + * @param opInfo userOp fields and info collected during validation + * @param context the context returned in validatePaymasterUserOp + * @param actualGas the gas used so far by this user operation + */ + function _handlePostOp(uint256 opIndex, IPaymaster.PostOpMode mode, UserOpInfo memory opInfo, bytes memory context, uint256 actualGas) private returns (uint256 actualGasCost) { + uint256 preGas = gasleft(); + unchecked { + address refundAddress; + MemoryUserOp memory mUserOp = opInfo.mUserOp; + uint256 gasPrice = getUserOpGasPrice(mUserOp); + + address paymaster = mUserOp.paymaster; + if (paymaster == address(0)) { + refundAddress = mUserOp.sender; + } else { + refundAddress = paymaster; + if (context.length > 0) { + actualGasCost = actualGas * gasPrice; + if (mode != IPaymaster.PostOpMode.postOpReverted) { + IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost); + } else { + // solhint-disable-next-line no-empty-blocks + try IPaymaster(paymaster).postOp{gas : mUserOp.verificationGasLimit}(mode, context, actualGasCost) {} + catch Error(string memory reason) { + revert FailedOp(opIndex, string.concat("AA50 postOp reverted: ", reason)); + } + catch { + revert FailedOp(opIndex, "AA50 postOp revert"); + } + } + } + } + actualGas += preGas - gasleft(); + actualGasCost = actualGas * gasPrice; + if (opInfo.prefund < actualGasCost) { + revert FailedOp(opIndex, "AA51 prefund below actualGasCost"); + } + uint256 refund = opInfo.prefund - actualGasCost; + _incrementDeposit(refundAddress, refund); + bool success = mode == IPaymaster.PostOpMode.opSucceeded; + emit UserOperationEvent(opInfo.userOpHash, mUserOp.sender, mUserOp.paymaster, mUserOp.nonce, success, actualGasCost, actualGas); + } // unchecked + } + + /** + * the gas price this UserOp agrees to pay. + * relayer/block builder might submit the TX with higher priorityFee, but the user should not + */ + function getUserOpGasPrice(MemoryUserOp memory mUserOp) internal view returns (uint256) { + unchecked { + uint256 maxFeePerGas = mUserOp.maxFeePerGas; + uint256 maxPriorityFeePerGas = mUserOp.maxPriorityFeePerGas; + if (maxFeePerGas == maxPriorityFeePerGas) { + //legacy mode (for networks that don't support basefee opcode) + return maxFeePerGas; + } + return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); + } + } + + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } + + function getOffsetOfMemoryBytes(bytes memory data) internal pure returns (uint256 offset) { + assembly {offset := data} + } + + function getMemoryBytesFromOffset(uint256 offset) internal pure returns (bytes memory data) { + assembly {data := offset} + } + + //place the NUMBER opcode in the code. + // this is used as a marker during simulation, as this OP is completely banned from the simulated code of the + // account and paymaster. + function numberMarker() internal view { + assembly {mstore(0, number())} + } +} + diff --git a/packages/hebao_v3/contracts/account-abstraction/core/Helpers.sol b/packages/hebao_v3/contracts/account-abstraction/core/Helpers.sol new file mode 100644 index 000000000..6767fd669 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/Helpers.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable no-inline-assembly */ + +/** + * returned data from validateUserOp. + * validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData` + * @param aggregator - address(0) - the account validated the signature by itself. + * address(1) - the account failed to validate the signature. + * otherwise - this is an address of a signature aggregator that must be used to validate the signature. + * @param validAfter - this UserOp is valid only after this timestamp. + * @param validaUntil - this UserOp is valid only up to this timestamp. + */ + struct ValidationData { + address aggregator; + uint48 validAfter; + uint48 validUntil; + } + +//extract sigFailed, validAfter, validUntil. +// also convert zero validUntil to type(uint48).max + function _parseValidationData(uint validationData) pure returns (ValidationData memory data) { + address aggregator = address(uint160(validationData)); + uint48 validUntil = uint48(validationData >> 160); + if (validUntil == 0) { + validUntil = type(uint48).max; + } + uint48 validAfter = uint48(validationData >> (48 + 160)); + return ValidationData(aggregator, validAfter, validUntil); + } + +// intersect account and paymaster ranges. + function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) { + ValidationData memory accountValidationData = _parseValidationData(validationData); + ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData); + address aggregator = accountValidationData.aggregator; + if (aggregator == address(0)) { + aggregator = pmValidationData.aggregator; + } + uint48 validAfter = accountValidationData.validAfter; + uint48 validUntil = accountValidationData.validUntil; + uint48 pmValidAfter = pmValidationData.validAfter; + uint48 pmValidUntil = pmValidationData.validUntil; + + if (validAfter < pmValidAfter) validAfter = pmValidAfter; + if (validUntil > pmValidUntil) validUntil = pmValidUntil; + return ValidationData(aggregator, validAfter, validUntil); + } + +/** + * helper to pack the return value for validateUserOp + * @param data - the ValidationData to pack + */ + function _packValidationData(ValidationData memory data) pure returns (uint256) { + return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48)); + } + +/** + * helper to pack the return value for validateUserOp, when not using an aggregator + * @param sigFailed - true for signature failure, false for success + * @param validUntil last timestamp this UserOperation is valid (or zero for infinite) + * @param validAfter first timestamp this UserOperation is valid + */ + function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) { + return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48)); + } + +/** + * keccak function over calldata. + * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it. + */ + function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { + assembly { + let mem := mload(0x40) + let len := data.length + calldatacopy(mem, data.offset, len) + ret := keccak256(mem, len) + } + } + diff --git a/packages/hebao_v3/contracts/account-abstraction/core/NonceManager.sol b/packages/hebao_v3/contracts/account-abstraction/core/NonceManager.sol new file mode 100644 index 000000000..f0bc20dbf --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/NonceManager.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../interfaces/IEntryPoint.sol"; + +/** + * nonce management functionality + */ +contract NonceManager is INonceManager { + + /** + * The next valid sequence number for a given nonce key. + */ + mapping(address => mapping(uint192 => uint256)) public nonceSequenceNumber; + + function getNonce(address sender, uint192 key) + public view override returns (uint256 nonce) { + return nonceSequenceNumber[sender][key] | (uint256(key) << 64); + } + + // allow an account to manually increment its own nonce. + // (mainly so that during construction nonce can be made non-zero, + // to "absorb" the gas cost of first nonce increment to 1st transaction (construction), + // not to 2nd transaction) + function incrementNonce(uint192 key) public override { + nonceSequenceNumber[msg.sender][key]++; + } + + /** + * validate nonce uniqueness for this account. + * called just after validateUserOp() + */ + function _validateAndUpdateNonce(address sender, uint256 nonce) internal returns (bool) { + + uint192 key = uint192(nonce >> 64); + uint64 seq = uint64(nonce); + return nonceSequenceNumber[sender][key]++ == seq; + } + +} diff --git a/packages/hebao_v3/contracts/account-abstraction/core/SenderCreator.sol b/packages/hebao_v3/contracts/account-abstraction/core/SenderCreator.sol new file mode 100644 index 000000000..36fad7b91 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/SenderCreator.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/** + * helper contract for EntryPoint, to call userOp.initCode from a "neutral" address, + * which is explicitly not the entryPoint itself. + */ +contract SenderCreator { + + /** + * call the "initCode" factory to create and return the sender account address + * @param initCode the initCode value from a UserOp. contains 20 bytes of factory address, followed by calldata + * @return sender the returned address of the created account, or zero address on failure. + */ + function createSender(bytes calldata initCode) external returns (address sender) { + address factory = address(bytes20(initCode[0 : 20])); + bytes memory initCallData = initCode[20 :]; + bool success; + /* solhint-disable no-inline-assembly */ + assembly { + success := call(gas(), factory, 0, add(initCallData, 0x20), mload(initCallData), 0, 32) + sender := mload(0) + } + if (!success) { + sender = address(0); + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/core/StakeManager.sol b/packages/hebao_v3/contracts/account-abstraction/core/StakeManager.sol new file mode 100644 index 000000000..e5ca2b97d --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/core/StakeManager.sol @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +import "../interfaces/IStakeManager.sol"; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable not-rely-on-time */ +/** + * manage deposits and stakes. + * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) + * stake is value locked for at least "unstakeDelay" by a paymaster. + */ +abstract contract StakeManager is IStakeManager { + + /// maps paymaster to their deposits and stakes + mapping(address => DepositInfo) public deposits; + + /// @inheritdoc IStakeManager + function getDepositInfo(address account) public view returns (DepositInfo memory info) { + return deposits[account]; + } + + // internal method to return just the stake info + function _getStakeInfo(address addr) internal view returns (StakeInfo memory info) { + DepositInfo storage depositInfo = deposits[addr]; + info.stake = depositInfo.stake; + info.unstakeDelaySec = depositInfo.unstakeDelaySec; + } + + /// return the deposit (for gas payment) of the account + function balanceOf(address account) public view returns (uint256) { + return deposits[account].deposit; + } + + receive() external payable { + depositTo(msg.sender); + } + + function _incrementDeposit(address account, uint256 amount) internal { + DepositInfo storage info = deposits[account]; + uint256 newAmount = info.deposit + amount; + require(newAmount <= type(uint112).max, "deposit overflow"); + info.deposit = uint112(newAmount); + } + + /** + * add to the deposit of the given account + */ + function depositTo(address account) public payable { + _incrementDeposit(account, msg.value); + DepositInfo storage info = deposits[account]; + emit Deposited(account, info.deposit); + } + + /** + * add to the account's stake - amount and delay + * any pending unstake is first cancelled. + * @param unstakeDelaySec the new lock duration before the deposit can be withdrawn. + */ + function addStake(uint32 unstakeDelaySec) public payable { + DepositInfo storage info = deposits[msg.sender]; + require(unstakeDelaySec > 0, "must specify unstake delay"); + require(unstakeDelaySec >= info.unstakeDelaySec, "cannot decrease unstake time"); + uint256 stake = info.stake + msg.value; + require(stake > 0, "no stake specified"); + require(stake <= type(uint112).max, "stake overflow"); + deposits[msg.sender] = DepositInfo( + info.deposit, + true, + uint112(stake), + unstakeDelaySec, + 0 + ); + emit StakeLocked(msg.sender, stake, unstakeDelaySec); + } + + /** + * attempt to unlock the stake. + * the value can be withdrawn (using withdrawStake) after the unstake delay. + */ + function unlockStake() external { + DepositInfo storage info = deposits[msg.sender]; + require(info.unstakeDelaySec != 0, "not staked"); + require(info.staked, "already unstaking"); + uint48 withdrawTime = uint48(block.timestamp) + info.unstakeDelaySec; + info.withdrawTime = withdrawTime; + info.staked = false; + emit StakeUnlocked(msg.sender, withdrawTime); + } + + + /** + * withdraw from the (unlocked) stake. + * must first call unlockStake and wait for the unstakeDelay to pass + * @param withdrawAddress the address to send withdrawn value. + */ + function withdrawStake(address payable withdrawAddress) external { + DepositInfo storage info = deposits[msg.sender]; + uint256 stake = info.stake; + require(stake > 0, "No stake to withdraw"); + require(info.withdrawTime > 0, "must call unlockStake() first"); + require(info.withdrawTime <= block.timestamp, "Stake withdrawal is not due"); + info.unstakeDelaySec = 0; + info.withdrawTime = 0; + info.stake = 0; + emit StakeWithdrawn(msg.sender, withdrawAddress, stake); + (bool success,) = withdrawAddress.call{value : stake}(""); + require(success, "failed to withdraw stake"); + } + + /** + * withdraw from the deposit. + * @param withdrawAddress the address to send withdrawn value. + * @param withdrawAmount the amount to withdraw. + */ + function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external { + DepositInfo storage info = deposits[msg.sender]; + require(withdrawAmount <= info.deposit, "Withdraw amount too large"); + info.deposit = uint112(info.deposit - withdrawAmount); + emit Withdrawn(msg.sender, withdrawAddress, withdrawAmount); + (bool success,) = withdrawAddress.call{value : withdrawAmount}(""); + require(success, "failed to withdraw"); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/IAccount.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/IAccount.sol new file mode 100644 index 000000000..1600de3d7 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/IAccount.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "./UserOperation.sol"; + +interface IAccount { + + /** + * Validate user's signature and nonce + * the entryPoint will make the call to the recipient only if this validation call returns successfully. + * signature failure should be reported by returning SIG_VALIDATION_FAILED (1). + * This allows making a "simulation call" without a valid signature + * Other failures (e.g. nonce mismatch, or invalid signature format) should still revert to signal failure. + * + * @dev Must validate caller is the entryPoint. + * Must validate the signature and nonce + * @param userOp the operation that is about to be executed. + * @param userOpHash hash of the user's request data. can be used as the basis for signature. + * @param missingAccountFunds missing funds on the account's deposit in the entrypoint. + * This is the minimum amount to transfer to the sender(entryPoint) to be able to make the call. + * The excess is left as a deposit in the entrypoint, for future calls. + * can be withdrawn anytime using "entryPoint.withdrawTo()" + * In case there is a paymaster in the request (or the current deposit is high enough), this value will be zero. + * @return validationData packaged ValidationData structure. use `_packValidationData` and `_unpackValidationData` to encode and decode + * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, + * otherwise, an address of an "authorizer" contract. + * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" + * <6-byte> validAfter - first timestamp this operation is valid + * If an account doesn't use time-range, it is enough to return SIG_VALIDATION_FAILED value (1) for signature failure. + * Note that the validation code cannot use block.timestamp (or block.number) directly. + */ + function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) + external returns (uint256 validationData); +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/IAggregator.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/IAggregator.sol new file mode 100644 index 000000000..086c6f322 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/IAggregator.sol @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "./UserOperation.sol"; + +/** + * Aggregated Signatures validator. + */ +interface IAggregator { + + /** + * validate aggregated signature. + * revert if the aggregated signature does not match the given list of operations. + */ + function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external view; + + /** + * validate signature of a single userOp + * This method is should be called by bundler after EntryPoint.simulateValidation() returns (reverts) with ValidationResultWithAggregation + * First it validates the signature over the userOp. Then it returns data to be used when creating the handleOps. + * @param userOp the userOperation received from the user. + * @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps. + * (usually empty, unless account and aggregator support some kind of "multisig" + */ + function validateUserOpSignature(UserOperation calldata userOp) + external view returns (bytes memory sigForUserOp); + + /** + * aggregate multiple signatures into a single value. + * This method is called off-chain to calculate the signature to pass with handleOps() + * bundler MAY use optimized custom code perform this aggregation + * @param userOps array of UserOperations to collect the signatures from. + * @return aggregatedSignature the aggregated signature + */ + function aggregateSignatures(UserOperation[] calldata userOps) external view returns (bytes memory aggregatedSignature); +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/IEntryPoint.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/IEntryPoint.sol new file mode 100644 index 000000000..69ce75c8b --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/IEntryPoint.sol @@ -0,0 +1,205 @@ +/** + ** Account-Abstraction (EIP-4337) singleton EntryPoint implementation. + ** Only one instance required on each chain. + **/ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable no-inline-assembly */ +/* solhint-disable reason-string */ + +import "./UserOperation.sol"; +import "./IStakeManager.sol"; +import "./IAggregator.sol"; +import "./INonceManager.sol"; + +interface IEntryPoint is IStakeManager, INonceManager { + + /*** + * An event emitted after each successful request + * @param userOpHash - unique identifier for the request (hash its entire content, except signature). + * @param sender - the account that generates this request. + * @param paymaster - if non-null, the paymaster that pays for this request. + * @param nonce - the nonce value from the request. + * @param success - true if the sender transaction succeeded, false if reverted. + * @param actualGasCost - actual amount paid (by account or paymaster) for this UserOperation. + * @param actualGasUsed - total gas used by this UserOperation (including preVerification, creation, validation and execution). + */ + event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed); + + /** + * account "sender" was deployed. + * @param userOpHash the userOp that deployed this account. UserOperationEvent will follow. + * @param sender the account that is deployed + * @param factory the factory used to deploy this account (in the initCode) + * @param paymaster the paymaster used by this UserOp + */ + event AccountDeployed(bytes32 indexed userOpHash, address indexed sender, address factory, address paymaster); + + /** + * An event emitted if the UserOperation "callData" reverted with non-zero length + * @param userOpHash the request unique identifier. + * @param sender the sender of this request + * @param nonce the nonce used in the request + * @param revertReason - the return bytes from the (reverted) call to "callData". + */ + event UserOperationRevertReason(bytes32 indexed userOpHash, address indexed sender, uint256 nonce, bytes revertReason); + + /** + * an event emitted by handleOps(), before starting the execution loop. + * any event emitted before this event, is part of the validation. + */ + event BeforeExecution(); + + /** + * signature aggregator used by the following UserOperationEvents within this bundle. + */ + event SignatureAggregatorChanged(address indexed aggregator); + + /** + * a custom revert error of handleOps, to identify the offending op. + * NOTE: if simulateValidation passes successfully, there should be no reason for handleOps to fail on it. + * @param opIndex - index into the array of ops to the failed one (in simulateValidation, this is always zero) + * @param reason - revert reason + * The string starts with a unique code "AAmn", where "m" is "1" for factory, "2" for account and "3" for paymaster issues, + * so a failure can be attributed to the correct entity. + * Should be caught in off-chain handleOps simulation and not happen on-chain. + * Useful for mitigating DoS attempts against batchers or for troubleshooting of factory/account/paymaster reverts. + */ + error FailedOp(uint256 opIndex, string reason); + + /** + * error case when a signature aggregator fails to verify the aggregated signature it had created. + */ + error SignatureValidationFailed(address aggregator); + + /** + * Successful result from simulateValidation. + * @param returnInfo gas and time-range returned values + * @param senderInfo stake information about the sender + * @param factoryInfo stake information about the factory (if any) + * @param paymasterInfo stake information about the paymaster (if any) + */ + error ValidationResult(ReturnInfo returnInfo, + StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo); + + /** + * Successful result from simulateValidation, if the account returns a signature aggregator + * @param returnInfo gas and time-range returned values + * @param senderInfo stake information about the sender + * @param factoryInfo stake information about the factory (if any) + * @param paymasterInfo stake information about the paymaster (if any) + * @param aggregatorInfo signature aggregation info (if the account requires signature aggregator) + * bundler MUST use it to verify the signature, or reject the UserOperation + */ + error ValidationResultWithAggregation(ReturnInfo returnInfo, + StakeInfo senderInfo, StakeInfo factoryInfo, StakeInfo paymasterInfo, + AggregatorStakeInfo aggregatorInfo); + + /** + * return value of getSenderAddress + */ + error SenderAddressResult(address sender); + + /** + * return value of simulateHandleOp + */ + error ExecutionResult(uint256 preOpGas, uint256 paid, uint48 validAfter, uint48 validUntil, bool targetSuccess, bytes targetResult); + + //UserOps handled, per aggregator + struct UserOpsPerAggregator { + UserOperation[] userOps; + + // aggregator address + IAggregator aggregator; + // aggregated signature + bytes signature; + } + + /** + * Execute a batch of UserOperation. + * no signature aggregator is used. + * if any account requires an aggregator (that is, it returned an aggregator when + * performing simulateValidation), then handleAggregatedOps() must be used instead. + * @param ops the operations to execute + * @param beneficiary the address to receive the fees + */ + function handleOps(UserOperation[] calldata ops, address payable beneficiary) external; + + /** + * Execute a batch of UserOperation with Aggregators + * @param opsPerAggregator the operations to execute, grouped by aggregator (or address(0) for no-aggregator accounts) + * @param beneficiary the address to receive the fees + */ + function handleAggregatedOps( + UserOpsPerAggregator[] calldata opsPerAggregator, + address payable beneficiary + ) external; + + /** + * generate a request Id - unique identifier for this request. + * the request ID is a hash over the content of the userOp (except the signature), the entrypoint and the chainid. + */ + function getUserOpHash(UserOperation calldata userOp) external view returns (bytes32); + + /** + * Simulate a call to account.validateUserOp and paymaster.validatePaymasterUserOp. + * @dev this method always revert. Successful result is ValidationResult error. other errors are failures. + * @dev The node must also verify it doesn't use banned opcodes, and that it doesn't reference storage outside the account's data. + * @param userOp the user operation to validate. + */ + function simulateValidation(UserOperation calldata userOp) external; + + /** + * gas and return values during simulation + * @param preOpGas the gas used for validation (including preValidationGas) + * @param prefund the required prefund for this operation + * @param sigFailed validateUserOp's (or paymaster's) signature check failed + * @param validAfter - first timestamp this UserOp is valid (merging account and paymaster time-range) + * @param validUntil - last timestamp this UserOp is valid (merging account and paymaster time-range) + * @param paymasterContext returned by validatePaymasterUserOp (to be passed into postOp) + */ + struct ReturnInfo { + uint256 preOpGas; + uint256 prefund; + bool sigFailed; + uint48 validAfter; + uint48 validUntil; + bytes paymasterContext; + } + + /** + * returned aggregated signature info. + * the aggregator returned by the account, and its current stake. + */ + struct AggregatorStakeInfo { + address aggregator; + StakeInfo stakeInfo; + } + + /** + * Get counterfactual sender address. + * Calculate the sender contract address that will be generated by the initCode and salt in the UserOperation. + * this method always revert, and returns the address in SenderAddressResult error + * @param initCode the constructor code to be passed into the UserOperation. + */ + function getSenderAddress(bytes memory initCode) external; + + + /** + * simulate full execution of a UserOperation (including both validation and target execution) + * this method will always revert with "ExecutionResult". + * it performs full validation of the UserOperation, but ignores signature error. + * an optional target address is called after the userop succeeds, and its value is returned + * (before the entire call is reverted) + * Note that in order to collect the the success/failure of the target call, it must be executed + * with trace enabled to track the emitted events. + * @param op the UserOperation to simulate + * @param target if nonzero, a target address to call after userop simulation. If called, the targetSuccess and targetResult + * are set to the return from that call. + * @param targetCallData callData to pass to target address + */ + function simulateHandleOp(UserOperation calldata op, address target, bytes calldata targetCallData) external; +} + diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/INonceManager.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/INonceManager.sol new file mode 100644 index 000000000..fe649130b --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/INonceManager.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +interface INonceManager { + + /** + * Return the next nonce for this sender. + * Within a given key, the nonce values are sequenced (starting with zero, and incremented by one on each userop) + * But UserOp with different keys can come with arbitrary order. + * + * @param sender the account address + * @param key the high 192 bit of the nonce + * @return nonce a full nonce to pass for next UserOp with this sender. + */ + function getNonce(address sender, uint192 key) + external view returns (uint256 nonce); + + /** + * Manually increment the nonce of the sender. + * This method is exposed just for completeness.. + * Account does NOT need to call it, neither during validation, nor elsewhere, + * as the EntryPoint will update the nonce regardless. + * Possible use-case is call it with various keys to "initialize" their nonces to one, so that future + * UserOperations will not pay extra for the first transaction with a given key. + */ + function incrementNonce(uint192 key) external; +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/IPaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/IPaymaster.sol new file mode 100644 index 000000000..af50367ac --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/IPaymaster.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "./UserOperation.sol"; + +/** + * the interface exposed by a paymaster contract, who agrees to pay the gas for user's operations. + * a paymaster must hold a stake to cover the required entrypoint stake and also the gas for the transaction. + */ +interface IPaymaster { + + enum PostOpMode { + opSucceeded, // user op succeeded + opReverted, // user op reverted. still has to pay for gas. + postOpReverted //user op succeeded, but caused postOp to revert. Now it's a 2nd call, after user's op was deliberately reverted. + } + + /** + * payment validation: check if paymaster agrees to pay. + * Must verify sender is the entryPoint. + * Revert to reject this request. + * Note that bundlers will reject this method if it changes the state, unless the paymaster is trusted (whitelisted) + * The paymaster pre-pays using its deposit, and receive back a refund after the postOp method returns. + * @param userOp the user operation + * @param userOpHash hash of the user's request data. + * @param maxCost the maximum cost of this transaction (based on maximum gas and gas price from userOp) + * @return context value to send to a postOp + * zero length to signify postOp is not required. + * @return validationData signature and time-range of this operation, encoded the same as the return value of validateUserOperation + * <20-byte> sigAuthorizer - 0 for valid signature, 1 to mark signature failure, + * otherwise, an address of an "authorizer" contract. + * <6-byte> validUntil - last timestamp this operation is valid. 0 for "indefinite" + * <6-byte> validAfter - first timestamp this operation is valid + * Note that the validation code cannot use block.timestamp (or block.number) directly. + */ + function validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + external returns (bytes memory context, uint256 validationData); + + /** + * post-operation handler. + * Must verify sender is the entryPoint + * @param mode enum with the following options: + * opSucceeded - user operation succeeded. + * opReverted - user op reverted. still has to pay for gas. + * postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert. + * Now this is the 2nd call, after user's op was deliberately reverted. + * @param context - the context value returned by validatePaymasterUserOp + * @param actualGasCost - actual gas used so far (without this postOp call). + */ + function postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) external; +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/IStakeManager.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/IStakeManager.sol new file mode 100644 index 000000000..c19c1bab8 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/IStakeManager.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +/** + * manage deposits and stakes. + * deposit is just a balance used to pay for UserOperations (either by a paymaster or an account) + * stake is value locked for at least "unstakeDelay" by the staked entity. + */ +interface IStakeManager { + + event Deposited( + address indexed account, + uint256 totalDeposit + ); + + event Withdrawn( + address indexed account, + address withdrawAddress, + uint256 amount + ); + + /// Emitted when stake or unstake delay are modified + event StakeLocked( + address indexed account, + uint256 totalStaked, + uint256 unstakeDelaySec + ); + + /// Emitted once a stake is scheduled for withdrawal + event StakeUnlocked( + address indexed account, + uint256 withdrawTime + ); + + event StakeWithdrawn( + address indexed account, + address withdrawAddress, + uint256 amount + ); + + /** + * @param deposit the entity's deposit + * @param staked true if this entity is staked. + * @param stake actual amount of ether staked for this entity. + * @param unstakeDelaySec minimum delay to withdraw the stake. + * @param withdrawTime - first block timestamp where 'withdrawStake' will be callable, or zero if already locked + * @dev sizes were chosen so that (deposit,staked, stake) fit into one cell (used during handleOps) + * and the rest fit into a 2nd cell. + * 112 bit allows for 10^15 eth + * 48 bit for full timestamp + * 32 bit allows 150 years for unstake delay + */ + struct DepositInfo { + uint112 deposit; + bool staked; + uint112 stake; + uint32 unstakeDelaySec; + uint48 withdrawTime; + } + + //API struct used by getStakeInfo and simulateValidation + struct StakeInfo { + uint256 stake; + uint256 unstakeDelaySec; + } + + /// @return info - full deposit information of given account + function getDepositInfo(address account) external view returns (DepositInfo memory info); + + /// @return the deposit (for gas payment) of the account + function balanceOf(address account) external view returns (uint256); + + /** + * add to the deposit of the given account + */ + function depositTo(address account) external payable; + + /** + * add to the account's stake - amount and delay + * any pending unstake is first cancelled. + * @param _unstakeDelaySec the new lock duration before the deposit can be withdrawn. + */ + function addStake(uint32 _unstakeDelaySec) external payable; + + /** + * attempt to unlock the stake. + * the value can be withdrawn (using withdrawStake) after the unstake delay. + */ + function unlockStake() external; + + /** + * withdraw from the (unlocked) stake. + * must first call unlockStake and wait for the unstakeDelay to pass + * @param withdrawAddress the address to send withdrawn value. + */ + function withdrawStake(address payable withdrawAddress) external; + + /** + * withdraw from the deposit. + * @param withdrawAddress the address to send withdrawn value. + * @param withdrawAmount the amount to withdraw. + */ + function withdrawTo(address payable withdrawAddress, uint256 withdrawAmount) external; +} diff --git a/packages/hebao_v3/contracts/account-abstraction/interfaces/UserOperation.sol b/packages/hebao_v3/contracts/account-abstraction/interfaces/UserOperation.sol new file mode 100644 index 000000000..46ca75c6d --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/interfaces/UserOperation.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable no-inline-assembly */ + +import {calldataKeccak} from "../core/Helpers.sol"; + +/** + * User Operation struct + * @param sender the sender account of this request. + * @param nonce unique value the sender uses to verify it is not a replay. + * @param initCode if set, the account contract will be created by this constructor/ + * @param callData the method call to execute on this account. + * @param callGasLimit the gas limit passed to the callData method call. + * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp. + * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead. + * @param maxFeePerGas same as EIP-1559 gas parameter. + * @param maxPriorityFeePerGas same as EIP-1559 gas parameter. + * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender. + * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID. + */ + struct UserOperation { + + address sender; + uint256 nonce; + bytes initCode; + bytes callData; + uint256 callGasLimit; + uint256 verificationGasLimit; + uint256 preVerificationGas; + uint256 maxFeePerGas; + uint256 maxPriorityFeePerGas; + bytes paymasterAndData; + bytes signature; + } + +/** + * Utility functions helpful when working with UserOperation structs. + */ +library UserOperationLib { + + function getSender(UserOperation calldata userOp) internal pure returns (address) { + address data; + //read sender from userOp, which is first userOp member (saves 800 gas...) + assembly {data := calldataload(userOp)} + return address(uint160(data)); + } + + //relayer/block builder might submit the TX with higher priorityFee, but the user should not + // pay above what he signed for. + function gasPrice(UserOperation calldata userOp) internal view returns (uint256) { + unchecked { + uint256 maxFeePerGas = userOp.maxFeePerGas; + uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; + if (maxFeePerGas == maxPriorityFeePerGas) { + //legacy mode (for networks that don't support basefee opcode) + return maxFeePerGas; + } + return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); + } + } + + function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) { + address sender = getSender(userOp); + uint256 nonce = userOp.nonce; + bytes32 hashInitCode = calldataKeccak(userOp.initCode); + bytes32 hashCallData = calldataKeccak(userOp.callData); + uint256 callGasLimit = userOp.callGasLimit; + uint256 verificationGasLimit = userOp.verificationGasLimit; + uint256 preVerificationGas = userOp.preVerificationGas; + uint256 maxFeePerGas = userOp.maxFeePerGas; + uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; + bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); + + return abi.encode( + sender, nonce, + hashInitCode, hashCallData, + callGasLimit, verificationGasLimit, preVerificationGas, + maxFeePerGas, maxPriorityFeePerGas, + hashPaymasterAndData + ); + } + + function hash(UserOperation calldata userOp) internal pure returns (bytes32) { + return keccak256(pack(userOp)); + } + + function min(uint256 a, uint256 b) internal pure returns (uint256) { + return a < b ? a : b; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/DepositPaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/samples/DepositPaymaster.sol new file mode 100644 index 000000000..84bfffcec --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/DepositPaymaster.sol @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable reason-string */ + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; + +import "../core/BasePaymaster.sol"; +import "./IOracle.sol"; + +/** + * A token-based paymaster that accepts token deposits + * The deposit is only a safeguard: the user pays with his token balance. + * only if the user didn't approve() the paymaster, or if the token balance is not enough, the deposit will be used. + * thus the required deposit is to cover just one method call. + * The deposit is locked for the current block: the user must issue unlockTokenDeposit() to be allowed to withdraw + * (but can't use the deposit for this or further operations) + * + * paymasterAndData holds the paymaster address followed by the token address to use. + * @notice This paymaster will be rejected by the standard rules of EIP4337, as it uses an external oracle. + * (the standard rules ban accessing data of an external contract) + * It can only be used if it is "whitelisted" by the bundler. + * (technically, it can be used by an "oracle" which returns a static value, without accessing any storage) + */ +contract DepositPaymaster is BasePaymaster { + + using UserOperationLib for UserOperation; + using SafeERC20 for IERC20; + + //calculated cost of the postOp + uint256 constant public COST_OF_POST = 35000; + + IOracle private constant NULL_ORACLE = IOracle(address(0)); + mapping(IERC20 => IOracle) public oracles; + mapping(IERC20 => mapping(address => uint256)) public balances; + mapping(address => uint256) public unlockBlock; + + constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) { + //owner account is unblocked, to allow withdraw of paid tokens; + unlockTokenDeposit(); + } + + /** + * owner of the paymaster should add supported tokens + */ + function addToken(IERC20 token, IOracle tokenPriceOracle) external onlyOwner { + require(oracles[token] == NULL_ORACLE, "Token already set"); + oracles[token] = tokenPriceOracle; + } + + /** + * deposit tokens that a specific account can use to pay for gas. + * The sender must first approve this paymaster to withdraw these tokens (they are only withdrawn in this method). + * Note depositing the tokens is equivalent to transferring them to the "account" - only the account can later + * use them - either as gas, or using withdrawTo() + * + * @param token the token to deposit. + * @param account the account to deposit for. + * @param amount the amount of token to deposit. + */ + function addDepositFor(IERC20 token, address account, uint256 amount) external { + //(sender must have approval for the paymaster) + token.safeTransferFrom(msg.sender, address(this), amount); + require(oracles[token] != NULL_ORACLE, "unsupported token"); + balances[token][account] += amount; + if (msg.sender == account) { + lockTokenDeposit(); + } + } + + /** + * @return amount - the amount of given token deposited to the Paymaster. + * @return _unlockBlock - the block height at which the deposit can be withdrawn. + */ + function depositInfo(IERC20 token, address account) public view returns (uint256 amount, uint256 _unlockBlock) { + amount = balances[token][account]; + _unlockBlock = unlockBlock[account]; + } + + /** + * unlock deposit, so that it can be withdrawn. + * can't be called in the same block as withdrawTo() + */ + function unlockTokenDeposit() public { + unlockBlock[msg.sender] = block.number; + } + + /** + * lock the tokens deposited for this account so they can be used to pay for gas. + * after calling unlockTokenDeposit(), the account can't use this paymaster until the deposit is locked. + */ + function lockTokenDeposit() public { + unlockBlock[msg.sender] = 0; + } + + /** + * withdraw tokens. + * can only be called after unlock() is called in a previous block. + * @param token the token deposit to withdraw + * @param target address to send to + * @param amount amount to withdraw + */ + function withdrawTokensTo(IERC20 token, address target, uint256 amount) public { + require(unlockBlock[msg.sender] != 0 && block.number > unlockBlock[msg.sender], "DepositPaymaster: must unlockTokenDeposit"); + balances[token][msg.sender] -= amount; + token.safeTransfer(target, amount); + } + + /** + * translate the given eth value to token amount + * @param token the token to use + * @param ethBought the required eth value we want to "buy" + * @return requiredTokens the amount of tokens required to get this amount of eth + */ + function getTokenValueOfEth(IERC20 token, uint256 ethBought) internal view virtual returns (uint256 requiredTokens) { + IOracle oracle = oracles[token]; + require(oracle != NULL_ORACLE, "DepositPaymaster: unsupported token"); + return oracle.getTokenValueOfEth(ethBought); + } + + /** + * Validate the request: + * The sender should have enough deposit to pay the max possible cost. + * Note that the sender's balance is not checked. If it fails to pay from its balance, + * this deposit will be used to compensate the paymaster for the transaction. + */ + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + internal view override returns (bytes memory context, uint256 validationData) { + + (userOpHash); + // verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough + require(userOp.verificationGasLimit > COST_OF_POST, "DepositPaymaster: gas too low for postOp"); + + bytes calldata paymasterAndData = userOp.paymasterAndData; + require(paymasterAndData.length == 20+20, "DepositPaymaster: paymasterAndData must specify token"); + IERC20 token = IERC20(address(bytes20(paymasterAndData[20:]))); + address account = userOp.getSender(); + uint256 maxTokenCost = getTokenValueOfEth(token, maxCost); + uint256 gasPriceUserOp = userOp.gasPrice(); + require(unlockBlock[account] == 0, "DepositPaymaster: deposit not locked"); + require(balances[token][account] >= maxTokenCost, "DepositPaymaster: deposit too low"); + return (abi.encode(account, token, gasPriceUserOp, maxTokenCost, maxCost),0); + } + + /** + * perform the post-operation to charge the sender for the gas. + * in normal mode, use transferFrom to withdraw enough tokens from the sender's balance. + * in case the transferFrom fails, the _postOp reverts and the entryPoint will call it again, + * this time in *postOpReverted* mode. + * In this mode, we use the deposit to pay (which we validated to be large enough) + */ + function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override { + + (address account, IERC20 token, uint256 gasPricePostOp, uint256 maxTokenCost, uint256 maxCost) = abi.decode(context, (address, IERC20, uint256, uint256, uint256)); + //use same conversion rate as used for validation. + uint256 actualTokenCost = (actualGasCost + COST_OF_POST * gasPricePostOp) * maxTokenCost / maxCost; + if (mode != PostOpMode.postOpReverted) { + // attempt to pay with tokens: + token.safeTransferFrom(account, address(this), actualTokenCost); + } else { + //in case above transferFrom failed, pay with deposit: + balances[token][account] -= actualTokenCost; + } + balances[token][owner()] += actualTokenCost; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/IOracle.sol b/packages/hebao_v3/contracts/account-abstraction/samples/IOracle.sol new file mode 100644 index 000000000..06fdf2a5d --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/IOracle.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +interface IOracle { + + /** + * return amount of tokens that are required to receive that much eth. + */ + function getTokenValueOfEth(uint256 ethOutput) external view returns (uint256 tokenInput); +} + diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccount.sol b/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccount.sol new file mode 100644 index 000000000..6c1a19825 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccount.sol @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable no-inline-assembly */ +/* solhint-disable reason-string */ + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts/proxy/utils/Initializable.sol"; +import "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; + +import "../core/BaseAccount.sol"; +import "./callback/TokenCallbackHandler.sol"; + +/** + * minimal account. + * this is sample minimal account. + * has execute, eth handling methods + * has a single signer that can send requests through the entryPoint. + */ +contract SimpleAccount is BaseAccount, TokenCallbackHandler, UUPSUpgradeable, Initializable { + using ECDSA for bytes32; + + address public owner; + + IEntryPoint private immutable _entryPoint; + + event SimpleAccountInitialized(IEntryPoint indexed entryPoint, address indexed owner); + + modifier onlyOwner() { + _onlyOwner(); + _; + } + + /// @inheritdoc BaseAccount + function entryPoint() public view virtual override returns (IEntryPoint) { + return _entryPoint; + } + + + // solhint-disable-next-line no-empty-blocks + receive() external payable {} + + constructor(IEntryPoint anEntryPoint) { + _entryPoint = anEntryPoint; + _disableInitializers(); + } + + function _onlyOwner() internal view { + //directly from EOA owner, or through the account itself (which gets redirected through execute()) + require(msg.sender == owner || msg.sender == address(this), "only owner"); + } + + /** + * execute a transaction (called directly from owner, or by entryPoint) + */ + function execute(address dest, uint256 value, bytes calldata func) external { + _requireFromEntryPointOrOwner(); + _call(dest, value, func); + } + + /** + * execute a sequence of transactions + */ + function executeBatch(address[] calldata dest, bytes[] calldata func) external { + _requireFromEntryPointOrOwner(); + require(dest.length == func.length, "wrong array lengths"); + for (uint256 i = 0; i < dest.length; i++) { + _call(dest[i], 0, func[i]); + } + } + + /** + * @dev The _entryPoint member is immutable, to reduce gas consumption. To upgrade EntryPoint, + * a new implementation of SimpleAccount must be deployed with the new EntryPoint address, then upgrading + * the implementation by calling `upgradeTo()` + */ + function initialize(address anOwner) public virtual initializer { + _initialize(anOwner); + } + + function _initialize(address anOwner) internal virtual { + owner = anOwner; + emit SimpleAccountInitialized(_entryPoint, owner); + } + + // Require the function call went through EntryPoint or owner + function _requireFromEntryPointOrOwner() internal view { + require(msg.sender == address(entryPoint()) || msg.sender == owner, "account: not Owner or EntryPoint"); + } + + /// implement template method of BaseAccount + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal override virtual returns (uint256 validationData) { + bytes32 hash = userOpHash.toEthSignedMessageHash(); + if (owner != hash.recover(userOp.signature)) + return SIG_VALIDATION_FAILED; + return 0; + } + + function _call(address target, uint256 value, bytes memory data) internal { + (bool success, bytes memory result) = target.call{value : value}(data); + if (!success) { + assembly { + revert(add(result, 32), mload(result)) + } + } + } + + /** + * check current account deposit in the entryPoint + */ + function getDeposit() public view returns (uint256) { + return entryPoint().balanceOf(address(this)); + } + + /** + * deposit more funds for this account in the entryPoint + */ + function addDeposit() public payable { + entryPoint().depositTo{value : msg.value}(address(this)); + } + + /** + * withdraw value from the account's deposit + * @param withdrawAddress target to send to + * @param amount to withdraw + */ + function withdrawDepositTo(address payable withdrawAddress, uint256 amount) public onlyOwner { + entryPoint().withdrawTo(withdrawAddress, amount); + } + + function _authorizeUpgrade(address newImplementation) internal view override { + (newImplementation); + _onlyOwner(); + } +} + diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccountFactory.sol b/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccountFactory.sol new file mode 100644 index 000000000..25f37f152 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/SimpleAccountFactory.sol @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +import "./SimpleAccount.sol"; + +/** + * A sample factory contract for SimpleAccount + * A UserOperations "initCode" holds the address of the factory, and a method call (to createAccount, in this sample factory). + * The factory's createAccount returns the target account address even if it is already installed. + * This way, the entryPoint.getSenderAddress() can be called either before or after the account is created. + */ +contract SimpleAccountFactory { + SimpleAccount public immutable accountImplementation; + + constructor(IEntryPoint _entryPoint) { + accountImplementation = new SimpleAccount(_entryPoint); + } + + /** + * create an account, and return its address. + * returns the address even if the account is already deployed. + * Note that during UserOperation execution, this method is called only if the account is not deployed. + * This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation + */ + function createAccount(address owner,uint256 salt) public returns (SimpleAccount ret) { + address addr = getAddress(owner, salt); + uint codeSize = addr.code.length; + if (codeSize > 0) { + return SimpleAccount(payable(addr)); + } + ret = SimpleAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}( + address(accountImplementation), + abi.encodeCall(SimpleAccount.initialize, (owner)) + ))); + } + + /** + * calculate the counterfactual address of this account as it would be returned by createAccount() + */ + function getAddress(address owner,uint256 salt) public view returns (address) { + return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked( + type(ERC1967Proxy).creationCode, + abi.encode( + address(accountImplementation), + abi.encodeCall(SimpleAccount.initialize, (owner)) + ) + ))); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/TokenPaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/samples/TokenPaymaster.sol new file mode 100644 index 000000000..452080716 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/TokenPaymaster.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable reason-string */ + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../core/BasePaymaster.sol"; + +/** + * A sample paymaster that defines itself as a token to pay for gas. + * The paymaster IS the token to use, since a paymaster cannot use an external contract. + * Also, the exchange rate has to be fixed, since it can't reference an external Uniswap or other exchange contract. + * subclass should override "getTokenValueOfEth" to provide actual token exchange rate, settable by the owner. + * Known Limitation: this paymaster is exploitable when put into a batch with multiple ops (of different accounts): + * - while a single op can't exploit the paymaster (if postOp fails to withdraw the tokens, the user's op is reverted, + * and then we know we can withdraw the tokens), multiple ops with different senders (all using this paymaster) + * in a batch can withdraw funds from 2nd and further ops, forcing the paymaster itself to pay (from its deposit) + * - Possible workarounds are either use a more complex paymaster scheme (e.g. the DepositPaymaster) or + * to whitelist the account and the called method ids. + */ +contract TokenPaymaster is BasePaymaster, ERC20 { + + //calculated cost of the postOp + uint256 constant public COST_OF_POST = 15000; + + address public immutable theFactory; + + constructor(address accountFactory, string memory _symbol, IEntryPoint _entryPoint) ERC20(_symbol, _symbol) BasePaymaster(_entryPoint) { + theFactory = accountFactory; + //make it non-empty + _mint(address(this), 1); + + //owner is allowed to withdraw tokens from the paymaster's balance + _approve(address(this), msg.sender, type(uint).max); + } + + + /** + * helpers for owner, to mint and withdraw tokens. + * @param recipient - the address that will receive the minted tokens. + * @param amount - the amount it will receive. + */ + function mintTokens(address recipient, uint256 amount) external onlyOwner { + _mint(recipient, amount); + } + + /** + * transfer paymaster ownership. + * owner of this paymaster is allowed to withdraw funds (tokens transferred to this paymaster's balance) + * when changing owner, the old owner's withdrawal rights are revoked. + */ + function transferOwnership(address newOwner) public override virtual onlyOwner { + // remove allowance of current owner + _approve(address(this), owner(), 0); + super.transferOwnership(newOwner); + // new owner is allowed to withdraw tokens from the paymaster's balance + _approve(address(this), newOwner, type(uint).max); + } + + //Note: this method assumes a fixed ratio of token-to-eth. subclass should override to supply oracle + // or a setter. + function getTokenValueOfEth(uint256 valueEth) internal view virtual returns (uint256 valueToken) { + return valueEth / 100; + } + + /** + * validate the request: + * if this is a constructor call, make sure it is a known account. + * verify the sender has enough tokens. + * (since the paymaster is also the token, there is no notion of "approval") + */ + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund) + internal view override returns (bytes memory context, uint256 validationData) { + uint256 tokenPrefund = getTokenValueOfEth(requiredPreFund); + + // verificationGasLimit is dual-purposed, as gas limit for postOp. make sure it is high enough + // make sure that verificationGasLimit is high enough to handle postOp + require(userOp.verificationGasLimit > COST_OF_POST, "TokenPaymaster: gas too low for postOp"); + + if (userOp.initCode.length != 0) { + _validateConstructor(userOp); + require(balanceOf(userOp.sender) >= tokenPrefund, "TokenPaymaster: no balance (pre-create)"); + } else { + + require(balanceOf(userOp.sender) >= tokenPrefund, "TokenPaymaster: no balance"); + } + + return (abi.encode(userOp.sender), 0); + } + + // when constructing an account, validate constructor code and parameters + // we trust our factory (and that it doesn't have any other public methods) + function _validateConstructor(UserOperation calldata userOp) internal virtual view { + address factory = address(bytes20(userOp.initCode[0 : 20])); + require(factory == theFactory, "TokenPaymaster: wrong account factory"); + } + + /** + * actual charge of user. + * this method will be called just after the user's TX with mode==OpSucceeded|OpReverted (account pays in both cases) + * BUT: if the user changed its balance in a way that will cause postOp to revert, then it gets called again, after reverting + * the user's TX , back to the state it was before the transaction started (before the validatePaymasterUserOp), + * and the transaction should succeed there. + */ + function _postOp(PostOpMode mode, bytes calldata context, uint256 actualGasCost) internal override { + //we don't really care about the mode, we just pay the gas with the user's tokens. + (mode); + address sender = abi.decode(context, (address)); + uint256 charge = getTokenValueOfEth(actualGasCost + COST_OF_POST); + //actualGasCost is known to be no larger than the above requiredPreFund, so the transfer should succeed. + _transfer(sender, address(this), charge); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/VerifyingPaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/samples/VerifyingPaymaster.sol new file mode 100644 index 000000000..556ba5c23 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/VerifyingPaymaster.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable reason-string */ +/* solhint-disable no-inline-assembly */ + +import "../core/BasePaymaster.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +/** + * A sample paymaster that uses external service to decide whether to pay for the UserOp. + * The paymaster trusts an external signer to sign the transaction. + * The calling user must pass the UserOp to that external signer first, which performs + * whatever off-chain verification before signing the UserOp. + * Note that this signature is NOT a replacement for the account-specific signature: + * - the paymaster checks a signature to agree to PAY for GAS. + * - the account checks a signature to prove identity and account ownership. + */ +contract VerifyingPaymaster is BasePaymaster { + + using ECDSA for bytes32; + using UserOperationLib for UserOperation; + + address public immutable verifyingSigner; + + uint256 private constant VALID_TIMESTAMP_OFFSET = 20; + + uint256 private constant SIGNATURE_OFFSET = 84; + + constructor(IEntryPoint _entryPoint, address _verifyingSigner) BasePaymaster(_entryPoint) { + verifyingSigner = _verifyingSigner; + } + + mapping(address => uint256) public senderNonce; + + function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) { + // lighter signature scheme. must match UserOp.ts#packUserOp + bytes calldata pnd = userOp.paymasterAndData; + // copy directly the userOp from calldata up to (but not including) the paymasterAndData. + // this encoding depends on the ABI encoding of calldata, but is much lighter to copy + // than referencing each field separately. + assembly { + let ofs := userOp + let len := sub(sub(pnd.offset, ofs), 32) + ret := mload(0x40) + mstore(0x40, add(ret, add(len, 32))) + mstore(ret, len) + calldatacopy(add(ret, 32), ofs, len) + } + } + + /** + * return the hash we're going to sign off-chain (and validate on-chain) + * this method is called by the off-chain service, to sign the request. + * it is called on-chain from the validatePaymasterUserOp, to validate the signature. + * note that this signature covers all fields of the UserOperation, except the "paymasterAndData", + * which will carry the signature itself. + */ + function getHash(UserOperation calldata userOp, uint48 validUntil, uint48 validAfter) + public view returns (bytes32) { + //can't use userOp.hash(), since it contains also the paymasterAndData itself. + + return keccak256(abi.encode( + pack(userOp), + block.chainid, + address(this), + senderNonce[userOp.getSender()], + validUntil, + validAfter + )); + } + + /** + * verify our external signer signed this request. + * the "paymasterAndData" is expected to be the paymaster and a signature over the entire request params + * paymasterAndData[:20] : address(this) + * paymasterAndData[20:84] : abi.encode(validUntil, validAfter) + * paymasterAndData[84:] : signature + */ + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 /*userOpHash*/, uint256 requiredPreFund) + internal override returns (bytes memory context, uint256 validationData) { + (requiredPreFund); + + (uint48 validUntil, uint48 validAfter, bytes calldata signature) = parsePaymasterAndData(userOp.paymasterAndData); + //ECDSA library supports both 64 and 65-byte long signatures. + // we only "require" it here so that the revert reason on invalid signature will be of "VerifyingPaymaster", and not "ECDSA" + require(signature.length == 64 || signature.length == 65, "VerifyingPaymaster: invalid signature length in paymasterAndData"); + bytes32 hash = ECDSA.toEthSignedMessageHash(getHash(userOp, validUntil, validAfter)); + senderNonce[userOp.getSender()]++; + + //don't revert on signature failure: return SIG_VALIDATION_FAILED + if (verifyingSigner != ECDSA.recover(hash, signature)) { + return ("",_packValidationData(true,validUntil,validAfter)); + } + + //no need for other on-chain validation: entire UserOp should have been checked + // by the external service prior to signing it. + return ("",_packValidationData(false,validUntil,validAfter)); + } + + function parsePaymasterAndData(bytes calldata paymasterAndData) public pure returns(uint48 validUntil, uint48 validAfter, bytes calldata signature) { + (validUntil, validAfter) = abi.decode(paymasterAndData[VALID_TIMESTAMP_OFFSET:SIGNATURE_OFFSET],(uint48, uint48)); + signature = paymasterAndData[SIGNATURE_OFFSET:]; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccount.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccount.sol new file mode 100644 index 000000000..efc64ce15 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccount.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../SimpleAccount.sol"; +import "./IBLSAccount.sol"; + +/** + * Minimal BLS-based account that uses an aggregated signature. + * The account must maintain its own BLS public key, and expose its trusted signature aggregator. + * Note that unlike the "standard" SimpleAccount, this account can't be called directly + * (normal SimpleAccount uses its "signer" address as both the ecrecover signer, and as a legitimate + * Ethereum sender address. Obviously, a BLS public key is not a valid Ethereum sender address.) + */ +contract BLSAccount is SimpleAccount, IBLSAccount { + address public immutable aggregator; + uint256[4] private publicKey; + + // The constructor is used only for the "implementation" and only sets immutable values. + // Mutable value slots for proxy accounts are set by the 'initialize' function. + constructor(IEntryPoint anEntryPoint, address anAggregator) SimpleAccount(anEntryPoint) { + aggregator = anAggregator; + } + + /** + * The initializer for the BLSAccount instance. + * @param aPublicKey public key from a BLS keypair that will have a full ownership and control of this account. + */ + function initialize(uint256[4] memory aPublicKey) public virtual initializer { + super._initialize(address(0)); + _setBlsPublicKey(aPublicKey); + } + + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal override view returns (uint256 validationData) { + + (userOp, userOpHash); + if (userOp.initCode.length != 0) { + // BLSSignatureAggregator.getUserOpPublicKey() assumes that during account creation, the public key is + // the suffix of the initCode. + // The account MUST validate it + bytes32 pubKeyHash = keccak256(abi.encode(getBlsPublicKey())); + require(keccak256(userOp.initCode[userOp.initCode.length - 128 :]) == pubKeyHash, "wrong pubkey"); + } + return _packValidationData(ValidationData(aggregator, 0,0)); + } + + /** + * Allows the owner to set or change the BLS key. + * @param newPublicKey public key from a BLS keypair that will have a full ownership and control of this account. + */ + function setBlsPublicKey(uint256[4] memory newPublicKey) public onlyOwner { + _setBlsPublicKey(newPublicKey); + } + + function _setBlsPublicKey(uint256[4] memory newPublicKey) internal { + emit PublicKeyChanged(publicKey, newPublicKey); + publicKey = newPublicKey; + } + + /// @inheritdoc IBLSAccount + function getBlsPublicKey() public override view returns (uint256[4] memory) { + return publicKey; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccountFactory.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccountFactory.sol new file mode 100644 index 000000000..4096a3839 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSAccountFactory.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +import "../../interfaces/IEntryPoint.sol"; +import "./BLSAccount.sol"; + +/* solhint-disable no-inline-assembly */ + +/** + * Based on SimpleAccountFactory. + * Cannot be a subclass since both constructor and createAccount depend on the + * constructor and initializer of the actual account contract. + */ +contract BLSAccountFactory { + BLSAccount public immutable accountImplementation; + + constructor(IEntryPoint entryPoint, address aggregator){ + accountImplementation = new BLSAccount(entryPoint, aggregator); + } + + /** + * create an account, and return its address. + * returns the address even if the account is already deployed. + * Note that during UserOperation execution, this method is called only if the account is not deployed. + * This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation + * Also note that our BLSSignatureAggregator requires that the public key is the last parameter + */ + function createAccount(uint256 salt, uint256[4] calldata aPublicKey) public returns (BLSAccount) { + + // the BLSSignatureAggregator depends on the public-key being the last 4 uint256 of msg.data. + uint slot; + assembly {slot := aPublicKey} + require(slot == msg.data.length - 128, "wrong pubkey offset"); + + address addr = getAddress(salt, aPublicKey); + uint codeSize = addr.code.length; + if (codeSize > 0) { + return BLSAccount(payable(addr)); + } + return BLSAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}( + address(accountImplementation), + abi.encodeCall(BLSAccount.initialize, aPublicKey) + ))); + } + + /** + * calculate the counterfactual address of this account as it would be returned by createAccount() + */ + function getAddress(uint256 salt, uint256[4] memory aPublicKey) public view returns (address) { + return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked( + type(ERC1967Proxy).creationCode, + abi.encode( + address(accountImplementation), + abi.encodeCall(BLSAccount.initialize, (aPublicKey)) + ) + ))); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSHelper.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSHelper.sol new file mode 100644 index 000000000..fdb60e0ff --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSHelper.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +// code taken from : https://github.com/witnet/elliptic-curve-solidity/blob/master/contracts/EllipticCurve.sol +// missing core functions from "thehubbleproject/bls": jacAdd (and sum) +library BLSHelper { + + struct XY { + uint x; + uint y; + } + /** + * sum all the points in the array + * NOTE: the "ecAdd" (below) has a special case where x1==y2. + * @param points an array of bytes32[2], representing an (x,y) of a point + * @param _pp the modulus of the curve + * @return ret the sum of all points + */ + function sum(XY[] memory points, uint256 _pp) internal pure returns (XY memory ret){ + uint x = points[0].x; + uint y = points[0].y; + uint z = 1; + + for (uint i = 1; i < points.length; i++) { + (x, y, z) = jacAdd(x, y, z, points[i].x, points[i].y, 1, _pp); + } + (x, y) = toAffine(x, y, z, _pp); + ret.x = x; + ret.y = y; + } + + /// @dev Adds two points (x1, y1, z1) and (x2, y2, z2). + /// @param _x1 coordinate x of P1 + /// @param _y1 coordinate y of P1 + /// @param _z1 coordinate z of P1 + /// @param _x2 coordinate x of square + /// @param _y2 coordinate y of square + /// @param _z2 coordinate z of square + /// @param _pp the modulus + /// @return (qx, qy, qz) P1+square in Jacobian + function jacAdd( + uint256 _x1, + uint256 _y1, + uint256 _z1, + uint256 _x2, + uint256 _y2, + uint256 _z2, + uint256 _pp) + internal pure returns (uint256, uint256, uint256) + { + if (_x1 == 0 && _y1 == 0) + return (_x2, _y2, _z2); + if (_x2 == 0 && _y2 == 0) + return (_x1, _y1, _z1); + + // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5 + uint[4] memory zs; + // z1^2, z1^3, z2^2, z2^3 + zs[0] = mulmod(_z1, _z1, _pp); + zs[1] = mulmod(_z1, zs[0], _pp); + zs[2] = mulmod(_z2, _z2, _pp); + zs[3] = mulmod(_z2, zs[2], _pp); + + // u1, s1, u2, s2 + zs = [ + mulmod(_x1, zs[2], _pp), + mulmod(_y1, zs[3], _pp), + mulmod(_x2, zs[0], _pp), + mulmod(_y2, zs[1], _pp) + ]; + + // In case of zs[0] == zs[2] && zs[1] == zs[3], double function should be used + require(zs[0] != zs[2] || zs[1] != zs[3], "Use jacDouble function instead"); + + uint[4] memory hr; + //h + hr[0] = addmod(zs[2], _pp - zs[0], _pp); + //r + hr[1] = addmod(zs[3], _pp - zs[1], _pp); + //h^2 + hr[2] = mulmod(hr[0], hr[0], _pp); + // h^3 + hr[3] = mulmod(hr[2], hr[0], _pp); + // qx = -h^3 -2u1h^2+r^2 + uint256 qx = addmod(mulmod(hr[1], hr[1], _pp), _pp - hr[3], _pp); + qx = addmod(qx, _pp - mulmod(2, mulmod(zs[0], hr[2], _pp), _pp), _pp); + // qy = -s1*z1*h^3+r(u1*h^2 -x^3) + uint256 qy = mulmod(hr[1], addmod(mulmod(zs[0], hr[2], _pp), _pp - qx, _pp), _pp); + qy = addmod(qy, _pp - mulmod(zs[1], hr[3], _pp), _pp); + // qz = h*z1*z2 + uint256 qz = mulmod(hr[0], mulmod(_z1, _z2, _pp), _pp); + return (qx, qy, qz); + } + + + /// @dev Converts a point (x, y, z) expressed in Jacobian coordinates to affine coordinates (x', y', 1). + /// @param _x coordinate x + /// @param _y coordinate y + /// @param _z coordinate z + /// @param _pp the modulus + /// @return (x', y') affine coordinates + function toAffine( + uint256 _x, + uint256 _y, + uint256 _z, + uint256 _pp) + internal pure returns (uint256, uint256) + { + uint256 zInv = invMod(_z, _pp); + uint256 zInv2 = mulmod(zInv, zInv, _pp); + uint256 x2 = mulmod(_x, zInv2, _pp); + uint256 y2 = mulmod(_y, mulmod(zInv, zInv2, _pp), _pp); + + return (x2, y2); + } + + + /// @dev Modular euclidean inverse of a number (mod p). + /// @param _x The number + /// @param _pp The modulus + /// @return q such that x*q = 1 (mod _pp) + function invMod(uint256 _x, uint256 _pp) internal pure returns (uint256) { + require(_x != 0 && _x != _pp && _pp != 0, "Invalid number"); + uint256 q = 0; + uint256 newT = 1; + uint256 r = _pp; + uint256 t; + while (_x != 0) { + t = r / _x; + (q, newT) = (newT, addmod(q, (_pp - mulmod(t, newT, _pp)), _pp)); + (r, _x) = (_x, r - t * _x); + } + + return q; + } + + /// @dev Doubles a point (x, y, z). + /// @param _x coordinate x of P1 + /// @param _y coordinate y of P1 + /// @param _z coordinate z of P1 + /// @param _aa the a scalar in the curve equation + /// @param _pp the modulus + /// @return (qx, qy, qz) 2P in Jacobian + function jacDouble( + uint256 _x, + uint256 _y, + uint256 _z, + uint256 _aa, + uint256 _pp) + internal pure returns (uint256, uint256, uint256) + { + if (_z == 0) + return (_x, _y, _z); + + // We follow the equations described in https://pdfs.semanticscholar.org/5c64/29952e08025a9649c2b0ba32518e9a7fb5c2.pdf Section 5 + // Note: there is a bug in the paper regarding the m parameter, M=3*(x1^2)+a*(z1^4) + // x, y, z at this point represent the squares of _x, _y, _z + uint256 x = mulmod(_x, _x, _pp); //x1^2 + uint256 y = mulmod(_y, _y, _pp); //y1^2 + uint256 z = mulmod(_z, _z, _pp); //z1^2 + + // s + uint s = mulmod(4, mulmod(_x, y, _pp), _pp); + // m + uint m = addmod(mulmod(3, x, _pp), mulmod(_aa, mulmod(z, z, _pp), _pp), _pp); + + // x, y, z at this point will be reassigned and rather represent qx, qy, qz from the paper + // This allows to reduce the gas cost and stack footprint of the algorithm + // qx + x = addmod(mulmod(m, m, _pp), _pp - addmod(s, s, _pp), _pp); + // qy = -8*y1^4 + M(S-T) + y = addmod(mulmod(m, addmod(s, _pp - x, _pp), _pp), _pp - mulmod(8, mulmod(y, y, _pp), _pp), _pp); + // qz = 2*y1*z1 + z = mulmod(2, mulmod(_y, _z, _pp), _pp); + + return (x, y, z); + } + + /// @dev Add two points (x1, y1) and (x2, y2) in affine coordinates. + /// @param _x1 coordinate x of P1 + /// @param _y1 coordinate y of P1 + /// @param _x2 coordinate x of P2 + /// @param _y2 coordinate y of P2 + /// @param _aa constant of the curve + /// @param _pp the modulus + /// @return (qx, qy) = P1+P2 in affine coordinates + function ecAdd( + uint256 _x1, + uint256 _y1, + uint256 _x2, + uint256 _y2, + uint256 _aa, + uint256 _pp) + internal pure returns (uint256, uint256) + { + uint x = 0; + uint y = 0; + uint z = 0; + + // Double if x1==x2 else add + if (_x1 == _x2) { + // y1 = -y2 mod p + if (addmod(_y1, _y2, _pp) == 0) { + return (0, 0); + } else { + // P1 = P2 + (x, y, z) = jacDouble( + _x1, + _y1, + 1, + _aa, + _pp); + } + } else { + (x, y, z) = jacAdd( + _x1, + _y1, + 1, + _x2, + _y2, + 1, + _pp); + } + // Get back to affine + return toAffine( + x, + y, + z, + _pp); + } + +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSSignatureAggregator.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSSignatureAggregator.sol new file mode 100644 index 000000000..60ea291b5 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/BLSSignatureAggregator.sol @@ -0,0 +1,164 @@ +//SPDX-License-Identifier: Unlicense +pragma solidity >=0.8.4 <0.9.0; +pragma abicoder v2; + +import "../../interfaces/IAggregator.sol"; +import "../../interfaces/IEntryPoint.sol"; +import {BLSOpen} from "./lib/BLSOpen.sol"; +import "./IBLSAccount.sol"; +import "./BLSHelper.sol"; + +/** + * A BLS-based signature aggregator, to validate aggregated signature of multiple UserOps if BLSAccount + */ +contract BLSSignatureAggregator is IAggregator { + using UserOperationLib for UserOperation; + + bytes32 public constant BLS_DOMAIN = keccak256("eip4337.bls.domain"); + + //copied from BLS.sol + uint256 public constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + /** + * @return publicKey - the public key from a BLS keypair the Aggregator will use to verify this UserOp; + * normally public key will be queried from the deployed BLSAccount itself; + * the public key will be read from the 'initCode' if the account is not deployed yet; + */ + function getUserOpPublicKey(UserOperation memory userOp) public view returns (uint256[4] memory publicKey) { + bytes memory initCode = userOp.initCode; + if (initCode.length > 0) { + publicKey = getTrailingPublicKey(initCode); + } else { + return IBLSAccount(userOp.sender).getBlsPublicKey{gas : 50000}(); + } + } + + /** + * return the trailing 4 words of input data + */ + function getTrailingPublicKey(bytes memory data) public pure returns (uint256[4] memory publicKey) { + uint len = data.length; + require(len > 32 * 4, "data too short for sig"); + + /* solhint-disable-next-line no-inline-assembly */ + assembly { + // actual buffer starts at data+32, so last 128 bytes start at data+32+len-128 = data+len-96 + let ofs := sub(add(data, len), 96) + mstore(publicKey, mload(ofs)) + mstore(add(publicKey, 32), mload(add(ofs, 32))) + mstore(add(publicKey, 64), mload(add(ofs, 64))) + mstore(add(publicKey, 96), mload(add(ofs, 96))) + } + } + + /// @inheritdoc IAggregator + function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) + external view override { + require(signature.length == 64, "BLS: invalid signature"); + (uint256[2] memory blsSignature) = abi.decode(signature, (uint256[2])); + + uint userOpsLen = userOps.length; + uint256[4][] memory blsPublicKeys = new uint256[4][](userOpsLen); + uint256[2][] memory messages = new uint256[2][](userOpsLen); + for (uint256 i = 0; i < userOpsLen; i++) { + + UserOperation memory userOp = userOps[i]; + blsPublicKeys[i] = getUserOpPublicKey(userOp); + + messages[i] = _userOpToMessage(userOp, _getPublicKeyHash(blsPublicKeys[i])); + } + require(BLSOpen.verifyMultiple(blsSignature, blsPublicKeys, messages), "BLS: validateSignatures failed"); + } + + /** + * get a hash of userOp + * NOTE: this hash is not the same as UserOperation.hash() + * (slightly less efficient, since it uses memory userOp) + */ + function internalUserOpHash(UserOperation memory userOp) internal pure returns (bytes32) { + return keccak256(abi.encode( + userOp.sender, + userOp.nonce, + keccak256(userOp.initCode), + keccak256(userOp.callData), + userOp.callGasLimit, + userOp.verificationGasLimit, + userOp.preVerificationGas, + userOp.maxFeePerGas, + userOp.maxPriorityFeePerGas, + keccak256(userOp.paymasterAndData) + )); + } + + /** + * return the BLS "message" for the given UserOp. + * the account checks the signature over this value using its public key + */ + function userOpToMessage(UserOperation memory userOp) public view returns (uint256[2] memory) { + bytes32 publicKeyHash = _getPublicKeyHash(getUserOpPublicKey(userOp)); + return _userOpToMessage(userOp, publicKeyHash); + } + + function _userOpToMessage(UserOperation memory userOp, bytes32 publicKeyHash) internal view returns (uint256[2] memory) { + bytes32 userOpHash = _getUserOpHash(userOp, publicKeyHash); + return BLSOpen.hashToPoint(BLS_DOMAIN, abi.encodePacked(userOpHash)); + } + + // helper for test + function getUserOpHash(UserOperation memory userOp) public view returns (bytes32) { + bytes32 publicKeyHash = _getPublicKeyHash(getUserOpPublicKey(userOp)); + return _getUserOpHash(userOp, publicKeyHash); + } + + function _getUserOpHash(UserOperation memory userOp, bytes32 publicKeyHash) internal view returns (bytes32) { + return keccak256(abi.encode(internalUserOpHash(userOp), publicKeyHash, address(this), block.chainid)); + } + + function _getPublicKeyHash(uint256[4] memory publicKey) internal pure returns(bytes32) { + return keccak256(abi.encode(publicKey)); + } + /** + * validate signature of a single userOp + * This method is called after EntryPoint.simulateValidation() returns an aggregator. + * First it validates the signature over the userOp. then it return data to be used when creating the handleOps: + * @param userOp the userOperation received from the user. + * @return sigForUserOp the value to put into the signature field of the userOp when calling handleOps. + * (usually empty, unless account and aggregator support some kind of "multisig" + */ + function validateUserOpSignature(UserOperation calldata userOp) + external view returns (bytes memory sigForUserOp) { + uint256[2] memory signature = abi.decode(userOp.signature, (uint256[2])); + uint256[4] memory pubkey = getUserOpPublicKey(userOp); + uint256[2] memory message = _userOpToMessage(userOp, _getPublicKeyHash(pubkey)); + + require(BLSOpen.verifySingle(signature, pubkey, message), "BLS: wrong sig"); + return ""; + } + + + /** + * aggregate multiple signatures into a single value. + * This method is called off-chain to calculate the signature to pass with handleOps() + * bundler MAY use optimized custom code perform this aggregation + * @param userOps array of UserOperations to collect the signatures from. + * @return aggregatedSignature the aggregated signature + */ + function aggregateSignatures(UserOperation[] calldata userOps) external pure returns (bytes memory aggregatedSignature) { + BLSHelper.XY[] memory points = new BLSHelper.XY[](userOps.length); + for (uint i = 0; i < points.length; i++) { + (uint256 x, uint256 y) = abi.decode(userOps[i].signature, (uint256, uint256)); + points[i] = BLSHelper.XY(x, y); + } + BLSHelper.XY memory sum = BLSHelper.sum(points, N); + return abi.encode(sum.x, sum.y); + } + + /** + * allow staking for this aggregator + * there is no limit on stake or delay, but it is not a problem, since it is a permissionless + * signature aggregator, which doesn't support unstaking. + */ + function addStake(IEntryPoint entryPoint, uint32 delay) external payable { + entryPoint.addStake{value : msg.value}(delay); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/IBLSAccount.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/IBLSAccount.sol new file mode 100644 index 000000000..c34da4fbf --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/IBLSAccount.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >=0.7.6; + +import "../../interfaces/IAccount.sol"; + +/** + * a BLS account should expose its own public key. + */ +interface IBLSAccount is IAccount { + event PublicKeyChanged(uint256[4] oldPublicKey, uint256[4] newPublicKey); + + /** + * @return public key from a BLS keypair that is used to verify the BLS signature, both separately and aggregated. + */ + function getBlsPublicKey() external view returns (uint256[4] memory); +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/BLSOpen.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/BLSOpen.sol new file mode 100644 index 000000000..c6d0a98eb --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/BLSOpen.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: MIT +pragma solidity >= 0.6.12; + +import { BLS } from "./hubble-contracts/contracts/libs/BLS.sol"; + +library BLSOpen { + function verifySingle( + uint256[2] memory signature, + uint256[4] memory pubkey, + uint256[2] memory message + ) external view returns (bool) { + uint256[4][] memory pubkeys = new uint256[4][](1); + uint256[2][] memory messages = new uint256[2][](1); + pubkeys[0] = pubkey; + messages[0] = message; + + (bool verified, bool callSuccess) = BLS.verifyMultiple( + signature, + pubkeys, + messages + ); + return callSuccess && verified; + + // // NB: (result, success) opposite of `call` convention (success, result). + // (bool verified, bool callSuccess) = BLS.verifySingle( + // signature, + // pubkey, + // message + // ); + // return callSuccess && verified; + } + + function verifyMultiple( + uint256[2] memory signature, + uint256[4][] memory pubkeys, + uint256[2][] memory messages + ) external view returns (bool) { + (bool verified, bool callSuccess) = BLS.verifyMultiple( + signature, + pubkeys, + messages + ); + return callSuccess && verified; + } + + function hashToPoint( + bytes32 domain, + bytes memory message + ) external view returns (uint256[2] memory) { + return BLS.hashToPoint( + domain, + message + ); + } + + function isZeroBLSKey(uint256[4] memory blsKey) public pure returns (bool) { + bool isZero = true; + for (uint256 i=0; isZero && i<4; i++) { + isZero = (blsKey[i] == 0); + } + return isZero; + } + +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BLS.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BLS.sol new file mode 100644 index 000000000..e02bc10c3 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BLS.sol @@ -0,0 +1,440 @@ +// SPDX-License-Identifier: MIT +pragma solidity >= 0.6.12; + +import { ModexpInverse, ModexpSqrt } from "./ModExp.sol"; +import { + BNPairingPrecompileCostEstimator +} from "./BNPairingPrecompileCostEstimator.sol"; + +/** + @title Boneh–Lynn–Shacham (BLS) signature scheme on Barreto-Naehrig 254 bit curve (BN-254) + @notice We use BLS signature aggregation to reduce the size of signature data to store on chain. + @dev We use G1 points for signatures and messages, and G2 points for public keys + */ +library BLS { + // Field order + // prettier-ignore + uint256 private constant N = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Negated genarator of G2 + // prettier-ignore + uint256 private constant N_G2_X1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; + // prettier-ignore + uint256 private constant N_G2_X0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; + // prettier-ignore + uint256 private constant N_G2_Y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; + // prettier-ignore + uint256 private constant N_G2_Y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; + + // sqrt(-3) + // prettier-ignore + uint256 private constant Z0 = 0x0000000000000000b3c4d79d41a91759a9e4c7e359b6b89eaec68e62effffffd; + // (sqrt(-3) - 1) / 2 + // prettier-ignore + uint256 private constant Z1 = 0x000000000000000059e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe; + + // prettier-ignore + uint256 private constant T24 = 0x1000000000000000000000000000000000000000000000000; + // prettier-ignore + uint256 private constant MASK24 = 0xffffffffffffffffffffffffffffffffffffffffffffffff; + + // estimator address +// address private constant COST_ESTIMATOR_ADDRESS = new 0x22E4a5251C1F02de8369Dd6f192033F6CB7531A4; + + function verifySingle( + uint256[2] memory signature, + uint256[4] memory pubkey, + uint256[2] memory message + ) internal view returns (bool, bool) { + uint256[12] memory input = + [ + signature[0], + signature[1], + N_G2_X1, + N_G2_X0, + N_G2_Y1, + N_G2_Y0, + message[0], + message[1], + pubkey[1], + pubkey[0], + pubkey[3], + pubkey[2] + ]; + uint256[1] memory out; + uint256 precompileGasCost = gasleft(); +// BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost( +// 2 +// ); + bool callSuccess; + // solium-disable-next-line security/no-inline-assembly + assembly { + callSuccess := staticcall( + precompileGasCost, + 8, + input, + 384, + out, + 0x20 + ) + } + if (!callSuccess) { + return (false, false); + } + return (out[0] != 0, true); + } + + function verifyMultiple( + uint256[2] memory signature, + uint256[4][] memory pubkeys, + uint256[2][] memory messages + ) internal view returns (bool checkResult, bool callSuccess) { + uint256 size = pubkeys.length; + require(size > 0, "BLS: number of public key is zero"); + require( + size == messages.length, + "BLS: number of public keys and messages must be equal" + ); + uint256 inputSize = (size + 1) * 6; + uint256[] memory input = new uint256[](inputSize); + input[0] = signature[0]; + input[1] = signature[1]; + input[2] = N_G2_X1; + input[3] = N_G2_X0; + input[4] = N_G2_Y1; + input[5] = N_G2_Y0; + for (uint256 i = 0; i < size; i++) { + input[i * 6 + 6] = messages[i][0]; + input[i * 6 + 7] = messages[i][1]; + input[i * 6 + 8] = pubkeys[i][1]; + input[i * 6 + 9] = pubkeys[i][0]; + input[i * 6 + 10] = pubkeys[i][3]; + input[i * 6 + 11] = pubkeys[i][2]; + } + uint256[1] memory out; + + // prettier-ignore + uint256 precompileGasCost = gasleft(); +// uint256 precompileGasCost = BNPairingPrecompileCostEstimator(COST_ESTIMATOR_ADDRESS).getGasCost(size + 1); + // solium-disable-next-line security/no-inline-assembly + assembly { + callSuccess := staticcall( + precompileGasCost, + 8, + add(input, 0x20), + mul(inputSize, 0x20), + out, + 0x20 + ) + } + if (!callSuccess) { + return (false, false); + } + return (out[0] != 0, true); + } + + /** + @notice Fouque-Tibouchi Hash to Curve + */ + function hashToPoint(bytes32 domain, bytes memory message) + internal + view + returns (uint256[2] memory) + { + uint256[2] memory u = hashToField(domain, message); + uint256[2] memory p0 = mapToPoint(u[0]); + uint256[2] memory p1 = mapToPoint(u[1]); + uint256[4] memory bnAddInput; + bnAddInput[0] = p0[0]; + bnAddInput[1] = p0[1]; + bnAddInput[2] = p1[0]; + bnAddInput[3] = p1[1]; + bool success; + // solium-disable-next-line security/no-inline-assembly + assembly { + success := staticcall(sub(gas(), 2000), 6, bnAddInput, 128, p0, 64) + switch success + case 0 { + invalid() + } + } + require(success, "BLS: bn add call failed"); + return p0; + } + + function mapToPoint(uint256 _x) + internal + pure + returns (uint256[2] memory p) + { + require(_x < N, "mapToPointFT: invalid field element"); + uint256 x = _x; + + (, bool decision) = sqrt(x); + + uint256 a0 = mulmod(x, x, N); + a0 = addmod(a0, 4, N); + uint256 a1 = mulmod(x, Z0, N); + uint256 a2 = mulmod(a1, a0, N); + a2 = inverse(a2); + a1 = mulmod(a1, a1, N); + a1 = mulmod(a1, a2, N); + + // x1 + a1 = mulmod(x, a1, N); + x = addmod(Z1, N - a1, N); + // check curve + a1 = mulmod(x, x, N); + a1 = mulmod(a1, x, N); + a1 = addmod(a1, 3, N); + bool found; + (a1, found) = sqrt(a1); + if (found) { + if (!decision) { + a1 = N - a1; + } + return [x, a1]; + } + + // x2 + x = N - addmod(x, 1, N); + // check curve + a1 = mulmod(x, x, N); + a1 = mulmod(a1, x, N); + a1 = addmod(a1, 3, N); + (a1, found) = sqrt(a1); + if (found) { + if (!decision) { + a1 = N - a1; + } + return [x, a1]; + } + + // x3 + x = mulmod(a0, a0, N); + x = mulmod(x, x, N); + x = mulmod(x, a2, N); + x = mulmod(x, a2, N); + x = addmod(x, 1, N); + // must be on curve + a1 = mulmod(x, x, N); + a1 = mulmod(a1, x, N); + a1 = addmod(a1, 3, N); + (a1, found) = sqrt(a1); + require(found, "BLS: bad ft mapping implementation"); + if (!decision) { + a1 = N - a1; + } + return [x, a1]; + } + + function isValidSignature(uint256[2] memory signature) + internal + pure + returns (bool) + { + if ((signature[0] >= N) || (signature[1] >= N)) { + return false; + } else { + return isOnCurveG1(signature); + } + } + + function isOnCurveG1(uint256[2] memory point) + internal + pure + returns (bool _isOnCurve) + { + // solium-disable-next-line security/no-inline-assembly + assembly { + let t0 := mload(point) + let t1 := mload(add(point, 32)) + let t2 := mulmod(t0, t0, N) + t2 := mulmod(t2, t0, N) + t2 := addmod(t2, 3, N) + t1 := mulmod(t1, t1, N) + _isOnCurve := eq(t1, t2) + } + } + + function isOnCurveG2(uint256[4] memory point) + internal + pure + returns (bool _isOnCurve) + { + // solium-disable-next-line security/no-inline-assembly + assembly { + // x0, x1 + let t0 := mload(point) + let t1 := mload(add(point, 32)) + // x0 ^ 2 + let t2 := mulmod(t0, t0, N) + // x1 ^ 2 + let t3 := mulmod(t1, t1, N) + // 3 * x0 ^ 2 + let t4 := add(add(t2, t2), t2) + // 3 * x1 ^ 2 + let t5 := addmod(add(t3, t3), t3, N) + // x0 * (x0 ^ 2 - 3 * x1 ^ 2) + t2 := mulmod(add(t2, sub(N, t5)), t0, N) + // x1 * (3 * x0 ^ 2 - x1 ^ 2) + t3 := mulmod(add(t4, sub(N, t3)), t1, N) + + // x ^ 3 + b + t0 := addmod( + t2, + 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5, + N + ) + t1 := addmod( + t3, + 0x009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2, + N + ) + + // y0, y1 + t2 := mload(add(point, 64)) + t3 := mload(add(point, 96)) + // y ^ 2 + t4 := mulmod(addmod(t2, t3, N), addmod(t2, sub(N, t3), N), N) + t3 := mulmod(shl(1, t2), t3, N) + + // y ^ 2 == x ^ 3 + b + _isOnCurve := and(eq(t0, t4), eq(t1, t3)) + } + } + + function sqrt(uint256 xx) internal pure returns (uint256 x, bool hasRoot) { + x = ModexpSqrt.run(xx); + hasRoot = mulmod(x, x, N) == xx; + } + + function inverse(uint256 a) internal pure returns (uint256) { + return ModexpInverse.run(a); + } + + function hashToField(bytes32 domain, bytes memory messages) + internal + pure + returns (uint256[2] memory) + { + bytes memory _msg = expandMsgTo96(domain, messages); + uint256 u0; + uint256 u1; + uint256 a0; + uint256 a1; + // solium-disable-next-line security/no-inline-assembly + assembly { + let p := add(_msg, 24) + u1 := and(mload(p), MASK24) + p := add(_msg, 48) + u0 := and(mload(p), MASK24) + a0 := addmod(mulmod(u1, T24, N), u0, N) + p := add(_msg, 72) + u1 := and(mload(p), MASK24) + p := add(_msg, 96) + u0 := and(mload(p), MASK24) + a1 := addmod(mulmod(u1, T24, N), u0, N) + } + return [a0, a1]; + } + + function expandMsgTo96(bytes32 domain, bytes memory message) + internal + pure + returns (bytes memory) + { + // zero<64>|msg|lib_str<2>|I2OSP(0, 1)<1>|dst|dst_len<1> + uint256 t0 = message.length; + bytes memory msg0 = new bytes(32 + t0 + 64 + 4); + bytes memory out = new bytes(96); + // b0 + // solium-disable-next-line security/no-inline-assembly + assembly { + let p := add(msg0, 96) + for { + let z := 0 + } lt(z, t0) { + z := add(z, 32) + } { + mstore(add(p, z), mload(add(message, add(z, 32)))) + } + p := add(p, t0) + + mstore8(p, 0) + p := add(p, 1) + mstore8(p, 96) + p := add(p, 1) + mstore8(p, 0) + p := add(p, 1) + + mstore(p, domain) + p := add(p, 32) + mstore8(p, 32) + } + bytes32 b0 = sha256(msg0); + bytes32 bi; + t0 = 32 + 34; + + // resize intermediate message + // solium-disable-next-line security/no-inline-assembly + assembly { + mstore(msg0, t0) + } + + // b1 + + // solium-disable-next-line security/no-inline-assembly + assembly { + mstore(add(msg0, 32), b0) + mstore8(add(msg0, 64), 1) + mstore(add(msg0, 65), domain) + mstore8(add(msg0, add(32, 65)), 32) + } + + bi = sha256(msg0); + + // solium-disable-next-line security/no-inline-assembly + assembly { + mstore(add(out, 32), bi) + } + + // b2 + + // solium-disable-next-line security/no-inline-assembly + assembly { + let t := xor(b0, bi) + mstore(add(msg0, 32), t) + mstore8(add(msg0, 64), 2) + mstore(add(msg0, 65), domain) + mstore8(add(msg0, add(32, 65)), 32) + } + + bi = sha256(msg0); + + // solium-disable-next-line security/no-inline-assembly + assembly { + mstore(add(out, 64), bi) + } + + // b3 + + // solium-disable-next-line security/no-inline-assembly + assembly { + let t := xor(b0, bi) + mstore(add(msg0, 32), t) + mstore8(add(msg0, 64), 3) + mstore(add(msg0, 65), domain) + mstore8(add(msg0, add(32, 65)), 32) + } + + bi = sha256(msg0); + + // solium-disable-next-line security/no-inline-assembly + assembly { + mstore(add(out, 96), bi) + } + + return out; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BNPairingPrecompileCostEstimator.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BNPairingPrecompileCostEstimator.sol new file mode 100644 index 000000000..30d04a40d --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/BNPairingPrecompileCostEstimator.sol @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.6.12; + +contract BNPairingPrecompileCostEstimator { + uint256 public baseCost; + uint256 public perPairCost; + + // G1 Generator + uint256 private constant G1_X = 1; + uint256 private constant G1_Y = 2; + + // G2 genarator + // prettier-ignore + uint256 private constant G2_X0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; + // prettier-ignore + uint256 private constant G2_X1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; + // prettier-ignore + uint256 private constant G2_Y0 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; + // prettier-ignore + uint256 private constant G2_Y1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; + + // G2 negated genarator y coordinates + // prettier-ignore + uint256 private constant N_G2_Y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; + // prettier-ignore + uint256 private constant N_G2_Y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; + + function run() external { + _run(); + } + + function getGasCost(uint256 pairCount) external view returns (uint256) { + return pairCount * perPairCost + baseCost; + } + + function _run() internal { + uint256 gasCost1Pair = _gasCost1Pair(); + uint256 gasCost2Pair = _gasCost2Pair(); + perPairCost = gasCost2Pair - gasCost1Pair; + baseCost = gasCost1Pair - perPairCost; + } + + function _gasCost1Pair() internal view returns (uint256) { + uint256[6] memory input = [G1_X, G1_Y, G2_X1, G2_X0, G2_Y1, G2_Y0]; + uint256[1] memory out; + bool callSuccess; + uint256 suppliedGas = gasleft() - 2000; + require( + gasleft() > 2000, + "BNPairingPrecompileCostEstimator: not enough gas, single pair" + ); + uint256 gasT0 = gasleft(); + // solium-disable-next-line security/no-inline-assembly + assembly { + callSuccess := staticcall(suppliedGas, 8, input, 192, out, 0x20) + } + uint256 gasCost = gasT0 - gasleft(); + require( + callSuccess, + "BNPairingPrecompileCostEstimator: single pair call is failed" + ); + require( + out[0] == 0, + "BNPairingPrecompileCostEstimator: single pair call result must be 0" + ); + return gasCost; + } + + function _gasCost2Pair() internal view returns (uint256) { + uint256[12] memory input = + [ + G1_X, + G1_Y, + G2_X1, + G2_X0, + G2_Y1, + G2_Y0, + G1_X, + G1_Y, + G2_X1, + G2_X0, + N_G2_Y1, + N_G2_Y0 + ]; + uint256[1] memory out; + bool callSuccess; + uint256 suppliedGas = gasleft() - 2000; + require( + gasleft() > 2000, + "BNPairingPrecompileCostEstimator: not enough gas, couple pair" + ); + uint256 gasT0 = gasleft(); + // solium-disable-next-line security/no-inline-assembly + assembly { + callSuccess := staticcall(suppliedGas, 8, input, 384, out, 0x20) + } + uint256 gasCost = gasT0 - gasleft(); + require( + callSuccess, + "BNPairingPrecompileCostEstimator: couple pair call is failed" + ); + require( + out[0] == 1, + "BNPairingPrecompileCostEstimator: couple pair call result must be 1" + ); + return gasCost; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/ModExp.sol b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/ModExp.sol new file mode 100644 index 000000000..6fd08f118 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/bls/lib/hubble-contracts/contracts/libs/ModExp.sol @@ -0,0 +1,652 @@ +// SPDX-License-Identifier: MIT +pragma solidity >= 0.6.12; + +/** + @title Compute Inverse by Modular Exponentiation + @notice Compute $input^(N - 2) mod N$ using Addition Chain method. + Where N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + and N - 2 = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45 + @dev the function body is generated with the modified addchain script + see https://github.com/kobigurk/addchain/commit/2c37a2ace567a9bdc680b4e929c94aaaa3ec700f + */ +library ModexpInverse { + function run(uint256 t2) internal pure returns (uint256 t0) { + // solium-disable-next-line security/no-inline-assembly + assembly { + let + n + := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + t0 := mulmod(t2, t2, n) + let t5 := mulmod(t0, t2, n) + let t1 := mulmod(t5, t0, n) + let t3 := mulmod(t5, t5, n) + let t8 := mulmod(t1, t0, n) + let t4 := mulmod(t3, t5, n) + let t6 := mulmod(t3, t1, n) + t0 := mulmod(t3, t3, n) + let t7 := mulmod(t8, t3, n) + t3 := mulmod(t4, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + } + } +} + +/** + @title Compute Squre Root by Modular Exponentiation + @notice Compute $input^{(N + 1) / 4} mod N$ using Addition Chain method. + Where N = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + and (N + 1) / 4 = 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52 + */ +library ModexpSqrt { + function run(uint256 t6) internal pure returns (uint256 t0) { + // solium-disable-next-line security/no-inline-assembly + assembly { + let + n + := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + + t0 := mulmod(t6, t6, n) + let t4 := mulmod(t0, t6, n) + let t2 := mulmod(t4, t0, n) + let t3 := mulmod(t4, t4, n) + let t8 := mulmod(t2, t0, n) + let t1 := mulmod(t3, t4, n) + let t5 := mulmod(t3, t2, n) + t0 := mulmod(t3, t3, n) + let t7 := mulmod(t8, t3, n) + t3 := mulmod(t1, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t8, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t7, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t6, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t5, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t4, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t3, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t2, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t0, n) + t0 := mulmod(t0, t1, n) + t0 := mulmod(t0, t0, n) + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/callback/TokenCallbackHandler.sol b/packages/hebao_v3/contracts/account-abstraction/samples/callback/TokenCallbackHandler.sol new file mode 100644 index 000000000..d7ed9cbbb --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/callback/TokenCallbackHandler.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable no-empty-blocks */ + +import "@openzeppelin/contracts/utils/introspection/IERC165.sol"; +import "@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol"; +import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol"; + +/** + * Token callback handler. + * Handles supported tokens' callbacks, allowing account receiving these tokens. + */ +contract TokenCallbackHandler is IERC777Recipient, IERC721Receiver, IERC1155Receiver { + function tokensReceived( + address, + address, + address, + uint256, + bytes calldata, + bytes calldata + ) external pure override { + } + + function onERC721Received( + address, + address, + uint256, + bytes calldata + ) external pure override returns (bytes4) { + return IERC721Receiver.onERC721Received.selector; + } + + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes calldata + ) external pure override returns (bytes4) { + return IERC1155Receiver.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] calldata, + uint256[] calldata, + bytes calldata + ) external pure override returns (bytes4) { + return IERC1155Receiver.onERC1155BatchReceived.selector; + } + + function supportsInterface(bytes4 interfaceId) external view virtual override returns (bool) { + return + interfaceId == type(IERC721Receiver).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId || + interfaceId == type(IERC165).interfaceId; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Fallback.sol b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Fallback.sol new file mode 100644 index 000000000..4cc0978d5 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Fallback.sol @@ -0,0 +1,89 @@ +//SPDX-License-Identifier: GPL +pragma solidity ^0.8.7; + +/* solhint-disable no-inline-assembly */ + +import "@gnosis.pm/safe-contracts/contracts/handler/DefaultCallbackHandler.sol"; +import "@gnosis.pm/safe-contracts/contracts/GnosisSafe.sol"; +import "@openzeppelin/contracts/interfaces/IERC1271.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "../../interfaces/IAccount.sol"; +import "./EIP4337Manager.sol"; + +using ECDSA for bytes32; + +/** + * The GnosisSafe enables adding custom functions implementation to the Safe by setting a 'fallbackHandler'. + * This 'fallbackHandler' adds an implementation of 'validateUserOp' to the GnosisSafe. + * Note that the implementation of the 'validateUserOp' method is located in the EIP4337Manager. + * Upon receiving the 'validateUserOp', a Safe with EIP4337Fallback enabled makes a 'delegatecall' to EIP4337Manager. + */ +contract EIP4337Fallback is DefaultCallbackHandler, IAccount, IERC1271 { + bytes4 internal constant ERC1271_MAGIC_VALUE = 0x1626ba7e; + + address immutable public eip4337manager; + constructor(address _eip4337manager) { + eip4337manager = _eip4337manager; + } + + /** + * delegate the contract call to the EIP4337Manager + */ + function delegateToManager() internal returns (bytes memory) { + // delegate entire msg.data (including the appended "msg.sender") to the EIP4337Manager + // will work only for GnosisSafe contracts + GnosisSafe safe = GnosisSafe(payable(msg.sender)); + (bool success, bytes memory ret) = safe.execTransactionFromModuleReturnData(eip4337manager, 0, msg.data, Enum.Operation.DelegateCall); + if (!success) { + assembly { + revert(add(ret, 32), mload(ret)) + } + } + return ret; + } + + /** + * called from the Safe. delegate actual work to EIP4337Manager + */ + function validateUserOp(UserOperation calldata, bytes32, uint256) override external returns (uint256 deadline){ + bytes memory ret = delegateToManager(); + return abi.decode(ret, (uint256)); + } + + /** + * Helper for wallet to get the next nonce. + */ + function getNonce() public returns (uint256 nonce) { + bytes memory ret = delegateToManager(); + (nonce) = abi.decode(ret, (uint256)); + } + + /** + * called from the Safe. delegate actual work to EIP4337Manager + */ + function executeAndRevert( + address, + uint256, + bytes memory, + Enum.Operation + ) external { + delegateToManager(); + } + + function isValidSignature( + bytes32 _hash, + bytes memory _signature + ) external override view returns (bytes4) { + bytes32 hash = _hash.toEthSignedMessageHash(); + address recovered = hash.recover(_signature); + + GnosisSafe safe = GnosisSafe(payable(address(msg.sender))); + + // Validate signatures + if (safe.isOwner(recovered)) { + return ERC1271_MAGIC_VALUE; + } else { + return 0xffffffff; + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Manager.sol b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Manager.sol new file mode 100644 index 000000000..2a687ada5 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/EIP4337Manager.sol @@ -0,0 +1,197 @@ +//SPDX-License-Identifier: GPL +pragma solidity ^0.8.7; + +/* solhint-disable avoid-low-level-calls */ +/* solhint-disable no-inline-assembly */ +/* solhint-disable reason-string */ + +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@gnosis.pm/safe-contracts/contracts/GnosisSafe.sol"; +import "@gnosis.pm/safe-contracts/contracts/base/Executor.sol"; +import "@gnosis.pm/safe-contracts/contracts/examples/libraries/GnosisSafeStorage.sol"; +import "./EIP4337Fallback.sol"; +import "../../interfaces/IAccount.sol"; +import "../../interfaces/IEntryPoint.sol"; +import "../../utils/Exec.sol"; + + using ECDSA for bytes32; + +/** + * Main EIP4337 module. + * Called (through the fallback module) using "delegate" from the GnosisSafe as an "IAccount", + * so must implement validateUserOp + * holds an immutable reference to the EntryPoint + * Inherits GnosisSafe so that it can reference the memory storage + */ +contract EIP4337Manager is IAccount, GnosisSafeStorage, Executor { + + address public immutable eip4337Fallback; + address public immutable entryPoint; + + // return value in case of signature failure, with no time-range. + // equivalent to _packValidationData(true,0,0); + uint256 constant internal SIG_VALIDATION_FAILED = 1; + + address internal constant SENTINEL_MODULES = address(0x1); + + constructor(address anEntryPoint) { + entryPoint = anEntryPoint; + eip4337Fallback = address(new EIP4337Fallback(address(this))); + } + + /** + * delegate-called (using execFromModule) through the fallback, so "real" msg.sender is attached as last 20 bytes + */ + function validateUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 missingAccountFunds) + external override returns (uint256 validationData) { + address msgSender = address(bytes20(msg.data[msg.data.length - 20 :])); + require(msgSender == entryPoint, "account: not from entrypoint"); + + GnosisSafe pThis = GnosisSafe(payable(address(this))); + bytes32 hash = userOpHash.toEthSignedMessageHash(); + address recovered = hash.recover(userOp.signature); + require(threshold == 1, "account: only threshold 1"); + if (!pThis.isOwner(recovered)) { + validationData = SIG_VALIDATION_FAILED; + } + + // mimic normal Safe nonce behaviour: prevent parallel nonces + require(userOp.nonce < type(uint64).max, "account: nonsequential nonce"); + + if (missingAccountFunds > 0) { + //Note: MAY pay more than the minimum, to deposit for future transactions + (bool success,) = payable(msgSender).call{value : missingAccountFunds}(""); + (success); + //ignore failure (its EntryPoint's job to verify, not account.) + } + } + + /** + * Execute a call but also revert if the execution fails. + * The default behavior of the Safe is to not revert if the call fails, + * which is challenging for integrating with ERC4337 because then the + * EntryPoint wouldn't know to emit the UserOperationRevertReason event, + * which the frontend/client uses to capture the reason for the failure. + */ + function executeAndRevert( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation + ) external { + address msgSender = address(bytes20(msg.data[msg.data.length - 20 :])); + require(msgSender == entryPoint, "account: not from entrypoint"); + require(msg.sender == eip4337Fallback, "account: not from EIP4337Fallback"); + + bool success = execute( + to, + value, + data, + operation, + type(uint256).max + ); + + bytes memory returnData = Exec.getReturnData(type(uint256).max); + // Revert with the actual reason string + // Adopted from: https://github.com/Uniswap/v3-periphery/blob/464a8a49611272f7349c970e0fadb7ec1d3c1086/contracts/base/Multicall.sol#L16-L23 + if (!success) { + if (returnData.length < 68) revert(); + assembly { + returnData := add(returnData, 0x04) + } + revert(abi.decode(returnData, (string))); + } + } + + /** + * Helper for wallet to get the next nonce. + */ + function getNonce() public view returns (uint256) { + return IEntryPoint(entryPoint).getNonce(address(this), 0); + } + + /** + * set up a safe as EIP-4337 enabled. + * called from the GnosisSafeAccountFactory during construction time + * - enable 3 modules (this module, fallback and the entrypoint) + * - this method is called with delegateCall, so the module (usually itself) is passed as parameter, and "this" is the safe itself + */ + function setup4337Modules( + EIP4337Manager manager //the manager (this contract) + ) external { + GnosisSafe safe = GnosisSafe(payable(address(this))); + require(!safe.isModuleEnabled(manager.entryPoint()), "setup4337Modules: entrypoint already enabled"); + require(!safe.isModuleEnabled(manager.eip4337Fallback()), "setup4337Modules: eip4337Fallback already enabled"); + safe.enableModule(manager.entryPoint()); + safe.enableModule(manager.eip4337Fallback()); + } + + /** + * replace EIP4337 module, to support a new EntryPoint. + * must be called using execTransaction and Enum.Operation.DelegateCall + * @param prevModule returned by getCurrentEIP4337Manager + * @param oldManager the old EIP4337 manager to remove, returned by getCurrentEIP4337Manager + * @param newManager the new EIP4337Manager, usually with a new EntryPoint + */ + function replaceEIP4337Manager(address prevModule, EIP4337Manager oldManager, EIP4337Manager newManager) public { + GnosisSafe pThis = GnosisSafe(payable(address(this))); + address oldFallback = oldManager.eip4337Fallback(); + require(pThis.isModuleEnabled(oldFallback), "replaceEIP4337Manager: oldManager is not active"); + pThis.disableModule(oldFallback, oldManager.entryPoint()); + pThis.disableModule(prevModule, oldFallback); + + address eip4337fallback = newManager.eip4337Fallback(); + + pThis.enableModule(newManager.entryPoint()); + pThis.enableModule(eip4337fallback); + pThis.setFallbackHandler(eip4337fallback); + + validateEip4337(pThis, newManager); + } + + /** + * Validate this gnosisSafe is callable through the EntryPoint. + * the test is might be incomplete: we check that we reach our validateUserOp and fail on signature. + * we don't test full transaction + */ + function validateEip4337(GnosisSafe safe, EIP4337Manager manager) public { + + // this prevents mistaken replaceEIP4337Manager to disable the module completely. + // minimal signature that pass "recover" + bytes memory sig = new bytes(65); + sig[64] = bytes1(uint8(27)); + sig[2] = bytes1(uint8(1)); + sig[35] = bytes1(uint8(1)); + uint256 nonce = uint256(IEntryPoint(manager.entryPoint()).getNonce(address(safe), 0)); + UserOperation memory userOp = UserOperation(address(safe), nonce, "", "", 0, 1000000, 0, 0, 0, "", sig); + UserOperation[] memory userOps = new UserOperation[](1); + userOps[0] = userOp; + IEntryPoint _entryPoint = IEntryPoint(payable(manager.entryPoint())); + try _entryPoint.handleOps(userOps, payable(msg.sender)) { + revert("validateEip4337: handleOps must fail"); + } catch (bytes memory error) { + if (keccak256(error) != keccak256(abi.encodeWithSignature("FailedOp(uint256,string)", 0, "AA24 signature error"))) { + revert(string(error)); + } + } + } + /** + * enumerate modules, and find the currently active EIP4337 manager (and previous module) + * @return prev prev module, needed by replaceEIP4337Manager + * @return manager the current active EIP4337Manager + */ + function getCurrentEIP4337Manager(GnosisSafe safe) public view returns (address prev, address manager) { + prev = address(SENTINEL_MODULES); + (address[] memory modules,) = safe.getModulesPaginated(SENTINEL_MODULES, 100); + for (uint i = 0; i < modules.length; i++) { + address module = modules[i]; + try EIP4337Fallback(module).eip4337manager() returns (address _manager) { + return (prev, _manager); + } + // solhint-disable-next-line no-empty-blocks + catch {} + prev = module; + } + return (address(0), address(0)); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/GnosisAccountFactory.sol b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/GnosisAccountFactory.sol new file mode 100644 index 000000000..459846a7f --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/samples/gnosis/GnosisAccountFactory.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@gnosis.pm/safe-contracts/contracts/proxies/GnosisSafeProxyFactory.sol"; +import "./EIP4337Manager.sol"; + +/** + * A wrapper factory contract to deploy GnosisSafe as an ERC-4337 account contract. + */ +contract GnosisSafeAccountFactory { + + GnosisSafeProxyFactory public immutable proxyFactory; + address public immutable safeSingleton; + EIP4337Manager public immutable eip4337Manager; + + constructor(GnosisSafeProxyFactory _proxyFactory, address _safeSingleton, EIP4337Manager _eip4337Manager) { + proxyFactory = _proxyFactory; + safeSingleton = _safeSingleton; + eip4337Manager = _eip4337Manager; + } + + function createAccount(address owner,uint256 salt) public returns (address) { + address addr = getAddress(owner, salt); + uint codeSize = addr.code.length; + if (codeSize > 0) { + return addr; + } + return address(proxyFactory.createProxyWithNonce( + safeSingleton, getInitializer(owner), salt)); + } + + function getInitializer(address owner) internal view returns (bytes memory) { + address[] memory owners = new address[](1); + owners[0] = owner; + uint threshold = 1; + address eip4337fallback = eip4337Manager.eip4337Fallback(); + + bytes memory setup4337Modules = abi.encodeCall( + EIP4337Manager.setup4337Modules, (eip4337Manager)); + + return abi.encodeCall(GnosisSafe.setup, ( + owners, threshold, + address (eip4337Manager), setup4337Modules, + eip4337fallback, + address(0), 0, payable(0) //no payment receiver + )); + } + + /** + * calculate the counterfactual address of this account as it would be returned by createAccount() + * (uses the same "create2 signature" used by GnosisSafeProxyFactory.createProxyWithNonce) + */ + function getAddress(address owner,uint256 salt) public view returns (address) { + bytes memory initializer = getInitializer(owner); + //copied from deployProxyWithNonce + bytes32 salt2 = keccak256(abi.encodePacked(keccak256(initializer), salt)); + bytes memory deploymentData = abi.encodePacked(proxyFactory.proxyCreationCode(), uint256(uint160(safeSingleton))); + return Create2.computeAddress(bytes32(salt2), keccak256(deploymentData), address (proxyFactory)); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/BrokenBlsAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/BrokenBlsAccount.sol new file mode 100644 index 000000000..2e3cf2bc2 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/BrokenBlsAccount.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +import "../samples/SimpleAccount.sol"; +import "../samples/bls/IBLSAccount.sol"; + +/** + * for testing: a BLS account that fails to return its public-key (completely ignores its publickey) + * this is a copy of the normal bls account, but it returns a public-key unrelated to the one it is constructed with. + */ +contract BrokenBLSAccount is SimpleAccount, IBLSAccount { + address public immutable aggregator; + + // The constructor is used only for the "implementation" and only sets immutable values. + // Mutable values slots for proxy accounts are set by the 'initialize' function. + constructor(IEntryPoint anEntryPoint, address anAggregator) SimpleAccount(anEntryPoint) { + aggregator = anAggregator; + } + + function initialize(uint256[4] memory aPublicKey) public virtual initializer { + (aPublicKey); + super._initialize(address(0)); + } + + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal override view returns (uint256 validationData) { + + (userOp, userOpHash); + return _packValidationData(ValidationData(aggregator, 0,0)); + } + + function getBlsPublicKey() external override pure returns (uint256[4] memory) { + uint256[4] memory pubkey; + return pubkey; + } +} + + +/** + * Based n SimpleAccountFactory + * can't be a subclass, since both constructor and createAccount depend on the + * actual wallet contract constructor and initializer + */ +contract BrokenBLSAccountFactory { + BrokenBLSAccount public immutable accountImplementation; + + constructor(IEntryPoint entryPoint, address aggregator){ + accountImplementation = new BrokenBLSAccount(entryPoint, aggregator); + } + + /** + * create an account, and return its address. + * returns the address even if the account is already deployed. + * Note that during UserOperation execution, this method is called only if the account is not deployed. + * This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation + * Also note that out BLSSignatureAggregator requires that the public-key is the last parameter + */ + function createAccount(uint salt, uint256[4] memory aPublicKey) public returns (BrokenBLSAccount) { + + address addr = getAddress(salt, aPublicKey); + uint codeSize = addr.code.length; + if (codeSize > 0) { + return BrokenBLSAccount(payable(addr)); + } + return BrokenBLSAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}( + address(accountImplementation), + abi.encodeCall(BrokenBLSAccount.initialize, aPublicKey) + ))); + } + + /** + * calculate the counterfactual address of this account as it would be returned by createAccount() + */ + function getAddress(uint salt, uint256[4] memory aPublicKey) public view returns (address) { + return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked( + type(ERC1967Proxy).creationCode, + abi.encode( + address(accountImplementation), + abi.encodeCall(BrokenBLSAccount.initialize, (aPublicKey)) + ) + ))); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/MaliciousAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/MaliciousAccount.sol new file mode 100644 index 000000000..5b840e4f0 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/MaliciousAccount.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; +import "../interfaces/IAccount.sol"; +import "../interfaces/IEntryPoint.sol"; +import "../core/EntryPoint.sol"; + +contract MaliciousAccount is IAccount { + IEntryPoint private ep; + constructor(IEntryPoint _ep) payable { + ep = _ep; + } + function validateUserOp(UserOperation calldata userOp, bytes32, uint256 missingAccountFunds) + external returns (uint256 validationData) { + ep.depositTo{value : missingAccountFunds}(address(this)); + // Now calculate basefee per EntryPoint.getUserOpGasPrice() and compare it to the basefe we pass off-chain in the signature + uint256 externalBaseFee = abi.decode(userOp.signature, (uint256)); + uint256 requiredGas = userOp.callGasLimit + userOp.verificationGasLimit + userOp.preVerificationGas; + uint256 gasPrice = missingAccountFunds / requiredGas; + uint256 basefee = gasPrice - userOp.maxPriorityFeePerGas; + require (basefee == externalBaseFee, "Revert after first validation"); + return 0; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccount.sol new file mode 100644 index 000000000..23bf2954d --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccount.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../samples/SimpleAccount.sol"; + +/** + * test aggregated-signature account. + * works only with TestAggregatedSignature, which doesn't really check signature, but nonce sum + * a true aggregated account should expose data (e.g. its public key) to the aggregator. + */ +contract TestAggregatedAccount is SimpleAccount { + address public immutable aggregator; + + // The constructor is used only for the "implementation" and only sets immutable values. + // Mutable value slots for proxy accounts are set by the 'initialize' function. + constructor(IEntryPoint anEntryPoint, address anAggregator) SimpleAccount(anEntryPoint) { + aggregator = anAggregator; + } + + /// @inheritdoc SimpleAccount + function initialize(address) public virtual override initializer { + super._initialize(address(0)); + } + + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal override view returns (uint256 validationData) { + (userOp, userOpHash); + return _packValidationData(ValidationData(aggregator, 0, 0)); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccountFactory.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccountFactory.sol new file mode 100644 index 000000000..edaba58cc --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestAggregatedAccountFactory.sol @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; + +import "./TestAggregatedAccount.sol"; + +/** + * Based on SimpleAccountFactory. + * Cannot be a subclass since both constructor and createAccount depend on the + * constructor and initializer of the actual account contract. + */ +contract TestAggregatedAccountFactory { + TestAggregatedAccount public immutable accountImplementation; + + constructor(IEntryPoint anEntryPoint, address anAggregator){ + accountImplementation = new TestAggregatedAccount(anEntryPoint, anAggregator); + } + + /** + * create an account, and return its address. + * returns the address even if the account is already deployed. + * Note that during UserOperation execution, this method is called only if the account is not deployed. + * This method returns an existing account address so that entryPoint.getSenderAddress() would work even after account creation + */ + function createAccount(address owner,uint256 salt) public returns (TestAggregatedAccount ret) { + address addr = getAddress(owner, salt); + uint codeSize = addr.code.length; + if (codeSize > 0) { + return TestAggregatedAccount(payable(addr)); + } + ret = TestAggregatedAccount(payable(new ERC1967Proxy{salt : bytes32(salt)}( + address(accountImplementation), + abi.encodeCall(TestAggregatedAccount.initialize, (owner)) + ))); + } + + /** + * calculate the counterfactual address of this account as it would be returned by createAccount() + */ + function getAddress(address owner,uint256 salt) public view returns (address) { + return Create2.computeAddress(bytes32(salt), keccak256(abi.encodePacked( + type(ERC1967Proxy).creationCode, + abi.encode( + address(accountImplementation), + abi.encodeCall(TestAggregatedAccount.initialize, (owner)) + ) + ))); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestCounter.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestCounter.sol new file mode 100644 index 000000000..0ac2c888a --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestCounter.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +//sample "receiver" contract, for testing "exec" from account. +contract TestCounter { + mapping(address => uint256) public counters; + + function count() public { + counters[msg.sender] = counters[msg.sender] + 1; + } + + function countFail() public pure { + revert("count failed"); + } + + function justemit() public { + emit CalledFrom(msg.sender); + } + + event CalledFrom(address sender); + + //helper method to waste gas + // repeat - waste gas on writing storage in a loop + // junk - dynamic buffer to stress the function size. + mapping(uint256 => uint256) public xxx; + uint256 public offset; + + function gasWaster(uint256 repeat, string calldata /*junk*/) external { + for (uint256 i = 1; i <= repeat; i++) { + offset++; + xxx[offset] = i; + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestExpirePaymaster.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestExpirePaymaster.sol new file mode 100644 index 000000000..51036a1cf --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestExpirePaymaster.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +import "../core/BasePaymaster.sol"; + +/** + * test expiry mechanism: paymasterData encodes the "validUntil" and validAfter" times + */ +contract TestExpirePaymaster is BasePaymaster { + // solhint-disable no-empty-blocks + constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) + {} + + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + internal virtual override view + returns (bytes memory context, uint256 validationData) { + (userOp, userOpHash, maxCost); + (uint48 validAfter, uint48 validUntil) = abi.decode(userOp.paymasterAndData[20 :], (uint48, uint48)); + validationData = _packValidationData(false, validUntil, validAfter); + context = ""; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestExpiryAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestExpiryAccount.sol new file mode 100644 index 000000000..294f4aaf5 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestExpiryAccount.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +import "../samples/SimpleAccount.sol"; + +/** + * A test account, for testing expiry. + * add "temporary" owners, each with a time range (since..till) times for each. + * NOTE: this is not a full "session key" implementation: a real session key should probably limit + * other things, like target contracts and methods to be called. + * also, the "since" value is not really useful, only for testing the entrypoint. + */ +contract TestExpiryAccount is SimpleAccount { + using ECDSA for bytes32; + + mapping(address => uint48) public ownerAfter; + mapping(address => uint48) public ownerUntil; + + // solhint-disable-next-line no-empty-blocks + constructor(IEntryPoint anEntryPoint) SimpleAccount(anEntryPoint) {} + + function initialize(address anOwner) public virtual override initializer { + super._initialize(anOwner); + addTemporaryOwner(anOwner, 0, type(uint48).max); + } + + // As this is a test contract, no need for proxy, so no need to disable init + // solhint-disable-next-line no-empty-blocks + function _disableInitializers() internal override {} + + function addTemporaryOwner(address owner, uint48 _after, uint48 _until) public onlyOwner { + require(_until > _after, "wrong until/after"); + ownerAfter[owner] = _after; + ownerUntil[owner] = _until; + } + + /// implement template method of BaseAccount + function _validateSignature(UserOperation calldata userOp, bytes32 userOpHash) + internal override view returns (uint256 validationData) { + bytes32 hash = userOpHash.toEthSignedMessageHash(); + address signer = hash.recover(userOp.signature); + uint48 _until = ownerUntil[signer]; + uint48 _after = ownerAfter[signer]; + + //we have "until" value for all valid owners. so zero means "invalid signature" + bool sigFailed = _until == 0; + return _packValidationData(sigFailed, _until, _after); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestHelpers.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestHelpers.sol new file mode 100644 index 000000000..2ddb83c77 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestHelpers.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../core/Helpers.sol"; + +contract TestHelpers { + + function parseValidationData(uint validationData) public pure returns (ValidationData memory) { + return _parseValidationData(validationData); + } + + function intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) public pure returns (ValidationData memory) { + return _intersectTimeRange(validationData, paymasterValidationData); + } + + function packValidationDataStruct(ValidationData memory data) public pure returns (uint256) { + return _packValidationData(data); + } + + function packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) public pure returns (uint256) { + return _packValidationData(sigFailed, validUntil, validAfter); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestOracle.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestOracle.sol new file mode 100644 index 000000000..e7d11f16f --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestOracle.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../samples/IOracle.sol"; + +contract TestOracle is IOracle { + function getTokenValueOfEth(uint256 ethOutput) external pure override returns (uint256 tokenInput) { + return ethOutput * 2; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestPaymasterAcceptAll.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestPaymasterAcceptAll.sol new file mode 100644 index 000000000..6445717d6 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestPaymasterAcceptAll.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; + +import "../core/BasePaymaster.sol"; + +/** + * test paymaster, that pays for everything, without any check. + */ +contract TestPaymasterAcceptAll is BasePaymaster { + + constructor(IEntryPoint _entryPoint) BasePaymaster(_entryPoint) { + // to support "deterministic address" factory + // solhint-disable avoid-tx-origin + if (tx.origin != msg.sender) { + _transferOwnership(tx.origin); + } + + } + + function _validatePaymasterUserOp(UserOperation calldata userOp, bytes32 userOpHash, uint256 maxCost) + internal virtual override view + returns (bytes memory context, uint256 validationData) { + (userOp, userOpHash, maxCost); + return ("", maxCost == 12345 ? 1 : 0); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestRevertAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestRevertAccount.sol new file mode 100644 index 000000000..d7c376c49 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestRevertAccount.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; +/* solhint-disable no-inline-assembly */ + +import "../samples/SimpleAccount.sol"; +contract TestRevertAccount is IAccount { + IEntryPoint private ep; + constructor(IEntryPoint _ep) payable { + ep = _ep; + } + + function validateUserOp(UserOperation calldata, bytes32, uint256 missingAccountFunds) + external override returns (uint256 validationData) { + ep.depositTo{value : missingAccountFunds}(address(this)); + return 0; + } + + function revertLong(uint256 length) public pure{ + assembly { + revert(0, length) + } + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestSignatureAggregator.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestSignatureAggregator.sol new file mode 100644 index 000000000..97b9eb5f9 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestSignatureAggregator.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable reason-string */ + +import "../interfaces/IAggregator.sol"; +import "../interfaces/IEntryPoint.sol"; +import "../samples/SimpleAccount.sol"; + +/** + * test signature aggregator. + * the aggregated signature is the SUM of the nonce fields.. + */ +contract TestSignatureAggregator is IAggregator { + + /// @inheritdoc IAggregator + function validateSignatures(UserOperation[] calldata userOps, bytes calldata signature) external pure override { + uint sum = 0; + for (uint i = 0; i < userOps.length; i++) { + uint nonce = userOps[i].nonce; + sum += nonce; + } + require(signature.length == 32, "TestSignatureValidator: sig must be uint"); + (uint sig) = abi.decode(signature, (uint)); + require(sig == sum, "TestSignatureValidator: aggregated signature mismatch (nonce sum)"); + } + + /// @inheritdoc IAggregator + function validateUserOpSignature(UserOperation calldata) + external pure returns (bytes memory) { + return ""; + } + + /** + * dummy test aggregator: sum all nonce values of UserOps. + */ + function aggregateSignatures(UserOperation[] calldata userOps) external pure returns (bytes memory aggregatedSignature) { + uint sum = 0; + for (uint i = 0; i < userOps.length; i++) { + sum += userOps[i].nonce; + } + return abi.encode(sum); + } + + /** + * Calls the 'addStake' method of the EntryPoint. Forwards the entire msg.value to this call. + * @param entryPoint - the EntryPoint to send the stake to. + * @param delay - the new lock duration before the deposit can be withdrawn. + */ + function addStake(IEntryPoint entryPoint, uint32 delay) external payable { + entryPoint.addStake{value: msg.value}(delay); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestToken.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestToken.sol new file mode 100644 index 000000000..41997b71a --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestToken.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract TestToken is ERC20 { + constructor () + // solhint-disable-next-line no-empty-blocks + ERC20("TST", "TestToken") { + } + + function mint(address sender, uint256 amount) external { + _mint(sender, amount); + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestUtil.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestUtil.sol new file mode 100644 index 000000000..0372ee8e5 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestUtil.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "../interfaces/UserOperation.sol"; + +contract TestUtil { + using UserOperationLib for UserOperation; + + function packUserOp(UserOperation calldata op) external pure returns (bytes memory){ + return op.pack(); + } + +} diff --git a/packages/hebao_v3/contracts/account-abstraction/test/TestWarmColdAccount.sol b/packages/hebao_v3/contracts/account-abstraction/test/TestWarmColdAccount.sol new file mode 100644 index 000000000..76f35bc80 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/test/TestWarmColdAccount.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity ^0.8.12; +/* solhint-disable no-inline-assembly */ + +import "../interfaces/IEntryPoint.sol"; +import "../interfaces/IAccount.sol"; + +// Using eip-2929 (https://eips.ethereum.org/EIPS/eip-2929) warm/cold storage access gas costs to detect simulation vs execution +// COLD_ACCOUNT_ACCESS_COST == 2600, COLD_SLOAD_COST == 2100, WARM_STORAGE_READ_COST == 100 +contract TestWarmColdAccount is IAccount { + IEntryPoint private ep; + uint public state = 1; + constructor(IEntryPoint _ep) payable { + ep = _ep; + } + + function validateUserOp(UserOperation calldata userOp, bytes32, uint256 missingAccountFunds) + external override returns (uint256 validationData) { + ep.depositTo{value : missingAccountFunds}(address(this)); + if (userOp.nonce == 1) { + // can only succeed if storage is already warm + this.touchStorage{gas: 1000}(); + } else if (userOp.nonce == 2) { + address paymaster = address(bytes20(userOp.paymasterAndData[: 20])); + // can only succeed if storage is already warm + this.touchPaymaster{gas: 1000}(paymaster); + } + return 0; + } + + function touchStorage() public view returns (uint256) { + return state; + } + + function touchPaymaster(address paymaster) public view returns (uint256) { + return paymaster.code.length; + } +} diff --git a/packages/hebao_v3/contracts/account-abstraction/utils/Exec.sol b/packages/hebao_v3/contracts/account-abstraction/utils/Exec.sol new file mode 100644 index 000000000..69d653d93 --- /dev/null +++ b/packages/hebao_v3/contracts/account-abstraction/utils/Exec.sol @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: LGPL-3.0-only +pragma solidity >=0.7.5 <0.9.0; + +// solhint-disable no-inline-assembly + +/** + * Utility functions helpful when making different kinds of contract calls in Solidity. + */ +library Exec { + + function call( + address to, + uint256 value, + bytes memory data, + uint256 txGas + ) internal returns (bool success) { + assembly { + success := call(txGas, to, value, add(data, 0x20), mload(data), 0, 0) + } + } + + function staticcall( + address to, + bytes memory data, + uint256 txGas + ) internal view returns (bool success) { + assembly { + success := staticcall(txGas, to, add(data, 0x20), mload(data), 0, 0) + } + } + + function delegateCall( + address to, + bytes memory data, + uint256 txGas + ) internal returns (bool success) { + assembly { + success := delegatecall(txGas, to, add(data, 0x20), mload(data), 0, 0) + } + } + + // get returned data from last call or calldelegate + function getReturnData(uint256 maxLen) internal pure returns (bytes memory returnData) { + assembly { + let len := returndatasize() + if gt(len, maxLen) { + len := maxLen + } + let ptr := mload(0x40) + mstore(0x40, add(ptr, add(len, 0x20))) + mstore(ptr, len) + returndatacopy(add(ptr, 0x20), 0, len) + returnData := ptr + } + } + + // revert with explicit byte array (probably reverted info from call) + function revertWithData(bytes memory returnData) internal pure { + assembly { + revert(add(returnData, 32), mload(returnData)) + } + } + + function callAndRevert(address to, bytes memory data, uint256 maxLen) internal { + bool success = call(to,0,data,gasleft()); + if (!success) { + revertWithData(getReturnData(maxLen)); + } + } +} diff --git a/packages/hebao_v3/contracts/base/ConnectorRegistry.sol b/packages/hebao_v3/contracts/base/ConnectorRegistry.sol new file mode 100644 index 000000000..24f0a3184 --- /dev/null +++ b/packages/hebao_v3/contracts/base/ConnectorRegistry.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/access/Ownable.sol"; +import "@openzeppelin/contracts/access/AccessControl.sol"; +import "../iface/IConnectorRegistry.sol"; + +contract ConnectorRegistry is AccessControl, Ownable, IConnectorRegistry { + bytes32 public constant MANAGER = keccak256("MANAGER"); + + mapping(address => bool) public connectors; + + modifier onlyManager() { + require(hasRole(MANAGER, msg.sender), "not a manager"); + _; + } + + constructor() { + _grantRole(DEFAULT_ADMIN_ROLE, owner()); + _grantRole(MANAGER, owner()); + } + + function addConnectors( + address[] calldata _connectors + ) external onlyManager { + for (uint i = 0; i < _connectors.length; ++i) { + // allow to add same connectors multiple times + if (!connectors[_connectors[i]]) { + connectors[_connectors[i]] = true; + } + } + } + + function removeConnectors( + address[] calldata _connectors + ) external onlyManager { + for (uint i = 0; i < _connectors.length; ++i) { + if (connectors[_connectors[i]]) { + connectors[_connectors[i]] = false; + } + } + } + + /** + * @dev Check if Connector addresses are enabled. + * @param connectorAddrs Array of Connector Names. + */ + function isConnectors( + address[] calldata connectorAddrs + ) external view returns (bool isOk) { + isOk = true; + uint len = connectorAddrs.length; + for (uint i = 0; i < len; i++) { + if (!connectors[connectorAddrs[i]]) { + isOk = false; + break; + } + } + } +} diff --git a/packages/hebao_v3/contracts/base/DelayedImplementationManager.sol b/packages/hebao_v3/contracts/base/DelayedImplementationManager.sol new file mode 100644 index 000000000..a92e6638f --- /dev/null +++ b/packages/hebao_v3/contracts/base/DelayedImplementationManager.sol @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../lib/Ownable.sol"; + +/** + * @title DelayedImplementationManager + * @author Kongliang Zhong - + */ +contract DelayedImplementationManager is Ownable { + address public currImpl; + address public nextImpl; + uint public nextEffectiveTime; + + event UpgradeScheduled(address nextImpl, uint effectiveTime); + event UpgradeCancelled(address nextImpl); + event ImplementationChanged(address newImpl); + + constructor(address initImpl) { + require(initImpl != address(0), "ZERO_ADDRESS"); + currImpl = initImpl; + } + + /** + * @dev Allows the proxy owner to upgrade the current version of the proxy. + * @param _nextImpl representing the address of the next implementation to be set. + * @param _daysToDelay representing the amount of days after the next implementation take effect. + */ + function delayedUpgradeTo( + address _nextImpl, + uint _daysToDelay + ) public onlyOwner { + if (_nextImpl == address(0)) { + require( + nextImpl != address(0) && _daysToDelay == 0, + "INVALID_ARGS" + ); + emit UpgradeCancelled(nextImpl); + nextImpl = address(0); + } else { + require(_daysToDelay >= 1, "INVALID_DAYS"); + // solhint-disable-next-line not-rely-on-time + uint _nextEffectiveTime = block.timestamp + _daysToDelay * 1 days; + nextImpl = _nextImpl; + nextEffectiveTime = _nextEffectiveTime; + emit UpgradeScheduled(_nextImpl, _nextEffectiveTime); + } + } + + /** + * @dev Allows everyone to replace implementation after effective time. + */ + function executeUpgrade() public { + require( + // solhint-disable-next-line not-rely-on-time + nextImpl != address(0) && block.timestamp >= nextEffectiveTime, + "NOT_IN_EFFECT" + ); + currImpl = nextImpl; + nextImpl = address(0); + emit ImplementationChanged(currImpl); + } +} diff --git a/packages/hebao_v3/contracts/base/ForwardProxy.sol b/packages/hebao_v3/contracts/base/ForwardProxy.sol new file mode 100644 index 000000000..e9a6af690 --- /dev/null +++ b/packages/hebao_v3/contracts/base/ForwardProxy.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/proxy/Proxy.sol"; +import "./DelayedImplementationManager.sol"; + +/** + * @title ForwardProxy + * @author Kongliang Zhong - + */ +contract ForwardProxy is Proxy { + DelayedImplementationManager public immutable implManager; + + constructor(address _implManager) { + require(_implManager != address(0), "ZERO_ADDRESS"); + implManager = DelayedImplementationManager(_implManager); + } + + function _implementation() internal view override returns (address) { + return implManager.currImpl(); + } +} diff --git a/packages/hebao_v3/contracts/base/LoopringCreate2Deployer.sol b/packages/hebao_v3/contracts/base/LoopringCreate2Deployer.sol new file mode 100644 index 000000000..5a56b3423 --- /dev/null +++ b/packages/hebao_v3/contracts/base/LoopringCreate2Deployer.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "../lib/DelayTargetSelectorBasedAccessManager.sol"; + +contract LoopringCreate2Deployer is DelayTargetSelectorBasedAccessManager { + event Deployed(address addr, uint256 salt); + + function deploy(bytes memory code, uint256 salt) public { + address addr; + // solhint-disable-next-line no-inline-assembly + assembly { + addr := create2(0, add(code, 0x20), mload(code), salt) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + + emit Deployed(addr, salt); + } +} diff --git a/packages/hebao_v3/contracts/base/LoopringPaymaster.sol b/packages/hebao_v3/contracts/base/LoopringPaymaster.sol new file mode 100644 index 000000000..515016d1d --- /dev/null +++ b/packages/hebao_v3/contracts/base/LoopringPaymaster.sol @@ -0,0 +1,355 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +/* solhint-disable reason-string */ +/* solhint-disable no-inline-assembly */ + +import "../account-abstraction/core/BasePaymaster.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/access/AccessControl.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +import "../lib/LoopringErrors.sol"; + +/** + * A sample paymaster that uses external service to decide whether to pay for the UserOp. + * The paymaster trusts an external signer to sign the transaction. + * The calling user must pass the UserOp to that external signer first, which performs + * whatever off-chain verification before signing the UserOp. + * Note that this signature is NOT a replacement for the account-specific signature: + * - the paymaster checks a signature to agree to PAY for GAS. + * - the account checks a signature to prove identity and account ownership. + */ +contract LoopringPaymaster is BasePaymaster, AccessControl { + using ECDSA for bytes32; + using UserOperationLib for UserOperation; + using SafeERC20 for IERC20; + + uint256 private constant VALID_TIMESTAMP_OFFSET = 20; + + uint256 private constant SIGNATURE_OFFSET = 84; + + // calculated cost of the postOp + uint256 private constant COST_OF_POST = 60000; + uint8 private constant PRICE_DECIMAL = 8; + bytes32 public constant SIGNER = keccak256("SIGNER"); + + mapping(address => bool) public registeredToken; + mapping(address => mapping(address => uint256)) public balances; + mapping(address => uint256) public unlockBlock; + + event PaymasterEvent( + bytes32 indexed userOpHash, + address token, + uint256 valueOfEth, + uint256 actualETHCost, + uint256 actualTokenCost + ); + + error TokenLocked(address token, address user, uint256 unlockedBlockNumber); + error TokenUnregistered(address token); + error TokenRegistered(address token); + error InvalidSignatureLength(uint256 length); + error NoEnoughTokenBalance(address user, uint256 tokenRequiredPreFund); + + constructor( + IEntryPoint _entryPoint, + address paymasterOwner + ) BasePaymaster(_entryPoint) { + _require(paymasterOwner != address(0), Errors.ZERO_ADDRESS); + _transferOwnership(paymasterOwner); + _grantRole(DEFAULT_ADMIN_ROLE, owner()); + _grantRole(SIGNER, paymasterOwner); + } + + receive() external payable { + revert("eth rejected"); + } + + struct DecodedData { + address token; + uint48 validUntil; + // uint48 validAfter; + uint256 valueOfEth; + } + + /** + * return the hash we're going to sign off-chain (and validate on-chain) + * this method is called by the off-chain service, to sign the request. + * it is called on-chain from the validatePaymasterUserOp, to validate the signature. + * note that this signature covers all fields of the UserOperation, except the "paymasterAndData", + * which will carry the signature itself. + */ + function getHash( + UserOperation calldata userOp, + bytes32 dataHash + ) public view returns (bytes32) { + //can't use userOp.hash(), since it contains also the paymasterAndData itself. + return + keccak256( + abi.encode( + userOp.getSender(), + userOp.nonce, + keccak256(userOp.initCode), + keccak256(userOp.callData), + userOp.callGasLimit, + userOp.verificationGasLimit, + userOp.preVerificationGas, + userOp.maxFeePerGas, + userOp.maxPriorityFeePerGas, + // data of paymaster + block.chainid, + address(this), + dataHash + ) + ); + } + + /** + * verify our external signer signed this request. + * the "paymasterAndData" is expected to be the paymaster and a signature over the entire request params + * paymasterAndData[:20] : address(this) + * paymasterAndData[20:84] : abi.encode(validUntil, validAfter) + * paymasterAndData[84:] : signature + */ + function _validatePaymasterUserOp( + UserOperation calldata userOp, + bytes32 userOpHash, + uint256 requiredPreFund + ) internal view override returns (bytes memory, uint256) { + address sender = userOp.getSender(); + ( + DecodedData memory decodedData, + bytes memory signature + ) = parsePaymasterAndData(userOp.paymasterAndData); + _require( + registeredToken[decodedData.token], + Errors.TOKEN_NOT_REGISTERED + ); + + //ECDSA library supports both 64 and 65-byte long signatures. + // we only "require" it here so that the revert reason on invalid signature will be of "VerifyingPaymaster", and not "ECDSA" + _require( + signature.length == 64 || signature.length == 65, + Errors.INVALID_SIGNATURE_LENGTH + ); + + // NOTE(cannot use basefee during validation) + uint256 costOfPost = userOp.maxFeePerGas * COST_OF_POST; + // skip allowance check to allow user to start without any eth to pay for approve + if (decodedData.valueOfEth > 0) { + uint256 tokenRequiredPreFund = ((requiredPreFund + costOfPost) * + 10 ** PRICE_DECIMAL) / decodedData.valueOfEth; + _require( + (unlockBlock[sender] == 0 && + balances[decodedData.token][sender] >= + tokenRequiredPreFund) || + IERC20(decodedData.token).balanceOf(sender) >= + tokenRequiredPreFund, + Errors.NO_ENOUGH_TOKEN_BALANCE + ); + } + bytes32 hash = ECDSA.toEthSignedMessageHash( + getHash( + userOp, + keccak256( + abi.encodePacked( + decodedData.token, + decodedData.validUntil, + // decodedData.validAfter, + decodedData.valueOfEth + ) + ) + ) + ); + + //don't revert on signature failure: return SIG_VALIDATION_FAILED + if (!hasRole(SIGNER, hash.recover(signature))) { + return ( + "", + _packValidationData( + true, + decodedData.validUntil, + uint48(0) /*decodedData.validAfter*/ + ) + ); + } + + //no need for other on-chain validation: entire UserOp should have been checked + // by the external service prior to signing it. + return ( + abi.encode( + userOpHash, + sender, + decodedData.token, + costOfPost, + decodedData.valueOfEth + ), + _packValidationData( + false, + decodedData.validUntil, + uint48(0) /*decodedData.validAfter*/ + ) + ); + } + + function parsePaymasterAndData( + bytes calldata paymasterAndData + ) + public + pure + returns (DecodedData memory decodedData, bytes memory signature) + { + ( + decodedData.token, + decodedData.validUntil, + decodedData.valueOfEth, + signature + ) = abi.decode( + paymasterAndData[VALID_TIMESTAMP_OFFSET:], + (address, uint48, uint256, bytes) + ); + } + + /** + * post-operation handler. + * (verified to be called only through the entryPoint) + * @dev if subclass returns a non-empty context from validatePaymasterUserOp, it must also implement this method. + * @param mode enum with the following options: + * opSucceeded - user operation succeeded. + * opReverted - user op reverted. still has to pay for gas. + * postOpReverted - user op succeeded, but caused postOp (in mode=opSucceeded) to revert. + * Now this is the 2nd call, after user's op was deliberately reverted. + * @param context - the context value returned by validatePaymasterUserOp + * @param actualGasCost - actual gas used so far (without this postOp call). + */ + function _postOp( + PostOpMode mode, + bytes calldata context, + uint256 actualGasCost + ) internal override { + (mode); + ( + bytes32 userOpHash, + address account, + address payable token, + uint256 costOfPost, + uint256 valueOfEth + ) = abi.decode(context, (bytes32, address, address, uint256, uint256)); + uint256 actualTokenCost; + uint256 actualETHCost = actualGasCost + costOfPost; + if (valueOfEth > 0) { + actualTokenCost = + (actualETHCost * 10 ** PRICE_DECIMAL) / + valueOfEth; + + if (balances[token][account] >= actualTokenCost) { + balances[token][account] -= actualTokenCost; + } else { + // attempt to pay with tokens: + IERC20(token).safeTransferFrom( + account, + address(this), + actualTokenCost + ); + } + balances[token][owner()] += actualTokenCost; + } + + emit PaymasterEvent( + userOpHash, + token, + valueOfEth, + actualETHCost, + actualTokenCost + ); + } + + //////////////////////////////////// + // gas tank + + /** + * owner of the paymaster should add supported tokens + */ + function addToken(address token) external onlyOwner { + _require(token != address(0), Errors.ZERO_ADDRESS); + _require(!registeredToken[token], Errors.TOKEN_ALREADY_REGISTERED); + registeredToken[token] = true; + } + + function removeToken(address token) external onlyOwner { + _require(token != address(0), Errors.ZERO_ADDRESS); + _require(registeredToken[token], Errors.TOKEN_NOT_REGISTERED); + registeredToken[token] = false; + } + + /** + * deposit tokens that a specific account can use to pay for gas. + * The sender must first approve this paymaster to withdraw these tokens (they are only withdrawn in this method). + * Note depositing the tokens is equivalent to transferring them to the "account" - only the account can later + * use them - either as gas, or using withdrawTo() + * + * @param token the token to deposit. + * @param account the account to deposit for. + * @param amount the amount of token to deposit. + */ + function addDepositFor( + address token, + address account, + uint256 amount + ) external { + _require(registeredToken[token], Errors.TOKEN_NOT_REGISTERED); + //(sender must have approval for the paymaster) + IERC20(token).safeTransferFrom(msg.sender, address(this), amount); + balances[token][account] += amount; + if (msg.sender == account) { + lockTokenDeposit(); + } + } + + function depositInfo( + address token, + address account + ) public view returns (uint256 amount, uint256 _unlockBlock) { + amount = balances[token][account]; + _unlockBlock = unlockBlock[account]; + } + + /** + * unlock deposit, so that it can be withdrawn. + * can't be called in the same block as withdrawTo() + */ + function unlockTokenDeposit() public { + unlockBlock[msg.sender] = block.number; + } + + /** + * lock the tokens deposited for this account so they can be used to pay for gas. + * after calling unlockTokenDeposit(), the account can't use this paymaster until the deposit is locked. + */ + function lockTokenDeposit() public { + unlockBlock[msg.sender] = 0; + } + + /** + * withdraw tokens. + * can only be called after unlock() is called in a previous block. + * @param token the token deposit to withdraw + * @param target address to send to + * @param amount amount to withdraw + */ + function withdrawTokensTo( + address token, + address target, + uint256 amount + ) public { + uint256 unlockedBlockNumber = unlockBlock[msg.sender]; + _require( + unlockedBlockNumber != 0 && block.number > unlockedBlockNumber, + Errors.PAYMASTER_TOKEN_LOCKED + ); + balances[token][msg.sender] -= amount; + IERC20(token).safeTransfer(target, amount); + } +} diff --git a/packages/hebao_v3/contracts/base/OfficialGuardian.sol b/packages/hebao_v3/contracts/base/OfficialGuardian.sol new file mode 100644 index 000000000..c3c0d5f03 --- /dev/null +++ b/packages/hebao_v3/contracts/base/OfficialGuardian.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../lib/ERC1271.sol"; +import "../lib/OwnerManagable.sol"; +import "../lib/SignatureUtil.sol"; +import "../lib/LoopringErrors.sol"; + +/// @title OfficialGuardian +/// @author Freeman Zhong - +contract OfficialGuardian is OwnerManagable, ERC1271 { + using SignatureUtil for bytes32; + + /// @dev init owner for proxy contract: + function initOwner(address _owner) external { + _require(_owner != address(0), Errors.ZERO_ADDRESS); + _require(owner == address(0), Errors.INITIALIZED_ALREADY); + owner = _owner; + } + + function isValidSignature( + bytes32 _signHash, + bytes calldata _signature + ) public view override returns (bytes4) { + return + isManager(_signHash.recoverECDSASigner(_signature)) + ? ERC1271_MAGICVALUE + : bytes4(0); + } + + function transact( + address target, + uint value, + bytes calldata data + ) external onlyManager returns (bool success, bytes memory returnData) { + // solhint-disable-next-line avoid-low-level-calls + (success, returnData) = target.call{value: value}(data); + _require(success, Errors.OFFICIALGUARDIAN_CALL_FAILED); + } +} diff --git a/packages/hebao_v3/contracts/base/SmartWallet.sol b/packages/hebao_v3/contracts/base/SmartWallet.sol new file mode 100644 index 000000000..f10a56d65 --- /dev/null +++ b/packages/hebao_v3/contracts/base/SmartWallet.sol @@ -0,0 +1,528 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/ILoopringWalletV2.sol"; +import "../account-abstraction/interfaces/IEntryPoint.sol"; +import "../account-abstraction/core/BaseAccount.sol"; + +import "../lib/EIP712.sol"; +import "../lib/ERC1271.sol"; +import "../thirdparty/erc165/IERC165.sol"; +import "../thirdparty/erc1155/ERC1155Holder.sol"; +import "../thirdparty/erc721/ERC721Holder.sol"; + +import "./libwallet/ERC20Lib.sol"; +import "./libwallet/ERC1271Lib.sol"; +import "./libwallet/WalletData.sol"; +import "./libwallet/LockLib.sol"; +import "./libwallet/GuardianLib.sol"; +import "./libwallet/InheritanceLib.sol"; +import "./libwallet/WhitelistLib.sol"; +import "./libwallet/QuotaLib.sol"; +import "./libwallet/RecoverLib.sol"; +import "./libwallet/UpgradeLib.sol"; +import "../lib/LoopringErrors.sol"; + +/// @title SmartWallet +/// @dev Main smart wallet contract +/// @author Brecht Devos - +abstract contract SmartWallet is + ILoopringWalletV2, + ERC1271, + IERC165, + ERC721Holder, + ERC1155Holder, + BaseAccount +{ + using ERC20Lib for Wallet; + using ERC1271Lib for Wallet; + using LockLib for Wallet; + using GuardianLib for Wallet; + using InheritanceLib for Wallet; + using WhitelistLib for Wallet; + using QuotaLib for Wallet; + using RecoverLib for Wallet; + using UpgradeLib for Wallet; + using AutomationLib for Wallet; + + bytes32 public immutable domainSeparator; + PriceOracle public immutable priceOracle; + address public immutable blankOwner; + IEntryPoint internal immutable _entryPoint; + address internal immutable connectorRegistry; + + // WARNING: Do not delete wallet state data to make this implementation + // compatible with early versions. + // + // ----- DATA LAYOUT BEGINS ----- + // Always needs to be first + address internal masterCopy; + + bool internal isImplementationContract; + + Wallet public wallet; + // ----- DATA LAYOUT ENDS ----- + + /// @dev We need to make sure the implemenation contract cannot be initialized + /// and used to do delegate calls to arbitrary contracts. + modifier disableInImplementationContract() { + _require( + !isImplementationContract, + Errors.DISALLOWED_ON_IMPLEMENTATION_CONTRACT + ); + _; + } + + modifier canTransferOwnership() { + _require( + msg.sender == blankOwner && wallet.owner == blankOwner, + Errors.NOT_ALLOWED_TO_SET_OWNER + ); + _; + } + + modifier onlyFromEntryPoint() { + _require( + msg.sender == address(entryPoint()), + Errors.ONLY_FROM_ENTRYPOINT + ); + wallet.touchLastActiveWhenRequired(); + _; + } + + // Require the function call went through EntryPoint or wallet self or owner + modifier onlyFromEntryPointOrWalletOrOwnerWhenUnlocked() { + _require( + msg.sender == address(this) || + ((msg.sender == address(entryPoint()) || + msg.sender == wallet.owner) && !wallet.locked), + Errors.NOT_OWNER_SELF_OR_ENTRYPOINT_OR_LOCKED + ); + wallet.touchLastActiveWhenRequired(); + _; + } + + /// @inheritdoc BaseAccount + function entryPoint() public view virtual override returns (IEntryPoint) { + if (wallet.entryPoint != address(0)) { + return IEntryPoint(wallet.entryPoint); + } + return _entryPoint; + } + + constructor( + PriceOracle _priceOracle, + address _blankOwner, + IEntryPoint entryPointInput, + address _connectorRegistry + ) { + isImplementationContract = true; + _require(_connectorRegistry != address(0), Errors.ZERO_ADDRESS); + _require(address(entryPointInput) != address(0), Errors.ZERO_ADDRESS); + _entryPoint = entryPointInput; + connectorRegistry = _connectorRegistry; + + domainSeparator = EIP712.hash( + EIP712.Domain("LoopringWallet", "2.0.0", address(this)) + ); + + priceOracle = _priceOracle; + blankOwner = _blankOwner; + } + + /// @dev Set up this wallet. + /// + /// Note that calling this method more than once will throw. + /// + /// @param owner The owner of this wallet, must not be address(0). + /// @param guardians The guardians of this wallet. + function initialize( + address owner, + address[] calldata guardians, + uint quota, + address inheritor, + address feeRecipient, + address feeToken, + uint feeAmount + ) external override disableInImplementationContract { + _require(wallet.owner == address(0), Errors.INITIALIZED_ALREADY); + _require(owner != address(0), Errors.INVALID_OWNER); + + wallet.owner = owner; + wallet.creationTimestamp = uint64(block.timestamp); + wallet.addGuardiansImmediately(guardians); + + if (quota != 0) { + wallet.setQuota(quota, 0); + } + + if (inheritor != address(0)) { + wallet.setInheritor(inheritor, 365 days); + } + + // Pay for the wallet creation using wallet funds + if (feeRecipient != address(0) && feeAmount > 0) { + ERC20Lib.transfer(feeToken, feeRecipient, feeAmount); + } + } + + receive() external payable {} + + function getOwner() public view override returns (address) { + return wallet.owner; + } + + function getCreationTimestamp() public view override returns (uint64) { + return wallet.creationTimestamp; + } + + // + // Owner + // + function transferOwnership(address _owner) external canTransferOwnership { + _require(_owner != address(0), Errors.INVALID_OWNER); + wallet.owner = _owner; + } + + // + // ERC1271 + // + function isValidSignature( + bytes32 signHash, + bytes calldata signature + ) public view override returns (bytes4 magicValue) { + return wallet.isValidSignature(ERC1271_MAGICVALUE, signHash, signature); + } + + // + // Upgrade + // + + function changeMasterCopy( + address newMasterCopy + ) external onlyFromEntryPoint { + UpgradeLib.changeMasterCopy(newMasterCopy); + masterCopy = newMasterCopy; + } + + function getMasterCopy() public view returns (address) { + return masterCopy; + } + + // + // change entrypoint + // + function changeEntryPoint( + address newEntryPoint + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + _require(newEntryPoint != address(0), Errors.ZERO_ADDRESS); + _require( + address(entryPoint()) != newEntryPoint, + Errors.INVALID_SAME_ENTRYPOINT + ); + wallet.entryPoint = newEntryPoint; + } + + // + // Guardians + // + function addGuardian( + address guardian + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.addGuardian(guardian); + } + + function addGuardianWA(address guardian) external onlyFromEntryPoint { + wallet.addGuardianWA(guardian); + } + + function removeGuardian( + address guardian + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.removeGuardian(guardian); + } + + function removeGuardianWA(address guardian) external onlyFromEntryPoint { + wallet.removeGuardianWA(guardian); + } + + function resetGuardians( + address[] calldata newGuardians + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.resetGuardians(newGuardians); + } + + function resetGuardiansWA( + address[] calldata newGuardians + ) external onlyFromEntryPoint { + wallet.resetGuardiansWA(newGuardians); + } + + function isGuardian( + address addr, + bool includePendingAddition + ) public view returns (bool) { + return wallet.isGuardian(addr, includePendingAddition); + } + + function getGuardians( + bool includePendingAddition + ) public view returns (Guardian[] memory) { + return GuardianLib.guardians(wallet, includePendingAddition); + } + + // + // Inheritance + // + + function setInheritor( + address inheritor, + uint32 waitingPeriod + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.setInheritor(inheritor, waitingPeriod); + } + + // no need to record last active time here before inherit + function inherit( + address newOwner, + address[] calldata newGuardians + ) external { + // allow inherit from inheritor or entrypoint + _require( + msg.sender == address(entryPoint()) || + msg.sender == wallet.inheritor, + Errors.NOT_ENTRYPOINT_OR_INHERITOR + ); + wallet.inherit(newOwner, newGuardians); + } + + // + // Lock + // + + function lock() external { + wallet.lock(address(entryPoint())); + } + + function unlock() external onlyFromEntryPoint { + wallet.unlock(); + } + + // + // Quota + // + + function changeDailyQuota( + uint newQuota + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.changeDailyQuota(newQuota); + } + + function changeDailyQuotaWA(uint newQuota) external onlyFromEntryPoint { + wallet.changeDailyQuotaWA(newQuota); + } + + // + // Recover + // + + function recover( + address newOwner, + address[] calldata newGuardians + ) external onlyFromEntryPoint { + wallet.recover(newOwner, newGuardians); + } + + // + // Whitelist + // + + function addToWhitelist( + address addr + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + _require(addr != address(0), Errors.ZERO_ADDRESS); + wallet.addToWhitelist(addr); + } + + function addToWhitelistWA(address addr) external onlyFromEntryPoint { + _require(addr != address(0), Errors.ZERO_ADDRESS); + wallet.addToWhitelistWA(addr); + } + + function removeFromWhitelist( + address addr + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + _require(addr != address(0), Errors.ZERO_ADDRESS); + wallet.removeFromWhitelist(addr); + } + + function getWhitelistEffectiveTime( + address addr + ) public view returns (uint) { + return wallet.whitelisted[addr]; + } + + function isWhitelisted(address addr) public view returns (bool) { + return wallet.isAddressWhitelisted(addr); + } + + // + // ERC20 + // + + function transferToken( + address token, + address to, + uint amount, + bytes calldata logdata, + bool forceUseQuota + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.transferToken( + priceOracle, + token, + to, + amount, + logdata, + forceUseQuota + ); + } + + function transferTokenWA( + address token, + address to, + uint amount, + bytes calldata logdata + ) external onlyFromEntryPoint { + ERC20Lib.transferTokenWA(token, to, amount, logdata); + } + + function callContract( + address to, + uint value, + bytes calldata data, + bool forceUseQuota + ) + external + onlyFromEntryPointOrWalletOrOwnerWhenUnlocked + returns (bytes memory) + { + return wallet.callContract(priceOracle, to, value, data, forceUseQuota); + } + + function callContractWA( + address to, + uint value, + bytes calldata data + ) external onlyFromEntryPoint returns (bytes memory) { + return ERC20Lib.callContractWA(to, value, data); + } + + function approveToken( + address token, + address to, + uint amount, + bool forceUseQuota + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + wallet.approveToken(priceOracle, token, to, amount, forceUseQuota); + } + + function approveTokenWA( + address token, + address to, + uint amount + ) external onlyFromEntryPoint { + ERC20Lib.approveTokenWA(token, to, amount); + } + + function approveThenCallContract( + address token, + address to, + uint amount, + uint value, + bytes calldata data, + bool forceUseQuota + ) + external + onlyFromEntryPointOrWalletOrOwnerWhenUnlocked + returns (bytes memory) + { + return + wallet.approveThenCallContract( + priceOracle, + token, + to, + amount, + value, + data, + forceUseQuota + ); + } + + function approveThenCallContractWA( + address token, + address to, + uint amount, + uint value, + bytes calldata data + ) external onlyFromEntryPoint returns (bytes memory returnData) { + returnData = ERC20Lib.approveThenCallContractWA( + token, + to, + amount, + value, + data + ); + } + + // ERC165 + function supportsInterface( + bytes4 interfaceId + ) external pure override returns (bool) { + return + interfaceId == type(ERC1271).interfaceId || + interfaceId == type(IERC165).interfaceId || + interfaceId == type(IERC721Receiver).interfaceId || + interfaceId == type(IERC1155Receiver).interfaceId; + } + + function isExecutorOrOwner(address executor) external view returns (bool) { + return AutomationLib.isExecutorOrOwner(wallet, executor); + } + + function approveExecutor( + address executor, + uint256 validUntil + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + _require(executor != address(0), Errors.ZERO_ADDRESS); + return AutomationLib.approveExecutor(wallet, executor, validUntil); + } + + function unApproveExecutor( + address executor + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + _require( + AutomationLib.isExecutorOrOwner(wallet, executor), + Errors.NOT_EXECUTOR + ); + return AutomationLib.unApproveExecutor(wallet, executor); + } + + function castFromEntryPoint( + address[] calldata targets, + bytes[] calldata datas + ) external onlyFromEntryPoint { + AutomationLib.cast(connectorRegistry, targets, datas); + } + + function castFromExecutor( + address[] calldata targets, + bytes[] calldata datas + ) external { + _require( + AutomationLib.isExecutorOrOwner(wallet, msg.sender), + Errors.NOT_EXECUTOR + ); + AutomationLib.cast(connectorRegistry, targets, datas); + } +} diff --git a/packages/hebao_v3/contracts/base/SmartWalletV3.sol b/packages/hebao_v3/contracts/base/SmartWalletV3.sol new file mode 100644 index 000000000..a8d3cc9cd --- /dev/null +++ b/packages/hebao_v3/contracts/base/SmartWalletV3.sol @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import {SmartWallet} from "./SmartWallet.sol"; +import "../account-abstraction/core/BaseAccount.sol"; +import "../account-abstraction/interfaces/IEntryPoint.sol"; +import "../iface/PriceOracle.sol"; +import "./libwallet/WalletData.sol"; +import "./libwallet/GuardianLib.sol"; +import "./libwallet/RecoverLib.sol"; +import "./libwallet/QuotaLib.sol"; +import "./libwallet/RecoverLib.sol"; +import "../lib/EIP712.sol"; +import "./libwallet/UpgradeLib.sol"; +import "./libwallet/WhitelistLib.sol"; +import "./libwallet/ApprovalLib.sol"; +import "./libwallet/ERC20Lib.sol"; +import "./libwallet/AutomationLib.sol"; +import "../lib/SignatureUtil.sol"; +import "../lib/LoopringErrors.sol"; + +contract SmartWalletV3 is SmartWallet { + constructor( + PriceOracle _priceOracle, + address _blankOwner, + IEntryPoint entryPointInput, + address connectorRegistry + ) + SmartWallet( + _priceOracle, + _blankOwner, + entryPointInput, + connectorRegistry + ) + {} + + function selfBatchCall( + bytes[] calldata data + ) external onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + for (uint i = 0; i < data.length; i++) { + // solhint-disable-next-line avoid-low-level-calls + (bool success, ) = address(this).call(data[i]); + _require(success, Errors.BATCHED_CALL_FAILED); + } + } + + /** + * check current account deposit in the entryPoint + */ + function getDeposit() public view returns (uint256) { + return entryPoint().balanceOf(address(this)); + } + + /** + * deposit more funds for this account in the entryPoint + */ + function addDeposit() public payable { + entryPoint().depositTo{value: msg.value}(address(this)); + } + + /** + * withdraw value from the account's deposit + * @param withdrawAddress target to send to + * @param amount to withdraw + */ + function withdrawDepositTo( + address payable withdrawAddress, + uint256 amount + ) public onlyFromEntryPointOrWalletOrOwnerWhenUnlocked { + entryPoint().withdrawTo(withdrawAddress, amount); + } + + /// implement template method of BaseAccount + function _validateSignature( + UserOperation calldata userOp, + bytes32 userOpHash + ) internal virtual override returns (uint256 sigTimeRange) { + return + ApprovalLib.validateSignature( + wallet, + userOp, + userOpHash, + domainSeparator + ); + } +} diff --git a/packages/hebao_v3/contracts/base/WalletDeploymentLib.sol b/packages/hebao_v3/contracts/base/WalletDeploymentLib.sol new file mode 100644 index 000000000..96754868c --- /dev/null +++ b/packages/hebao_v3/contracts/base/WalletDeploymentLib.sol @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/utils/Create2.sol"; +import "../thirdparty/proxies/WalletProxy.sol"; +import "../lib/LoopringErrors.sol"; + +/// @title WalletDeploymentLib +/// @dev Functionality to compute wallet addresses and to deploy wallets +/// @author Brecht Devos - +contract WalletDeploymentLib { + address public immutable walletImplementation; + + string private constant WALLET_CREATION = "WALLET_CREATION"; + + constructor(address _walletImplementation) { + _require(_walletImplementation != address(0), Errors.ZERO_ADDRESS); + walletImplementation = _walletImplementation; + } + + function getWalletCode() public view returns (bytes memory) { + return + abi.encodePacked( + type(WalletProxy).creationCode, + abi.encode(walletImplementation) + ); + } + + function computeWalletSalt( + address owner, + uint salt + ) public pure returns (bytes32) { + return keccak256(abi.encodePacked(WALLET_CREATION, owner, salt)); + } + + function _deploy( + address owner, + uint salt + ) internal returns (address wallet) { + wallet = Create2.deploy( + 0, + computeWalletSalt(owner, salt), + getWalletCode() + ); + } + + function _computeWalletAddress( + address owner, + uint salt, + address deployer + ) internal view returns (address) { + return + Create2.computeAddress( + computeWalletSalt(owner, salt), + keccak256(getWalletCode()), + deployer + ); + } +} diff --git a/packages/hebao_v3/contracts/base/WalletFactory.sol b/packages/hebao_v3/contracts/base/WalletFactory.sol new file mode 100644 index 000000000..98e91f19b --- /dev/null +++ b/packages/hebao_v3/contracts/base/WalletFactory.sol @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/ILoopringWalletV2.sol"; +import "../lib/EIP712.sol"; +import "../lib/SignatureUtil.sol"; +import "./WalletDeploymentLib.sol"; +import "../lib/Ownable.sol"; +import "../lib/AddressSet.sol"; + +/// @title WalletFactory +/// @dev A factory contract to create a new wallet by deploying a proxy +/// in front of a real wallet. +/// @author Daniel Wang - +contract WalletFactory is WalletDeploymentLib, Ownable, AddressSet { + bytes32 internal constant OPERATOR = keccak256("__OPERATOR__"); + using SignatureUtil for bytes32; + + event WalletCreated(address wallet, address owner); + + event OperatorRemoved(address indexed operator); + event OperatorAdded(address indexed operator); + + bytes32 public immutable domainSeparator; + + bytes32 private constant CREATE_WALLET_TYPEHASH = + keccak256( + "createWallet(address owner,address[] guardians,uint256 quota,address inheritor,address feeRecipient,address feeToken,uint256 maxFeeAmount,uint256 salt)" + ); + + ///////////////////////////////// opeartor /////////////////// + modifier onlyOperator() { + require(isOperator(msg.sender), "NOT A OPERATOR"); + _; + } + + function isOperator(address addr) public view returns (bool) { + return isAddressInSet(OPERATOR, addr); + } + + /// @dev Gets the operators. + /// @return The list of operators. + function operators() public view returns (address[] memory) { + return addressesInSet(OPERATOR); + } + + /// @dev Gets the number of operators. + /// @return The numer of operators. + function numOperators() public view returns (uint) { + return numAddressesInSet(OPERATOR); + } + + /// @dev Adds a new operator. + /// @param operator The new address to add. + function addOperator(address operator) public onlyOwner { + addOperatorInternal(operator); + } + + /// @dev Removes a operator. + /// @param operator The operator to remove. + function removeOperator(address operator) public onlyOwner { + removeAddressFromSet(OPERATOR, operator); + emit OperatorRemoved(operator); + } + + function addOperatorInternal(address operator) internal { + addAddressToSet(OPERATOR, operator, true); + emit OperatorAdded(operator); + } + + struct WalletConfig { + address owner; + address[] guardians; + uint quota; + address inheritor; + address feeRecipient; + address feeToken; + uint maxFeeAmount; + uint salt; + bytes signature; + } + + struct WalletConfigV2 { + address owner; + address initOwner; + address[] guardians; + uint quota; + address inheritor; + address feeRecipient; + address feeToken; + uint maxFeeAmount; + uint salt; + } + + constructor( + address _walletImplementation + ) WalletDeploymentLib(_walletImplementation) { + domainSeparator = EIP712.hash( + EIP712.Domain("WalletFactory", "2.0.0", address(this)) + ); + } + + /// @dev Create a new wallet by deploying a proxy. + /// @param config The wallet's config. + /// @param feeAmount The fee amount actually paid. + /// @return wallet The new wallet address + function createWallet( + WalletConfig calldata config, + uint feeAmount + ) external onlyOperator returns (address wallet) { + require(feeAmount <= config.maxFeeAmount, "INVALID_FEE_AMOUNT"); + + _validateConfig(config); + wallet = _deploy(config.owner, config.salt); + _initializeWallet(wallet, config, feeAmount); + } + + /// @dev Create a new wallet by deploying a proxy. + /// @param config The wallet's config. + /// @param feeAmount The fee amount actually paid. + /// @return wallet The new wallet address + function createWalletByOperator( + WalletConfigV2 calldata config, + uint feeAmount + ) external onlyOperator returns (address wallet) { + require(feeAmount <= config.maxFeeAmount, "INVALID_FEE_AMOUNT"); + + require(config.owner != address(0), "INVALID_OWNER"); + wallet = _deploy(config.initOwner, config.salt); + ILoopringWalletV2(wallet).initialize( + config.owner, + config.guardians, + config.quota, + config.inheritor, + config.feeRecipient, + config.feeToken, + feeAmount + ); + + emit WalletCreated(wallet, config.owner); + } + + /// @dev Computes the wallet address + /// @param salt The initial wallet owner. + /// @param salt A salt. + /// @return wallet The wallet address + function computeWalletAddress( + address owner, + uint salt + ) public view returns (address) { + return _computeWalletAddress(owner, salt, address(this)); + } + + // --- Internal functions --- + + function _initializeWallet( + address wallet, + WalletConfig calldata config, + uint feeAmount + ) internal { + ILoopringWalletV2(wallet).initialize( + config.owner, + config.guardians, + config.quota, + config.inheritor, + config.feeRecipient, + config.feeToken, + feeAmount + ); + + emit WalletCreated(wallet, config.owner); + } + + function _validateConfig(WalletConfig calldata config) private view { + require(config.owner != address(0), "INVALID_OWNER"); + + bytes32 dataHash = keccak256( + abi.encode( + CREATE_WALLET_TYPEHASH, + config.owner, + keccak256(abi.encodePacked(config.guardians)), + config.quota, + config.inheritor, + config.feeRecipient, + config.feeToken, + config.maxFeeAmount, + config.salt + ) + ); + + bytes32 signHash = EIP712.hashPacked(domainSeparator, dataHash); + require( + signHash.verifySignature(config.owner, config.signature), + "INVALID_SIGNATURE" + ); + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/ApprovalLib.sol b/packages/hebao_v3/contracts/base/libwallet/ApprovalLib.sol new file mode 100644 index 000000000..aad02a33f --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/ApprovalLib.sol @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../../thirdparty/BytesUtil.sol"; +import {SmartWallet} from "../SmartWallet.sol"; +import "../../lib/EIP712.sol"; +import "../../lib/SignatureUtil.sol"; +import "./GuardianLib.sol"; +import "./WalletData.sol"; +import "./RecoverLib.sol"; +import "./QuotaLib.sol"; +import "./RecoverLib.sol"; +import "./UpgradeLib.sol"; +import "./WhitelistLib.sol"; +import "./ApprovalLib.sol"; +import "./ERC20Lib.sol"; +import "./AutomationLib.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; + +import "../../account-abstraction/core/Helpers.sol"; +import "../../account-abstraction/interfaces/UserOperation.sol"; + +/// @title ApprovalLib +/// @dev Utility library for better handling of signed wallet requests. +/// This library must be deployed and linked to other modules. +/// +/// @author Daniel Wang - +library ApprovalLib { + using SignatureUtil for bytes32; + using BytesUtil for bytes; + using ECDSA for bytes32; + using ApprovalLib for Wallet; + + uint256 internal constant SIG_VALIDATION_FAILED = 1; + + function verifyApproval( + Wallet storage wallet, + bytes32 approvedHash, + SigRequirement sigRequirement, + Approval memory approval + ) internal returns (uint256) { + // Save hash to prevent replay attacks + require(!wallet.hashes[approvedHash], "HASH_EXIST"); + wallet.hashes[approvedHash] = true; + + if ( + approvedHash.verifySignatures( + approval.signers, + approval.signatures + ) && + GuardianLib.requireMajority( + wallet, + approval.signers, + sigRequirement + ) + ) { + return + _packValidationData( + false, + approval.validUntil, + uint48(0) /*valid immediately*/ + ); + } + return SIG_VALIDATION_FAILED; + } + + struct LocalVar { + bytes32 hash; + bytes4 methodId; + uint256 sigTimeRange; + } + + /// implement template method of BaseAccount + function validateSignature( + Wallet storage wallet, + UserOperation calldata userOp, + bytes32 userOpHash, + bytes32 domainSeparator + ) public returns (uint256) { + LocalVar memory localVar; + localVar.hash = userOpHash.toEthSignedMessageHash(); + if (userOp.callData.length >= 4) { + localVar.methodId = userOp.callData.toBytes4(0); + if (isDataless(userOp)) { + bytes memory data = userOp.callData[4:]; + (Approval memory approval, bytes memory ownerSignature) = abi + .decode(userOp.signature, (Approval, bytes)); + + // then check guardians signature for actions + if (localVar.methodId == SmartWallet.addGuardianWA.selector) { + bytes32 approvedHash = GuardianLib + .encodeApprovalForAddGuardian( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + GuardianLib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == SmartWallet.removeGuardianWA.selector + ) { + bytes32 approvedHash = GuardianLib + .encodeApprovalForRemoveGuardian( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + GuardianLib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == SmartWallet.resetGuardiansWA.selector + ) { + bytes32 approvedHash = GuardianLib + .encodeApprovalForResetGuardians( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + GuardianLib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == SmartWallet.changeDailyQuotaWA.selector + ) { + bytes32 approvedHash = QuotaLib + .encodeApprovalForChangeDailyQuota( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + QuotaLib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == SmartWallet.addToWhitelistWA.selector + ) { + bytes32 approvedHash = WhitelistLib + .encodeApprovalForAddToWhitelist( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + WhitelistLib.SIG_REQUIREMENT, + approval + ); + } + + if (localVar.methodId == SmartWallet.transferTokenWA.selector) { + bytes32 approvedHash = ERC20Lib + .encodeApprovalForTransferToken( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + ERC20Lib.SIG_REQUIREMENT, + approval + ); + } + + if (localVar.methodId == SmartWallet.callContractWA.selector) { + bytes32 approvedHash = ERC20Lib + .encodeApprovalForCallContract( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + ERC20Lib.SIG_REQUIREMENT, + approval + ); + } + + if (localVar.methodId == SmartWallet.approveTokenWA.selector) { + bytes32 approvedHash = ERC20Lib + .encodeApprovalForApproveToken( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + ERC20Lib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == + SmartWallet.approveThenCallContractWA.selector + ) { + bytes32 approvedHash = ERC20Lib + .encodeApprovalForApproveThenCallContract( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + ERC20Lib.SIG_REQUIREMENT, + approval + ); + } + + if (localVar.methodId == SmartWallet.unlock.selector) { + bytes32 approvedHash = LockLib.encodeApprovalForUnlock( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + LockLib.SIG_REQUIREMENT, + approval + ); + } + + if ( + localVar.methodId == SmartWallet.changeMasterCopy.selector + ) { + bytes32 approvedHash = UpgradeLib + .encodeApprovalForChangeMasterCopy( + data, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + UpgradeLib.SIG_REQUIREMENT, + approval + ); + } + + if (localVar.methodId == SmartWallet.recover.selector) { + (address newOwner, address[] memory newGuardians) = abi + .decode(data, (address, address[])); + bytes32 approvedHash = RecoverLib.encodeApprovalForRecover( + newOwner, + newGuardians, + domainSeparator, + approval.validUntil + ); + localVar.sigTimeRange = wallet.verifyApproval( + approvedHash, + RecoverLib.SIG_REQUIREMENT, + approval + ); + if ( + !localVar.hash.verifySignature(newOwner, ownerSignature) + ) return SIG_VALIDATION_FAILED; + } + + // check owner signature first + // check signature of new owner when recover + if ( + localVar.methodId != SmartWallet.recover.selector && + !localVar.hash.verifySignature(wallet.owner, ownerSignature) + ) { + return SIG_VALIDATION_FAILED; + } + + return localVar.sigTimeRange; + } + + if (localVar.methodId == SmartWallet.inherit.selector) { + if ( + localVar.hash.verifySignature( + wallet.inheritor, + userOp.signature + ) + ) { + return 0; + } + return SIG_VALIDATION_FAILED; + } + + if (localVar.methodId == SmartWallet.castFromEntryPoint.selector) { + // automation can be used only when wallet is unlocked + require(!wallet.locked, "wallet is locked"); + (address executor, bytes memory executorSignature) = abi.decode( + userOp.signature, + (address, bytes) + ); + if ( + AutomationLib.isExecutorOrOwner(wallet, executor) && + localVar.hash.verifySignature(executor, executorSignature) + ) { + return 0; + } + return SIG_VALIDATION_FAILED; + } + } + + require(!wallet.locked, "wallet is locked"); + + if (!localVar.hash.verifySignature(wallet.owner, userOp.signature)) + return SIG_VALIDATION_FAILED; + return 0; + } + + function isDataless( + UserOperation calldata userOp + ) internal pure returns (bool) { + // We don't require any data in the meta tx when + // - the meta-tx has no nonce + // - the meta-tx needs to be successful + // - a function is called that requires a majority of guardians and fails when replayed + bytes4 methodId = userOp.callData.toBytes4(0); + return (methodId == SmartWallet.changeMasterCopy.selector || + methodId == SmartWallet.addGuardianWA.selector || + methodId == SmartWallet.removeGuardianWA.selector || + methodId == SmartWallet.resetGuardiansWA.selector || + methodId == SmartWallet.unlock.selector || + methodId == SmartWallet.changeDailyQuotaWA.selector || + methodId == SmartWallet.recover.selector || + methodId == SmartWallet.addToWhitelistWA.selector || + methodId == SmartWallet.transferTokenWA.selector || + methodId == SmartWallet.callContractWA.selector || + methodId == SmartWallet.approveTokenWA.selector || + methodId == SmartWallet.approveThenCallContractWA.selector); + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/AutomationLib.sol b/packages/hebao_v3/contracts/base/libwallet/AutomationLib.sol new file mode 100644 index 000000000..7e8fd6993 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/AutomationLib.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./InheritanceLib.sol"; +import "./WalletData.sol"; +import "../../account-abstraction/interfaces/UserOperation.sol"; +import "../../iface/IConnectorRegistry.sol"; + +library AutomationLib { + using InheritanceLib for Wallet; + + event AutomationApproveExecutor( + address wallet, + address executor, + uint validUntils + ); + + event AutomationUnapproveExecutor(address wallet, address executor); + + function _spell( + address _target, + bytes memory _data + ) private returns (bytes memory response) { + require(_target != address(0), "target-invalid"); + // solhint-disable-next-line no-inline-assembly + assembly { + let succeeded := delegatecall( + gas(), + _target, + add(_data, 0x20), + mload(_data), + 0, + 0 + ) + let size := returndatasize() + + response := mload(0x40) + mstore( + 0x40, + add(response, and(add(add(size, 0x20), 0x1f), not(0x1f))) + ) + mstore(response, size) + returndatacopy(add(response, 0x20), 0, size) + + switch iszero(succeeded) + case 1 { + // throw if delegatecall failed + returndatacopy(0x00, 0x00, size) + revert(0x00, size) + } + } + } + + function isExecutorOrOwner( + Wallet storage wallet, + address executor + ) internal view returns (bool) { + bool isOwner = executor == wallet.owner; + bool isExecutor = wallet.executorsPermission[executor] > + // solhint-disable-next-line not-rely-on-time + block.timestamp; + return isExecutor || isOwner; + } + + function cast( + address connectorRegistry, + address[] calldata targets, + bytes[] calldata datas + ) internal { + require(connectorRegistry != address(0), "disabled connector registry"); + uint256 _length = targets.length; + require(_length == datas.length, "different length"); + // check all targets is valid + require( + IConnectorRegistry(connectorRegistry).isConnectors(targets), + "valid connector" + ); + for (uint i = 0; i < _length; i++) { + _spell(targets[i], datas[i]); + } + } + + function approveExecutor( + Wallet storage wallet, + address executor, + uint256 validUntil + ) internal { + require( + wallet.executorsPermission[executor] < validUntil, + "approve failed" + ); + wallet.executorsPermission[executor] = validUntil; + emit AutomationApproveExecutor(address(this), executor, validUntil); + } + + function unApproveExecutor( + Wallet storage wallet, + address executor + ) internal { + wallet.executorsPermission[executor] = 0; + emit AutomationUnapproveExecutor(address(this), executor); + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/ERC1271Lib.sol b/packages/hebao_v3/contracts/base/libwallet/ERC1271Lib.sol new file mode 100644 index 000000000..cd307f153 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/ERC1271Lib.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../../lib/SignatureUtil.sol"; +import "./WalletData.sol"; + +/// @title ERC1271Lib +/// @author Brecht Devos - +library ERC1271Lib { + using SignatureUtil for bytes32; + + // Note that we allow chained wallet ownership: + // Wallet1 owned by Wallet2, Wallet2 owned by Wallet3, ..., WaleltN owned by an EOA. + // The verificaiton of Wallet1's signature will succeed if the final EOA's signature is + // valid. + function isValidSignature( + Wallet storage wallet, + bytes4 erc1271MagicValue, + bytes32 signHash, + bytes calldata signature + ) public view returns (bytes4 magicValue) { + if (wallet.locked) { + return 0; + } + + if (signHash.verifySignature(wallet.owner, signature)) { + return erc1271MagicValue; + } else { + return 0; + } + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/ERC20Lib.sol b/packages/hebao_v3/contracts/base/libwallet/ERC20Lib.sol new file mode 100644 index 000000000..14f68300a --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/ERC20Lib.sol @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "../../lib/AddressUtil.sol"; +import "../../iface/PriceOracle.sol"; +import "../../thirdparty/BytesUtil.sol"; +import "./WhitelistLib.sol"; +import "./QuotaLib.sol"; +import "../../lib/EIP712.sol"; + +/// @title ERC20Lib +/// @author Brecht Devos - +/// @author Daniel Wang - +library ERC20Lib { + using AddressUtil for address; + using BytesUtil for bytes; + using WhitelistLib for Wallet; + using QuotaLib for Wallet; + using SafeERC20 for IERC20; + + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + event Transfered(address token, address to, uint amount, bytes logdata); + event Approved(address token, address spender, uint amount); + event ContractCalled(address to, uint value, bytes data); + + bytes32 private constant TRANSFER_TOKEN_TYPEHASH = + keccak256( + "transferToken(address wallet,uint256 validUntil,address token,address to,uint256 amount,bytes logdata)" + ); + bytes32 private constant APPROVE_TOKEN_TYPEHASH = + keccak256( + "approveToken(address wallet,uint256 validUntil,address token,address to,uint256 amount)" + ); + bytes32 private constant CALL_CONTRACT_TYPEHASH = + keccak256( + "callContract(address wallet,uint256 validUntil,address to,uint256 value,bytes data)" + ); + bytes32 private constant APPROVE_THEN_CALL_CONTRACT_TYPEHASH = + keccak256( + "approveThenCallContract(address wallet,uint256 validUntil,address token,address to,uint256 amount,uint256 value,bytes data)" + ); + + function transferToken( + Wallet storage wallet, + PriceOracle priceOracle, + address token, + address to, + uint amount, + bytes calldata logdata, + bool forceUseQuota + ) external { + if (forceUseQuota || !wallet.isAddressWhitelisted(to)) { + wallet.checkAndAddToSpent(priceOracle, token, amount); + } + _transferWithEvent(token, to, amount, logdata); + } + + function transferTokenWA( + address token, + address to, + uint amount, + bytes calldata logdata + ) external { + _transferWithEvent(token, to, amount, logdata); + } + + function callContract( + Wallet storage wallet, + PriceOracle priceOracle, + address to, + uint value, + bytes calldata data, + bool forceUseQuota + ) external returns (bytes memory returnData) { + if (forceUseQuota || !wallet.isAddressWhitelisted(to)) { + wallet.checkAndAddToSpent(priceOracle, address(0), value); + } + + return _callContractInternal(to, value, data, priceOracle); + } + + function callContractWA( + address to, + uint value, + bytes calldata data + ) external returns (bytes memory returnData) { + returnData = _callContractInternal( + to, + value, + data, + PriceOracle(address(0)) + ); + } + + function approveToken( + Wallet storage wallet, + PriceOracle priceOracle, + address token, + address to, + uint amount, + bool forceUseQuota + ) external { + uint additionalAllowance = _approveInternal(token, to, amount); + + if (forceUseQuota || !wallet.isAddressWhitelisted(to)) { + wallet.checkAndAddToSpent(priceOracle, token, additionalAllowance); + } + } + + function approveTokenWA(address token, address to, uint amount) external { + _approveInternal(token, to, amount); + } + + function approveThenCallContract( + Wallet storage wallet, + PriceOracle priceOracle, + address token, + address to, + uint amount, + uint value, + bytes calldata data, + bool forceUseQuota + ) external returns (bytes memory returnData) { + uint additionalAllowance = _approveInternal(token, to, amount); + + if (forceUseQuota || !wallet.isAddressWhitelisted(to)) { + wallet.checkAndAddToSpent(priceOracle, token, additionalAllowance); + wallet.checkAndAddToSpent(priceOracle, address(0), value); + } + + return _callContractInternal(to, value, data, priceOracle); + } + + function approveThenCallContractWA( + address token, + address to, + uint amount, + uint value, + bytes calldata data + ) external returns (bytes memory returnData) { + _approveInternal(token, to, amount); + returnData = _callContractInternal( + to, + value, + data, + PriceOracle(address(0)) + ); + } + + function transfer(address token, address to, uint amount) public { + if (token == address(0)) { + to.sendETHAndVerify(amount, gasleft()); + } else { + IERC20(token).safeTransfer(to, amount); + } + } + + // --- Internal functions --- + + function _transferWithEvent( + address token, + address to, + uint amount, + bytes calldata logdata + ) private { + transfer(token, to, amount); + emit Transfered(token, to, amount, logdata); + } + + function _approveInternal( + address token, + address spender, + uint amount + ) private returns (uint additionalAllowance) { + // Current allowance + uint allowance = IERC20(token).allowance(address(this), spender); + + if (amount != allowance) { + // First reset the approved amount if needed + if (allowance > 0) { + IERC20(token).safeApprove(spender, 0); + } + // Now approve the requested amount + IERC20(token).safeApprove(spender, amount); + } + + // If we increased the allowance, calculate by how much + if (amount > allowance) { + additionalAllowance = amount - allowance; + } + emit Approved(token, spender, amount); + } + + function _callContractInternal( + address to, + uint value, + bytes calldata txData, + PriceOracle priceOracle + ) private returns (bytes memory returnData) { + require(to != address(this), "SELF_CALL_DISALLOWED"); + + if (priceOracle != PriceOracle(address(0))) { + if (txData.length >= 4) { + bytes4 methodId = txData.toBytes4(0); + // bytes4(keccak256("transfer(address,uint256)")) = 0xa9059cbb + // bytes4(keccak256("approve(address,uint256)")) = 0x095ea7b3 + if ( + methodId == bytes4(0xa9059cbb) || + methodId == bytes4(0x095ea7b3) + ) { + // Disallow general calls to token contracts (for tokens that have price data + // so the quota is actually used). + require( + priceOracle.tokenValue(to, 1e18) == 0, + "CALL_DISALLOWED" + ); + } + } + } + + bool success; + (success, returnData) = to.call{value: value}(txData); + require(success, "CALL_FAILED"); + + emit ContractCalled(to, value, txData); + } + + function encodeApprovalForTransferToken( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + (address token, address to, uint amount, bytes memory logdata) = abi + .decode(data, (address, address, uint, bytes)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + TRANSFER_TOKEN_TYPEHASH, + address(this), + validUntil, + token, + to, + amount, + keccak256(logdata) + ) + ) + ); + return approvedHash; + } + + function encodeApprovalForApproveToken( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + (address token, address to, uint256 amount) = abi.decode( + data, + (address, address, uint) + ); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + APPROVE_TOKEN_TYPEHASH, + address(this), + validUntil, + token, + to, + amount + ) + ) + ); + return approvedHash; + } + + function encodeApprovalForCallContract( + bytes calldata callData, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + (address to, uint256 value, bytes memory data) = abi.decode( + callData, + (address, uint, bytes) + ); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + CALL_CONTRACT_TYPEHASH, + address(this), + validUntil, + to, + value, + keccak256(data) + ) + ) + ); + return approvedHash; + } + + struct ApprovalThenCallData { + address token; + address to; + uint256 amount; + uint256 value; + bytes data; + } + + function encodeApprovalForApproveThenCallContract( + bytes calldata callData, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + ApprovalThenCallData memory approvalThenCallData; + ( + approvalThenCallData.token, + approvalThenCallData.to, + approvalThenCallData.amount, + approvalThenCallData.value, + approvalThenCallData.data + ) = abi.decode(callData, (address, address, uint256, uint256, bytes)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + APPROVE_THEN_CALL_CONTRACT_TYPEHASH, + address(this), + validUntil, + approvalThenCallData.token, + approvalThenCallData.to, + approvalThenCallData.amount, + approvalThenCallData.value, + keccak256(approvalThenCallData.data) + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/GuardianLib.sol b/packages/hebao_v3/contracts/base/libwallet/GuardianLib.sol new file mode 100644 index 000000000..4a33e8379 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/GuardianLib.sol @@ -0,0 +1,502 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "../../lib/SignatureUtil.sol"; +import "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import "./ApprovalLib.sol"; +import "../../lib/EIP712.sol"; +import "../../lib/LoopringErrors.sol"; + +/// @title GuardianModule +/// @author Brecht Devos - +/// @author Daniel Wang - +library GuardianLib { + using AddressUtil for address; + using SafeCast for uint; + using SignatureUtil for bytes32; + + uint private constant MAX_GUARDIANS = 10; + uint private constant GUARDIAN_PENDING_PERIOD = 3 days; + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + bytes32 private constant ADD_GUARDIAN_TYPEHASH = + keccak256( + "addGuardian(address wallet,uint256 validUntil,address guardian)" + ); + bytes32 private constant REMOVE_GUARDIAN_TYPEHASH = + keccak256( + "removeGuardian(address wallet,uint256 validUntil,address guardian)" + ); + bytes32 private constant RESET_GUARDIANS_TYPEHASH = + keccak256( + "resetGuardians(address wallet,uint256 validUntil,address[] guardians)" + ); + + event GuardianAdded(address guardian, uint effectiveTime); + event GuardianRemoved(address guardian, uint effectiveTime); + + function addGuardiansImmediately( + Wallet storage wallet, + address[] calldata _guardians + ) external { + address guardian = address(0); + for (uint i = 0; i < _guardians.length; i++) { + _require(_guardians[i] > guardian, Errors.INVALID_ORDERING); + guardian = _guardians[i]; + _addGuardian(wallet, guardian, 0, true); + } + } + + function addGuardian(Wallet storage wallet, address guardian) external { + _addGuardian(wallet, guardian, GUARDIAN_PENDING_PERIOD, false); + } + + function addGuardianWA(Wallet storage wallet, address guardian) external { + _addGuardian(wallet, guardian, 0, true); + } + + function removeGuardian(Wallet storage wallet, address guardian) external { + _removeGuardian(wallet, guardian, GUARDIAN_PENDING_PERIOD, false); + } + + function removeGuardianWA( + Wallet storage wallet, + address guardian + ) external { + _removeGuardian(wallet, guardian, 0, true); + } + + function resetGuardians( + Wallet storage wallet, + address[] calldata newGuardians + ) external { + Guardian[] memory allGuardians = guardians(wallet, true); + for (uint i = 0; i < allGuardians.length; i++) { + _removeGuardian( + wallet, + allGuardians[i].addr, + GUARDIAN_PENDING_PERIOD, + false + ); + } + + for (uint j = 0; j < newGuardians.length; j++) { + _addGuardian( + wallet, + newGuardians[j], + GUARDIAN_PENDING_PERIOD, + false + ); + } + } + + function resetGuardiansWA( + Wallet storage wallet, + address[] calldata newGuardians + ) external { + removeAllGuardians(wallet); + for (uint i = 0; i < newGuardians.length; i++) { + _addGuardian(wallet, newGuardians[i], 0, true); + } + } + + function requireMajority( + Wallet storage wallet, + address[] memory signers, + SigRequirement requirement + ) internal view returns (bool) { + // We always need at least one signer + if (signers.length == 0) { + return false; + } + + // Calculate total group sizes + Guardian[] memory allGuardians = guardians(wallet, false); + _require(allGuardians.length > 0, Errors.NO_GUARDIANS); + + address lastSigner; + bool walletOwnerSigned = false; + address owner = wallet.owner; + for (uint i = 0; i < signers.length; i++) { + // Check for duplicates + _require(signers[i] > lastSigner, Errors.INVALID_SIGNERS_ORDER); + lastSigner = signers[i]; + + if (signers[i] == owner) { + walletOwnerSigned = true; + } else { + bool _isGuardian = false; + for (uint j = 0; j < allGuardians.length; j++) { + if (allGuardians[j].addr == signers[i]) { + _isGuardian = true; + break; + } + } + _require(_isGuardian, Errors.SIGNER_NOT_GUARDIAN); + } + } + + if (requirement == SigRequirement.OWNER_OR_ANY_GUARDIAN) { + return signers.length == 1; + } else if (requirement == SigRequirement.ANY_GUARDIAN) { + _require( + !walletOwnerSigned, + Errors.WALLET_OWNER_SIGNATURE_NOT_ALLOWED + ); + return signers.length == 1; + } + + // Check owner requirements + if (requirement == SigRequirement.MAJORITY_OWNER_REQUIRED) { + _require(walletOwnerSigned, Errors.WALLET_OWNER_SIGNATURE_REQUIRED); + } else if (requirement == SigRequirement.MAJORITY_OWNER_NOT_ALLOWED) { + _require( + !walletOwnerSigned, + Errors.WALLET_OWNER_SIGNATURE_NOT_ALLOWED + ); + } + + uint numExtendedSigners = allGuardians.length; + if (walletOwnerSigned) { + numExtendedSigners += 1; + _require( + signers.length > 1, + Errors.NO_GUARDIAN_SIGNED_BESIDES_OWNER + ); + } + + return signers.length >= (numExtendedSigners >> 1) + 1; + } + + function isGuardian( + Wallet storage wallet, + address addr, + bool includePendingAddition + ) public view returns (bool) { + Guardian memory g = _getGuardian(wallet, addr); + return _isActiveOrPendingAddition(g, includePendingAddition); + } + + function guardians( + Wallet storage wallet, + bool includePendingAddition + ) public view returns (Guardian[] memory _guardians) { + _guardians = new Guardian[](wallet.guardians.length); + uint index = 0; + for (uint i = 0; i < wallet.guardians.length; i++) { + Guardian memory g = wallet.guardians[i]; + if (_isActiveOrPendingAddition(g, includePendingAddition)) { + _guardians[index] = g; + index++; + } + } + // solhint-disable-next-line no-inline-assembly + assembly { + mstore(_guardians, index) + } + } + + function numGuardians( + Wallet storage wallet, + bool includePendingAddition + ) public view returns (uint count) { + for (uint i = 0; i < wallet.guardians.length; i++) { + Guardian memory g = wallet.guardians[i]; + if (_isActiveOrPendingAddition(g, includePendingAddition)) { + count++; + } + } + } + + function removeAllGuardians(Wallet storage wallet) internal { + uint size = wallet.guardians.length; + if (size == 0) return; + + for (uint i = 0; i < wallet.guardians.length; i++) { + delete wallet.guardianIdx[wallet.guardians[i].addr]; + } + delete wallet.guardians; + } + + function cancelPendingGuardians(Wallet storage wallet) internal { + bool cancelled = false; + for (uint i = 0; i < wallet.guardians.length; i++) { + Guardian memory g = wallet.guardians[i]; + if (_isPendingAddition(g)) { + wallet.guardians[i].status = uint8(GuardianStatus.REMOVE); + wallet.guardians[i].timestamp = 0; + cancelled = true; + } + if (_isPendingRemoval(g)) { + wallet.guardians[i].status = uint8(GuardianStatus.ADD); + wallet.guardians[i].timestamp = 0; + cancelled = true; + } + } + _cleanRemovedGuardians(wallet, true); + } + + function storeGuardian( + Wallet storage wallet, + address addr, + uint validSince, + bool alwaysOverride + ) internal returns (uint) { + _require(validSince >= block.timestamp, Errors.INVALID_VALID_SINCE); + _require(addr != address(0), Errors.ZERO_ADDRESS); + _require(addr != address(this), Errors.INVALID_GUARDIAN_ADDRESS); + + uint pos = wallet.guardianIdx[addr]; + + if (pos == 0) { + // Add the new guardian + Guardian memory _g = Guardian( + addr, + uint8(GuardianStatus.ADD), + validSince.toUint64() + ); + wallet.guardians.push(_g); + wallet.guardianIdx[addr] = wallet.guardians.length; + + _cleanRemovedGuardians(wallet, false); + return validSince; + } + + Guardian memory g = wallet.guardians[pos - 1]; + + if (_isRemoved(g)) { + wallet.guardians[pos - 1].status = uint8(GuardianStatus.ADD); + wallet.guardians[pos - 1].timestamp = validSince.toUint64(); + return validSince; + } + + if (_isPendingRemoval(g)) { + wallet.guardians[pos - 1].status = uint8(GuardianStatus.ADD); + wallet.guardians[pos - 1].timestamp = 0; + return 0; + } + + if (_isPendingAddition(g)) { + if (!alwaysOverride) return g.timestamp; + + wallet.guardians[pos - 1].timestamp = validSince.toUint64(); + return validSince; + } + + _require(_isAdded(g), Errors.UNEXPECTED_RESULT); + return 0; + } + + function deleteGuardian( + Wallet storage wallet, + address addr, + uint validUntil, + bool alwaysOverride + ) internal returns (uint) { + _require(validUntil >= block.timestamp, Errors.INVALID_VALID_UNTIL); + _require(addr != address(0), Errors.INVALID_GUARDIAN_ADDRESS); + + uint pos = wallet.guardianIdx[addr]; + _require(pos > 0, Errors.GUARDIAN_NOT_EXISTS); + + Guardian memory g = wallet.guardians[pos - 1]; + + if (_isAdded(g)) { + wallet.guardians[pos - 1].status = uint8(GuardianStatus.REMOVE); + wallet.guardians[pos - 1].timestamp = validUntil.toUint64(); + return validUntil; + } + + if (_isPendingAddition(g)) { + wallet.guardians[pos - 1].status = uint8(GuardianStatus.REMOVE); + wallet.guardians[pos - 1].timestamp = 0; + return 0; + } + + if (_isPendingRemoval(g)) { + if (!alwaysOverride) return g.timestamp; + + wallet.guardians[pos - 1].timestamp = validUntil.toUint64(); + return validUntil; + } + + _require(_isRemoved(g), Errors.UNEXPECTED_RESULT); + return 0; + } + + // --- Internal functions --- + + function _addGuardian( + Wallet storage wallet, + address guardian, + uint pendingPeriod, + bool alwaysOverride + ) internal { + uint _numGuardians = numGuardians(wallet, true); + _require(_numGuardians < MAX_GUARDIANS, Errors.TOO_MANY_GUARDIANS); + _require(guardian != wallet.owner, Errors.GUARDIAN_CAN_NOT_BE_OWNER); + + uint validSince = block.timestamp + 1; + if (_numGuardians >= 2) { + validSince = block.timestamp + pendingPeriod; + } + validSince = storeGuardian( + wallet, + guardian, + validSince, + alwaysOverride + ); + emit GuardianAdded(guardian, validSince); + } + + function _removeGuardian( + Wallet storage wallet, + address guardian, + uint pendingPeriod, + bool alwaysOverride + ) private { + uint validUntil = block.timestamp + pendingPeriod; + validUntil = deleteGuardian( + wallet, + guardian, + validUntil, + alwaysOverride + ); + emit GuardianRemoved(guardian, validUntil); + } + + function _getGuardian( + Wallet storage wallet, + address addr + ) private view returns (Guardian memory guardian) { + uint pos = wallet.guardianIdx[addr]; + if (pos > 0) { + guardian = wallet.guardians[pos - 1]; + } + } + + function _isAdded(Guardian memory guardian) private view returns (bool) { + return + guardian.status == uint8(GuardianStatus.ADD) && + guardian.timestamp <= block.timestamp; + } + + function _isPendingAddition( + Guardian memory guardian + ) private view returns (bool) { + return + guardian.status == uint8(GuardianStatus.ADD) && + guardian.timestamp > block.timestamp; + } + + function _isRemoved(Guardian memory guardian) private view returns (bool) { + return + guardian.status == uint8(GuardianStatus.REMOVE) && + guardian.timestamp <= block.timestamp; + } + + function _isPendingRemoval( + Guardian memory guardian + ) private view returns (bool) { + return + guardian.status == uint8(GuardianStatus.REMOVE) && + guardian.timestamp > block.timestamp; + } + + function _isActive(Guardian memory guardian) private view returns (bool) { + return _isAdded(guardian) || _isPendingRemoval(guardian); + } + + function _isActiveOrPendingAddition( + Guardian memory guardian, + bool includePendingAddition + ) private view returns (bool) { + return + _isActive(guardian) || + (includePendingAddition && _isPendingAddition(guardian)); + } + + function _cleanRemovedGuardians(Wallet storage wallet, bool force) private { + uint count = wallet.guardians.length; + if (!force && count < 10) return; + + for (int i = int(count) - 1; i >= 0; i--) { + Guardian memory g = wallet.guardians[uint(i)]; + if (_isRemoved(g)) { + Guardian memory lastGuardian = wallet.guardians[ + wallet.guardians.length - 1 + ]; + + if (g.addr != lastGuardian.addr) { + wallet.guardians[uint(i)] = lastGuardian; + wallet.guardianIdx[lastGuardian.addr] = uint(i) + 1; + } + wallet.guardians.pop(); + delete wallet.guardianIdx[g.addr]; + } + } + } + + function encodeApprovalForAddGuardian( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + address guardian = abi.decode(data, (address)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + ADD_GUARDIAN_TYPEHASH, + address(this), + validUntil, + guardian + ) + ) + ); + return approvedHash; + } + + function encodeApprovalForRemoveGuardian( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + address guardian = abi.decode(data, (address)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + REMOVE_GUARDIAN_TYPEHASH, + address(this), + validUntil, + guardian + ) + ) + ); + return approvedHash; + } + + function encodeApprovalForResetGuardians( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + address[] memory newGuardians = abi.decode(data, (address[])); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + RESET_GUARDIANS_TYPEHASH, + address(this), + validUntil, + keccak256(abi.encodePacked(newGuardians)) + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/InheritanceLib.sol b/packages/hebao_v3/contracts/base/libwallet/InheritanceLib.sol new file mode 100644 index 000000000..daa77ec7c --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/InheritanceLib.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "./GuardianLib.sol"; +import "./LockLib.sol"; +import "./Utils.sol"; + +/// @title InheritanceLib +/// @author Brecht Devos - +library InheritanceLib { + using GuardianLib for Wallet; + using InheritanceLib for Wallet; + using LockLib for Wallet; + using Utils for address; + + // The minimal number of guardians for recovery and locking. + uint private constant TOUCH_GRACE_PERIOD = 30 days; + + event Inherited(address inheritor, address newOwner); + + event InheritorChanged(address inheritor, uint32 waitingPeriod); + + function touchLastActiveWhenRequired(Wallet storage wallet) internal { + if ( + wallet.inheritor != address(0) && + block.timestamp > wallet.lastActive + TOUCH_GRACE_PERIOD + ) { + wallet.lastActive = uint64(block.timestamp); + } + } + + function setInheritor( + Wallet storage wallet, + address inheritor, + uint32 waitingPeriod + ) internal { + if (inheritor == address(0)) { + require(waitingPeriod == 0, "INVALID_WAITING_PERIOD"); + } else { + require( + waitingPeriod >= TOUCH_GRACE_PERIOD, + "INVALID_WAITING_PERIOD" + ); + } + + require(inheritor != address(this), "INVALID_ARGS"); + wallet.inheritor = inheritor; + wallet.inheritWaitingPeriod = waitingPeriod; + wallet.lastActive = uint64(block.timestamp); + + emit InheritorChanged(inheritor, waitingPeriod); + } + + function inherit( + Wallet storage wallet, + address newOwner, + address[] calldata newGuardians + ) external { + require(wallet.owner != newOwner, "IS_WALLET_OWNER"); + require(newOwner.isValidWalletOwner(), "INVALID_NEW_WALLET_OWNER"); + require( + uint(wallet.lastActive) + uint(wallet.inheritWaitingPeriod) < + block.timestamp, + "TOO_EARLY" + ); + + if (newGuardians.length > 0) { + for (uint i = 0; i < newGuardians.length; i++) { + require( + newGuardians[i] != newOwner, + "INVALID_NEW_WALLET_GUARDIAN" + ); + } + wallet.removeAllGuardians(); + wallet.addGuardiansImmediately(newGuardians); + } else { + if (wallet.isGuardian(newOwner, true)) { + wallet.deleteGuardian(newOwner, block.timestamp, true); + } + wallet.cancelPendingGuardians(); + } + wallet.setInheritor(address(0), 0); + wallet.setLock(address(this), false); + + wallet.owner = newOwner; + + emit Inherited(wallet.inheritor, newOwner); + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/LockLib.sol b/packages/hebao_v3/contracts/base/libwallet/LockLib.sol new file mode 100644 index 000000000..e583028f8 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/LockLib.sol @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "./GuardianLib.sol"; +import "./ApprovalLib.sol"; +import "../../lib/LoopringErrors.sol"; + +/// @title LockLib +/// @author Brecht Devos - +library LockLib { + using GuardianLib for Wallet; + using ApprovalLib for Wallet; + + event WalletLocked(address by, bool locked); + + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + bytes32 private constant UNLOCK_TYPEHASH = + keccak256("unlock(address wallet,uint256 validUntil)"); + + function lock(Wallet storage wallet, address entryPoint) public { + _require( + msg.sender == address(this) || + msg.sender == wallet.owner || + msg.sender == entryPoint || + wallet.isGuardian(msg.sender, false), + Errors.NOT_FROM_WALLET_OR_OWNER_OR_GUARDIAN + ); + // cannot lock wallet when no any guardian exists + _require(wallet.numGuardians(true) > 0, Errors.NO_GUARDIANS); + setLock(wallet, msg.sender, true); + } + + function unlock(Wallet storage wallet) public { + setLock(wallet, msg.sender, false); + } + + function setLock(Wallet storage wallet, address by, bool locked) internal { + wallet.locked = locked; + emit WalletLocked(by, locked); + } + + function encodeApprovalForUnlock( + bytes calldata, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256(abi.encode(UNLOCK_TYPEHASH, address(this), validUntil)) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/QuotaLib.sol b/packages/hebao_v3/contracts/base/libwallet/QuotaLib.sol new file mode 100644 index 000000000..9d255a481 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/QuotaLib.sol @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "../../iface/PriceOracle.sol"; +import "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import "./ApprovalLib.sol"; +import "../../lib/EIP712.sol"; +import "../../lib/LoopringErrors.sol"; + +/// @title QuotaLib +/// @dev This store maintains daily spending quota for each wallet. +/// A rolling daily limit is used. +library QuotaLib { + using SafeCast for uint; + + uint128 private constant MAX_QUOTA = type(uint128).max; + uint256 private constant QUOTA_PENDING_PERIOD = 1 days; + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + bytes32 private constant CHANGE_DAILY_QUOTE_TYPEHASH = + keccak256( + "changeDailyQuota(address wallet,uint256 validUntil,uint256 newQuota)" + ); + + event QuotaScheduled( + address wallet, + uint pendingQuota, + uint64 pendingUntil + ); + + function changeDailyQuota(Wallet storage wallet, uint newQuota) public { + setQuota(wallet, newQuota, block.timestamp + QUOTA_PENDING_PERIOD); + } + + function changeDailyQuotaWA(Wallet storage wallet, uint newQuota) public { + setQuota(wallet, newQuota, 0); + } + + function checkAndAddToSpent( + Wallet storage wallet, + PriceOracle priceOracle, + address token, + uint amount + ) internal { + Quota memory q = wallet.quota; + uint available = _availableQuota(q); + if (available != MAX_QUOTA) { + uint value = (token == address(0)) + ? amount + : ( + (address(priceOracle) == address(0)) + ? 0 + : priceOracle.tokenValue(token, amount) + ); + + if (value > 0) { + _require(available >= value, Errors.QUOTA_EXCEEDED); + _addToSpent(wallet, q, value); + } + } + } + + // 0 for newQuota indicates unlimited quota, or daily quota is disabled. + function setQuota( + Wallet storage wallet, + uint newQuota, + uint effectiveTime + ) internal { + _require(newQuota <= MAX_QUOTA, Errors.INVALID_QUOTA); + if (newQuota == MAX_QUOTA) { + newQuota = 0; + } + + uint __currentQuota = currentQuota(wallet); + // Always allow the quota to be changed immediately when the quota doesn't increase + if ( + (__currentQuota >= newQuota && newQuota != 0) || __currentQuota == 0 + ) { + effectiveTime = 0; + } + + Quota storage quota = wallet.quota; + quota.currentQuota = __currentQuota.toUint128(); + quota.pendingQuota = newQuota.toUint128(); + quota.pendingUntil = effectiveTime.toUint64(); + + emit QuotaScheduled(address(this), newQuota, quota.pendingUntil); + } + + // Returns 0 to indiciate unlimited quota + function currentQuota(Wallet storage wallet) internal view returns (uint) { + return _currentQuota(wallet.quota); + } + + // Returns 0 to indiciate unlimited quota + function pendingQuota( + Wallet storage wallet + ) internal view returns (uint __pendingQuota, uint __pendingUntil) { + return _pendingQuota(wallet.quota); + } + + function spentQuota(Wallet storage wallet) internal view returns (uint) { + return _spentQuota(wallet.quota); + } + + function availableQuota( + Wallet storage wallet + ) internal view returns (uint) { + return _availableQuota(wallet.quota); + } + + function hasEnoughQuota( + Wallet storage wallet, + uint requiredAmount + ) internal view returns (bool) { + return _hasEnoughQuota(wallet.quota, requiredAmount); + } + + // --- Internal functions --- + + function _currentQuota(Quota memory q) private view returns (uint) { + return + q.pendingUntil <= block.timestamp ? q.pendingQuota : q.currentQuota; + } + + function _pendingQuota( + Quota memory q + ) private view returns (uint __pendingQuota, uint __pendingUntil) { + if (q.pendingUntil > 0 && q.pendingUntil > block.timestamp) { + __pendingQuota = q.pendingQuota; + __pendingUntil = q.pendingUntil; + } + } + + function _spentQuota(Quota memory q) private view returns (uint) { + uint timeSinceLastSpent = block.timestamp - q.spentTimestamp; + if (timeSinceLastSpent < 1 days) { + return + uint(q.spentAmount) - + (timeSinceLastSpent * q.spentAmount) / + 1 days; + } else { + return 0; + } + } + + function _availableQuota(Quota memory q) private view returns (uint) { + uint quota = _currentQuota(q); + if (quota == 0) { + return MAX_QUOTA; + } + uint spent = _spentQuota(q); + return quota > spent ? quota - spent : 0; + } + + function _hasEnoughQuota( + Quota memory q, + uint requiredAmount + ) private view returns (bool) { + return _availableQuota(q) >= requiredAmount; + } + + function _addToSpent( + Wallet storage wallet, + Quota memory q, + uint amount + ) private { + Quota storage s = wallet.quota; + s.spentAmount = (_spentQuota(q) + amount).toUint128(); + s.spentTimestamp = uint64(block.timestamp); + } + + function encodeApprovalForChangeDailyQuota( + bytes memory data, + bytes32 domainSeparator, + uint256 validUntil + ) internal view returns (bytes32) { + uint256 newQuota = abi.decode(data, (uint)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + CHANGE_DAILY_QUOTE_TYPEHASH, + address(this), + validUntil, + newQuota + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/RecoverLib.sol b/packages/hebao_v3/contracts/base/libwallet/RecoverLib.sol new file mode 100644 index 000000000..6a67cad22 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/RecoverLib.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "./GuardianLib.sol"; +import "./LockLib.sol"; +import "./Utils.sol"; +import "./ApprovalLib.sol"; +import "../../lib/LoopringErrors.sol"; + +/// @title RecoverLib +/// @author Brecht Devos - +library RecoverLib { + using GuardianLib for Wallet; + using LockLib for Wallet; + using Utils for address; + + event Recovered(address newOwner); + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_NOT_ALLOWED; + + bytes32 private constant RECOVER_TYPEHASH = + keccak256( + "recover(address wallet,uint256 validUntil,address newOwner,address[] newGuardians)" + ); + + /// @dev Recover a wallet by setting a new owner and guardians. + /// @param newOwner The new owner address to set. + /// @param newGuardians The new guardians addresses to set. + function recover( + Wallet storage wallet, + address newOwner, + address[] calldata newGuardians + ) external { + _require(wallet.owner != newOwner, Errors.IS_SAME_OWNER); + _require( + newOwner.isValidWalletOwner(), + Errors.INVALID_NEW_WALLET_OWNER + ); + + wallet.owner = newOwner; + wallet.setLock(address(this), false); + + if (newGuardians.length > 0) { + for (uint i = 0; i < newGuardians.length; i++) { + _require( + newGuardians[i] != newOwner, + Errors.INVALID_NEW_WALLET_GUARDIAN + ); + } + wallet.removeAllGuardians(); + wallet.addGuardiansImmediately(newGuardians); + } else { + if (wallet.isGuardian(newOwner, true)) { + wallet.deleteGuardian(newOwner, block.timestamp, true); + } + wallet.cancelPendingGuardians(); + } + + emit Recovered(newOwner); + } + + function encodeApprovalForRecover( + address newOwner, + address[] calldata newGuardians, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + RECOVER_TYPEHASH, + address(this), + validUntil, + newOwner, + keccak256(abi.encodePacked(newGuardians)) + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/UpgradeLib.sol b/packages/hebao_v3/contracts/base/libwallet/UpgradeLib.sol new file mode 100644 index 000000000..41ade4dc3 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/UpgradeLib.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./ApprovalLib.sol"; +import "./WalletData.sol"; +import "../../lib/EIP712.sol"; +import "../../lib/LoopringErrors.sol"; + +/// @title UpgradeLib +/// @author Brecht Devos - +library UpgradeLib { + using ApprovalLib for Wallet; + + event ChangedMasterCopy(address masterCopy); + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + bytes32 private constant CHANGE_MASTER_COPY_TYPEHASH = + keccak256( + "changeMasterCopy(address wallet,uint256 validUntil,address masterCopy)" + ); + + function changeMasterCopy(address newMasterCopy) external { + _require(newMasterCopy != address(0), Errors.INVALID_MASTER_COPY); + + emit ChangedMasterCopy(newMasterCopy); + } + + function encodeApprovalForChangeMasterCopy( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + address masterCopy = abi.decode(data, (address)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + CHANGE_MASTER_COPY_TYPEHASH, + address(this), + validUntil, + masterCopy + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/Utils.sol b/packages/hebao_v3/contracts/base/libwallet/Utils.sol new file mode 100644 index 000000000..1b35726e7 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/Utils.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../../lib/AddressUtil.sol"; + +/// @title Utils +/// @author Brecht Devos - +library Utils { + using AddressUtil for address; + + function isValidWalletOwner(address addr) internal view returns (bool) { + return addr != address(0) && !addr.isContract(); + } +} diff --git a/packages/hebao_v3/contracts/base/libwallet/WalletData.sol b/packages/hebao_v3/contracts/base/libwallet/WalletData.sol new file mode 100644 index 000000000..39e303f20 --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/WalletData.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +enum SigRequirement { + MAJORITY_OWNER_NOT_ALLOWED, + MAJORITY_OWNER_ALLOWED, + MAJORITY_OWNER_REQUIRED, + OWNER_OR_ANY_GUARDIAN, + ANY_GUARDIAN +} + +struct Approval { + address[] signers; + bytes[] signatures; + uint48 validUntil; + // uint48 validAfter; + // bytes32 salt; +} + +// Optimized to fit into 64 bytes (2 slots) +struct Quota { + uint128 currentQuota; + uint128 pendingQuota; + uint128 spentAmount; + uint64 spentTimestamp; + uint64 pendingUntil; +} + +enum GuardianStatus { + REMOVE, // Being removed or removed after validUntil timestamp + ADD // Being added or added after validSince timestamp. +} + +// Optimized to fit into 32 bytes (1 slot) +struct Guardian { + address addr; + uint8 status; + uint64 timestamp; // validSince if status = ADD; validUntil if adding = REMOVE; +} + +// struct ExecutorsPermission { +// address[] connectors; +// mapping(address => uint) connectorsPermission; +// } +struct AutomationPermission { + address[] executors; + mapping(address => mapping(address => uint)) executorsPermission; + mapping(address => address[]) executorsConnectors; +} + +struct Wallet { + address owner; + uint64 creationTimestamp; + // relayer => nonce + uint nonce; + // hash => consumed + mapping(bytes32 => bool) hashes; + bool locked; + Guardian[] guardians; + mapping(address => uint) guardianIdx; + address inheritor; + uint32 inheritWaitingPeriod; + uint64 lastActive; // the latest timestamp the owner is considered to be active + Quota quota; + // whitelisted address => effective timestamp + mapping(address => uint) whitelisted; + address entryPoint; + // executor => validUntil + mapping(address => uint) executorsPermission; +} diff --git a/packages/hebao_v3/contracts/base/libwallet/WhitelistLib.sol b/packages/hebao_v3/contracts/base/libwallet/WhitelistLib.sol new file mode 100644 index 000000000..03aebd8fa --- /dev/null +++ b/packages/hebao_v3/contracts/base/libwallet/WhitelistLib.sol @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./WalletData.sol"; +import "./ApprovalLib.sol"; + +/// @title WhitelistLib +/// @dev This store maintains a wallet's whitelisted addresses. +library WhitelistLib { + using WhitelistLib for Wallet; + + uint256 private constant WHITELIST_PENDING_PERIOD = 1 days; + SigRequirement public constant SIG_REQUIREMENT = + SigRequirement.MAJORITY_OWNER_REQUIRED; + + bytes32 private constant ADD_TO_WHITELIST_TYPEHASH = + keccak256( + "addToWhitelist(address wallet,uint256 validUntil,address addr)" + ); + + event Whitelisted(address addr, bool whitelisted, uint effectiveTime); + + function addToWhitelist(Wallet storage wallet, address addr) external { + wallet._addToWhitelist( + addr, + block.timestamp + WHITELIST_PENDING_PERIOD + ); + } + + function addToWhitelistWA(Wallet storage wallet, address addr) external { + wallet._addToWhitelist(addr, block.timestamp); + } + + function removeFromWhitelist(Wallet storage wallet, address addr) external { + wallet._removeFromWhitelist(addr); + } + + function isAddressWhitelisted( + Wallet storage wallet, + address addr + ) internal view returns (bool) { + uint effectiveTime = wallet.whitelisted[addr]; + return effectiveTime > 0 && effectiveTime <= block.timestamp; + } + + // --- Internal functions --- + + function _addToWhitelist( + Wallet storage wallet, + address addr, + uint effectiveTime + ) internal { + require(wallet.whitelisted[addr] == 0, "ADDRESS_ALREADY_WHITELISTED"); + uint effective = effectiveTime >= block.timestamp + ? effectiveTime + : block.timestamp; + wallet.whitelisted[addr] = effective; + emit Whitelisted(addr, true, effective); + } + + function _removeFromWhitelist( + Wallet storage wallet, + address addr + ) internal { + delete wallet.whitelisted[addr]; + emit Whitelisted(addr, false, 0); + } + + function encodeApprovalForAddToWhitelist( + bytes calldata data, + bytes32 domainSeparator, + uint256 validUntil + ) external view returns (bytes32) { + address addr = abi.decode(data, (address)); + bytes32 approvedHash = EIP712.hashPacked( + domainSeparator, + keccak256( + abi.encode( + ADD_TO_WHITELIST_TYPEHASH, + address(this), + validUntil, + addr + ) + ) + ); + return approvedHash; + } +} diff --git a/packages/hebao_v3/contracts/connectors/1inch.sol b/packages/hebao_v3/contracts/connectors/1inch.sol new file mode 100644 index 000000000..90b1d3bb4 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/1inch.sol @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "./base_connector.sol"; + +interface OneInchInterace { + function swap( + TokenInterface fromToken, + TokenInterface toToken, + uint256 fromTokenAmount, + uint256 minReturnAmount, + uint256 guaranteedAmount, + address payable referrer, + address[] calldata callAddresses, + bytes calldata callDataConcat, + uint256[] calldata starts, + uint256[] calldata gasLimitsAndValues + ) external payable returns (uint256 returnAmount); +} + +struct OneInchData { + TokenInterface sellToken; + TokenInterface buyToken; + uint _sellAmt; + uint _buyAmt; + uint unitAmt; + bytes callData; +} + +contract OneInchV5Connector is BaseConnector { + using SafeERC20 for IERC20; + + address internal constant ONEINCH_ADDR = + 0x1111111254EEB25477B68fb85Ed929f73A960582; + + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + /** + * @dev 1inch API swap handler + * @param oneInchData - contains data returned from 1inch API. Struct defined in interfaces.sol + * @param ethAmt - Eth to swap for .value() + */ + function oneInchSwap( + OneInchData memory oneInchData, + uint ethAmt + ) internal returns (uint buyAmt) { + TokenInterface buyToken = oneInchData.buyToken; + (uint _buyDec, uint _sellDec) = getTokensDec( + buyToken, + oneInchData.sellToken + ); + uint _sellAmt18 = convertTo18(_sellDec, oneInchData._sellAmt); + uint _slippageAmt = convert18ToDec( + _buyDec, + wmul(oneInchData.unitAmt, _sellAmt18) + ); + + uint initalBal = getTokenBal(buyToken); + + // solium-disable-next-line security/no-call-value + (bool success, ) = ONEINCH_ADDR.call{value: ethAmt}( + oneInchData.callData + ); + if (!success) revert("1Inch-swap-failed"); + + uint finalBal = getTokenBal(buyToken); + + buyAmt = sub(finalBal, initalBal); + + require(_slippageAmt <= buyAmt, "Too much slippage"); + } + + /** + * @dev Gets the swapping data from 1inch's API. + * @param oneInchData Struct with multiple swap data defined in interfaces.sol + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function _sell( + OneInchData memory oneInchData, + uint setId + ) internal returns (OneInchData memory) { + TokenInterface _sellAddr = oneInchData.sellToken; + + uint ethAmt; + if (address(_sellAddr) == ETH_ADDR) { + ethAmt = oneInchData._sellAmt; + } else { + IERC20(address(_sellAddr)).safeApprove( + ONEINCH_ADDR, + oneInchData._sellAmt + ); + } + + oneInchData._buyAmt = oneInchSwap(oneInchData, ethAmt); + setUint(setId, oneInchData._buyAmt); + + return oneInchData; + } + + /** + * @dev Sell ETH/ERC20_Token using 1Inch. + * @notice Swap tokens from exchanges like kyber, 0x etc, with calculation done off-chain. + * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAmt The amount of the token to sell. + * @param unitAmt The amount of buyAmt/sellAmt with slippage. + * @param callData Data from 1inch API. + * @param setId ID stores the amount of token brought. + */ + function sell( + address buyAddr, + address sellAddr, + uint sellAmt, + uint unitAmt, + bytes calldata callData, + uint setId + ) external payable { + OneInchData memory oneInchData = OneInchData({ + buyToken: TokenInterface(buyAddr), + sellToken: TokenInterface(sellAddr), + unitAmt: unitAmt, + callData: callData, + _sellAmt: sellAmt, + _buyAmt: 0 + }); + + oneInchData = _sell(oneInchData, setId); + } +} diff --git a/packages/hebao_v3/contracts/connectors/aavev3.sol b/packages/hebao_v3/contracts/connectors/aavev3.sol new file mode 100644 index 000000000..81dd21f3b --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/aavev3.sol @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./base_connector.sol"; + +interface AaveInterface { + function supply( + address asset, + uint256 amount, + address onBehalfOf, + uint16 referralCode + ) external; + + function withdraw( + address asset, + uint256 amount, + address to + ) external returns (uint256); + + function borrow( + address asset, + uint256 amount, + uint256 interestRateMode, + uint16 referralCode, + address onBehalfOf + ) external; + + function repay( + address asset, + uint256 amount, + uint256 interestRateMode, + address onBehalfOf + ) external returns (uint256); + + function repayWithATokens( + address asset, + uint256 amount, + uint256 interestRateMode + ) external returns (uint256); + + function setUserUseReserveAsCollateral( + address asset, + bool useAsCollateral + ) external; + + function swapBorrowRateMode( + address asset, + uint256 interestRateMode + ) external; + + function setUserEMode(uint8 categoryId) external; +} + +interface AavePoolProviderInterface { + function getPool() external view returns (address); +} + +interface AaveDataProviderInterface { + function getReserveTokensAddresses( + address _asset + ) + external + view + returns ( + address aTokenAddress, + address stableDebtTokenAddress, + address variableDebtTokenAddress + ); + + function getUserReserveData( + address _asset, + address _user + ) + external + view + returns ( + uint256 currentATokenBalance, + uint256 currentStableDebt, + uint256 currentVariableDebt, + uint256 principalStableDebt, + uint256 scaledVariableDebt, + uint256 stableBorrowRate, + uint256 liquidityRate, + uint40 stableRateLastUpdated, + bool usageAsCollateralEnabled + ); + + function getReserveEModeCategory( + address asset + ) external view returns (uint256); +} + +contract AaveV3Connector is BaseConnector { + using SafeERC20 for IERC20; + + /** + * @dev Aave Pool Provider + */ + AavePoolProviderInterface internal constant AAVE_PROVIDER = + AavePoolProviderInterface(0x2f39d218133AFaB8F2B819B1066c7E434Ad94E9e); + + /** + * @dev Aave Pool Data Provider + */ + AaveDataProviderInterface internal constant AAVE_DATA = + AaveDataProviderInterface(0x7B4EB56E7CD4b454BA8ff71E4518426369a138a3); + + /** + * @dev Aave Referral Code + */ + uint16 internal constant REFERRAL_CODE = 3228; + + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + /** + * @dev Checks if collateral is enabled for an asset + * @param token token address of the asset.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + */ + + function getIsColl(address token) internal view returns (bool isCol) { + (, , , , , , , , isCol) = AAVE_DATA.getUserReserveData( + token, + address(this) + ); + } + + /** + * @dev Get total debt balance & fee for an asset + * @param token token address of the debt.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param rateMode Borrow rate mode (Stable = 1, Variable = 2) + */ + function getPaybackBalance( + address token, + uint256 rateMode + ) internal view returns (uint256) { + (, uint256 stableDebt, uint256 variableDebt, , , , , , ) = AAVE_DATA + .getUserReserveData(token, address(this)); + return rateMode == 1 ? stableDebt : variableDebt; + } + + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Deposit a token to Aave v3 for lending / collaterization. + * @param token The address of the token to deposit.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(AAVE_PROVIDER.getPool()); + + bool isEth = token == ETH_ADDR; + address _token = isEth ? WETH_ADDR : token; + + TokenInterface tokenContract = TokenInterface(_token); + + if (isEth) { + _amt = _amt == type(uint256).max ? address(this).balance : _amt; + convertEthToWeth(isEth, tokenContract, _amt); + } else { + _amt = _amt == type(uint256).max + ? tokenContract.balanceOf(address(this)) + : _amt; + } + + IERC20(address(tokenContract)).safeApprove(address(aave), _amt); + + aave.supply(_token, _amt, address(this), REFERRAL_CODE); + + if (!getIsColl(_token)) { + aave.setUserUseReserveAsCollateral(_token, true); + } + + setUint(setId, _amt); + } + + /** + * @dev Withdraw ETH/ERC20_Token. + * @notice Withdraw deposited token from Aave v3 + * @param token The address of the token to withdraw.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdraw( + address token, + uint256 amt, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(AAVE_PROVIDER.getPool()); + bool isEth = token == ETH_ADDR; + address _token = isEth ? WETH_ADDR : token; + + TokenInterface tokenContract = TokenInterface(_token); + + uint256 initialBal = tokenContract.balanceOf(address(this)); + aave.withdraw(_token, _amt, address(this)); + uint256 finalBal = tokenContract.balanceOf(address(this)); + + _amt = sub(finalBal, initialBal); + + convertWethToEth(isEth, tokenContract, _amt); + + setUint(setId, _amt); + } + + /** + * @dev Borrow ETH/ERC20_Token. + * @notice Borrow a token using Aave v3 + * @param token The address of the token to borrow.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to borrow. + * @param rateMode The type of debt. (For Stable: 1, Variable: 2) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrow( + address token, + uint256 amt, + uint256 rateMode, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(AAVE_PROVIDER.getPool()); + + bool isEth = token == ETH_ADDR; + address _token = isEth ? WETH_ADDR : token; + + aave.borrow(_token, _amt, rateMode, REFERRAL_CODE, address(this)); + convertWethToEth(isEth, TokenInterface(_token), _amt); + + setUint(setId, _amt); + } + + /** + * @dev Payback borrowed ETH/ERC20_Token. + * @notice Payback debt owed. + * @param token The address of the token to payback.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param rateMode The type of debt paying back. (For Stable: 1, Variable: 2) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function payback( + address token, + uint256 amt, + uint256 rateMode, + uint256 getId, + uint256 setId + ) external payable { + uint256 _amt = getUint(getId, amt); + + AaveInterface aave = AaveInterface(AAVE_PROVIDER.getPool()); + + bool isEth = token == ETH_ADDR; + address _token = isEth ? WETH_ADDR : token; + + TokenInterface tokenContract = TokenInterface(_token); + + _amt = _amt == type(uint256).max + ? getPaybackBalance(_token, rateMode) + : _amt; + + if (isEth) convertEthToWeth(isEth, tokenContract, _amt); + + IERC20(address(tokenContract)).safeApprove(address(aave), _amt); + + aave.repay(_token, _amt, rateMode, address(this)); + + setUint(setId, _amt); + } +} diff --git a/packages/hebao_v3/contracts/connectors/base_connector.sol b/packages/hebao_v3/contracts/connectors/base_connector.sol new file mode 100644 index 000000000..850dbc574 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/base_connector.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface TokenInterface { + function approve(address, uint256) external; + function transfer(address, uint) external; + function transferFrom(address, address, uint) external; + function deposit() external payable; + function withdraw(uint) external; + function balanceOf(address) external view returns (uint); + function decimals() external view returns (uint); +} + +interface MemoryInterface { + function getUint(uint id) external returns (uint num); + function setUint(uint id, uint val) external; +} + +contract DSMath { + uint internal constant WAD = 10 ** 18; + uint internal constant RAY = 10 ** 27; + + function sub(uint x, uint y) internal pure virtual returns (uint z) { + z = x - y; + } + + function mul(uint x, uint y) internal pure returns (uint z) { + z = x * y; + } + + function wmul(uint x, uint y) internal pure returns (uint z) { + z = (x * y + WAD / 2) / WAD; + } + + function wdiv(uint x, uint y) internal pure returns (uint z) { + z = (x * WAD + y / 2) / y; + } + + function rdiv(uint x, uint y) internal pure returns (uint z) { + z = (x * RAY + y / 2) / y; + } + + function rmul(uint x, uint y) internal pure returns (uint z) { + z = (x * y + RAY / 2) / RAY; + } + + function toInt(uint x) internal pure returns (int y) { + y = int(x); + require(y >= 0, "int-overflow"); + } + + function toUint(int256 x) internal pure returns (uint256) { + require(x >= 0, "int-overflow"); + return uint256(x); + } + + function toRad(uint wad) internal pure returns (uint rad) { + rad = mul(wad, 10 ** 27); + } +} + +contract BaseConnector is DSMath { + using SafeERC20 for IERC20; + + address internal constant ETH_ADDR = + 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + address internal constant WETH_ADDR = + 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; + + MemoryInterface public immutable instaMemory; + + constructor(address _instaMemory) { + instaMemory = MemoryInterface(_instaMemory); + } + + function getUint(uint getId, uint val) internal returns (uint returnVal) { + returnVal = getId == 0 ? val : instaMemory.getUint(getId); + } + + /** + * @dev Set Uint value in InstaMemory Contract. + */ + function setUint(uint setId, uint val) internal virtual { + if (setId != 0) instaMemory.setUint(setId, val); + } + + function changeEthAddress( + address buy, + address sell + ) internal pure returns (TokenInterface _buy, TokenInterface _sell) { + _buy = buy == ETH_ADDR + ? TokenInterface(WETH_ADDR) + : TokenInterface(buy); + _sell = sell == ETH_ADDR + ? TokenInterface(WETH_ADDR) + : TokenInterface(sell); + } + + function convertEthToWeth( + bool isEth, + TokenInterface token, + uint amount + ) internal { + if (isEth) token.deposit{value: amount}(); + } + + function convertWethToEth( + bool isEth, + TokenInterface token, + uint amount + ) internal { + if (isEth) { + IERC20(address(token)).safeApprove(address(token), amount); + token.withdraw(amount); + } + } + + function getTokensDec( + TokenInterface buyAddr, + TokenInterface sellAddr + ) internal view returns (uint buyDec, uint sellDec) { + buyDec = address(buyAddr) == ETH_ADDR ? 18 : buyAddr.decimals(); + sellDec = address(sellAddr) == ETH_ADDR ? 18 : sellAddr.decimals(); + } + + function convert18ToDec( + uint _dec, + uint256 _amt + ) internal pure returns (uint256 amt) { + amt = (_amt / 10 ** (18 - _dec)); + } + + function convertTo18( + uint _dec, + uint256 _amt + ) internal pure returns (uint256 amt) { + amt = mul(_amt, 10 ** (18 - _dec)); + } + + function getTokenBal( + TokenInterface token + ) internal view returns (uint _amt) { + _amt = address(token) == ETH_ADDR + ? address(this).balance + : token.balanceOf(address(this)); + } +} diff --git a/packages/hebao_v3/contracts/connectors/compound.sol b/packages/hebao_v3/contracts/connectors/compound.sol new file mode 100644 index 000000000..53312b574 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/compound.sol @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +/** + * @title Compound. + * @dev Lending & Borrowing. + */ + +import "./base_connector.sol"; + +interface CTokenInterface { + function mint(uint mintAmount) external returns (uint); + function redeem(uint redeemTokens) external returns (uint); + function borrow(uint borrowAmount) external returns (uint); + function repayBorrow(uint repayAmount) external returns (uint); + function repayBorrowBehalf( + address borrower, + uint repayAmount + ) external returns (uint); // For ERC20 + function liquidateBorrow( + address borrower, + uint repayAmount, + address cTokenCollateral + ) external returns (uint); + + function borrowBalanceCurrent(address account) external returns (uint); + function redeemUnderlying(uint redeemAmount) external returns (uint); + function exchangeRateCurrent() external returns (uint); + + function balanceOf(address owner) external view returns (uint256 balance); + + function isCToken() external view returns (bool); + function underlying() external view returns (address); + function borrowBalanceStored(address account) external view returns (uint); + function exchangeRateStored() external view returns (uint); +} + +interface CETHInterface { + function mint() external payable; + function repayBorrow() external payable; + function repayBorrowBehalf(address borrower) external payable; + function liquidateBorrow( + address borrower, + address cTokenCollateral + ) external payable; +} + +interface ComptrollerInterface { + function enterMarkets( + address[] calldata cTokens + ) external returns (uint[] memory); + function exitMarket(address cTokenAddress) external returns (uint); + function getAssetsIn( + address account + ) external view returns (address[] memory); + function getAccountLiquidity( + address account + ) external view returns (uint, uint, uint); + function claimComp(address) external; +} + +contract CompoundConnector is BaseConnector { + using SafeERC20 for IERC20; + + /** + * @dev Compound Comptroller + */ + ComptrollerInterface internal constant COMP_TROLLER = + ComptrollerInterface(0x3d9819210A31b4961b30EF54bE2aeD79B9c9Cd3B); + + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Deposit a token to Compound for lending / collaterization. + * @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens deposited. + */ + function deposit( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + enterMarket(cToken); + if (token == ETH_ADDR) { + _amt = _amt == type(uint).max ? address(this).balance : _amt; + CETHInterface(cToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == type(uint).max + ? tokenContract.balanceOf(address(this)) + : _amt; + IERC20(address(tokenContract)).safeApprove(cToken, _amt); + require(CTokenInterface(cToken).mint(_amt) == 0, "deposit-failed"); + } + setUint(setId, _amt); + } + + /** + * @dev Withdraw ETH/ERC20_Token. + * @notice Withdraw deposited token from Compound + * @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to withdraw. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdraw( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + if (_amt == type(uint).max) { + TokenInterface tokenContract = TokenInterface(token); + uint initialBal = token == ETH_ADDR + ? address(this).balance + : tokenContract.balanceOf(address(this)); + require( + cTokenContract.redeem( + cTokenContract.balanceOf(address(this)) + ) == 0, + "full-withdraw-failed" + ); + uint finalBal = token == ETH_ADDR + ? address(this).balance + : tokenContract.balanceOf(address(this)); + _amt = finalBal - initialBal; + } else { + require( + cTokenContract.redeemUnderlying(_amt) == 0, + "withdraw-failed" + ); + } + setUint(setId, _amt); + } + + /** + * @dev Borrow ETH/ERC20_Token. + * @notice Borrow a token using Compound + * @param token The address of the token to borrow. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to borrow. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens borrowed. + */ + function borrow( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + enterMarket(cToken); + require(CTokenInterface(cToken).borrow(_amt) == 0, "borrow-failed"); + setUint(setId, _amt); + } + + /** + * @dev Payback borrowed ETH/ERC20_Token. + * @notice Payback debt owed. + * @param token The address of the token to payback. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to payback. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of tokens paid back. + */ + function payback( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + _amt = _amt == type(uint).max + ? cTokenContract.borrowBalanceCurrent(address(this)) + : _amt; + + if (token == ETH_ADDR) { + require(address(this).balance >= _amt, "not-enough-eth"); + CETHInterface(cToken).repayBorrow{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + require( + tokenContract.balanceOf(address(this)) >= _amt, + "not-enough-token" + ); + IERC20(address(tokenContract)).safeApprove(cToken, _amt); + require(cTokenContract.repayBorrow(_amt) == 0, "repay-failed."); + } + setUint(setId, _amt); + } + + /** + * @dev Deposit ETH/ERC20_Token. + * @notice Same as depositRaw. The only difference is this method stores cToken amount in set ID. + * @param token The address of the token to deposit. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param amt The amount of the token to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of cTokens received. + */ + function depositCToken( + address token, + address cToken, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + enterMarket(cToken); + + CTokenInterface ctokenContract = CTokenInterface(cToken); + uint initialBal = ctokenContract.balanceOf(address(this)); + + if (token == ETH_ADDR) { + _amt = _amt == type(uint).max ? address(this).balance : _amt; + CETHInterface(cToken).mint{value: _amt}(); + } else { + TokenInterface tokenContract = TokenInterface(token); + _amt = _amt == type(uint).max + ? tokenContract.balanceOf(address(this)) + : _amt; + IERC20(address(tokenContract)).safeApprove(cToken, _amt); + require(ctokenContract.mint(_amt) == 0, "deposit-ctoken-failed."); + } + + uint _cAmt; + + { + uint finalBal = ctokenContract.balanceOf(address(this)); + _cAmt = sub(finalBal, initialBal); + + setUint(setId, _cAmt); + } + } + + /** + * @dev Withdraw CETH/CERC20_Token using cToken Amt. + * @notice Same as withdrawRaw. The only difference is this method fetch cToken amount in get ID. + * @param token The address of the token to withdraw. (For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cToken The address of the corresponding cToken. + * @param cTokenAmt The amount of cTokens to withdraw + * @param getId ID to retrieve cTokenAmt + * @param setId ID stores the amount of tokens withdrawn. + */ + function withdrawCToken( + address token, + address cToken, + uint cTokenAmt, + uint getId, + uint setId + ) public payable { + uint _cAmt = getUint(getId, cTokenAmt); + require( + token != address(0) && cToken != address(0), + "invalid token/ctoken address" + ); + + CTokenInterface cTokenContract = CTokenInterface(cToken); + TokenInterface tokenContract = TokenInterface(token); + _cAmt = _cAmt == type(uint).max + ? cTokenContract.balanceOf(address(this)) + : _cAmt; + + uint withdrawAmt; + { + uint initialBal = token != ETH_ADDR + ? tokenContract.balanceOf(address(this)) + : address(this).balance; + require(cTokenContract.redeem(_cAmt) == 0, "redeem-failed"); + uint finalBal = token != ETH_ADDR + ? tokenContract.balanceOf(address(this)) + : address(this).balance; + + withdrawAmt = sub(finalBal, initialBal); + } + + setUint(setId, withdrawAmt); + } + + /** + * @dev Liquidate a position. + * @notice Liquidate a position. + * @param borrower Borrower's Address. + * @param tokenToPay The address of the token to pay for liquidation.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param cTokenPay Corresponding cToken address. + * @param tokenInReturn The address of the token to return for liquidation. + * @param cTokenColl Corresponding cToken address. + * @param amt The token amount to pay for liquidation. + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of paid for liquidation. + */ + function liquidate( + address borrower, + address tokenToPay, + address cTokenPay, + address tokenInReturn, + address cTokenColl, + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint _amt = getUint(getId, amt); + require( + tokenToPay != address(0) && cTokenPay != address(0), + "invalid token/ctoken address" + ); + require( + tokenInReturn != address(0) && cTokenColl != address(0), + "invalid token/ctoken address" + ); + + CTokenInterface cTokenContract = CTokenInterface(cTokenPay); + + { + (, , uint shortfal) = COMP_TROLLER.getAccountLiquidity(borrower); + require(shortfal != 0, "account-cannot-be-liquidated"); + _amt = _amt == type(uint).max + ? cTokenContract.borrowBalanceCurrent(borrower) + : _amt; + } + + if (tokenToPay == ETH_ADDR) { + require(address(this).balance >= _amt, "not-enought-eth"); + CETHInterface(cTokenPay).liquidateBorrow{value: _amt}( + borrower, + cTokenColl + ); + } else { + TokenInterface tokenContract = TokenInterface(tokenToPay); + require( + tokenContract.balanceOf(address(this)) >= _amt, + "not-enough-token" + ); + IERC20(address(tokenContract)).safeApprove(cTokenPay, _amt); + require( + cTokenContract.liquidateBorrow(borrower, _amt, cTokenColl) == 0, + "liquidate-failed" + ); + } + setUint(setId, _amt); + } + + /** + * @dev enter compound market + */ + function enterMarket(address cToken) internal { + address[] memory markets = COMP_TROLLER.getAssetsIn(address(this)); + bool isEntered = false; + for (uint i = 0; i < markets.length; i++) { + if (markets[i] == cToken) { + isEntered = true; + } + } + if (!isEntered) { + address[] memory toEnter = new address[](1); + toEnter[0] = cToken; + COMP_TROLLER.enterMarkets(toEnter); + } + } +} diff --git a/packages/hebao_v3/contracts/connectors/flashloan/BalancerFlashloan.sol b/packages/hebao_v3/contracts/connectors/flashloan/BalancerFlashloan.sol new file mode 100644 index 000000000..acd18e49b --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/flashloan/BalancerFlashloan.sol @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "./IFlashLoanRecipient.sol"; +import "./IVault.sol"; +import "@openzeppelin/contracts/utils/Address.sol"; +import "../../lib/LoopringErrors.sol"; + +interface FlashLoanPoolInterface { + function flashLoan( + address token, + uint256 amount, + bytes memory userData + ) external; +} + +contract BalancerFlashLoan is IFlashLoanRecipient, FlashLoanPoolInterface { + address public immutable vault; + + using SafeERC20 for IERC20; + + struct CastData { + address target; + IERC20 token; + bytes data; + uint256 amount; + } + + constructor(address _vault) { + _require(_vault != address(0), Errors.ZERO_ADDRESS); + vault = _vault; + } + + function receiveFlashLoan( + IERC20[] memory tokens, + uint256[] memory amounts, + uint256[] memory /*feeAmounts*/, + bytes memory userData + ) external override { + // check msg.sender + _require(msg.sender == vault, Errors.NOT_FROM_BALANCER_VAULT); + + for (uint256 i = 0; i < tokens.length; ++i) { + CastData memory cd; + cd.token = tokens[i]; + _require(address(cd.token) != address(0), Errors.ZERO_TOKEN); + cd.amount = amounts[i]; + (cd.target, cd.data) = abi.decode(userData, (address, bytes)); + + cd.token.safeTransfer(cd.target, cd.amount); + + // execute from smartwallet + Address.functionCall( + cd.target, + cd.data, + "flashloan-fallback-failed" + ); + + // Return loan + cd.token.safeTransfer(vault, cd.amount); + } + } + + function flashLoan( + address token, + uint256 amount, + bytes memory data + ) external { + IERC20[] memory tokens = new IERC20[](1); + tokens[0] = IERC20(token); + uint256[] memory amounts = new uint256[](1); + amounts[0] = amount; + // including `from` address + bytes memory userData = abi.encode(msg.sender, data); + + IBalancerVault(vault).flashLoan( + IFlashLoanRecipient(address(this)), + tokens, + amounts, + userData + ); + } +} diff --git a/packages/hebao_v3/contracts/connectors/flashloan/IFlashLoanRecipient.sol b/packages/hebao_v3/contracts/connectors/flashloan/IFlashLoanRecipient.sol new file mode 100644 index 000000000..0654cd845 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/flashloan/IFlashLoanRecipient.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.17; + +// Inspired by Aave Protocol's IFlashLoanReceiver. + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +interface IFlashLoanRecipient { + /** + * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient. + * + * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this + * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the + * Vault, or else the entire flash loan will revert. + * + * `userData` is the same value passed in the `IVault.flashLoan` call. + */ + function receiveFlashLoan( + IERC20[] memory tokens, + uint256[] memory amounts, + uint256[] memory feeAmounts, + bytes memory userData + ) external; +} diff --git a/packages/hebao_v3/contracts/connectors/flashloan/IVault.sol b/packages/hebao_v3/contracts/connectors/flashloan/IVault.sol new file mode 100644 index 000000000..dafa68703 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/flashloan/IVault.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "./IFlashLoanRecipient.sol"; + +interface IBalancerVault { + function flashLoan( + IFlashLoanRecipient recipient, + IERC20[] calldata tokens, + uint256[] calldata amounts, + bytes calldata userData + ) external; +} diff --git a/packages/hebao_v3/contracts/connectors/flashloan/flashloan_connector.sol b/packages/hebao_v3/contracts/connectors/flashloan/flashloan_connector.sol new file mode 100644 index 000000000..2433318fe --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/flashloan/flashloan_connector.sol @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "../base_connector.sol"; +import {FlashLoanPoolInterface} from "./BalancerFlashloan.sol"; + +interface ApprovalInterface { + function approveExecutor(address executor, uint256 validUntil) external; + + function unApproveExecutor(address executor) external; +} + +contract FlashLoanConnector is BaseConnector { + using SafeERC20 for IERC20; + + FlashLoanPoolInterface public immutable flashLoanPool; + + constructor( + address _instaMemory, + address _flashLoanPool + ) BaseConnector(_instaMemory) { + flashLoanPool = FlashLoanPoolInterface(_flashLoanPool); + } + + /** + * @dev Borrow Flashloan and Cast spells. + * @param token Token Address. + * @param amt Token Amount. + * @param data targets & data for cast. + */ + function flashBorrowAndCast( + address token, + uint amt, + bytes calldata data + ) external payable { + (address[] memory targets, bytes[] memory callDatas) = abi.decode( + data, + (address[], bytes[]) + ); + ApprovalInterface(address(this)).approveExecutor( + address(flashLoanPool), + type(uint256).max + ); + + bytes memory callData = abi.encodeWithSignature( + "castFromExecutor(address[],bytes[])", + targets, + callDatas + ); + + flashLoanPool.flashLoan(token, amt, callData); + + ApprovalInterface(address(this)).unApproveExecutor( + address(flashLoanPool) + ); + } + + /** + * @dev Return token to InstaPool. + * @param token Token Address. + * @param amt Token Amount. + * @param getId Get token amount at this ID from `InstaMemory` Contract. + * @param setId Set token amount at this ID in `InstaMemory` Contract. + */ + function flashPayback( + address token, + uint amt, + uint getId, + uint setId + ) external payable { + uint _amt = getUint(getId, amt); + + IERC20 tokenContract = IERC20(token); + + if (token == ETH_ADDR) { + Address.sendValue(payable(address(flashLoanPool)), _amt); + } else { + tokenContract.safeTransfer(address(flashLoanPool), _amt); + } + + setUint(setId, _amt); + } +} diff --git a/packages/hebao_v3/contracts/connectors/lido.sol b/packages/hebao_v3/contracts/connectors/lido.sol new file mode 100644 index 000000000..892ce301e --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/lido.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; + +import "./base_connector.sol"; + +interface ILido { + function submit(address _referral) external payable returns (uint256); +} + +interface IWstETH { + function wrap(uint256 _stETHAmount) external returns (uint256); + function unwrap(uint256 _wstETHAmount) external returns (uint256); +} + +/** + * @title Stake Ether. + * @dev Stake ETH and receive stETH while staking. + */ + +contract LidoConnector is BaseConnector { + using SafeERC20 for IERC20; + + ILido internal constant LIDO = + ILido(0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84); + + IWstETH internal constant WSTETH = + IWstETH(0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0); + + address internal constant TREASURY = + 0x28849D2b63fA8D361e5fc15cB8aBB13019884d09; // Instadapp's treasury address + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + /** + * @dev deposit ETH into Lido. + * @notice stake Eth in Lido, users receive stETH tokens on a 1:1 basis representing their staked ETH. + * @param amt The amount of ETH to deposit. (For max: `uint256(-1)`) + * @param getId ID to retrieve amt. + * @param setId ID stores the amount of ETH deposited. + */ + function deposit(uint256 amt, uint256 getId, uint256 setId) public payable { + uint256 _amt = getUint(getId, amt); + + _amt = _amt == type(uint256).max ? address(this).balance : _amt; + LIDO.submit{value: amt}(TREASURY); + setUint(setId, _amt); + } + + // staking eth to receive sthETH and wrap it to wstETH + function wrapAndStaking( + uint256 amt, + uint256 getId, + uint256 setId + ) public payable { + uint256 _amt = getUint(getId, amt); + _amt = _amt == type(uint256).max ? address(this).balance : _amt; + Address.sendValue(payable(address(WSTETH)), _amt); + setUint(setId, _amt); + } + + // can only get stETH rather than ETH + function unwrap(uint256 amt, uint256 getId, uint256 setId) public { + uint256 _amt = getUint(getId, amt); + + TokenInterface tokenContract = TokenInterface(address(WSTETH)); + _amt = _amt == type(uint256).max + ? tokenContract.balanceOf(address(this)) + : _amt; + + WSTETH.unwrap(_amt); + + setUint(setId, _amt); + } +} diff --git a/packages/hebao_v3/contracts/connectors/memory.sol b/packages/hebao_v3/contracts/connectors/memory.sol new file mode 100644 index 000000000..7fb264719 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/memory.sol @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../lib/LoopringErrors.sol"; + +/** + * @title OwnedMemory. + * @dev Store Data For Cast Function. + */ + +contract Memory { + // Memory Bytes (Smart Account Address => Storage ID => Bytes). + mapping(address => mapping(uint => bytes32)) internal mbytes; // Use it to store execute data and delete in the same transaction + // Memory Uint (Smart Account Address => Storage ID => Uint). + mapping(address => mapping(uint => uint)) internal muint; // Use it to store execute data and delete in the same transaction + // Memory Address (Smart Account Address => Storage ID => Address). + mapping(address => mapping(uint => address)) internal maddr; // Use it to store execute data and delete in the same transaction + + /** + * @dev Store Bytes. + * @param _id Storage ID. + * @param _byte bytes data to store. + */ + function setBytes(uint _id, bytes32 _byte) public { + mbytes[msg.sender][_id] = _byte; + } + + /** + * @dev Get Stored Bytes. + * @param _id Storage ID. + */ + function getBytes(uint _id) public returns (bytes32 _byte) { + _byte = mbytes[msg.sender][_id]; + delete mbytes[msg.sender][_id]; + } + + /** + * @dev Store Uint. + * @param _id Storage ID. + * @param _num uint data to store. + */ + function setUint(uint _id, uint _num) public { + muint[msg.sender][_id] = _num; + } + + /** + * @dev Get Stored Uint. + * @param _id Storage ID. + */ + function getUint(uint _id) public returns (uint _num) { + _num = muint[msg.sender][_id]; + delete muint[msg.sender][_id]; + } + + /** + * @dev Store Address. + * @param _id Storage ID. + * @param _addr Address data to store. + */ + function setAddr(uint _id, address _addr) public { + maddr[msg.sender][_id] = _addr; + } + + /** + * @dev Get Stored Address. + * @param _id Storage ID. + */ + function getAddr(uint _id) public returns (address _addr) { + _addr = maddr[msg.sender][_id]; + delete maddr[msg.sender][_id]; + } +} + +contract OwnedMemory is Memory { + address public immutable master; + address private constant BROADCAST_ADDR = address(0); + + constructor() { + master = msg.sender; + } + + modifier isMaster() { + _require(msg.sender == master, Errors.MEMORY_NOT_MASTER); + _; + } + + /** + * @dev Get Stored Address. + * @param _id Storage ID. + */ + function getBroadcastAddr(uint _id) public view returns (address _addr) { + _addr = maddr[BROADCAST_ADDR][_id]; + } + + /** + * @dev Store Address. + * @param _id Storage ID. + * @param _addr Address data to store. + */ + function setBroadcastAddr(uint _id, address _addr) public isMaster { + maddr[BROADCAST_ADDR][_id] = _addr; + } +} diff --git a/packages/hebao_v3/contracts/connectors/uniswap.sol b/packages/hebao_v3/contracts/connectors/uniswap.sol new file mode 100644 index 000000000..40a65b8c9 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/uniswap.sol @@ -0,0 +1,402 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "./base_connector.sol"; + +interface IUniswapV2Router02 { + function factory() external pure returns (address); + + function addLiquidity( + address tokenA, + address tokenB, + uint amountADesired, + uint amountBDesired, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB, uint liquidity); + function removeLiquidity( + address tokenA, + address tokenB, + uint liquidity, + uint amountAMin, + uint amountBMin, + address to, + uint deadline + ) external returns (uint amountA, uint amountB); + function swapExactTokensForTokens( + uint amountIn, + uint amountOutMin, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + function swapTokensForExactTokens( + uint amountOut, + uint amountInMax, + address[] calldata path, + address to, + uint deadline + ) external returns (uint[] memory amounts); + + function quote( + uint amountA, + uint reserveA, + uint reserveB + ) external pure returns (uint amountB); + function getAmountOut( + uint amountIn, + uint reserveIn, + uint reserveOut + ) external pure returns (uint amountOut); + function getAmountIn( + uint amountOut, + uint reserveIn, + uint reserveOut + ) external pure returns (uint amountIn); + function getAmountsOut( + uint amountIn, + address[] calldata path + ) external view returns (uint[] memory amounts); + function getAmountsIn( + uint amountOut, + address[] calldata path + ) external view returns (uint[] memory amounts); +} + +interface IUniswapV2Factory { + function getPair( + address tokenA, + address tokenB + ) external view returns (address pair); + function allPairs(uint) external view returns (address pair); + function allPairsLength() external view returns (uint); + + function feeTo() external view returns (address); + function feeToSetter() external view returns (address); + + function createPair( + address tokenA, + address tokenB + ) external returns (address pair); +} + +contract UniswapConnector is BaseConnector { + using SafeERC20 for IERC20; + + IUniswapV2Router02 internal constant ROUTER = + IUniswapV2Router02(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D); + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + function deposit( + address tokenA, + address tokenB, + uint256 amtA, + uint256 unitAmt, + uint256 slippage, + uint256 getId, + uint256 setId + ) external payable { + uint _amt = getUint(getId, amtA); + + (, , uint _uniAmt) = _addLiquidity( + tokenA, + tokenB, + _amt, + unitAmt, + slippage + ); + setUint(setId, _uniAmt); + } + + /** + * @dev Withdraw Liquidity. + * @notice Withdraw Liquidity from a Uniswap v2 pool. + * @param tokenA The address of token A.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param tokenB The address of token B.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param uniAmt The amount of pool tokens to withdraw. + * @param unitAmtA The unit amount of amtA/uniAmt with slippage. + * @param unitAmtB The unit amount of amtB/uniAmt with slippage. + * @param getId ID to retrieve uniAmt. + * @param setIds Array of IDs to store the amount tokens received. + */ + function withdraw( + address tokenA, + address tokenB, + uint256 uniAmt, + uint256 unitAmtA, + uint256 unitAmtB, + uint256 getId, + uint256[] calldata setIds + ) external payable { + uint _amt = getUint(getId, uniAmt); + + (uint _amtA, uint _amtB, ) = _removeLiquidity( + tokenA, + tokenB, + _amt, + unitAmtA, + unitAmtB + ); + + setUint(setIds[0], _amtA); + setUint(setIds[1], _amtB); + } + + /** + * @dev Buy ETH/ERC20_Token. + * @notice Buy a token using a Uniswap v2 + * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param buyAmt The amount of tokens to buy. + * @param unitAmt The unit amount of sellAmt/buyAmt with slippage. + * @param getId ID to retrieve buyAmt. + * @param setId ID to store the amount of tokens sold. + */ + function buy( + address buyAddr, + address sellAddr, + uint256 buyAmt, + uint256 unitAmt, + uint256 getId, + uint256 setId + ) external payable { + uint _buyAmt = getUint(getId, buyAmt); + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress( + buyAddr, + sellAddr + ); + address[] memory paths = getPaths( + address(_buyAddr), + address(_sellAddr) + ); + + uint _slippageAmt = convert18ToDec( + _sellAddr.decimals(), + wmul(unitAmt, convertTo18(_buyAddr.decimals(), _buyAmt)) + ); + + checkPair(paths); + uint _expectedAmt = getExpectedSellAmt(paths, _buyAmt); + require(_slippageAmt >= _expectedAmt, "Too much slippage"); + + bool isEth = address(_sellAddr) == WETH_ADDR; + convertEthToWeth(isEth, _sellAddr, _expectedAmt); + IERC20(address(_sellAddr)).safeApprove(address(ROUTER), _expectedAmt); + + uint _sellAmt = ROUTER.swapTokensForExactTokens( + _buyAmt, + _expectedAmt, + paths, + address(this), + block.timestamp + 1 + )[0]; + + isEth = address(_buyAddr) == WETH_ADDR; + convertWethToEth(isEth, _buyAddr, _buyAmt); + + setUint(setId, _sellAmt); + } + + /** + * @dev Sell ETH/ERC20_Token. + * @notice Sell a token using a Uniswap v2 + * @param buyAddr The address of the token to buy.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAddr The address of the token to sell.(For ETH: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE) + * @param sellAmt The amount of the token to sell. + * @param unitAmt The unit amount of buyAmt/sellAmt with slippage. + * @param getId ID to retrieve sellAmt. + * @param setId ID stores the amount of token brought. + */ + function sell( + address buyAddr, + address sellAddr, + uint256 sellAmt, + uint256 unitAmt, + uint256 getId, + uint256 setId + ) external payable { + uint _sellAmt = getUint(getId, sellAmt); + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress( + buyAddr, + sellAddr + ); + address[] memory paths = getPaths( + address(_buyAddr), + address(_sellAddr) + ); + + if (_sellAmt == type(uint).max) { + _sellAmt = sellAddr == ETH_ADDR + ? address(this).balance + : _sellAddr.balanceOf(address(this)); + } + + uint _slippageAmt = convert18ToDec( + _buyAddr.decimals(), + wmul(unitAmt, convertTo18(_sellAddr.decimals(), _sellAmt)) + ); + + checkPair(paths); + uint _expectedAmt = getExpectedBuyAmt(paths, _sellAmt); + require(_slippageAmt <= _expectedAmt, "Too much slippage"); + + bool isEth = address(_sellAddr) == WETH_ADDR; + convertEthToWeth(isEth, _sellAddr, _sellAmt); + IERC20(address(_sellAddr)).safeApprove(address(ROUTER), _sellAmt); + + uint _buyAmt = ROUTER.swapExactTokensForTokens( + _sellAmt, + _expectedAmt, + paths, + address(this), + block.timestamp + 1 + )[1]; + + isEth = address(_buyAddr) == WETH_ADDR; + convertWethToEth(isEth, _buyAddr, _buyAmt); + + setUint(setId, _buyAmt); + } + + function getMinAmount( + TokenInterface token, + uint amt, + uint slippage + ) internal view returns (uint minAmt) { + uint _amt18 = convertTo18(token.decimals(), amt); + minAmt = wmul(_amt18, sub(WAD, slippage)); + minAmt = convert18ToDec(token.decimals(), minAmt); + } + + function _addLiquidity( + address tokenA, + address tokenB, + uint _amt, + uint unitAmt, + uint slippage + ) internal returns (uint _amtA, uint _amtB, uint _liquidity) { + (TokenInterface _tokenA, TokenInterface _tokenB) = changeEthAddress( + tokenA, + tokenB + ); + + _amtA = _amt == type(uint).max + ? getTokenBal(TokenInterface(tokenA)) + : _amt; + _amtB = convert18ToDec( + _tokenB.decimals(), + wmul(unitAmt, convertTo18(_tokenA.decimals(), _amtA)) + ); + + bool isEth = address(_tokenA) == WETH_ADDR; + convertEthToWeth(isEth, _tokenA, _amtA); + + isEth = address(_tokenB) == WETH_ADDR; + convertEthToWeth(isEth, _tokenB, _amtB); + + IERC20(tokenA).safeApprove(address(ROUTER), _amtA); + IERC20(tokenB).safeApprove(address(ROUTER), _amtB); + + uint minAmtA = getMinAmount(_tokenA, _amtA, slippage); + uint minAmtB = getMinAmount(_tokenB, _amtB, slippage); + (_amtA, _amtB, _liquidity) = ROUTER.addLiquidity( + address(_tokenA), + address(_tokenB), + _amtA, + _amtB, + minAmtA, + minAmtB, + address(this), + block.timestamp + 1 + ); + } + + function _removeLiquidity( + address tokenA, + address tokenB, + uint _amt, + uint unitAmtA, + uint unitAmtB + ) internal returns (uint _amtA, uint _amtB, uint _uniAmt) { + (TokenInterface _tokenA, TokenInterface _tokenB) = changeEthAddress( + tokenA, + tokenB + ); + address exchangeAddr = IUniswapV2Factory(ROUTER.factory()).getPair( + address(_tokenA), + address(_tokenB) + ); + require(exchangeAddr != address(0), "pair-not-found."); + + TokenInterface uniToken = TokenInterface(exchangeAddr); + _uniAmt = _amt == type(uint).max + ? uniToken.balanceOf(address(this)) + : _amt; + IERC20(exchangeAddr).safeApprove(address(ROUTER), _uniAmt); + + { + uint minAmtA = convert18ToDec( + _tokenA.decimals(), + wmul(unitAmtA, _uniAmt) + ); + uint minAmtB = convert18ToDec( + _tokenB.decimals(), + wmul(unitAmtB, _uniAmt) + ); + (_amtA, _amtB) = ROUTER.removeLiquidity( + address(_tokenA), + address(_tokenB), + _uniAmt, + minAmtA, + minAmtB, + address(this), + block.timestamp + 1 + ); + } + + bool isEth = address(_tokenA) == WETH_ADDR; + convertWethToEth(isEth, _tokenA, _amtA); + + isEth = address(_tokenB) == WETH_ADDR; + convertWethToEth(isEth, _tokenB, _amtB); + } + + function getExpectedBuyAmt( + address[] memory paths, + uint sellAmt + ) internal view returns (uint buyAmt) { + uint[] memory amts = ROUTER.getAmountsOut(sellAmt, paths); + buyAmt = amts[1]; + } + + function getExpectedSellAmt( + address[] memory paths, + uint buyAmt + ) internal view returns (uint sellAmt) { + uint[] memory amts = ROUTER.getAmountsIn(buyAmt, paths); + sellAmt = amts[0]; + } + + function checkPair(address[] memory paths) internal view { + address pair = IUniswapV2Factory(ROUTER.factory()).getPair( + paths[0], + paths[1] + ); + require(pair != address(0), "No-exchange-address"); + } + + function getPaths( + address buyAddr, + address sellAddr + ) internal pure returns (address[] memory paths) { + paths = new address[](2); + paths[0] = address(sellAddr); + paths[1] = address(buyAddr); + } +} diff --git a/packages/hebao_v3/contracts/connectors/uniswapv3.sol b/packages/hebao_v3/contracts/connectors/uniswapv3.sol new file mode 100644 index 000000000..3667b9c84 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/uniswapv3.sol @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +import "./base_connector.sol"; + +struct ExactInputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; + uint160 sqrtPriceLimitX96; +} + +struct ExactInputParams { + bytes path; + address recipient; + uint256 amountIn; + uint256 amountOutMinimum; +} + +struct ExactOutputSingleParams { + address tokenIn; + address tokenOut; + uint24 fee; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; + uint160 sqrtPriceLimitX96; +} + +struct ExactOutputParams { + bytes path; + address recipient; + uint256 amountOut; + uint256 amountInMaximum; +} + +/// @title Callback for IUniswapV3PoolActions#swap +/// @notice Any contract that calls IUniswapV3PoolActions#swap must implement this interface +interface IUniswapV3SwapCallback { + /// @notice Called to `msg.sender` after executing a swap via IUniswapV3Pool#swap. + /// @dev In the implementation you must pay the pool tokens owed for the swap. + /// The caller of this method must be checked to be a UniswapV3Pool deployed by the canonical UniswapV3Factory. + /// amount0Delta and amount1Delta can both be 0 if no tokens were swapped. + /// @param amount0Delta The amount of token0 that was sent (negative) or must be received (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token0 to the pool. + /// @param amount1Delta The amount of token1 that was sent (negative) or must be received (positive) by the pool by + /// the end of the swap. If positive, the callback must send that amount of token1 to the pool. + /// @param data Any data passed through by the caller via the IUniswapV3PoolActions#swap call + function uniswapV3SwapCallback( + int256 amount0Delta, + int256 amount1Delta, + bytes calldata data + ) external; +} + +interface IV3SwapRouter is IUniswapV3SwapCallback { + /// @notice Swaps `amountIn` of one token for as much as possible of another token + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the swap, encoded as `ExactInputSingleParams` in calldata + /// @return amountOut The amount of the received token + function exactInputSingle( + ExactInputSingleParams calldata params + ) external payable returns (uint256 amountOut); + + /// @notice Swaps `amountIn` of one token for as much as possible of another along the specified path + /// @dev Setting `amountIn` to 0 will cause the contract to look up its own balance, + /// and swap the entire amount, enabling contracts to send tokens before calling this function. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactInputParams` in calldata + /// @return amountOut The amount of the received token + function exactInput( + ExactInputParams calldata params + ) external payable returns (uint256 amountOut); + + /// @notice Swaps as little as possible of one token for `amountOut` of another token + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the swap, encoded as `ExactOutputSingleParams` in calldata + /// @return amountIn The amount of the input token + function exactOutputSingle( + ExactOutputSingleParams calldata params + ) external payable returns (uint256 amountIn); + + /// @notice Swaps as little as possible of one token for `amountOut` of another along the specified path (reversed) + /// that may remain in the router after the swap. + /// @param params The parameters necessary for the multi-hop swap, encoded as `ExactOutputParams` in calldata + /// @return amountIn The amount of the input token + function exactOutput( + ExactOutputParams calldata params + ) external payable returns (uint256 amountIn); +} + +interface IApproveAndCall {} + +/// @title Multicall interface +/// @notice Enables calling multiple methods in a single call to the contract +interface IMulticall {} + +/// @title MulticallExtended interface +/// @notice Enables calling multiple methods in a single call to the contract with optional validation +interface IMulticallExtended is IMulticall {} + +/// @title Self Permit +/// @notice Functionality to call permit on any EIP-2612-compliant token for use in the route +interface ISelfPermit {} + +/// @title Router token swapping functionality +/// @notice Functions for swapping tokens via Uniswap V2 +interface IV2SwapRouter {} + +interface ISwapRouter02 is + IV2SwapRouter, + IV3SwapRouter, + IApproveAndCall, + IMulticallExtended, + ISelfPermit +{} + +contract UniswapV3Connector is BaseConnector { + using SafeERC20 for IERC20; + + /** + * @dev uniswap v3 Swap Router + */ + ISwapRouter02 internal constant SWAP_ROUTER = + ISwapRouter02(0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45); + + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + struct BuyInfo { + address buyAddr; //token to be bought + address sellAddr; //token to be sold + uint24 fee; //pool fees for buyAddr-sellAddr token pair + uint256 unitAmt; //The unit amount of sellAmt/buyAmt with slippage + uint256 buyAmt; //amount of token to be bought + } + + struct SellInfo { + address buyAddr; //token to be bought + address sellAddr; //token to be sold + uint24 fee; //pool fees for buyAddr-sellAddr token pair + uint256 unitAmt; //The unit amount of sellAmt/buyAmt with slippage + uint256 sellAmt; //amount of token to be bought + } + + /** + * @dev Buy Function + * @notice Swap token(sellAddr) with token(buyAddr), buy token with minimum sell token + * @param buyData Data input for the buy action + * @param getId Id to get buyAmt + * @param setId Id to store sellAmt + */ + function _buy( + BuyInfo memory buyData, + uint256 getId, + uint256 setId + ) internal { + uint256 _buyAmt = getUint(getId, buyData.buyAmt); + + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress( + buyData.buyAddr, + buyData.sellAddr + ); + + uint256 _slippageAmt = convert18ToDec( + _sellAddr.decimals(), + wmul(buyData.unitAmt, convertTo18(_buyAddr.decimals(), _buyAmt)) + ); + bool isEth = address(buyData.sellAddr) == ETH_ADDR; + convertEthToWeth(isEth, _sellAddr, _slippageAmt); + IERC20(address(_sellAddr)).safeApprove( + address(SWAP_ROUTER), + _slippageAmt + ); + + ExactOutputSingleParams memory params = ExactOutputSingleParams({ + tokenIn: address(_sellAddr), + tokenOut: address(_buyAddr), + fee: buyData.fee, + recipient: address(this), + amountOut: _buyAmt, + amountInMaximum: _slippageAmt, //require(_sellAmt <= amountInMaximum) + sqrtPriceLimitX96: 0 + }); + + uint256 _sellAmt = SWAP_ROUTER.exactOutputSingle(params); + require(_slippageAmt >= _sellAmt, "Too much slippage"); + + if (_slippageAmt > _sellAmt) { + convertEthToWeth(isEth, _sellAddr, _slippageAmt - _sellAmt); + IERC20(address(_sellAddr)).safeApprove(address(SWAP_ROUTER), 0); + } + isEth = address(buyData.buyAddr) == ETH_ADDR; + convertWethToEth(isEth, _buyAddr, _buyAmt); + + setUint(setId, _sellAmt); + } + + /** + * @dev Sell Function + * @notice Swap token(sellAddr) with token(buyAddr), to get max buy tokens + * @param sellData Data input for the sell action + * @param getId Id to get buyAmt + * @param setId Id to store sellAmt + */ + function _sell( + SellInfo memory sellData, + uint256 getId, + uint256 setId + ) internal { + uint256 _sellAmt = getUint(getId, sellData.sellAmt); + (TokenInterface _buyAddr, TokenInterface _sellAddr) = changeEthAddress( + sellData.buyAddr, + sellData.sellAddr + ); + + if (_sellAmt == type(uint256).max) { + _sellAmt = sellData.sellAddr == ETH_ADDR + ? address(this).balance + : _sellAddr.balanceOf(address(this)); + } + + uint256 _slippageAmt = convert18ToDec( + _buyAddr.decimals(), + wmul(sellData.unitAmt, convertTo18(_sellAddr.decimals(), _sellAmt)) + ); + + bool isEth = address(sellData.sellAddr) == ETH_ADDR; + convertEthToWeth(isEth, _sellAddr, _sellAmt); + IERC20(address(_sellAddr)).safeApprove(address(SWAP_ROUTER), _sellAmt); + ExactInputSingleParams memory params = ExactInputSingleParams({ + tokenIn: address(_sellAddr), + tokenOut: address(_buyAddr), + fee: sellData.fee, + recipient: address(this), + amountIn: _sellAmt, + amountOutMinimum: _slippageAmt, //require(_buyAmt >= amountOutMinimum) + sqrtPriceLimitX96: 0 + }); + + uint256 _buyAmt = SWAP_ROUTER.exactInputSingle(params); + require(_slippageAmt <= _buyAmt, "Too much slippage"); + + isEth = address(sellData.buyAddr) == ETH_ADDR; + convertWethToEth(isEth, _buyAddr, _buyAmt); + + setUint(setId, _buyAmt); + } + + /** + * @dev Buy Function + * @notice Swap token(sellAddr) with token(buyAddr), buy token with minimum sell token + * @param _buyAddr token to be bought + * @param _sellAddr token to be sold + * @param _fee pool fees for buyAddr-sellAddr token pair + * @param _unitAmt The unit amount of sellAmt/buyAmt with slippage + * @param _buyAmt amount of token to be bought + * @param _getId Id to get buyAmt + * @param _setId Id to store sellAmt + */ + function buy( + address _buyAddr, + address _sellAddr, + uint24 _fee, + uint256 _unitAmt, + uint256 _buyAmt, + uint256 _getId, + uint256 _setId + ) external payable { + _buy( + BuyInfo({ + buyAddr: _buyAddr, + sellAddr: _sellAddr, + fee: _fee, + unitAmt: _unitAmt, + buyAmt: _buyAmt + }), + _getId, + _setId + ); + } + + /** + * @dev Sell Function + * @notice Swap token(sellAddr) with token(buyAddr), buy token with minimum sell token + * @param _buyAddr token to be bought + * @param _sellAddr token to be sold + * @param _fee pool fees for buyAddr-sellAddr token pair + * @param _unitAmt The unit amount of buyAmt/sellAmt with slippage + * @param _sellAmt amount of token to be sold + * @param _getId Id to get sellAmt + * @param _setId Id to store buyAmt + */ + function sell( + address _buyAddr, + address _sellAddr, + uint24 _fee, + uint256 _unitAmt, + uint256 _sellAmt, + uint256 _getId, + uint256 _setId + ) external payable { + _sell( + SellInfo({ + buyAddr: _buyAddr, + sellAddr: _sellAddr, + fee: _fee, + unitAmt: _unitAmt, + sellAmt: _sellAmt + }), + _getId, + _setId + ); + } +} diff --git a/packages/hebao_v3/contracts/connectors/weth.sol b/packages/hebao_v3/contracts/connectors/weth.sol new file mode 100644 index 000000000..cac2d8807 --- /dev/null +++ b/packages/hebao_v3/contracts/connectors/weth.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./base_connector.sol"; + +contract WETHConnector is BaseConnector { + TokenInterface internal constant WETH_CONTRACT = + TokenInterface(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); + constructor(address _instaMemory) BaseConnector(_instaMemory) {} + + function deposit(uint256 amt, uint256 getId, uint256 setId) public payable { + uint _amt = getUint(getId, amt); + _amt = _amt == type(uint256).max ? address(this).balance : _amt; + WETH_CONTRACT.deposit{value: _amt}(); + setUint(setId, _amt); + } + + function withdraw(uint amt, uint getId, uint setId) public payable { + uint _amt = getUint(getId, amt); + + _amt = _amt == type(uint256).max + ? WETH_CONTRACT.balanceOf(address(this)) + : _amt; + WETH_CONTRACT.withdraw(_amt); + setUint(setId, _amt); + } +} diff --git a/packages/hebao_v3/contracts/iface/IConnectorRegistry.sol b/packages/hebao_v3/contracts/iface/IConnectorRegistry.sol new file mode 100644 index 000000000..cd02a41a6 --- /dev/null +++ b/packages/hebao_v3/contracts/iface/IConnectorRegistry.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +interface IConnectorRegistry { + function addConnectors(address[] calldata _connectors) external; + + function removeConnectors(address[] calldata _connectors) external; + + function isConnectors( + address[] calldata connectorAddrs + ) external view returns (bool); +} diff --git a/packages/hebao_v3/contracts/iface/ILoopringWalletV2.sol b/packages/hebao_v3/contracts/iface/ILoopringWalletV2.sol new file mode 100644 index 000000000..c1676abdd --- /dev/null +++ b/packages/hebao_v3/contracts/iface/ILoopringWalletV2.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title Loopring SmartWallet V2 interface +/// @author Brecht Devos - +abstract contract ILoopringWalletV2 { + /// @dev Initializes the smart wallet. + /// @param owner The wallet owner address. + /// @param guardians The initial wallet guardians. + /// @param quota The initial wallet quota. + /// @param inheritor The inheritor of the wallet. + /// @param feeRecipient The address receiving the fee for creating the wallet. + /// @param feeToken The token to use for the fee payment. + /// @param feeAmount The amount of tokens paid to the fee recipient. + function initialize( + address owner, + address[] calldata guardians, + uint quota, + address inheritor, + address feeRecipient, + address feeToken, + uint feeAmount + ) external virtual; + + /// @dev Returns the timestamp the wallet was created. + /// @return The timestamp the wallet was created. + function getCreationTimestamp() public view virtual returns (uint64); + + /// @dev Returns the current wallet owner. + /// @return The current wallet owner. + function getOwner() public view virtual returns (address); +} diff --git a/packages/hebao_v3/contracts/iface/PriceOracle.sol b/packages/hebao_v3/contracts/iface/PriceOracle.sol new file mode 100644 index 000000000..d8dbecb80 --- /dev/null +++ b/packages/hebao_v3/contracts/iface/PriceOracle.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title PriceOracle +interface PriceOracle { + // @dev Return's the token's value in ETH + function tokenValue( + address token, + uint amount + ) external view returns (uint value); +} diff --git a/packages/hebao_v3/contracts/lib/AddressSet.sol b/packages/hebao_v3/contracts/lib/AddressSet.sol new file mode 100644 index 000000000..539687e8d --- /dev/null +++ b/packages/hebao_v3/contracts/lib/AddressSet.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title AddressSet +/// @author Daniel Wang - +contract AddressSet { + struct Set { + address[] addresses; + mapping(address => uint) positions; + uint count; + } + mapping(bytes32 => Set) private sets; + + function addAddressToSet( + bytes32 key, + address addr, + bool maintainList + ) internal { + Set storage set = sets[key]; + require(set.positions[addr] == 0, "ALREADY_IN_SET"); + + if (maintainList) { + require( + set.addresses.length == set.count, + "PREVIOUSLY_NOT_MAINTAILED" + ); + set.addresses.push(addr); + } else { + require(set.addresses.length == 0, "MUST_MAINTAIN"); + } + + set.count += 1; + set.positions[addr] = set.count; + } + + function removeAddressFromSet(bytes32 key, address addr) internal { + Set storage set = sets[key]; + uint pos = set.positions[addr]; + require(pos != 0, "NOT_IN_SET"); + + delete set.positions[addr]; + set.count -= 1; + + if (set.addresses.length > 0) { + address lastAddr = set.addresses[set.count]; + if (lastAddr != addr) { + set.addresses[pos - 1] = lastAddr; + set.positions[lastAddr] = pos; + } + set.addresses.pop(); + } + } + + function removeSet(bytes32 key) internal { + delete sets[key]; + } + + function isAddressInSet( + bytes32 key, + address addr + ) internal view returns (bool) { + return sets[key].positions[addr] != 0; + } + + function numAddressesInSet(bytes32 key) internal view returns (uint) { + Set storage set = sets[key]; + return set.count; + } + + function addressesInSet( + bytes32 key + ) internal view returns (address[] memory) { + Set storage set = sets[key]; + require(set.count == set.addresses.length, "NOT_MAINTAINED"); + return sets[key].addresses; + } +} diff --git a/packages/hebao_v3/contracts/lib/AddressUtil.sol b/packages/hebao_v3/contracts/lib/AddressUtil.sol new file mode 100644 index 000000000..85996a7c8 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/AddressUtil.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title Utility Functions for addresses +/// @author Daniel Wang - +/// @author Brecht Devos - +library AddressUtil { + using AddressUtil for *; + + function isContract(address addr) internal view returns (bool) { + // According to EIP-1052, 0x0 is the value returned for not-yet created accounts + // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned + // for accounts without code, i.e. `keccak256('')` + bytes32 codehash; + // solhint-disable-next-line no-inline-assembly + assembly { + codehash := extcodehash(addr) + } + return (codehash != 0x0 && + codehash != + 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470); + } + + function toPayable(address addr) internal pure returns (address payable) { + return payable(addr); + } + + // Works like address.send but with a customizable gas limit + // Make sure your code is safe for reentrancy when using this function! + function sendETH( + address to, + uint amount, + uint gasLimit + ) internal returns (bool success) { + if (amount == 0) { + return true; + } + address payable recipient = to.toPayable(); + /* solium-disable-next-line */ + (success, ) = recipient.call{value: amount, gas: gasLimit}(""); + } + + // Works like address.transfer but with a customizable gas limit + // Make sure your code is safe for reentrancy when using this function! + function sendETHAndVerify( + address to, + uint amount, + uint gasLimit + ) internal returns (bool success) { + success = to.sendETH(amount, gasLimit); + require(success, "TRANSFER_FAILURE"); + } + + // Works like call but is slightly more efficient when data + // needs to be copied from memory to do the call. + function fastCall( + address to, + uint gasLimit, + uint value, + bytes memory data + ) internal returns (bool success, bytes memory returnData) { + if (to != address(0)) { + // solhint-disable-next-line no-inline-assembly + assembly { + // Do the call + success := call( + gasLimit, + to, + value, + add(data, 32), + mload(data), + 0, + 0 + ) + // Copy the return data + let size := returndatasize() + returnData := mload(0x40) + mstore(returnData, size) + returndatacopy(add(returnData, 32), 0, size) + // Update free memory pointer + mstore(0x40, add(returnData, add(32, size))) + } + } + } + + // Like fastCall, but throws when the call is unsuccessful. + function fastCallAndVerify( + address to, + uint gasLimit, + uint value, + bytes memory data + ) internal returns (bytes memory returnData) { + bool success; + (success, returnData) = fastCall(to, gasLimit, value, data); + if (!success) { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(returnData, 32), mload(returnData)) + } + } + } +} diff --git a/packages/hebao_v3/contracts/lib/Claimable.sol b/packages/hebao_v3/contracts/lib/Claimable.sol new file mode 100644 index 000000000..ca2182c8e --- /dev/null +++ b/packages/hebao_v3/contracts/lib/Claimable.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./Ownable.sol"; + +/// @title Claimable +/// @author Brecht Devos - +/// @dev Extension for the Ownable contract, where the ownership needs +/// to be claimed. This allows the new owner to accept the transfer. +contract Claimable is Ownable { + address public pendingOwner; + + /// @dev Modifier throws if called by any account other than the pendingOwner. + modifier onlyPendingOwner() { + require(msg.sender == pendingOwner, "UNAUTHORIZED"); + _; + } + + /// @dev Allows the current owner to set the pendingOwner address. + /// @param newOwner The address to transfer ownership to. + function transferOwnership(address newOwner) public override onlyOwner { + require(newOwner != address(0) && newOwner != owner, "INVALID_ADDRESS"); + pendingOwner = newOwner; + } + + /// @dev Allows the pendingOwner address to finalize the transfer. + function claimOwnership() public onlyPendingOwner { + owner = pendingOwner; + pendingOwner = address(0); + + emit OwnershipTransferred(owner, pendingOwner); + } +} diff --git a/packages/hebao_v3/contracts/lib/DelayTargetSelectorBasedAccessManager.sol b/packages/hebao_v3/contracts/lib/DelayTargetSelectorBasedAccessManager.sol new file mode 100644 index 000000000..74faff3c1 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/DelayTargetSelectorBasedAccessManager.sol @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./Claimable.sol"; +import "../thirdparty/BytesUtil.sol"; + +/// @title SelectorBasedAccessManager +/// @author Daniel Wang - +contract DelayTargetSelectorBasedAccessManager is Claimable { + using BytesUtil for bytes; + + event PermissionUpdate( + address indexed user, + bytes4 indexed selector, + bool allowed + ); + + address public target; + mapping(address => mapping(bytes4 => bool)) public permissions; + + modifier withAccess(bytes4 selector) { + require(hasAccessTo(msg.sender, selector), "PERMISSION_DENIED"); + _; + } + + constructor() {} + + function grantAccess( + address user, + bytes4 selector, + bool granted + ) external onlyOwner { + require(permissions[user][selector] != granted, "INVALID_VALUE"); + permissions[user][selector] = granted; + emit PermissionUpdate(user, selector, granted); + } + + receive() external payable {} + + fallback() external payable { + transact(msg.data); + } + + function setTarget(address _target) public onlyOwner { + require(_target != address(0), "ZERO_ADDRESS"); + target = _target; + } + + function transact( + bytes memory data + ) public payable withAccess(data.toBytes4(0)) { + require(target != address(0), "ZERO_ADDRESS"); + (bool success, bytes memory returnData) = target.call{value: msg.value}( + data + ); + + if (!success) { + // solhint-disable-next-line no-inline-assembly + assembly { + revert(add(returnData, 32), mload(returnData)) + } + } + } + + function hasAccessTo( + address user, + bytes4 selector + ) public view returns (bool) { + return user == owner || permissions[user][selector]; + } +} diff --git a/packages/hebao_v3/contracts/lib/EIP712.sol b/packages/hebao_v3/contracts/lib/EIP712.sol new file mode 100644 index 000000000..2db16c5d4 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/EIP712.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +library EIP712 { + struct Domain { + string name; + string version; + address verifyingContract; + } + + bytes32 internal constant EIP712_DOMAIN_TYPEHASH = + keccak256( + "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)" + ); + + string internal constant EIP191_HEADER = "\x19\x01"; + + function hash(Domain memory domain) internal view returns (bytes32) { + return + keccak256( + abi.encode( + EIP712_DOMAIN_TYPEHASH, + keccak256(bytes(domain.name)), + keccak256(bytes(domain.version)), + block.chainid, + domain.verifyingContract + ) + ); + } + + function hashPacked( + bytes32 domainSeparator, + bytes32 dataHash + ) internal pure returns (bytes32) { + return + keccak256( + abi.encodePacked(EIP191_HEADER, domainSeparator, dataHash) + ); + } +} diff --git a/packages/hebao_v3/contracts/lib/ERC1271.sol b/packages/hebao_v3/contracts/lib/ERC1271.sol new file mode 100644 index 000000000..e3b1118a1 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/ERC1271.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +abstract contract ERC1271 { + // bytes4(keccak256("isValidSignature(bytes32,bytes)") + bytes4 internal constant ERC1271_MAGICVALUE = 0x1626ba7e; + + function isValidSignature( + bytes32 _hash, + bytes calldata _signature + ) public view virtual returns (bytes4 magicValue); +} diff --git a/packages/hebao_v3/contracts/lib/LoopringErrors.sol b/packages/hebao_v3/contracts/lib/LoopringErrors.sol new file mode 100644 index 000000000..211d0bf93 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/LoopringErrors.sol @@ -0,0 +1,290 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +pragma solidity ^0.8.17; + +// modified the codes from https://github.com/balancer/balancer-v2-monorepo/blob/master/pkg/interfaces/contracts/solidity-utils/helpers/BalancerErrors.sol + +// solhint-disable + +/** + * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are + * supported. + * Uses the default 'BAL' prefix for the error code + */ +function _require(bool condition, uint256 errorCode) pure { + if (!condition) _revert(errorCode); +} + +/** + * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are + * supported. + */ +function _require(bool condition, uint256 errorCode, bytes3 prefix) pure { + if (!condition) _revert(errorCode, prefix); +} + +/** + * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported. + * Uses the default 'LRC' prefix for the error code + */ +function _revert(uint256 errorCode) pure { + _revert(errorCode, 0x4c5243); // This is the raw byte representation of "LRC" +} + +/** + * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported. + */ +function _revert(uint256 errorCode, bytes3 prefix) pure { + uint256 prefixUint = uint256(uint24(prefix)); + // We're going to dynamically create a revert string based on the error code, with the following format: + // 'LRC#{errorCode}' + // where the code is left-padded with zeroes to three digits (so they range from 000 to 999). + // + // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a + // number (8 to 16 bits) than the individual string characters. + // + // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a + // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a + // safe place to rely on it without worrying about how its usage might affect e.g. memory contents. + assembly { + // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999 + // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for + // the '0' character. + + let units := add(mod(errorCode, 10), 0x30) + + errorCode := div(errorCode, 10) + let tenths := add(mod(errorCode, 10), 0x30) + + errorCode := div(errorCode, 10) + let hundreds := add(mod(errorCode, 10), 0x30) + + // With the individual characters, we can now construct the full string. + // We first append the '#' character (0x23) to the prefix. In the case of 'LRC', it results in 0x4c5243 ('LRC#') + // Then, we shift this by 24 (to provide space for the 3 bytes of the error code), and add the + // characters to it, each shifted by a multiple of 8. + // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits + // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte + // array). + let formattedPrefix := shl(24, add(0x23, shl(8, prefixUint))) + + let revertReason := shl( + 200, + add( + formattedPrefix, + add(add(units, shl(8, tenths)), shl(16, hundreds)) + ) + ) + + // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded + // message will have the following layout: + // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ] + + // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We + // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten. + mstore( + 0x0, + 0x08c379a000000000000000000000000000000000000000000000000000000000 + ) + // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away). + mstore( + 0x04, + 0x0000000000000000000000000000000000000000000000000000000000000020 + ) + // The string length is fixed: 7 characters. + mstore(0x24, 7) + // Finally, the string itself is stored. + mstore(0x44, revertReason) + + // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of + // the encoded message is therefore 4 + 32 + 32 + 32 = 100. + revert(0, 100) + } +} + +library Errors { + // Input + uint256 internal constant OUT_OF_BOUNDS = 100; + uint256 internal constant UNSORTED_ARRAY = 101; + uint256 internal constant UNSORTED_TOKENS = 102; + uint256 internal constant INPUT_LENGTH_MISMATCH = 103; + uint256 internal constant ZERO_ADDRESS = 104; + uint256 internal constant INVALID_VALID_SINCE = 105; + uint256 internal constant ZERO_TOKEN = 106; + uint256 internal constant MASTER_COPY_ZERO_ADDRESS = 107; + + // Shared pools + uint256 internal constant MIN_TOKENS = 200; + uint256 internal constant MAX_TOKENS = 201; + uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202; + uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203; + uint256 internal constant MINIMUM_BPT = 204; + uint256 internal constant CALLER_NOT_VAULT = 205; + uint256 internal constant UNINITIALIZED = 206; + uint256 internal constant BPT_IN_MAX_AMOUNT = 207; + uint256 internal constant BPT_OUT_MIN_AMOUNT = 208; + uint256 internal constant EXPIRED_PERMIT = 209; + uint256 internal constant NOT_TWO_TOKENS = 210; + uint256 internal constant DISABLED = 211; + + // Pools + uint256 internal constant BATCHED_CALL_FAILED = 300; + uint256 internal constant DISALLOWED_ON_IMPLEMENTATION_CONTRACT = 301; + uint256 internal constant NOT_ALLOWED_TO_SET_OWNER = 302; + uint256 internal constant ONLY_FROM_ENTRYPOINT = 303; + uint256 internal constant NOT_OWNER_SELF_OR_ENTRYPOINT_OR_LOCKED = 304; + uint256 internal constant INVALID_OWNER = 305; + uint256 internal constant INITIALIZED_ALREADY = 306; + uint256 internal constant INVALID_SAME_ENTRYPOINT = 307; + uint256 internal constant NOT_ENTRYPOINT_OR_INHERITOR = 308; + uint256 internal constant NOT_EXECUTOR = 309; + uint256 internal constant OFFICIALGUARDIAN_CALL_FAILED = 310; + uint256 internal constant NOT_FROM_BALANCER_VAULT = 311; + uint256 internal constant INVALID_SAME_MASTER_COPY = 312; + uint256 internal constant MEMORY_NOT_MASTER = 313; + uint256 internal constant ORACLE_QUERY_TOO_OLD = 314; + uint256 internal constant ORACLE_INVALID_INDEX = 315; + uint256 internal constant ORACLE_BAD_SECS = 316; + uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317; + uint256 internal constant AMP_ONGOING_UPDATE = 318; + uint256 internal constant AMP_RATE_TOO_HIGH = 319; + uint256 internal constant AMP_NO_ONGOING_UPDATE = 320; + uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321; + uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322; + uint256 internal constant RELAYER_NOT_CONTRACT = 323; + uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324; + uint256 internal constant REBALANCING_RELAYER_REENTERED = 325; + uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326; + uint256 internal constant SWAPS_DISABLED = 327; + uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328; + uint256 internal constant PRICE_RATE_OVERFLOW = 329; + uint256 internal constant INVALID_JOIN_EXIT_KIND_WHILE_SWAPS_DISABLED = 330; + uint256 internal constant WEIGHT_CHANGE_TOO_FAST = 331; + uint256 internal constant LOWER_GREATER_THAN_UPPER_TARGET = 332; + uint256 internal constant UPPER_TARGET_TOO_HIGH = 333; + uint256 internal constant UNHANDLED_BY_LINEAR_POOL = 334; + uint256 internal constant OUT_OF_TARGET_RANGE = 335; + uint256 internal constant UNHANDLED_EXIT_KIND = 336; + uint256 internal constant UNAUTHORIZED_EXIT = 337; + uint256 internal constant MAX_MANAGEMENT_SWAP_FEE_PERCENTAGE = 338; + uint256 internal constant UNHANDLED_BY_MANAGED_POOL = 339; + uint256 internal constant UNHANDLED_BY_PHANTOM_POOL = 340; + uint256 internal constant TOKEN_DOES_NOT_HAVE_RATE_PROVIDER = 341; + uint256 internal constant INVALID_INITIALIZATION = 342; + uint256 internal constant OUT_OF_NEW_TARGET_RANGE = 343; + uint256 internal constant FEATURE_DISABLED = 344; + uint256 internal constant UNINITIALIZED_POOL_CONTROLLER = 345; + uint256 internal constant SET_SWAP_FEE_DURING_FEE_CHANGE = 346; + uint256 internal constant SET_SWAP_FEE_PENDING_FEE_CHANGE = 347; + uint256 internal constant CHANGE_TOKENS_DURING_WEIGHT_CHANGE = 348; + uint256 internal constant CHANGE_TOKENS_PENDING_WEIGHT_CHANGE = 349; + uint256 internal constant MAX_WEIGHT = 350; + uint256 internal constant UNAUTHORIZED_JOIN = 351; + uint256 internal constant MAX_MANAGEMENT_AUM_FEE_PERCENTAGE = 352; + uint256 internal constant FRACTIONAL_TARGET = 353; + uint256 internal constant ADD_OR_REMOVE_BPT = 354; + uint256 internal constant INVALID_CIRCUIT_BREAKER_BOUNDS = 355; + uint256 internal constant CIRCUIT_BREAKER_TRIPPED = 356; + uint256 internal constant MALICIOUS_QUERY_REVERT = 357; + uint256 internal constant JOINS_EXITS_DISABLED = 358; + + // Lib + uint256 internal constant NO_GUARDIANS = 400; + uint256 internal constant INVALID_SIGNERS_ORDER = 401; + uint256 internal constant SIGNER_NOT_GUARDIAN = 402; + uint256 internal constant WALLET_OWNER_SIGNATURE_NOT_ALLOWED = 403; + uint256 internal constant WALLET_OWNER_SIGNATURE_REQUIRED = 404; + uint256 internal constant INVALID_ORDERING = 405; + uint256 internal constant NO_GUARDIAN_SIGNED_BESIDES_OWNER = 406; + uint256 internal constant INVALID_GUARDIAN_ADDRESS = 407; + uint256 internal constant NOT_FROM_WALLET_OR_OWNER_OR_GUARDIAN = 408; + uint256 internal constant QUOTA_EXCEEDED = 409; + uint256 internal constant INVALID_QUOTA = 410; + uint256 internal constant IS_SAME_OWNER = 411; + uint256 internal constant INVALID_NEW_WALLET_OWNER = 412; + uint256 internal constant INVALID_NEW_WALLET_GUARDIAN = 413; + uint256 internal constant UNEXPECTED_RESULT = 414; + uint256 internal constant INVALID_VALID_UNTIL = 415; + uint256 internal constant GUARDIAN_NOT_EXISTS = 416; + uint256 internal constant TOO_MANY_GUARDIANS = 417; + uint256 internal constant GUARDIAN_CAN_NOT_BE_OWNER = 418; + uint256 internal constant INVALID_MASTER_COPY = 419; + uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420; + uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421; + uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422; + uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423; + uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424; + uint256 internal constant BUFFER_PERIOD_EXPIRED = 425; + uint256 internal constant CALLER_IS_NOT_OWNER = 426; + uint256 internal constant NEW_OWNER_IS_ZERO = 427; + uint256 internal constant CODE_DEPLOYMENT_FAILED = 428; + uint256 internal constant CALL_TO_NON_CONTRACT = 429; + uint256 internal constant LOW_LEVEL_CALL_FAILED = 430; + uint256 internal constant NOT_PAUSED = 431; + uint256 internal constant ADDRESS_ALREADY_ALLOWLISTED = 432; + uint256 internal constant ADDRESS_NOT_ALLOWLISTED = 433; + uint256 internal constant ERC20_BURN_EXCEEDS_BALANCE = 434; + uint256 internal constant INVALID_OPERATION = 435; + uint256 internal constant CODEC_OVERFLOW = 436; + uint256 internal constant IN_RECOVERY_MODE = 437; + uint256 internal constant NOT_IN_RECOVERY_MODE = 438; + uint256 internal constant INDUCED_FAILURE = 439; + uint256 internal constant EXPIRED_SIGNATURE = 440; + uint256 internal constant MALFORMED_SIGNATURE = 441; + uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_UINT64 = 442; + uint256 internal constant UNHANDLED_FEE_TYPE = 443; + uint256 internal constant BURN_FROM_ZERO = 444; + + // Vault + uint256 internal constant INVALID_POOL_ID = 500; + uint256 internal constant CALLER_NOT_POOL = 501; + uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502; + uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503; + uint256 internal constant INVALID_SIGNATURE = 504; + uint256 internal constant EXIT_BELOW_MIN = 505; + uint256 internal constant JOIN_ABOVE_MAX = 506; + uint256 internal constant SWAP_LIMIT = 507; + uint256 internal constant SWAP_DEADLINE = 508; + uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509; + uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510; + uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511; + uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512; + uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513; + uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514; + uint256 internal constant INVALID_POST_LOAN_BALANCE = 515; + uint256 internal constant INSUFFICIENT_ETH = 516; + uint256 internal constant UNALLOCATED_ETH = 517; + uint256 internal constant ETH_TRANSFER = 518; + uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519; + uint256 internal constant TOKENS_MISMATCH = 520; + uint256 internal constant TOKEN_NOT_REGISTERED = 521; + uint256 internal constant TOKEN_ALREADY_REGISTERED = 522; + uint256 internal constant PAYMASTER_TOKEN_LOCKED = 523; + uint256 internal constant INVALID_SIGNATURE_LENGTH = 524; + uint256 internal constant NO_ENOUGH_TOKEN_BALANCE = 525; + + // Fees + uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600; + uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601; + uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602; + uint256 internal constant AUM_FEE_PERCENTAGE_TOO_HIGH = 603; + + // FeeSplitter + uint256 internal constant SPLITTER_FEE_PERCENTAGE_TOO_HIGH = 700; + + // Misc + uint256 internal constant UNIMPLEMENTED = 998; + uint256 internal constant SHOULD_NOT_HAPPEN = 999; +} diff --git a/packages/hebao_v3/contracts/lib/Ownable.sol b/packages/hebao_v3/contracts/lib/Ownable.sol new file mode 100644 index 000000000..258ca4f62 --- /dev/null +++ b/packages/hebao_v3/contracts/lib/Ownable.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title Ownable +/// @author Brecht Devos - +/// @dev The Ownable contract has an owner address, and provides basic +/// authorization control functions, this simplifies the implementation of +/// "user permissions". +contract Ownable { + address public owner; + + event OwnershipTransferred( + address indexed previousOwner, + address indexed newOwner + ); + + /// @dev The Ownable constructor sets the original `owner` of the contract + /// to the sender. + constructor() { + owner = msg.sender; + } + + /// @dev Throws if called by any account other than the owner. + modifier onlyOwner() { + require(msg.sender == owner, "UNAUTHORIZED"); + _; + } + + /// @dev Allows the current owner to transfer control of the contract to a + /// new owner. + /// @param newOwner The address to transfer ownership to. + function transferOwnership(address newOwner) public virtual onlyOwner { + require(newOwner != address(0), "ZERO_ADDRESS"); + emit OwnershipTransferred(owner, newOwner); + owner = newOwner; + } + + function renounceOwnership() public onlyOwner { + emit OwnershipTransferred(owner, address(0)); + owner = address(0); + } +} diff --git a/packages/hebao_v3/contracts/lib/OwnerManagable.sol b/packages/hebao_v3/contracts/lib/OwnerManagable.sol new file mode 100644 index 000000000..49d28401b --- /dev/null +++ b/packages/hebao_v3/contracts/lib/OwnerManagable.sol @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./AddressSet.sol"; +import "./Claimable.sol"; + +contract OwnerManagable is Claimable, AddressSet { + bytes32 internal constant MANAGER = keccak256("__MANAGED__"); + + event ManagerAdded(address indexed manager); + event ManagerRemoved(address indexed manager); + + modifier onlyManager() { + require(isManager(msg.sender), "NOT_MANAGER"); + _; + } + + modifier onlyOwnerOrManager() { + require( + msg.sender == owner || isManager(msg.sender), + "NOT_OWNER_OR_MANAGER" + ); + _; + } + + constructor() Claimable() {} + + /// @dev Gets the managers. + /// @return The list of managers. + function managers() public view returns (address[] memory) { + return addressesInSet(MANAGER); + } + + /// @dev Gets the number of managers. + /// @return The numer of managers. + function numManagers() public view returns (uint) { + return numAddressesInSet(MANAGER); + } + + /// @dev Checks if an address is a manger. + /// @param addr The address to check. + /// @return True if the address is a manager, False otherwise. + function isManager(address addr) public view returns (bool) { + return isAddressInSet(MANAGER, addr); + } + + /// @dev Adds a new manager. + /// @param manager The new address to add. + function addManager(address manager) public onlyOwner { + addManagerInternal(manager); + } + + /// @dev Removes a manager. + /// @param manager The manager to remove. + function removeManager(address manager) public onlyOwner { + removeAddressFromSet(MANAGER, manager); + emit ManagerRemoved(manager); + } + + function addManagerInternal(address manager) internal { + addAddressToSet(MANAGER, manager, true); + emit ManagerAdded(manager); + } +} diff --git a/packages/hebao_v3/contracts/lib/SignatureUtil.sol b/packages/hebao_v3/contracts/lib/SignatureUtil.sol new file mode 100644 index 000000000..51a706ccc --- /dev/null +++ b/packages/hebao_v3/contracts/lib/SignatureUtil.sol @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../thirdparty/BytesUtil.sol"; +import "./AddressUtil.sol"; +import "./ERC1271.sol"; + +/// @title SignatureUtil +/// @author Daniel Wang - +/// @dev This method supports multihash standard. Each signature's last byte indicates +/// the signature's type. +library SignatureUtil { + using BytesUtil for bytes; + using AddressUtil for address; + + enum SignatureType { + ILLEGAL, + INVALID, + EIP_712, + ETH_SIGN, + WALLET // deprecated + } + + bytes4 internal constant ERC1271_MAGICVALUE = 0x1626ba7e; + + function verifySignatures( + bytes32 signHash, + address[] memory signers, + bytes[] memory signatures + ) internal view returns (bool) { + require(signers.length == signatures.length, "BAD_SIGNATURE_DATA"); + address lastSigner; + for (uint i = 0; i < signers.length; i++) { + require(signers[i] > lastSigner, "INVALID_SIGNERS_ORDER"); + lastSigner = signers[i]; + if (!verifySignature(signHash, signers[i], signatures[i])) { + return false; + } + } + return true; + } + + function verifySignature( + bytes32 signHash, + address signer, + bytes memory signature + ) internal view returns (bool) { + if (signer == address(0)) { + return false; + } + + return + signer.isContract() + ? verifyERC1271Signature(signHash, signer, signature) + : verifyEOASignature(signHash, signer, signature); + } + + function recoverECDSASigner( + bytes32 signHash, + bytes memory signature + ) internal pure returns (address) { + if (signature.length != 65) { + return address(0); + } + + bytes32 r; + bytes32 s; + uint8 v; + // we jump 32 (0x20) as the first slot of bytes contains the length + // we jump 65 (0x41) per signature + // for v we load 32 bytes ending with v (the first 31 come from s) then apply a mask + // solhint-disable-next-line no-inline-assembly + assembly { + r := mload(add(signature, 0x20)) + s := mload(add(signature, 0x40)) + v := and(mload(add(signature, 0x41)), 0xff) + } + // See https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol + if ( + uint256(s) > + 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0 + ) { + return address(0); + } + if (v == 27 || v == 28) { + return ecrecover(signHash, v, r, s); + } else { + return address(0); + } + } + + function verifyEOASignature( + bytes32 signHash, + address signer, + bytes memory signature + ) private pure returns (bool success) { + if (signer == address(0)) { + return false; + } + + require( + signature.length == 65 || signature.length == 66, + "INVALID_SIGNATURE_LENGTH" + ); + + bool trimmed = false; + if (signature.length == 66) { + // Strip off the last byte of the signature by updating the length + // solhint-disable-next-line no-inline-assembly + assembly { + mstore(signature, 65) + } + + trimmed = true; + } + + success = (signer == recoverECDSASigner(signHash, signature)); + if (!success) { + bytes32 hash = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash) + ); + success = (signer == recoverECDSASigner(hash, signature)); + } + + if (trimmed) { + // Restore the signature length + // solhint-disable-next-line no-inline-assembly + assembly { + mstore(signature, 66) + } + } + } + + function verifyERC1271Signature( + bytes32 signHash, + address signer, + bytes memory signature + ) private view returns (bool) { + bytes memory callData = abi.encodeWithSelector( + ERC1271.isValidSignature.selector, + signHash, + signature + ); + (bool success, bytes memory result) = signer.staticcall(callData); + return (success && + result.length == 32 && + result.toBytes4(0) == ERC1271_MAGICVALUE); + } +} diff --git a/packages/hebao_v3/contracts/price/AggregationalPriceOracle.sol b/packages/hebao_v3/contracts/price/AggregationalPriceOracle.sol new file mode 100644 index 000000000..87ac904c3 --- /dev/null +++ b/packages/hebao_v3/contracts/price/AggregationalPriceOracle.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; + +/// @title AggregationalPriceOracle +contract AggregationalPriceOracle is PriceOracle { + address[] public oracles; + + constructor(address[] memory _oracles) { + oracles = _oracles; + } + + function tokenValue( + address token, + uint amount + ) public view override returns (uint) { + uint total; + uint count; + for (uint i = 0; i < oracles.length; i++) { + uint value = PriceOracle(oracles[i]).tokenValue(token, amount); + if (value > 0) { + count += 1; + total = total + value; + } + } + return count == 0 ? 0 : total / count; + } +} diff --git a/packages/hebao_v3/contracts/price/CachedPriceOracle.sol b/packages/hebao_v3/contracts/price/CachedPriceOracle.sol new file mode 100644 index 000000000..8d225d7f4 --- /dev/null +++ b/packages/hebao_v3/contracts/price/CachedPriceOracle.sol @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; +import "../lib/OwnerManagable.sol"; +import "@openzeppelin/contracts/utils/math/SafeCast.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; + +/// @title CachedPriceOracle +contract CachedPriceOracle is PriceOracle, OwnerManagable { + using SafeMath for uint; + using SafeCast for uint; + + uint public constant EXPIRY_PERIOD = 7 days; + + PriceOracle public oracle; + + event PriceCached(address token, uint amount, uint value, uint timestamp); + + // Optimized to fit into 32 bytes (1 slot) + struct TokenPrice { + uint128 amount; + uint96 value; + uint32 timestamp; + } + + mapping(address => TokenPrice) private prices; + + constructor(PriceOracle _oracle) { + oracle = _oracle; + } + + function tokenValue( + address token, + uint amount + ) public view override returns (uint) { + TokenPrice memory tp = prices[token]; + if ( + tp.timestamp > 0 && block.timestamp < tp.timestamp + EXPIRY_PERIOD + ) { + return uint(tp.value).mul(amount) / tp.amount; + } else { + return 0; + } + } + + function updateTokenPrice( + address token, + uint amount + ) external onlyManager returns (uint value) { + value = oracle.tokenValue(token, amount); + if (value > 0) { + _cacheTokenPrice(token, amount, value); + } + } + + function setTokenPrice( + address token, + uint amount, + uint value + ) external onlyManager { + _cacheTokenPrice(token, amount, value); + } + + function setOracle(PriceOracle _oracle) external onlyManager { + oracle = _oracle; + } + + function _cacheTokenPrice(address token, uint amount, uint value) internal { + prices[token].amount = amount.toUint128(); + prices[token].value = value.toUint96(); + prices[token].timestamp = block.timestamp.toUint32(); + emit PriceCached(token, amount, value, block.timestamp); + } +} diff --git a/packages/hebao_v3/contracts/price/KyberNetworkPriceOracle.sol b/packages/hebao_v3/contracts/price/KyberNetworkPriceOracle.sol new file mode 100644 index 000000000..13e755a13 --- /dev/null +++ b/packages/hebao_v3/contracts/price/KyberNetworkPriceOracle.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +abstract contract KyberNetworkProxy { + function getExpectedRate( + IERC20 src, + IERC20 dest, + uint srcQty + ) public view virtual returns (uint expectedRate, uint slippageRate); +} + +/// @title KyberNetworkPriceOracle +/// @dev Returns the value in Ether for any given ERC20 token. +contract KyberNetworkPriceOracle is PriceOracle { + KyberNetworkProxy public immutable kyber; + address public constant ETH_ADDR = + 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; + + constructor(KyberNetworkProxy _kyber) { + kyber = _kyber; + } + + function tokenValue( + address token, + uint amount + ) public view override returns (uint value) { + if (amount == 0) return 0; + if (token == address(0) || token == ETH_ADDR) { + return amount; + } + (uint expectedRate, ) = kyber.getExpectedRate( + IERC20(token), + IERC20(ETH_ADDR), + amount + ); + value = expectedRate * amount; + } +} diff --git a/packages/hebao_v3/contracts/price/UniswapV2PriceOracle.sol b/packages/hebao_v3/contracts/price/UniswapV2PriceOracle.sol new file mode 100644 index 000000000..44470a7b0 --- /dev/null +++ b/packages/hebao_v3/contracts/price/UniswapV2PriceOracle.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; +import "../thirdparty/uniswap2/IUniswapV2Factory.sol"; +import "../thirdparty/uniswap2/IUniswapV2Pair.sol"; + +/// @title Uniswap2PriceOracle +/// @dev Returns the value in Ether for any given ERC20 token. +contract UniswapV2PriceOracle is PriceOracle { + IUniswapV2Factory public immutable factory; + address public immutable wethAddress; + + constructor(IUniswapV2Factory _factory, address _wethAddress) { + factory = _factory; + wethAddress = _wethAddress; + require(_wethAddress != address(0), "INVALID_WETH_ADDRESS"); + } + + function tokenValue( + address token, + uint amount + ) public view override returns (uint) { + if (amount == 0) return 0; + if (token == address(0) || token == wethAddress) return amount; + + address pair = factory.getPair(token, wethAddress); + if (pair == address(0)) { + return 0; + } + + (uint112 reserve0, uint112 reserve1, ) = IUniswapV2Pair(pair) + .getReserves(); + + if (reserve0 == 0 || reserve1 == 0) { + return 0; + } + + if (token < wethAddress) { + return (amount * reserve1) / reserve0; + } else { + return (amount * reserve0) / reserve1; + } + } +} diff --git a/packages/hebao_v3/contracts/test/DummyImpl.sol b/packages/hebao_v3/contracts/test/DummyImpl.sol new file mode 100644 index 000000000..d9dad846e --- /dev/null +++ b/packages/hebao_v3/contracts/test/DummyImpl.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../base/libwallet/WalletData.sol"; +import "../base/libwallet/GuardianLib.sol"; + +contract DummySmartWallet { + using GuardianLib for Wallet; + // WARNING: Do not delete wallet state data to make this implementation + // compatible with early versions. + // + // ----- DATA LAYOUT BEGINS ----- + // Always needs to be first + address internal masterCopy; + Wallet public wallet; + event Invoked(string sth); + + function getMasterCopy() public view returns (address) { + return masterCopy; + } + + function emitSomething() public { + emit Invoked("hello world"); + } + + function getGuardians( + bool includePendingAddition + ) public view returns (Guardian[] memory) { + return GuardianLib.guardians(wallet, includePendingAddition); + } +} diff --git a/packages/hebao_v3/contracts/test/DummyToken.sol b/packages/hebao_v3/contracts/test/DummyToken.sol new file mode 100644 index 000000000..bcc8c0b92 --- /dev/null +++ b/packages/hebao_v3/contracts/test/DummyToken.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "./LRCToken.sol"; + +/// @author Kongliang Zhong - +contract DummyToken is LRCToken { + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals, + uint _totalSupply + ) LRCToken(_name, _symbol, _decimals, _totalSupply, msg.sender) {} + + function setBalance(address _target, uint _value) public { + uint currBalance = balanceOf(_target); + if (_value < currBalance) { + totalSupply_ = totalSupply_ - currBalance + _value; + } else { + totalSupply_ = totalSupply_ + _value - currBalance; + } + balances[_target] = _value; + } + + function addBalance(address _target, uint _value) public { + uint currBalance = balanceOf(_target); + require(_value + currBalance >= currBalance, "INVALID_VALUE"); + totalSupply_ = totalSupply_ + _value; + balances[_target] = currBalance + _value; + } +} diff --git a/packages/hebao_v3/contracts/test/LRCToken.sol b/packages/hebao_v3/contracts/test/LRCToken.sol new file mode 100644 index 000000000..1f85c863a --- /dev/null +++ b/packages/hebao_v3/contracts/test/LRCToken.sol @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/** + * @title ERC20Basic + * @dev Simpler version of ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/179 + */ +abstract contract ERC20Basic { + function totalSupply() public view virtual returns (uint); + + function balanceOf(address who) public view virtual returns (uint); + + function transfer(address to, uint value) public virtual returns (bool); + + event Transfer(address indexed from, address indexed to, uint value); +} + +/** + * @title Basic token + * @dev Basic version of StandardToken, with no allowances. + */ +contract BasicToken is ERC20Basic { + mapping(address => uint) internal balances; + uint internal totalSupply_; + + /** + * @dev total number of tokens in existence + */ + function totalSupply() public view virtual override returns (uint) { + return totalSupply_; + } + + /** + * @dev transfer token for a specified address + * @param _to The address to transfer to. + * @param _value The amount to be transferred. + */ + function transfer( + address _to, + uint _value + ) public virtual override returns (bool) { + // require(_to != address(0), "ZERO_ADDRESS"); + require( + _value <= balances[msg.sender], + "TRANSFER_INSUFFICIENT_BALANCE" + ); + // SafeMath.sub will throw if there is not enough balance. + balances[msg.sender] = balances[msg.sender] - _value; + balances[_to] = balances[_to] + _value; + emit Transfer(msg.sender, _to, _value); + return true; + } + + /** + * @dev Gets the balance of the specified address. + * @param _owner The address to query the the balance of. + * @return balance An uint representing the amount owned by the passed address. + */ + function balanceOf( + address _owner + ) public view virtual override returns (uint balance) { + return balances[_owner]; + } +} + +/** + * @title ERC20 interface + * @dev see https://github.com/ethereum/EIPs/issues/20 + */ +abstract contract AbsERC20 is ERC20Basic { + function allowance( + address owner, + address spender + ) public view virtual returns (uint); + + function transferFrom( + address from, + address to, + uint value + ) public virtual returns (bool); + + function approve(address spender, uint value) public virtual returns (bool); + + event Approval(address indexed owner, address indexed spender, uint value); +} + +/** + * @title Standard ERC20 token + * + * @dev Implementation of the basic standard token. + * @dev https://github.com/ethereum/EIPs/issues/20 + * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol + */ +contract StandardToken is AbsERC20, BasicToken { + mapping(address => mapping(address => uint)) internal allowed; + + /** + * @dev Transfer tokens from one address to another + * @param _from address The address which you want to send tokens from + * @param _to address The address which you want to transfer to + * @param _value uint the amount of tokens to be transferred + */ + function transferFrom( + address _from, + address _to, + uint _value + ) public override returns (bool) { + // require(_to != address(0), "ZERO_ADDRESS"); + require(_value <= balances[_from], "TRANSFERFROM_INSUFFICIENT_BALANCE"); + require( + _value <= allowed[_from][msg.sender], + "TRANSFERFROM_INSUFFICIENT_ALLOWANCE" + ); + balances[_from] = balances[_from] - _value; + balances[_to] = balances[_to] + _value; + allowed[_from][msg.sender] = allowed[_from][msg.sender] - _value; + emit Transfer(_from, _to, _value); + return true; + } + + /** + * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. + * + * Beware that changing an allowance with this method brings the risk that someone may use both the old + * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this + * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: + * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 + * @param _spender The address which will spend the funds. + * @param _value The amount of tokens to be spent. + */ + function approve( + address _spender, + uint _value + ) public override returns (bool) { + allowed[msg.sender][_spender] = _value; + emit Approval(msg.sender, _spender, _value); + return true; + } + + /** + * @dev Function to check the amount of tokens that an owner allowed to a spender. + * @param _owner address The address which owns the funds. + * @param _spender address The address which will spend the funds. + * @return A uint specifying the amount of tokens still available for the spender. + */ + function allowance( + address _owner, + address _spender + ) public view override returns (uint) { + return allowed[_owner][_spender]; + } + + /** + * @dev Increase the amount of tokens that an owner allowed to a spender. + * + * approve should be called when allowed[_spender] == 0. To increment + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _addedValue The amount of tokens to increase the allowance by. + */ + function increaseApproval( + address _spender, + uint _addedValue + ) public returns (bool) { + allowed[msg.sender][_spender] = + allowed[msg.sender][_spender] + + _addedValue; + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } + + /** + * @dev Decrease the amount of tokens that an owner allowed to a spender. + * + * approve should be called when allowed[_spender] == 0. To decrement + * allowed value is better to use this function to avoid 2 calls (and wait until + * the first transaction is mined) + * From MonolithDAO Token.sol + * @param _spender The address which will spend the funds. + * @param _subtractedValue The amount of tokens to decrease the allowance by. + */ + function decreaseApproval( + address _spender, + uint _subtractedValue + ) public returns (bool) { + uint oldValue = allowed[msg.sender][_spender]; + if (_subtractedValue > oldValue) { + allowed[msg.sender][_spender] = 0; + } else { + allowed[msg.sender][_spender] = oldValue - _subtractedValue; + } + emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); + return true; + } +} + +contract LRCToken is StandardToken { + string public name = "New Loopring token on ethereum"; + string public symbol = "LRC"; + uint8 public decimals = 18; + + event Burn(address indexed burner, uint value); + + function burn(uint _value) public returns (bool) { + require(_value <= balances[msg.sender], "BURN_INSUFFICIENT_BALANCE"); + + address burner = msg.sender; + balances[burner] = balances[burner] - _value; + totalSupply_ = totalSupply_ - _value; + emit Burn(burner, _value); + emit Transfer(burner, address(0), _value); + return true; + } + + function burnFrom(address _owner, uint _value) public returns (bool) { + require(_owner != address(0), "ZERO_ADDRESS"); + require(_value <= balances[_owner], "BURNFROM_INSUFFICIENT_BALANCE"); + require( + _value <= allowed[_owner][msg.sender], + "BURNFROM_INSUFFICIENT_ALLOWANCE" + ); + + balances[_owner] = balances[_owner] - _value; + allowed[_owner][msg.sender] = allowed[_owner][msg.sender] - _value; + totalSupply_ = totalSupply_ - _value; + + emit Burn(_owner, _value); + emit Transfer(_owner, address(0), _value); + return true; + } + + constructor( + string memory _name, + string memory _symbol, + uint8 _decimals, + uint _totalSupply, + address _firstHolder + ) { + require(_totalSupply > 0, "INVALID_VALUE"); + require(_firstHolder != address(0), "ZERO_ADDRESS"); + checkSymbolAndName(_symbol, _name); + + name = _name; + symbol = _symbol; + decimals = _decimals; + totalSupply_ = _totalSupply; + + balances[_firstHolder] = totalSupply_; + } + + // Make sure symbol has 3-8 chars in [A-Za-z._] and name has up to 128 chars. + function checkSymbolAndName( + string memory _symbol, + string memory _name + ) internal pure { + bytes memory s = bytes(_symbol); + require(s.length >= 3 && s.length <= 8, "INVALID_SIZE"); + for (uint i = 0; i < s.length; i++) { + // make sure symbol contains only [A-Za-z._] + require( + s[i] == 0x2E || + (s[i] == 0x5F) || + (s[i] >= 0x41 && s[i] <= 0x5A) || + (s[i] >= 0x61 && s[i] <= 0x7A), + "INVALID_VALUE" + ); + } + bytes memory n = bytes(_name); + require(n.length >= s.length && n.length <= 128, "INVALID_SIZE"); + for (uint i = 0; i < n.length; i++) { + require(n[i] >= 0x20 && n[i] <= 0x7E, "INVALID_VALUE"); + } + } +} diff --git a/packages/hebao_v3/contracts/test/PriceOracleDelegate.sol b/packages/hebao_v3/contracts/test/PriceOracleDelegate.sol new file mode 100644 index 000000000..cc15a4b8d --- /dev/null +++ b/packages/hebao_v3/contracts/test/PriceOracleDelegate.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; + +/// @title PriceOracle +contract PriceOracleDelegate is PriceOracle { + PriceOracle public immutable priceOracle; + + constructor(PriceOracle _priceOracle) { + priceOracle = _priceOracle; + } + + function tokenValue( + address token, + uint amount + ) public view override returns (uint value) { + return priceOracle.tokenValue(token, amount); + } +} diff --git a/packages/hebao_v3/contracts/test/TestCounter.sol b/packages/hebao_v3/contracts/test/TestCounter.sol new file mode 100644 index 000000000..1b8187350 --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestCounter.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +//sample "receiver" contract, for testing "exec" from account. +contract TestCounter { + mapping(address => uint256) public counters; + + function count() public { + counters[msg.sender] = counters[msg.sender] + 1; + } + + function justemit() public { + emit CalledFrom(msg.sender); + } + + event CalledFrom(address sender); + + //helper method to waste gas + // repeat - waste gas on writing storage in a loop + // junk - dynamic buffer to stress the function size. + mapping(uint256 => uint256) public xxx; + uint256 public offset; + + function gasWaster(uint256 repeat, string calldata /*junk*/) external { + for (uint256 i = 1; i <= repeat; i++) { + offset++; + xxx[offset] = i; + } + } +} diff --git a/packages/hebao_v3/contracts/test/TestKyberNetworkProxy.sol b/packages/hebao_v3/contracts/test/TestKyberNetworkProxy.sol new file mode 100644 index 000000000..9c5e8eaf1 --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestKyberNetworkProxy.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; + +contract TestKyberNetworkProxy { + uint public expectedRate; + + constructor(uint _expectedRate) { + expectedRate = _expectedRate; + } + + function getExpectedRate( + IERC20, + IERC20, + uint + ) public view virtual returns (uint _expectedRate, uint _slippageRate) { + _expectedRate = expectedRate; + _slippageRate = 1; + } +} diff --git a/packages/hebao_v3/contracts/test/TestPriceOracle.sol b/packages/hebao_v3/contracts/test/TestPriceOracle.sol new file mode 100644 index 000000000..0091a11e4 --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestPriceOracle.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../iface/PriceOracle.sol"; + +/// @title PriceOracle +contract TestPriceOracle is PriceOracle { + uint256 immutable price; + + constructor(uint256 _price) { + price = _price; + } + + // @dev Return's the token's value in ETH + function tokenValue( + address /*token*/, + uint amount + ) public view override returns (uint value) { + value = amount * price; + } +} diff --git a/packages/hebao_v3/contracts/test/TestTargetContract.sol b/packages/hebao_v3/contracts/test/TestTargetContract.sol new file mode 100644 index 000000000..26548be52 --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestTargetContract.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title TestTargetContract +/// @author Brecht Devos - +contract TestTargetContract { + uint public value = 12345; + + event Invoked(address sender); + + function functionDefault(uint _value) external returns (uint) { + value = _value; + emit Invoked(msg.sender); + return _value; + } + + function functionPayable(uint _value) external payable { + value = _value; + emit Invoked(msg.sender); + } + + function functionRevert(uint _value) external { + require(false, "IMMEDIATE_REVERT"); + value = _value; + } +} diff --git a/packages/hebao_v3/contracts/test/TestToken.sol b/packages/hebao_v3/contracts/test/TestToken.sol new file mode 100644 index 000000000..2bfb3439f --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestToken.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract TestToken is ERC20 { + constructor() + // solhint-disable-next-line no-empty-blocks + ERC20("TST", "TestToken") + {} + + function mint(address sender, uint256 amount) external { + _mint(sender, amount); + } +} diff --git a/packages/hebao_v3/contracts/test/TestUniswapV2Factory.sol b/packages/hebao_v3/contracts/test/TestUniswapV2Factory.sol new file mode 100644 index 000000000..8de2869cd --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestUniswapV2Factory.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title PriceOracle +contract TestUniswapV2Factory { + mapping(address => mapping(address => address)) public getPair; + + function addPair(address tokenA, address tokenB, address pair) external { + getPair[tokenA][tokenB] = pair; + getPair[tokenB][tokenA] = pair; + } +} diff --git a/packages/hebao_v3/contracts/test/TestUniswapV2Pair.sol b/packages/hebao_v3/contracts/test/TestUniswapV2Pair.sol new file mode 100644 index 000000000..ff7cb346b --- /dev/null +++ b/packages/hebao_v3/contracts/test/TestUniswapV2Pair.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +/// @title PriceOracle +contract TestUniswapV2Pair { + uint112 private reserve0; + uint112 private reserve1; + uint32 private blockTimestampLast; + + constructor(uint112 _reserve0, uint112 _reserve1) { + setReserves(_reserve0, _reserve1); + } + + function getReserves() + external + view + returns ( + uint112 _reserve0, + uint112 _reserve1, + uint32 _blockTimestampLast + ) + { + _reserve0 = reserve0; + _reserve1 = reserve1; + _blockTimestampLast = blockTimestampLast; + } + + function setReserves(uint112 _reserve0, uint112 _reserve1) public { + reserve0 = _reserve0; + reserve1 = _reserve1; + blockTimestampLast = uint32(block.timestamp); + } +} diff --git a/packages/hebao_v3/contracts/test/lib/AddressSetWrapper.sol b/packages/hebao_v3/contracts/test/lib/AddressSetWrapper.sol new file mode 100644 index 000000000..ff157b74c --- /dev/null +++ b/packages/hebao_v3/contracts/test/lib/AddressSetWrapper.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../../lib/AddressSet.sol"; + +/// @title AddressSetWrapper +/// @author Freeman Zhong - +contract AddressSetWrapper is AddressSet { + function add(bytes32 key, address addr, bool maintainList) external { + addAddressToSet(key, addr, maintainList); + } + + function remove(bytes32 key, address addr) external { + removeAddressFromSet(key, addr); + } + + function removeAll(bytes32 key) external { + removeSet(key); + } + + function isInSet(bytes32 key, address addr) external view returns (bool) { + return isAddressInSet(key, addr); + } + + function numInSet(bytes32 key) external view returns (uint) { + return numAddressesInSet(key); + } + + function getAddresses( + bytes32 key + ) external view returns (address[] memory) { + return addressesInSet(key); + } +} diff --git a/packages/hebao_v3/contracts/test/lib/SignatureUtilWrapper.sol b/packages/hebao_v3/contracts/test/lib/SignatureUtilWrapper.sol new file mode 100644 index 000000000..d82ed3db0 --- /dev/null +++ b/packages/hebao_v3/contracts/test/lib/SignatureUtilWrapper.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../../lib/ERC1271.sol"; +import "../../lib/SignatureUtil.sol"; +import "../../thirdparty/BytesUtil.sol"; +import "@openzeppelin/contracts/utils/math/SafeMath.sol"; + +/// @title AddressSetWrapper +/// @author Freeman Zhong - +contract SignatureUtilWrapper { + using BytesUtil for bytes; + using SafeMath for uint; + + function verifySignature( + bytes32 signHash, + address signer, + bytes calldata signature + ) external view returns (bool) { + return SignatureUtil.verifySignature(signHash, signer, signature); + } + + function recoverECDSASigner( + bytes32 signHash, + bytes calldata signature + ) external pure returns (address) { + uint signatureTypeOffset = signature.length.sub(1); + SignatureUtil.SignatureType signatureType = SignatureUtil.SignatureType( + signature.toUint8(signatureTypeOffset) + ); + + bytes memory stripped = signature.slice(0, signatureTypeOffset); + + if (signatureType == SignatureUtil.SignatureType.EIP_712) { + return SignatureUtil.recoverECDSASigner(signHash, stripped); + } else if (signatureType == SignatureUtil.SignatureType.ETH_SIGN) { + bytes32 hash = keccak256( + abi.encodePacked("\x19Ethereum Signed Message:\n32", signHash) + ); + return SignatureUtil.recoverECDSASigner(hash, stripped); + } else { + return address(0); + } + } +} diff --git a/packages/hebao_v3/contracts/test/tokens/GTO.sol b/packages/hebao_v3/contracts/test/tokens/GTO.sol new file mode 100644 index 000000000..c30bec4f2 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/GTO.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract GTO is DummyToken { + constructor() DummyToken("GTO_TEST", "GTO", 18, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/INDA.sol b/packages/hebao_v3/contracts/test/tokens/INDA.sol new file mode 100644 index 000000000..9cdfec3e9 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/INDA.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract INDA is DummyToken { + constructor() DummyToken("INDIVISIBLE_A", "INDA", 0, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/INDB.sol b/packages/hebao_v3/contracts/test/tokens/INDB.sol new file mode 100644 index 000000000..865887bdb --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/INDB.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract INDB is DummyToken { + constructor() DummyToken("INDIVISIBLE_B", "INDB", 0, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/LRC.sol b/packages/hebao_v3/contracts/test/tokens/LRC.sol new file mode 100644 index 000000000..132de2e02 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/LRC.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract LRC is DummyToken { + constructor() DummyToken("LRC_TEST", "LRC", 18, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/RDN.sol b/packages/hebao_v3/contracts/test/tokens/RDN.sol new file mode 100644 index 000000000..fa3ddf244 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/RDN.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract RDN is DummyToken { + constructor() DummyToken("RDN_TEST", "RDN", 18, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/REP.sol b/packages/hebao_v3/contracts/test/tokens/REP.sol new file mode 100644 index 000000000..1c4f36e6f --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/REP.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract REP is DummyToken { + constructor() DummyToken("REP_TEST", "REP", 18, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/USDT.sol b/packages/hebao_v3/contracts/test/tokens/USDT.sol new file mode 100644 index 000000000..adf992ed7 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/USDT.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract USDT is DummyToken { + constructor() DummyToken("USDT_TEST", "USDT", 6, 10 ** 20) {} +} diff --git a/packages/hebao_v3/contracts/test/tokens/WETH.sol b/packages/hebao_v3/contracts/test/tokens/WETH.sol new file mode 100644 index 000000000..5cc675648 --- /dev/null +++ b/packages/hebao_v3/contracts/test/tokens/WETH.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright 2017 Loopring Technology Limited. +pragma solidity ^0.8.17; + +import "../DummyToken.sol"; + +contract WETH is DummyToken { + constructor() DummyToken("WETH_TEST", "WETH", 18, 10 ** 27) {} +} diff --git a/packages/hebao_v3/contracts/thirdparty/BytesUtil.sol b/packages/hebao_v3/contracts/thirdparty/BytesUtil.sol new file mode 100644 index 000000000..0c3c5a82b --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/BytesUtil.sol @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: UNLICENSED +// Taken from https://github.com/GNSPS/solidity-bytes-utils/blob/master/contracts/BytesLib.sol +pragma solidity ^0.8.17; + +library BytesUtil { + function slice( + bytes memory _bytes, + uint _start, + uint _length + ) internal pure returns (bytes memory) { + require(_bytes.length >= (_start + _length)); + + bytes memory tempBytes; + + assembly { + switch iszero(_length) + case 0 { + // Get a location of some free memory and store it in tempBytes as + // Solidity does for memory variables. + tempBytes := mload(0x40) + + // The first word of the slice result is potentially a partial + // word read from the original array. To read it, we calculate + // the length of that partial word and start copying that many + // bytes into the array. The first word we copy will start with + // data we don't care about, but the last `lengthmod` bytes will + // land at the beginning of the contents of the new array. When + // we're done copying, we overwrite the full first word with + // the actual length of the slice. + let lengthmod := and(_length, 31) + + // The multiplication in the next line is necessary + // because when slicing multiples of 32 bytes (lengthmod == 0) + // the following copy loop was copying the origin's length + // and then ending prematurely not copying everything it should. + let mc := add( + add(tempBytes, lengthmod), + mul(0x20, iszero(lengthmod)) + ) + let end := add(mc, _length) + + for { + // The multiplication in the next line has the same exact purpose + // as the one above. + let cc := add( + add( + add(_bytes, lengthmod), + mul(0x20, iszero(lengthmod)) + ), + _start + ) + } lt(mc, end) { + mc := add(mc, 0x20) + cc := add(cc, 0x20) + } { + mstore(mc, mload(cc)) + } + + mstore(tempBytes, _length) + + //update free-memory pointer + //allocating the array padded to 32 bytes like the compiler does now + mstore(0x40, and(add(mc, 31), not(31))) + } + //if we want a zero-length slice let's just return a zero-length array + default { + tempBytes := mload(0x40) + + mstore(0x40, add(tempBytes, 0x20)) + } + } + + return tempBytes; + } + + function toAddress( + bytes memory _bytes, + uint _start + ) internal pure returns (address) { + require(_bytes.length >= (_start + 20)); + address tempAddress; + + assembly { + tempAddress := div( + mload(add(add(_bytes, 0x20), _start)), + 0x1000000000000000000000000 + ) + } + + return tempAddress; + } + + function toUint8( + bytes memory _bytes, + uint _start + ) internal pure returns (uint8) { + require(_bytes.length >= (_start + 1)); + uint8 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x1), _start)) + } + + return tempUint; + } + + function toUint16( + bytes memory _bytes, + uint _start + ) internal pure returns (uint16) { + require(_bytes.length >= (_start + 2)); + uint16 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x2), _start)) + } + + return tempUint; + } + + function toUint24( + bytes memory _bytes, + uint _start + ) internal pure returns (uint24) { + require(_bytes.length >= (_start + 3)); + uint24 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x3), _start)) + } + + return tempUint; + } + + function toUint32( + bytes memory _bytes, + uint _start + ) internal pure returns (uint32) { + require(_bytes.length >= (_start + 4)); + uint32 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x4), _start)) + } + + return tempUint; + } + + function toUint64( + bytes memory _bytes, + uint _start + ) internal pure returns (uint64) { + require(_bytes.length >= (_start + 8)); + uint64 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x8), _start)) + } + + return tempUint; + } + + function toUint96( + bytes memory _bytes, + uint _start + ) internal pure returns (uint96) { + require(_bytes.length >= (_start + 12)); + uint96 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0xc), _start)) + } + + return tempUint; + } + + function toUint128( + bytes memory _bytes, + uint _start + ) internal pure returns (uint128) { + require(_bytes.length >= (_start + 16)); + uint128 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x10), _start)) + } + + return tempUint; + } + + function toUint( + bytes memory _bytes, + uint _start + ) internal pure returns (uint256) { + require(_bytes.length >= (_start + 32)); + uint256 tempUint; + + assembly { + tempUint := mload(add(add(_bytes, 0x20), _start)) + } + + return tempUint; + } + + function toBytes4( + bytes memory _bytes, + uint _start + ) internal pure returns (bytes4) { + require(_bytes.length >= (_start + 4)); + bytes4 tempBytes4; + + assembly { + tempBytes4 := mload(add(add(_bytes, 0x20), _start)) + } + + return tempBytes4; + } + + function toBytes32( + bytes memory _bytes, + uint _start + ) internal pure returns (bytes32) { + require(_bytes.length >= (_start + 32)); + bytes32 tempBytes32; + + assembly { + tempBytes32 := mload(add(add(_bytes, 0x20), _start)) + } + + return tempBytes32; + } + + function fastSHA256(bytes memory data) internal view returns (bytes32) { + bytes32[] memory result = new bytes32[](1); + bool success; + assembly { + let ptr := add(data, 32) + success := staticcall( + sub(gas(), 2000), + 2, + ptr, + mload(data), + add(result, 32), + 32 + ) + } + require(success, "SHA256_FAILED"); + return result[0]; + } +} diff --git a/packages/hebao_v3/contracts/thirdparty/ERC165.sol b/packages/hebao_v3/contracts/thirdparty/ERC165.sol new file mode 100644 index 000000000..173a2c33e --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/ERC165.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +// Copied from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md. + +pragma solidity ^0.8.17; + +interface ERC165 { + /// @notice Query if a contract implements an interface + /// @param interfaceID The interface identifier, as specified in ERC-165 + /// @dev Interface identification is specified in ERC-165. This function + /// uses less than 30,000 gas. + /// @return `true` if the contract implements `interfaceID` and + /// `interfaceID` is not 0xffffffff, `false` otherwise + function supportsInterface(bytes4 interfaceID) external view returns (bool); +} diff --git a/packages/hebao_v3/contracts/thirdparty/erc1155/ERC1155Holder.sol b/packages/hebao_v3/contracts/thirdparty/erc1155/ERC1155Holder.sol new file mode 100644 index 000000000..e1d2bffce --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/erc1155/ERC1155Holder.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +import "./IERC1155Receiver.sol"; + +/** + * @dev _Available since v3.1._ + */ +contract ERC1155Holder is IERC1155Receiver { + function onERC1155Received( + address, + address, + uint256, + uint256, + bytes memory + ) public pure virtual override returns (bytes4) { + return this.onERC1155Received.selector; + } + + function onERC1155BatchReceived( + address, + address, + uint256[] memory, + uint256[] memory, + bytes memory + ) public pure virtual override returns (bytes4) { + return this.onERC1155BatchReceived.selector; + } +} diff --git a/packages/hebao_v3/contracts/thirdparty/erc1155/IERC1155Receiver.sol b/packages/hebao_v3/contracts/thirdparty/erc1155/IERC1155Receiver.sol new file mode 100644 index 000000000..c20288c9b --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/erc1155/IERC1155Receiver.sol @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +/** + * _Available since v3.1._ + */ +interface IERC1155Receiver { + /** + @dev Handles the receipt of a single ERC1155 token type. This function is + called at the end of a `safeTransferFrom` after the balance has been updated. + To accept the transfer, this must return + `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` + (i.e. 0xf23a6e61, or its own function selector). + @param operator The address which initiated the transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param id The ID of the token being transferred + @param value The amount of tokens being transferred + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed + */ + function onERC1155Received( + address operator, + address from, + uint256 id, + uint256 value, + bytes calldata data + ) external returns (bytes4); + + /** + @dev Handles the receipt of a multiple ERC1155 token types. This function + is called at the end of a `safeBatchTransferFrom` after the balances have + been updated. To accept the transfer(s), this must return + `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` + (i.e. 0xbc197c81, or its own function selector). + @param operator The address which initiated the batch transfer (i.e. msg.sender) + @param from The address which previously owned the token + @param ids An array containing ids of each token being transferred (order and length must match values array) + @param values An array containing amounts of each token being transferred (order and length must match ids array) + @param data Additional data with no specified format + @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed + */ + function onERC1155BatchReceived( + address operator, + address from, + uint256[] calldata ids, + uint256[] calldata values, + bytes calldata data + ) external returns (bytes4); +} diff --git a/packages/hebao_v3/contracts/thirdparty/erc165/IERC165.sol b/packages/hebao_v3/contracts/thirdparty/erc165/IERC165.sol new file mode 100644 index 000000000..cadb41880 --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/erc165/IERC165.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +/** + * @dev Interface of the ERC165 standard, as defined in the + * https://eips.ethereum.org/EIPS/eip-165[EIP]. + * + * Implementers can declare support of contract interfaces, which can then be + * queried by others ({ERC165Checker}). + * + * For an implementation, see {ERC165}. + */ +interface IERC165 { + /** + * @dev Returns true if this contract implements the interface defined by + * `interfaceId`. See the corresponding + * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] + * to learn more about how these ids are created. + * + * This function call must use less than 30 000 gas. + */ + function supportsInterface(bytes4 interfaceId) external view returns (bool); +} diff --git a/packages/hebao_v3/contracts/thirdparty/erc721/ERC721Holder.sol b/packages/hebao_v3/contracts/thirdparty/erc721/ERC721Holder.sol new file mode 100644 index 000000000..7f27edb64 --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/erc721/ERC721Holder.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +import "./IERC721Receiver.sol"; + +/** + * @dev Implementation of the {IERC721Receiver} interface. + * + * Accepts all token transfers. + * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. + */ +contract ERC721Holder is IERC721Receiver { + /** + * @dev See {IERC721Receiver-onERC721Received}. + * + * Always returns `IERC721Receiver.onERC721Received.selector`. + */ + function onERC721Received( + address, + address, + uint256, + bytes memory + ) public pure virtual override returns (bytes4) { + return this.onERC721Received.selector; + } +} diff --git a/packages/hebao_v3/contracts/thirdparty/erc721/IERC721Receiver.sol b/packages/hebao_v3/contracts/thirdparty/erc721/IERC721Receiver.sol new file mode 100644 index 000000000..d27370f0a --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/erc721/IERC721Receiver.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +/** + * @title ERC721 token receiver interface + * @dev Interface for any contract that wants to support safeTransfers + * from ERC721 asset contracts. + */ +interface IERC721Receiver { + /** + * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} + * by `operator` from `from`, this function is called. + * + * It must return its Solidity selector to confirm the token transfer. + * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. + * + * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`. + */ + function onERC721Received( + address operator, + address from, + uint256 tokenId, + bytes calldata data + ) external returns (bytes4); +} diff --git a/packages/hebao_v3/contracts/thirdparty/proxies/WalletProxy.sol b/packages/hebao_v3/contracts/thirdparty/proxies/WalletProxy.sol new file mode 100644 index 000000000..816f776d1 --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/proxies/WalletProxy.sol @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Taken from: https://github.com/gnosis/safe-contracts/blob/development/contracts/proxies/GnosisSafeProxy.sol +pragma solidity ^0.8.17; + +import "../../lib/LoopringErrors.sol"; + +/// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain +/// @author Richard Meissner - +interface IProxy { + function masterCopy() external view returns (address); +} + +/// @title WalletProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract. +/// @author Stefan George - +/// @author Richard Meissner - +contract WalletProxy { + // masterCopy always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated. + // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt` + address internal masterCopy; + + event Received(address indexed sender, uint value); + + /// @dev Constructor function sets address of master copy contract. + /// @param _masterCopy Master copy address. + constructor(address _masterCopy) { + _require(_masterCopy != address(0), Errors.MASTER_COPY_ZERO_ADDRESS); + _require(_masterCopy != masterCopy, Errors.INVALID_SAME_MASTER_COPY); + masterCopy = _masterCopy; + } + + /// @dev Fallback function forwards all transactions and returns all received return data. + fallback() external payable { + // solhint-disable-next-line no-inline-assembly + assembly { + let _masterCopy := and( + sload(0), + 0xffffffffffffffffffffffffffffffffffffffff + ) + // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s + if eq( + calldataload(0), + 0xa619486e00000000000000000000000000000000000000000000000000000000 + ) { + mstore(0, _masterCopy) + return(0, 0x20) + } + calldatacopy(0, 0, calldatasize()) + let success := delegatecall( + gas(), + _masterCopy, + 0, + calldatasize(), + 0, + 0 + ) + returndatacopy(0, 0, returndatasize()) + if eq(success, 0) { + revert(0, returndatasize()) + } + return(0, returndatasize()) + } + } + + receive() external payable { + emit Received(msg.sender, msg.value); + } +} diff --git a/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Factory.sol b/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Factory.sol new file mode 100644 index 000000000..78b8e582a --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Factory.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: UNLICENSED +// https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Factory.sol +pragma solidity ^0.8.17; + +interface IUniswapV2Factory { + event PairCreated( + address indexed token0, + address indexed token1, + address pair, + uint + ); + + function feeTo() external view returns (address); + + function feeToSetter() external view returns (address); + + function getPair( + address tokenA, + address tokenB + ) external view returns (address pair); + + function allPairs(uint) external view returns (address pair); + + function allPairsLength() external view returns (uint); + + function createPair( + address tokenA, + address tokenB + ) external returns (address pair); + + function setFeeTo(address) external; + + function setFeeToSetter(address) external; +} diff --git a/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Pair.sol b/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Pair.sol new file mode 100644 index 000000000..4aea18c1d --- /dev/null +++ b/packages/hebao_v3/contracts/thirdparty/uniswap2/IUniswapV2Pair.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: UNLICENSED +// https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/interfaces/IUniswapV2Pair.sol +pragma solidity ^0.8.17; + +interface IUniswapV2Pair { + function getReserves() + external + view + returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); +} diff --git a/packages/hebao_v3/deployments/create2.json b/packages/hebao_v3/deployments/create2.json new file mode 100644 index 000000000..2f5c6be54 --- /dev/null +++ b/packages/hebao_v3/deployments/create2.json @@ -0,0 +1,5 @@ +{ + "goerli": "0xd57d71A16D850038e7266E3885140A7E7d1Ba3fD", + "hardhat": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "sepolia": "0x100f3f74125c8c724c7c0ee81e4dd5626830dd9a" +} diff --git a/packages/hebao_v3/deployments/deployments.json b/packages/hebao_v3/deployments/deployments.json new file mode 100644 index 000000000..7779d2ac1 --- /dev/null +++ b/packages/hebao_v3/deployments/deployments.json @@ -0,0 +1,46 @@ +{ + "goerli": { + "LoopringCreate2Deployer": "0xd57d71A16D850038e7266E3885140A7E7d1Ba3fD", + "EntryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + "LoopringPaymaster": "0x7027C780771F4d13d59c179A868Aa5269Bc0D09C", + "SmartWalletImpl": "0x07707966b3Dd56400d2e099Ea4d20E088ea0e062", + "DelayedImplementationManager": "0xb200f9FF3568e977393F9e40Dfa32627BBaAcb91", + "ForwardProxy": "0x16a95B4e615DE64d40E43CD723c422f6eAF3DeAf", + "WalletFactory": "0xE5C8214342735a4c0Dc281B528E372C6A56513CD", + "SmartWallet": "0xce49F224CA69E4BCa519765bdc644f88fD017001", + "USDT": "0x85E48056F3Dc8899d4B57e21e9EEf2D4c079d5ff" + }, + "hardhat": { + "LoopringCreate2Deployer": "0x5FbDB2315678afecb367f032d93F642f64180aa3", + "EntryPoint": "0x67fC9E8D89f6599b65920496A0c41111a179617e", + "LoopringPaymaster": "0xE4c25F6816BCC6D160C080b0B456893e2F7659Dd", + "SmartWalletImpl": "0xD1585aB8FA51894acF4ece9bBcdB9D3cc6ec7Eb6", + "DelayedImplementationManager": "0xc4C1b2f57D424d1D7a48b768be91a23B8c72b3b0", + "ForwardProxy": "0xDfB46FdF9E35f75454B9D6FF187ea1e956f54126", + "WalletFactory": "0x75182bf345e3B78b6FFd4020035E627249e29Ba9", + "SmartWallet": "0x207088EB181359Fb963a6AE7F645969DAF812CcF", + "USDT": "0xa7517f4e2f844CB90d99B898cEC0487E4DFCf99c" + }, + "sepolia": { + "LoopringCreate2Deployer": "0x100f3f74125c8c724c7c0ee81e4dd5626830dd9a", + "EntryPoint": "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789", + "LoopringPaymaster": "0x45006b87a034fdB751b940FA3Ec55C243f6FbbF2", + "SmartWalletImpl": "0xaa4706c8E3bd1ec1F2Ca3234100624058AaaDfF8", + "DelayedImplementationManager": "0xD7aDEF9dB43b22Ca2c9Be79b440749135b8AEeF0", + "ForwardProxy": "0xEa089CF04E0bA72e11686eC791604C3D8a87E455", + "WalletFactory": "0x8Bd86790734f0a45F9e93722faCF4a4079B8898e", + "SmartWallet": "0xE01E3610717b9446fA244e579efA79bbB5d98Db9", + "USDT": "0xbb39a16E032a8F5cC8fe4E0043fD8C72f87755A2" + }, + "taiko6": { + "LoopringCreate2Deployer": "0x391fD52903D1531fd45F41c4A354533c91289F5F", + "EntryPoint": "0x779eEcA2315a44D20806217c005731aE7DDB5ca0", + "LoopringPaymaster": "0x9CA6FFC3cC53a50C7322ab7B70fd413C49A55Bfd", + "SmartWalletImpl": "0xaD54dF1D61399EbBca32c8c82DF081163e9f70f5", + "DelayedImplementationManager": "0x93cC2B5ABDa1830E9AcaDE3CB76E22D3082BFAe5", + "ForwardProxy": "0x23a19a97A2dA581e3d66Ef5Fd1eeA15024f55611", + "SmartWallet": "0xce49F224CA69E4BCa519765bdc644f88fD017001", + "WalletFactory": "0xe7d8df8F6546965A59dab007e8709965Efe1255d", + "USDT": "0xD69d3e64D71844BBDdA51Cd7f23ED3631E9FAC49" + } +} diff --git a/packages/hebao_v3/hardhat.config.ts b/packages/hebao_v3/hardhat.config.ts new file mode 100644 index 000000000..572280681 --- /dev/null +++ b/packages/hebao_v3/hardhat.config.ts @@ -0,0 +1,93 @@ +import '@nomicfoundation/hardhat-chai-matchers' +import '@nomiclabs/hardhat-ethers' +import '@typechain/hardhat' +import 'hardhat-gas-reporter' +import 'solidity-coverage' +import { type HardhatUserConfig } from 'hardhat/config' +import '@nomicfoundation/hardhat-verify' + +import * as dotenv from 'dotenv' + +dotenv.config() + +const privateKey = process.env.PRIVATE_KEY as string + +const config: HardhatUserConfig = { + defaultNetwork: 'hardhat', + networks: { + hardhat: { + forking: + process.env.FORK != null + ? { + // url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + url: 'https://eth-mainnet.g.alchemy.com/v2/mgHwlYpgAvGEiR_RCgPiTfvT-yyJ6T03', + blockNumber: 18482580 + } + : undefined + }, + ethereum: { + url: `https://mainnet.infura.io/v3/${process.env.INFURA_API_KEY}`, + accounts: [privateKey] + }, + + goerli: { + url: `https://goerli.infura.io/v3/${process.env.INFURA_API_KEY}`, + accounts: [privateKey] + }, + + taiko: { + url: 'https://l2rpc.hackathon.taiko.xyz', + accounts: [privateKey] + }, + taiko2: { + url: 'https://l2rpc.a2.taiko.xyz/', + accounts: [privateKey] + }, + taiko6: { + url: 'https://rpc.katla.taiko.xyz/', + accounts: [process.env.PRIVATE_KEY], + gasPrice: 2000000000 + }, + sepolia: { + url: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`, + accounts: [privateKey] + }, + + bsctestnet: { + url: 'https://data-seed-prebsc-1-s1.binance.org:8545', + accounts: [privateKey] + }, + + arbitrum_test: { + url: 'https://rinkeby.arbitrum.io/rpc', + accounts: [privateKey] + }, + + arbitrum_one: { + url: 'https://arb1.arbitrum.io/rpc', + accounts: [privateKey] + } + }, + + solidity: { + version: '0.8.17', + settings: { + optimizer: { + enabled: true, + runs: 200 + } + } + }, + + gasReporter: { + currency: 'USD', + gasPrice: 100 + }, + + etherscan: { + // Your API key for Etherscan + apiKey: process.env.ETHERSCAN_API_KEY + } +} + +export default config diff --git a/packages/hebao_v3/package.json b/packages/hebao_v3/package.json new file mode 100644 index 000000000..c94bc1d33 --- /dev/null +++ b/packages/hebao_v3/package.json @@ -0,0 +1,76 @@ +{ + "name": "hebao-v3", + "version": "1.3.0", + "description": "Hebao App's Smart Contracts", + "private": true, + "main": "index.js", + "license": "MIT", + "scripts": { + "clean": "hardhat clean", + "compile": "yarn clean && hardhat compile", + "deploy": "hardhat run script/deploy.ts", + "lint": "yarn lint:sol && yarn lint:ts && yarn prettier:check", + "lint:sol": "solhint -f unix \"contracts/**/*.sol\" --max-warnings 0", + "lint:ts": "eslint -f unix .", + "lint-fix": "yarn lint:ts --fix && yarn lint:sol --fix", + "prettier": "prettier --config ./.prettierrc.json --write \"**/*.{js,json,md,sol,ts}\"", + "prettier:check": "prettier --check --config ./.prettierrc.json \"**/*.{js,json,md,sol,ts}\"", + "test-local-aa": "yarn hardhat test $(find ./test/account-abstraction -type f -name '*.test.ts') --parallel", + "test-local-smartwallet": "yarn hardhat test $(find ./test -type f -name '*.test.ts' ! -path './test/automation/*' ! -path './test/account-abstraction/*') --parallel", + "test-local": "yarn test-local-aa && yarn test-local-smartwallet", + "test-fork": "FORK=1 hardhat test $(find ./test/automation -type f -name '*.test.ts') --parallel", + "test": "yarn run test-local && yarn run test-fork", + "coverage": "yarn clean && COVERAGE=1 FORK=1 hardhat coverage" + }, + "devDependencies": { + "@ethersproject/abi": "^5.4.7", + "@ethersproject/providers": "^5.4.7", + "@gnosis.pm/safe-contracts": "^1.3.0", + "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-network-helpers": "^1.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.3", + "@nomiclabs/hardhat-ethers": "^2.0.0", + "@thehubbleproject/bls": "^0.5.1", + "@typechain/ethers-v5": "^10.1.0", + "@typechain/hardhat": "^6.1.2", + "@types/chai": "^4.2.0", + "@types/lodash": "^4.14.194", + "@types/mocha": ">=9.1.0", + "@types/node": ">=12.0.0", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", + "chai": "^4.2.0", + "dotenv": "^8.0.0", + "eslint": "^8.54.0", + "eslint-config-prettier": "^9.0.0", + "eslint-config-standard": "^17.1.0", + "eslint-config-standard-with-typescript": "^40.0.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-functional": "^6.0.0", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-n": "^16.3.1", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.1.1", + "ethers": "^5.4.7", + "hardhat-gas-reporter": "^1.0.8", + "prettier": "^3.2.4", + "prettier-plugin-solidity": "^1.0.0-beta.13", + "rimraf": "^3.0.2", + "solhint": "^4.1.1", + "solhint-community": "^3.7.0", + "solhint-plugin-prettier": "^0.1.0", + "solidity-coverage": "^0.8.0", + "ts-node": ">=8.0.0", + "typechain": "^8.1.0", + "typescript": "^5.1.6" + }, + "dependencies": { + "@openzeppelin/contracts": "^4.8.1", + "glob": "^7.1.6", + "hardhat": "2.14.0", + "lodash": "^4.17.21" + }, + "workspaces": [ + "./*" + ] +} diff --git a/packages/hebao_v3/script/1inch_demo.ts b/packages/hebao_v3/script/1inch_demo.ts new file mode 100644 index 000000000..3a37d08da --- /dev/null +++ b/packages/hebao_v3/script/1inch_demo.ts @@ -0,0 +1,37 @@ +import { ethers } from 'hardhat' + +async function main(): Promise { + const { chainId } = await ethers.provider.getNetwork() + const apiBaseUrl = 'https://api.1inch.dev/swap/v5.2/' + chainId + const methodName = '/swap' + const walletAddress = '0xf848E69EA6e206E6e8F2fBFc46ddd27C73907979' + const headers = { + headers: { + Authorization: 'WOQAjIX5hCuXb879RVqvPYjkxD8cT23s', + accept: 'application/json' + } + } + const swapParam = { + fromTokenAddress: '0x111111111117dc0aa78b770fa6a738034120c302', // 1INCH + toTokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', // DAI + amount: '100000000000000000', + fromAddress: walletAddress, + slippage: '1', + disableEstimate: 'false', + allowPartialFill: 'false' + } + const url = + apiBaseUrl + + methodName + + '?' + + new URLSearchParams(swapParam).toString() + const res = await fetch(url, headers) + console.log(await res.json()) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/addresses.ts b/packages/hebao_v3/script/addresses.ts new file mode 100644 index 000000000..d9ad792ec --- /dev/null +++ b/packages/hebao_v3/script/addresses.ts @@ -0,0 +1,25 @@ +import * as fs from 'fs' + +export type DeploymentsAddress = Record< + string, + Record +> + +export function saveDeploymentsAddress( + addressBook: Record, + network: string, + deploymentsDir: string +): void { + if (!fs.existsSync(deploymentsDir)) { + fs.mkdirSync(deploymentsDir) + } + + const path = deploymentsDir + '/deployments.json' + let deployments: DeploymentsAddress = {} + if (fs.existsSync(path)) { + deployments = JSON.parse(fs.readFileSync(path, 'utf-8')) + } + deployments[network] = addressBook + fs.writeFileSync(path, JSON.stringify(deployments, null, 2)) + console.log(`deployments info is saved to ${path}`) +} diff --git a/packages/hebao_v3/script/demo.ts b/packages/hebao_v3/script/demo.ts new file mode 100644 index 000000000..05bbdda6b --- /dev/null +++ b/packages/hebao_v3/script/demo.ts @@ -0,0 +1,20 @@ +import { + testExecuteTx, + testExecuteTxWithEth, + testExecuteTxWithUSDCPaymaster +} from './demo_utils' +import { deployAll } from './deploy_utils' + +async function main(): Promise { + const fixture = await deployAll() + await testExecuteTx(fixture) + await testExecuteTxWithEth(fixture) + await testExecuteTxWithUSDCPaymaster(fixture) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/demo_utils.ts b/packages/hebao_v3/script/demo_utils.ts new file mode 100644 index 000000000..5a41090a3 --- /dev/null +++ b/packages/hebao_v3/script/demo_utils.ts @@ -0,0 +1,163 @@ +import { ethers } from 'hardhat' +import { + simulationResultCatch, + sendTx, + type PaymasterOption, + generateSignedUserOp +} from '../test/helper/utils' +import { type ContractReceipt } from '@ethersproject/contracts' + +export async function testExecuteTxWithEth( + fixture: any +): Promise { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + deployer, + sendUserOp, + create2 + } = fixture + // prepare mock usdt token first + await ( + await usdtToken.setBalance( + smartWallet.address, + ethers.utils.parseUnits('1000', 6) + ) + ).wait() + + /// /////////////////////////////////////// + // usdt token transfer test + const tokenAmount = ethers.utils.parseUnits('100', 6) + const transferToken = await usdtToken.populateTransaction.transfer( + deployer.address, + tokenAmount + ) + + await sendTx( + [transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + /// ///////////////////////////////// + // eth transfer test + const ethAmount = 1 + await ( + await deployer.sendTransaction({ + to: smartWallet.address, + value: ethAmount + }) + ).wait() + const transferEth = { + value: ethAmount, + to: deployer.address + } + await sendTx( + [transferEth], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + /// //////////////////////////// + // batch tx + // transfer usdt token by three times + + return sendTx( + [transferToken, transferToken, transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) +} + +export async function testExecuteTxWithUSDCPaymaster( + fixture: any +): Promise { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + deployer, + sendUserOp, + create2, + paymaster, + paymasterOwner + } = fixture + // prepare mock usdt token first + await ( + await usdtToken.setBalance( + smartWallet.address, + ethers.utils.parseUnits('1000', 6) + ) + ).wait() + + /// /////////////////////////////////////// + // usdt token transfer test + const tokenAmount = ethers.utils.parseUnits('100', 6) + await (await paymaster.addToken(usdtToken.address)).wait() + // approve paymaster before using usdt paymaster service + const approveToken = await usdtToken.populateTransaction.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + const transferToken = await usdtToken.populateTransaction.transfer( + deployer.address, + tokenAmount + ) + const paymasterOption: PaymasterOption = { + paymaster, + payToken: usdtToken, + paymasterOwner, + valueOfEth: ethers.utils.parseUnits('625', 12), + validUntil: 0 + } + + // approve token first + return sendTx( + [approveToken, transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) +} + +export async function testExecuteTx( + fixture: any +): Promise { + const { + entrypoint, + smartWallet, + smartWalletOwner, + sendUserOp, + create2 + } = fixture + /// /////////////////////////////////////// + // usdt token transfer test + const nonce = await smartWallet.populateTransaction.getNonce() + const signedUserOp = await generateSignedUserOp( + [nonce], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + undefined, + false + ) + + await entrypoint.callStatic + .simulateValidation(signedUserOp) + .catch(simulationResultCatch) + return sendUserOp(signedUserOp) +} diff --git a/packages/hebao_v3/script/deploy.ts b/packages/hebao_v3/script/deploy.ts new file mode 100644 index 000000000..6c52d4148 --- /dev/null +++ b/packages/hebao_v3/script/deploy.ts @@ -0,0 +1,19 @@ +import { deployAll } from './deploy_utils' +import { saveDeploymentsAddress } from './addresses' +import * as hre from 'hardhat' + +async function main(): Promise { + const { addressBook } = await deployAll() + saveDeploymentsAddress( + addressBook, + hre.network.name, + './deployments' + ) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/deploy_utils.ts b/packages/hebao_v3/script/deploy_utils.ts new file mode 100644 index 000000000..bc6d1ca07 --- /dev/null +++ b/packages/hebao_v3/script/deploy_utils.ts @@ -0,0 +1,220 @@ +import { type Contract } from 'ethers' +import { ethers } from 'hardhat' +import * as hre from 'hardhat' + +import { localUserOpSender } from '../test/helper/AASigner' +import { + deploySingle, + deployWalletImpl, + createSmartWallet +} from '../test/helper/utils' +import * as create2AddrJson from '../deployments/create2.json' +import { + EntryPoint__factory, + type LoopringCreate2Deployer, + LoopringPaymaster__factory, + SmartWalletV3__factory, + WalletFactory__factory, + USDT__factory +} from '../typechain-types' + +// eslint-disable-next-line +export async function deployAll() { + const addressBook: Record = {} + const signers = await ethers.getSigners() + const deployer = signers[0] + let paymasterOwner + if (hre.network.name === 'hardhat') { + // as a paymaster owner, enough eth is necessary + paymasterOwner = signers[1] + } else { + paymasterOwner = new ethers.Wallet( + process.env.PAYMASTER_OWNER_PRIVATE_KEY ?? + (process.env.PRIVATE_KEY as string), + ethers.provider + ) + } + const blankOwner = process.env.BLANK_OWNER ?? deployer.address + + // create2 factory + let create2: LoopringCreate2Deployer + // NOTE(update address when create2 factory contract is modified) + const create2Addr = (create2AddrJson as Record)[ + hre.network.name + ] + if ( + create2Addr !== undefined && + (await ethers.provider.getCode(create2Addr)) !== '0x' + ) { + console.log( + 'create2 factory is deployed already at : ', + create2Addr + ) + create2 = await ethers.getContractAt( + 'LoopringCreate2Deployer', + create2Addr + ) + } else { + create2 = await ( + await ethers.getContractFactory('LoopringCreate2Deployer') + ).deploy() + console.log('create2 factory is deployed at : ', create2.address) + } + addressBook.LoopringCreate2Deployer = create2.address + + // entrypoint and paymaster + // NOTE(uncomment when you need to deploy a new entrypoint contract) + let entrypoint: Contract + // const entrypointAddr = ethers.constants.AddressZero; + const entrypointAddr = '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' + if ((await ethers.provider.getCode(entrypointAddr)) !== '0x') { + entrypoint = await ethers.getContractAt( + 'EntryPoint', + entrypointAddr + ) + } else { + entrypoint = await deploySingle(create2, 'EntryPoint') + } + addressBook.EntryPoint = entrypoint.address + + const paymaster = await deploySingle(create2, 'LoopringPaymaster', [ + entrypoint.address, + paymasterOwner.address + ]) + addressBook.LoopringPaymaster = paymaster.address + + const smartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + blankOwner + ) + addressBook.SmartWalletImpl = smartWalletImpl.address + + const implStorage = await deploySingle( + create2, + 'DelayedImplementationManager', + // deployer as implementation manager + [smartWalletImpl.address] + ) + addressBook.DelayedImplementationManager = implStorage.address + + const forwardProxy = await deploySingle(create2, 'ForwardProxy', [ + implStorage.address + ]) + addressBook.ForwardProxy = forwardProxy.address + + const walletFactory = WalletFactory__factory.connect( + ( + await deploySingle(create2, 'WalletFactory', [ + forwardProxy.address + ]) + ).address, + deployer + ) + addressBook.WalletFactory = walletFactory.address + // transfer wallet factory ownership to deployer + const walletFactoryOwner = await walletFactory.owner() + if ( + create2.address.toLowerCase() === walletFactoryOwner.toLowerCase() + ) { + console.log('transfer wallet factory ownership to deployer') + await (await create2.setTarget(walletFactory.address)).wait() + const transferWalletFactoryOwnership = + await walletFactory.populateTransaction.transferOwnership( + deployer.address + ) + await ( + await create2.transact(transferWalletFactoryOwnership.data!) + ).wait() + } else { + console.log('ownership of wallet factory is transfered already') + } + + if ( + !((await walletFactory.isOperator(deployer.address)) as boolean) + ) { + await (await walletFactory.addOperator(deployer.address)).wait() + } + + // transfer DelayedImplementationManager ownership to deployer + if (create2.address === (await implStorage.owner())) { + console.log( + 'transfer DelayedImplementationManager ownership to deployer' + ) + await (await create2.setTarget(implStorage.address)).wait() + const transferImplStorageOwnership = + await implStorage.populateTransaction.transferOwnership( + deployer.address + ) + await ( + await create2.transact(transferImplStorageOwnership.data!) + ).wait() + } else { + console.log( + 'ownership of DelayedImplementationManager is transfered already' + ) + } + + // create demo wallet + console.log('create demo wallet...') + + const smartWalletOwner = new ethers.Wallet( + process.env.TEST_ACCOUNT_PRIVATE_KEY ?? deployer.address, + ethers.provider + ) + const sendUserOp = localUserOpSender(entrypoint.address, deployer) + + // owner cannot be guardians + const guardians: string[] = [ + '0x456ecAca6A1Bc3a71fC1955562d1d9BF662974D8' + ] + const salt = ethers.utils.formatBytes32String('0x5') + const smartWalletAddr = await walletFactory.computeWalletAddress( + smartWalletOwner.address, + salt + ) + if ((await ethers.provider.getCode(smartWalletAddr)) === '0x') { + await createSmartWallet( + smartWalletOwner, + guardians, + walletFactory, + salt + ) + } + + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + addressBook.SmartWallet = smartWallet.address + + // deploy mock usdt token for test. + const usdtToken = await deploySingle( + create2, + 'USDT', + undefined, + undefined, + 'contracts/test/tokens/USDT.sol:USDT' + ) + addressBook.USDT = usdtToken.address + return { + entrypoint: EntryPoint__factory.connect( + entrypoint.address, + deployer + ), + paymaster: LoopringPaymaster__factory.connect( + paymaster.address, + paymasterOwner + ), + forwardProxy, + smartWallet, + create2, + deployer, + paymasterOwner, + blankOwner, + smartWalletOwner, + usdtToken: USDT__factory.connect(usdtToken.address, deployer), + sendUserOp, + addressBook + } +} diff --git a/packages/hebao_v3/script/estimate_costofpost.ts b/packages/hebao_v3/script/estimate_costofpost.ts new file mode 100644 index 000000000..c4cee7db8 --- /dev/null +++ b/packages/hebao_v3/script/estimate_costofpost.ts @@ -0,0 +1,57 @@ +import { testExecuteTxWithUSDCPaymaster } from './demo_utils' +import { deployAll } from './deploy_utils' +import { type Log } from '@ethersproject/abstract-provider' +import { type Interface, type Result } from '@ethersproject/abi' +import { + LoopringPaymaster__factory, + EntryPoint__factory +} from '../typechain-types' + +function getEventArgs( + logs: Log[], + eventName: string, + iface: Interface +): Result { + const topic = iface.getEventTopic(eventName) + // only parse the first one + return iface.parseLog(logs.find((log) => log.topics[0] === topic)!) + .args +} + +// find out the best cost_of_post value used in paymaster +async function main(): Promise { + // send userop using paymaster and check emitted events: + // PaymasterEvent and UserOperationEvent, then check actualTokenCost + // value between them + const fixture = await deployAll() + const receipt = await testExecuteTxWithUSDCPaymaster(fixture) + const useroperationEvent = getEventArgs( + receipt.logs, + 'UserOperationEvent', + EntryPoint__factory.createInterface() + ) + const paymasterEvent = getEventArgs( + receipt.logs, + 'PaymasterEvent', + LoopringPaymaster__factory.createInterface() + ) + console.log( + paymasterEvent.actualETHCost, + useroperationEvent.actualGasCost + ) + // about 6k gas accounts for postop + console.log( + useroperationEvent.actualGasUsed.sub( + paymasterEvent.actualETHCost + .mul(useroperationEvent.actualGasUsed) + .div(useroperationEvent.actualGasCost) + ) + ) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/gastank_test.ts b/packages/hebao_v3/script/gastank_test.ts new file mode 100644 index 000000000..224884db9 --- /dev/null +++ b/packages/hebao_v3/script/gastank_test.ts @@ -0,0 +1,301 @@ +import { deployAll } from './deploy_utils' +import { ethers } from 'hardhat' +import { type BigNumber, type Signer } from 'ethers' +import { type TransactionRequest } from '@ethersproject/providers' +import { type Deferrable } from '@ethersproject/properties' +import { + sendTx, + type PaymasterOption, + evInfo +} from '../test/helper/utils' +import { + type USDT, + type EntryPoint, + type SmartWalletV3 +} from '../typechain-types' + +interface TestTransaction { + name: string + tx: Deferrable +} + +async function getTxs(usdtToken: USDT): Promise { + const receivedAddress = ethers.constants.AddressZero + const approveToken = await usdtToken.populateTransaction.approve( + receivedAddress, + ethers.constants.MaxUint256 + ) + const tokenAmount = ethers.utils.parseUnits('100', 6) + const transferToken = await usdtToken.populateTransaction.transfer( + receivedAddress, + tokenAmount + ) + const transferEth = { + value: 1, + to: receivedAddress + } + const txs = [ + { name: 'transferToken', tx: transferToken }, + { name: 'transferEth', tx: transferEth }, + { name: 'approveToken', tx: approveToken } + ] + return txs +} + +async function prepareTokens( + deployer: Signer, + smartWalletAddr: string, + depositAmount: BigNumber, + usdtToken: USDT +): Promise { + // mint more tokens than actual usage + await ( + await usdtToken.setBalance(smartWalletAddr, depositAmount.mul(2)) + ).wait() + await ( + await deployer.sendTransaction({ + to: smartWalletAddr, + value: ethers.utils.parseEther('100') + }) + ).wait() +} + +async function testGastankAtPaymaster(): Promise { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + deployer, + sendUserOp, + create2, + paymaster, + paymasterOwner + } = await deployAll() + // prepare mock usdt token first + const depositAmount = ethers.utils.parseUnits('10000', 6) + await prepareTokens( + deployer, + smartWallet.address, + depositAmount, + usdtToken + ) + await (await paymaster.addToken(usdtToken.address)).wait() + const paymasterOption: PaymasterOption = { + paymaster, + payToken: usdtToken, + paymasterOwner, + valueOfEth: ethers.utils.parseUnits('625', 12), + validUntil: 0 + } + const approveToken = await usdtToken.populateTransaction.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + // use eth to pay fee here + await sendTx( + [approveToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + + const addDepositFor = + await paymaster.populateTransaction.addDepositFor( + usdtToken.address, + smartWallet.address, + depositAmount + ) + const txs = await getTxs(usdtToken) + console.log(`\n----- test without gas tank -----\n`) + for (const { tx, name } of txs) { + console.log(`----- execute ${name} tx -----`) + // warmup + await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + + { + const { amount } = await paymaster.depositInfo( + usdtToken.address, + smartWallet.address + ) + if (amount.gt(0)) { + throw new Error( + `make sure no any deposited token to prevent from using gas tank` + ) + } + const recipt = await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + const events = await evInfo(entrypoint, recipt) + console.log( + `actualGasUsed of ${name} without gas tank`, + events[0].actualGasUsed + ) + } + } + + console.log(`\n----- test with gas tank -----\n`) + await sendTx( + [addDepositFor], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + for (const { tx, name } of txs) { + console.log(`----- execute ${name} tx -----`) + // using gas tank + const { amount } = await paymaster.depositInfo( + usdtToken.address, + smartWallet.address + ) + if (amount.eq(0)) { + throw new Error(`no any deposited token when using gas tank`) + } + const recipt = await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + const events = await evInfo(entrypoint, recipt) + console.log( + `actualGasUsed of ${name} with gas tank`, + events[0].actualGasUsed + ) + } +} + +async function withdrawAllEth( + entrypoint: EntryPoint, + smartWallet: SmartWalletV3 +): Promise { + const amountBefore = await entrypoint.balanceOf(smartWallet.address) + if (amountBefore.gt(0)) { + // withdraw all eth from entrypoint to execute userop without gas tank + await smartWallet.withdrawDepositTo( + ethers.constants.AddressZero, + amountBefore + ) + } +} + +async function testGastankAtEntrypoint(): Promise { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + deployer, + sendUserOp, + create2 + } = await deployAll() + const depositAmount = ethers.utils.parseUnits('10000', 6) + await prepareTokens( + deployer, + smartWallet.address, + depositAmount, + usdtToken + ) + // allow owner to send userop directly + await ( + await deployer.sendTransaction({ + to: smartWalletOwner.address, + value: ethers.utils.parseEther('100') + }) + ).wait() + const txs = await getTxs(usdtToken) + + console.log(`\n----- test without gas tank -----\n`) + for (const { tx, name } of txs) { + console.log(`----- execute ${name} tx -----`) + // warmup + await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + await withdrawAllEth(entrypoint, smartWallet) + const amount = await entrypoint.balanceOf(smartWallet.address) + if (amount.gt(0)) { + throw new Error( + `make sure no any eth deposited to prevent from using gas tank` + ) + } + const recipt = await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + const events = await evInfo(entrypoint, recipt) + console.log( + `actualGasUsed of ${name} without gas tank in entrypoint`, + events[0].actualGasUsed + ) + } + console.log(`\n----- test with gas tank -----\n`) + await entrypoint.depositTo(smartWallet.address, { + value: ethers.utils.parseEther('100') + }) + + for (const { tx, name } of txs) { + console.log(`----- execute ${name} tx -----`) + const amount = await entrypoint.balanceOf(smartWallet.address) + if (amount.eq(0)) { + throw new Error(`no any deposited eth when using gas tank`) + } + const recipt = await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + const events = await evInfo(entrypoint, recipt) + console.log( + `actualGasUsed of ${name} with gas tank in entrypoint`, + events[0].actualGasUsed + ) + } +} + +async function main(): Promise { + console.log(`\n----- test gas tank at paymaster -----\n`) + await testGastankAtPaymaster() + console.log(`\n----- test gas tank at entrypoint -----\n`) + await testGastankAtEntrypoint() +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/migration_test.ts b/packages/hebao_v3/script/migration_test.ts new file mode 100644 index 000000000..44a7f9120 --- /dev/null +++ b/packages/hebao_v3/script/migration_test.ts @@ -0,0 +1,55 @@ +import { ethers } from 'hardhat' +import { SmartWalletV3__factory } from '../typechain-types' + +import { deployWalletImpl } from '../test/helper/utils' + +async function main(): Promise { + const signers = await ethers.getSigners() + const deployer = signers[0] + const smartWalletOwner = new ethers.Wallet( + process.env.TEST_ACCOUNT_PRIVATE_KEY ?? deployer.address, + ethers.provider + ) + const smartWalletAddr = '0x44e7527ab6cFeB896e53e1F45B6177E81FC985a8' + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + const walletV2Info = await smartWallet.wallet() + console.log('wallet info before update', walletV2Info) + + let smartWalletImplAddr: string = + '0xC920EcfaE7ed1665976d3262E2600A1B3d964cC5' + if ((await ethers.provider.getCode(smartWalletImplAddr)) === '0x') { + // deploy new implementation when not exist + const create2Addr = '0xd57d71A16D850038e7266E3885140A7E7d1Ba3fD' + const create2 = await ethers.getContractAt( + 'LoopringCreate2Deployer', + create2Addr + ) + const entrypointAddr = + '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789' + const entrypoint = await ethers.getContractAt( + 'EntryPoint', + entrypointAddr + ) + const smartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + ethers.constants.AddressZero + ) + smartWalletImplAddr = smartWalletImpl.address + } + + // TODO(change mastercopy using guardians approval) + // await smartWallet.changeMasterCopy(smartWalletImplAddr) + // const walletV3Info = await smartWallet.wallet() + // console.log('wallet info after update', walletV3Info) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/prepare.ts b/packages/hebao_v3/script/prepare.ts new file mode 100644 index 000000000..4fe593646 --- /dev/null +++ b/packages/hebao_v3/script/prepare.ts @@ -0,0 +1,184 @@ +import { ethers } from 'hardhat' +import { + EntryPoint__factory, + SmartWalletV3__factory, + LoopringPaymaster__factory, + WalletFactory__factory, + USDT__factory +} from './../typechain-types' +import deploymentJson from '../deployments/deployments.json' +import * as hre from 'hardhat' + +interface DeploymentType { + EntryPoint: string + LoopringPaymaster: string + SmartWallet: string + WalletFactory: string + USDT: string +} + +async function main(): Promise { + // some addresses + // official entrypoint + if (!(hre.network.name in deploymentJson)) { + throw new Error(`unsupported network ${hre.network.name}`) + } + const deployment = ( + deploymentJson as Record + )[hre.network.name] + const entryPointAddr = deployment.EntryPoint + // loopring paymaster + const paymasterAddr = deployment.LoopringPaymaster + // loopring smart wallet + const smartWalletAddr = deployment.SmartWallet + // fake tokens + const usdtTokenAddr = deployment.USDT + + const deployer = (await ethers.getSigners())[0] + const smartWalletOwner = new ethers.Wallet( + process.env.TEST_ACCOUNT_PRIVATE_KEY ?? deployer.address, + ethers.provider + ) + const paymasterOwner = new ethers.Wallet( + process.env.PAYMASTER_OWNER_PRIVATE_KEY ?? deployer.address, + ethers.provider + ) + const entryPoint = EntryPoint__factory.connect( + entryPointAddr, + deployer + ) + const ethAmount = ethers.utils.parseEther('0.2') + const minAmount = ethers.utils.parseEther('0.05') + const paymaster = LoopringPaymaster__factory.connect( + paymasterAddr, + paymasterOwner + ) + const tokens = [ + usdtTokenAddr, + '0xaE404C050c3Da571AfefCFF5B6a64af451584000', // LRC + '0x1FEa9801725853622C33a23a86251e7c81898b25' // USDT + ] + // make sure usdt token is supported in paymaster + for (const token of tokens) { + if (await paymaster.registeredToken(token)) { + console.log(`token: ${token} is registerd already`) + } else { + await (await paymaster.addToken(token)).wait() + console.log(`token: ${token} is registerd successfully`) + } + // check success + } + + // signer for paymaster + const signers = ['0xf6c53560e79857ce12dde54782d487b743b70717'] + const signerRole = await paymaster.SIGNER() + for (const signer of signers) { + if (await paymaster.hasRole(signerRole, signer)) { + console.log(`operator ${signer} has permission already`) + } else { + await (await paymaster.grantRole(signerRole, signer)).wait() + console.log(`grant role to ${signer} successfully`) + } + } + + // add operator for wallet factory + const operators = [ + '0x3435259218bf656186F123B6d9129BF8D19c2941', + '0xd465F61eB0c067e648B81e43f97af8cCD54b3D17' + ] + const walletFactory = WalletFactory__factory.connect( + deployment.WalletFactory, + deployer + ) + for (const operator of operators) { + if (await walletFactory.isOperator(operator)) { + console.log(`operator ${operator} has permission already`) + } else { + await (await walletFactory.addOperator(operator)).wait() + console.log(`grant role to ${operator} successfully`) + } + } + + // prepare tokens for paymaster and smartwallet + if ((await entryPoint.balanceOf(paymasterAddr)).lt(minAmount)) { + await ( + await entryPoint.connect(deployer).depositTo(paymasterAddr, { + value: ethAmount + }) + ).wait() + } else { + console.log('paymaster has enough eth in entrypoint already') + } + + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + if ( + (await entryPoint.balanceOf(smartWallet.address)).lt(minAmount) + ) { + await ( + await entryPoint + .connect(deployer) + .depositTo(smartWallet.address, { + value: ethAmount + }) + ).wait() + } else { + console.log('smart wallet has enough eth in entrypoint already') + } + const usdtToken = USDT__factory.connect(usdtTokenAddr, deployer) + const tokenAmount = ethers.utils.parseUnits('100000', 6) + const minTokenAmount = ethers.utils.parseUnits('100', 6) + const { amount: depositedTokenAmount } = + await paymaster.depositInfo(usdtTokenAddr, smartWalletAddr) + // two options, one is deposit for user, the other is mint tokens to user + if (depositedTokenAmount.lt(minTokenAmount)) { + if ( + (await usdtToken.balanceOf(deployer.address)).lt(tokenAmount) + ) { + await ( + await usdtToken.setBalance(deployer.address, tokenAmount) + ).wait() + // deployer approve tokens to paymaster + await ( + await usdtToken + .connect(deployer) + .approve(paymasterAddr, tokenAmount) + ).wait() + } + await ( + await paymaster + .connect(deployer) + .addDepositFor(usdtTokenAddr, smartWalletAddr, tokenAmount) + ).wait() + } else { + console.log('smart wallet has enough usdt in paymaster already') + } + + const usdtBalance = await usdtToken.balanceOf(smartWallet.address) + if (usdtBalance.lt(minTokenAmount)) { + // prepare tokens for smartwallet + await ( + await usdtToken.setBalance(smartWallet.address, tokenAmount) + ).wait() + // approve tokens to paymaster + await ( + await smartWallet.approveToken( + usdtTokenAddr, + paymasterAddr, + tokenAmount, + false + ) + ).wait() + } else { + console.log('smart wallet has enough usdt already') + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/script/userop_check.ts b/packages/hebao_v3/script/userop_check.ts new file mode 100644 index 000000000..91675795d --- /dev/null +++ b/packages/hebao_v3/script/userop_check.ts @@ -0,0 +1,115 @@ +import { ethers } from 'hardhat' +import { + EntryPoint__factory, + SmartWalletV3__factory, + LoopringPaymaster__factory +} from './../typechain-types' +import * as hre from 'hardhat' +import deploymentJson from '../deployments/deployments.json' + +async function main(): Promise { + const signers = await ethers.getSigners() + const deployer = signers[0] + const userop = { + callData: + '0xff06ff56000000000000000000000000ae404c050c3da571afefcff5b6a64af4515840000000000000000000000000007027c780771f4d13d59c179a868aa5269bc0d09c0000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000', + callGasLimit: '0x17a8b', + entryPoint: '0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789', + hash: '0x2fb1e48ad4c112d5c31178955d24fe565e640c300750356f7f5c61f44b50f916', + initCode: '0x', + maxFeePerGas: '0x1d80', + maxPriorityFeePerGas: '0x1143', + metaTxType: 0, + nonce: '0x2', + paymasterAndData: + '0x7027c780771f4d13d59c179a868aa5269bc0d09c0000000000000000000000001fea9801725853622c33a23a86251e7c81898b250000000000000000000000000000000000000000000000000098567b0884fe330000000000000000000000000000000000000000000000000000000065c20d3c00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000041c3f2a7b267970ac8e8e91cbcedbc4421a189fbbc14856da752d99e1abd8831a04356f155be2d7b7a594db69d8833861ecd5b64e6f30ae6af24b87d046a0c2aa01b00000000000000000000000000000000000000000000000000000000000000', + preVerificationGas: '0xba9f', + sender: '0x7f2ea42a321240087220584dcc1c65afbdfbd811', + signature: + '0xc0205ed0c79a734105adea6aef3aace5d6e951f8ee39afd34fefac967c1ca862469bab7832155794484716bb4793fc15c22dc8899afb5ad9b0ec52839de4b64d1c', + verificationGasLimit: '0x22501' + } + + // const userop = { + // callData: + // '0xb9806d99000000000000000000000000d69d3e64d71844bbdda51cd7f23ed3631e9fac490000000000000000000000008686c21ff9ae737ce331479c3af00468a4998ba30000000000000000000000000000000000000000000000004563918244f4000000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023078000000000000000000000000000000000000000000000000000000000000', + // callGasLimit: '0x16769', + // entryPoint: '0x779eEcA2315a44D20806217c005731aE7DDB5ca0', + // hash: '0x244d0acf339bf7e6d501f08abab302fcf99ee4a7f3635b842c2f24076958377d', + // initCode: '0x', + // maxFeePerGas: '0x98968001', + // maxPriorityFeePerGas: '0x59682f00', + // metaTxType: 0, + // nonce: '0x18d05fd87e2', + // paymasterAndData: + // '0x9ca6ffc3cc53a50c7322ab7b70fd413c49a55bfd000000000000000000000000d69d3e64d71844bbdda51cd7f23ed3631e9fac49000000000000000000000000000000000000000000000000000000000000989b0000000000000000000000000000000000000000000000000000000065a361670000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004170ea418b2e715a952508948f0e07b7fca36fb16600659a6cdc6e66da481c1fb14d2a5a2ab8e301c204d180ceffd8ff2b83743dd8a9fe4ee8a04baf43ab63f69c1c00000000000000000000000000000000000000000000000000000000000000', + // preVerificationGas: '0xbc87', + // sender: '0xa45781f336f5f0ef24fda58089db59b47b922b59', + // signature: + // '0x4da29a0cd3ee263b40966aa7dca0287e17d53abe5a875eb5183c1223acd937183242d531ce57b9130ae869ab66829eda74de8a9ecca1b92926004ba5e74e2b361b', + // verificationGasLimit: '0x22661' + // } + + const smartWallet = SmartWalletV3__factory.connect( + userop.sender, + ethers.provider + ) + const smartWalletOwner = await smartWallet.getOwner() + const paymasterAddr = + deploymentJson[hre.network.name].LoopringPaymaster + const paymaster = LoopringPaymaster__factory.connect( + paymasterAddr, + deployer + ) + // const operator = '0xE6FDa200797a5B8116e69812344cE7D2A9F17B0B' + // const role = await paymaster.SIGNER() + // const isOperator = await paymaster.hasRole(role, operator) + // if (!isOperator) { + // throw new Error(`address: ${operator} is not a valid operator`) + // } + console.log( + ethers.utils.defaultAbiCoder.encode( + ['uint48', 'uint48'], + [12, 12] + ).length + ) + const result = ethers.utils.defaultAbiCoder.decode( + ['address', 'uint48', 'uint256', 'bytes'], + ethers.utils.hexDataSlice(userop.paymasterAndData, 20) + ) + // token, valueOfEth, validUntil, signature + const packedData = ethers.utils.solidityPack( + ['address', 'uint256', 'uint256'], + [result[0], result[1], result[2]] + ) + const hash = await paymaster.getHash(userop, packedData) + // check paymaster signature + // console.log('paymaster operator: ', operator) + console.log( + 'paymaster signer: ', + ethers.utils.verifyMessage(ethers.utils.arrayify(hash), result[3]) + ) + + // check wallet owner signature + const entryPointAddr = '0x779eEcA2315a44D20806217c005731aE7DDB5ca0' + const entryPoint = EntryPoint__factory.connect( + entryPointAddr, + ethers.provider + ) + const userOpHash = await entryPoint.getUserOpHash(userop) + console.log('smart wallet owner: ', smartWalletOwner) + console.log( + 'smart wallet signer: ', + ethers.utils.verifyMessage( + ethers.utils.arrayify(userOpHash), + userop.signature + ) + ) +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error) + process.exit(1) + }) diff --git a/packages/hebao_v3/test/account-abstraction/UserOp.ts b/packages/hebao_v3/test/account-abstraction/UserOp.ts new file mode 100644 index 000000000..92e8950bf --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/UserOp.ts @@ -0,0 +1,308 @@ +import { + ecsign, + keccak256 as keccak256_buffer, + toRpcSig +} from 'ethereumjs-util' +import { BigNumber, Contract, type Signer, type Wallet } from 'ethers' +import { + arrayify, + defaultAbiCoder, + hexDataSlice, + keccak256 +} from 'ethers/lib/utils' + +import { type EntryPoint } from '../../typechain-types' +import { Create2Factory } from '../helper/Create2Factory' + +import { type UserOperation } from './UserOperation' +import { AddressZero, callDataCost, rethrow } from './testutils' + +export function packUserOp( + op: UserOperation, + forSignature = true +): string { + if (forSignature) { + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes32', + 'bytes32', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes32' + ], + [ + op.sender, + op.nonce, + keccak256(op.initCode), + keccak256(op.callData), + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + keccak256(op.paymasterAndData) + ] + ) + } else { + // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes', + 'bytes', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes', + 'bytes' + ], + [ + op.sender, + op.nonce, + op.initCode, + op.callData, + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + op.paymasterAndData, + op.signature + ] + ) + } +} + +export function packUserOp1(op: UserOperation): string { + return defaultAbiCoder.encode( + [ + 'address', // sender + 'uint256', // nonce + 'bytes32', // initCode + 'bytes32', // callData + 'uint256', // callGasLimit + 'uint256', // verificationGasLimit + 'uint256', // preVerificationGas + 'uint256', // maxFeePerGas + 'uint256', // maxPriorityFeePerGas + 'bytes32' // paymasterAndData + ], + [ + op.sender, + op.nonce, + keccak256(op.initCode), + keccak256(op.callData), + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + keccak256(op.paymasterAndData) + ] + ) +} + +export function getUserOpHash( + op: UserOperation, + entryPoint: string, + chainId: number +): string { + const userOpHash = keccak256(packUserOp(op, true)) + const enc = defaultAbiCoder.encode( + ['bytes32', 'address', 'uint256'], + [userOpHash, entryPoint, chainId] + ) + return keccak256(enc) +} + +export const DefaultsForUserOp: UserOperation = { + sender: AddressZero, + nonce: 0, + initCode: '0x', + callData: '0x', + callGasLimit: 0, + verificationGasLimit: 150000, // default verification gas. will add create2 cost (3200+200*length) if initCode exists + preVerificationGas: 21000, // should also cover calldata cost. + maxFeePerGas: 0, + maxPriorityFeePerGas: 1e9, + paymasterAndData: '0x', + signature: '0x' +} + +export function signUserOp( + op: UserOperation, + signer: Wallet, + entryPoint: string, + chainId: number +): UserOperation { + const message = getUserOpHash(op, entryPoint, chainId) + const msg1 = Buffer.concat([ + Buffer.from('\x19Ethereum Signed Message:\n32', 'ascii'), + Buffer.from(arrayify(message)) + ]) + + const sig = ecsign( + keccak256_buffer(msg1), + Buffer.from(arrayify(signer.privateKey)) + ) + // that's equivalent of: await signer.signMessage(message); + // (but without "async" + const signedMessage1 = toRpcSig(sig.v, sig.r, sig.s) + return { + ...op, + signature: signedMessage1 + } +} + +export function fillUserOpDefaults( + op: Partial, + defaults = DefaultsForUserOp +): UserOperation { + const partial: any = { ...op } + // we want "item:undefined" to be used from defaults, and not override defaults, so we must explicitly + // remove those so "merge" will succeed. + for (const key in partial) { + if (partial[key] == null) { + // eslint-disable-next-line + delete partial[key] + } + } + const filled = { ...defaults, ...partial } + return filled +} + +// helper to fill structure: +// - default callGasLimit to estimate call from entryPoint to account (TODO: add overhead) +// if there is initCode: +// - calculate sender by eth_call the deployment code +// - default verificationGasLimit estimateGas of deployment code plus default 100000 +// no initCode: +// - update nonce from account.getNonce() +// entryPoint param is only required to fill in "sender address when specifying "initCode" +// nonce: assume contract as "getNonce()" function, and fill in. +// sender - only in case of construction: fill sender from initCode. +// callGasLimit: VERY crude estimation (by estimating call to account, and add rough entryPoint overhead +// verificationGasLimit: hard-code default at 100k. should add "create2" cost +export async function fillUserOp( + op: Partial, + entryPoint?: EntryPoint, + getNonceFunction = 'getNonce' +): Promise { + const op1 = { ...op } + const provider = entryPoint?.provider + if (op.initCode != null) { + const initAddr = hexDataSlice(op1.initCode!, 0, 20) + const initCallData = hexDataSlice(op1.initCode!, 20) + if (op1.nonce == null) op1.nonce = 0 + if (op1.sender == null) { + // hack: if the init contract is our known deployer, then we know what the address would be, without a view call + if ( + initAddr.toLowerCase() === + Create2Factory.contractAddress.toLowerCase() + ) { + const ctr = hexDataSlice(initCallData, 32) + const salt = hexDataSlice(initCallData, 0, 32) + op1.sender = Create2Factory.getDeployedAddress(ctr, salt) + } else { + // console.log('\t== not our deployer. our=', Create2Factory.contractAddress, 'got', initAddr) + if (provider == null) { + throw new Error('no entrypoint/provider') + } + op1.sender = await entryPoint!.callStatic + .getSenderAddress(op1.initCode!) + .catch((e) => e.errorArgs.sender) + } + } + if (op1.verificationGasLimit == null) { + if (provider == null) throw new Error('no entrypoint/provider') + const initEstimate = await provider.estimateGas({ + from: entryPoint?.address, + to: initAddr, + data: initCallData, + gasLimit: 10e6 + }) + op1.verificationGasLimit = BigNumber.from( + DefaultsForUserOp.verificationGasLimit + ).add(initEstimate) + } + } + if (op1.nonce == null) { + if (provider == null) { + throw new Error('must have entryPoint to autofill nonce') + } + const c = new Contract( + op.sender!, + [`function ${getNonceFunction}() view returns(uint256)`], + provider + ) + op1.nonce = await c[getNonceFunction]().catch(rethrow()) + } + if (op1.callGasLimit == null && op.callData != null) { + if (provider == null) { + throw new Error( + 'must have entryPoint for callGasLimit estimate' + ) + } + const gasEtimated = await provider.estimateGas({ + from: entryPoint?.address, + to: op1.sender, + data: op1.callData + }) + + // console.log('estim', op1.sender,'len=', op1.callData!.length, 'res=', gasEtimated) + // estimateGas assumes direct call from entryPoint. add wrapper cost. + op1.callGasLimit = gasEtimated // .add(55000) + } + if (op1.maxFeePerGas == null) { + if (provider == null) { + throw new Error('must have entryPoint to autofill maxFeePerGas') + } + const block = await provider.getBlock('latest') + op1.maxFeePerGas = block.baseFeePerGas!.add( + op1.maxPriorityFeePerGas ?? + DefaultsForUserOp.maxPriorityFeePerGas + ) + } + // TODO: this is exactly what fillUserOp below should do - but it doesn't. + // adding this manually + if (op1.maxPriorityFeePerGas == null) { + op1.maxPriorityFeePerGas = DefaultsForUserOp.maxPriorityFeePerGas + } + const op2 = fillUserOpDefaults(op1) + + if (BigNumber.from(op2.preVerificationGas).eq(0)) { + // TODO: we don't add overhead, which is ~21000 for a single TX, but much lower in a batch. + op2.preVerificationGas = callDataCost(packUserOp(op2, false)) + } + return op2 +} + +export async function fillAndSign( + op: Partial, + signer: Wallet | Signer, + entryPoint?: EntryPoint, + getNonceFunction = 'getNonce' +): Promise { + const provider = entryPoint?.provider + const op2 = await fillUserOp(op, entryPoint, getNonceFunction) + + const chainId = await provider! + .getNetwork() + .then((net) => net.chainId) + const message = arrayify( + getUserOpHash(op2, entryPoint!.address, chainId) + ) + + return { + ...op2, + signature: await signer.signMessage(message) + } +} diff --git a/packages/hebao_v3/test/account-abstraction/UserOperation.ts b/packages/hebao_v3/test/account-abstraction/UserOperation.ts new file mode 100644 index 000000000..e1270145b --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/UserOperation.ts @@ -0,0 +1,15 @@ +import type * as typ from './solidityTypes' + +export interface UserOperation { + sender: typ.address + nonce: typ.uint256 + initCode: typ.bytes + callData: typ.bytes + callGasLimit: typ.uint256 + verificationGasLimit: typ.uint256 + preVerificationGas: typ.uint256 + maxFeePerGas: typ.uint256 + maxPriorityFeePerGas: typ.uint256 + paymasterAndData: typ.bytes + signature: typ.bytes +} diff --git a/packages/hebao_v3/test/account-abstraction/aa.init.ts b/packages/hebao_v3/test/account-abstraction/aa.init.ts new file mode 100644 index 000000000..a559df9cc --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/aa.init.ts @@ -0,0 +1,9 @@ +import './chaiHelper' + +const ethers = require('ethers') +export const inspect_custom_symbol = Symbol.for( + 'nodejs.util.inspect.custom' +) +ethers.BigNumber.prototype[inspect_custom_symbol] = function () { + return `BigNumber ${parseInt(this._hex)}` +} diff --git a/packages/hebao_v3/test/account-abstraction/chaiHelper.ts b/packages/hebao_v3/test/account-abstraction/chaiHelper.ts new file mode 100644 index 000000000..5b49fcf33 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/chaiHelper.ts @@ -0,0 +1,72 @@ +// remap "eql" function to work nicely with EVM values. + +// cleanup "Result" object (returned on web3/ethers calls) +// remove "array" members, convert values to strings. +// so Result obj like +// { '0': "a", '1': 20, first: "a", second: 20 } +// becomes: +// { first: "a", second: "20" } +// map values inside object using mapping func. +import chai from 'chai' + +export function objValues( + obj: Record, + mapFunc: (val: any, key?: string) => any +): any { + return Object.keys(obj) + .filter((key) => key.match(/^[\d_]/) == null) + .reduce( + (set, key) => ({ + ...set, + [key]: mapFunc(obj[key], key) + }), + {} + ) +} + +/** + * cleanup a value of an object, for easier testing. + * - Result: this is an array which also contains named members. + * - obj.length*2 == Object.keys().length + * - remove the array elements, use just the named ones. + * - recursively handle inner members of object, arrays. + * - attempt toString. but if no normal value, recurse into fields. + */ +export function cleanValue(val: any): any { + if (val == null) return val + if (Array.isArray(val)) { + if (val.length * 2 === Object.keys(val).length) { + // "looks" like a Result object. + return objValues(val, cleanValue) + } + // its a plain array. map each array element + return val.map((val1) => cleanValue(val1)) + } + + const str = val.toString() + if (str !== '[object Object]') { + return str + } + + return objValues(val, cleanValue) +} + +// use cleanValue for comparing. MUCH easier, since numbers compare well with bignumbers, etc + +chai.Assertion.overwriteMethod('eql', (original) => { + return function (this: any, expected: any) { + const _actual = cleanValue(this._obj) + const _expected = cleanValue(expected) + // original.apply(this,arguments) + this._obj = _actual + original.apply(this, [_expected]) + // assert.deepEqual(_actual, _expected) + // ctx.assert( + // _actual == _expected, + // 'expected #{act} to equal #{exp}', + // 'expected #{act} to be different from #{exp}', + // _expected, + // _actual + // ); + } +}) diff --git a/packages/hebao_v3/test/account-abstraction/create2factory.test.ts b/packages/hebao_v3/test/account-abstraction/create2factory.test.ts new file mode 100644 index 000000000..555e71744 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/create2factory.test.ts @@ -0,0 +1,54 @@ +import { type Provider } from '@ethersproject/providers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { TestToken__factory } from '../../typechain-types' +import { Create2Factory } from '../helper/Create2Factory' + +describe('test Create2Factory', () => { + let factory: Create2Factory + let provider: Provider + before(async () => { + provider = ethers.provider + factory = new Create2Factory(provider) + }) + it.skip('should deploy the factory', async () => { + console.log(await factory._isFactoryDeployed()) + expect(await factory._isFactoryDeployed()).to.equal( + false, + 'factory exists before test deploy' + ) + await factory.deployFactory() + expect(await factory._isFactoryDeployed()).to.equal( + true, + 'factory failed to deploy' + ) + }) + + it('should deploy to known address', async () => { + const initCode = TestToken__factory.bytecode + + const addr = Create2Factory.getDeployedAddress(initCode, 0) + + expect( + await provider.getCode(addr).then((code) => code.length) + ).to.equal(2) + await factory.deploy(initCode, 0) + expect( + await provider.getCode(addr).then((code) => code.length) + ).to.gt(100) + }) + it('should deploy to different address based on salt', async () => { + const initCode = TestToken__factory.bytecode + + const addr = Create2Factory.getDeployedAddress(initCode, 123) + + expect( + await provider.getCode(addr).then((code) => code.length) + ).to.equal(2) + await factory.deploy(initCode, 123) + expect( + await provider.getCode(addr).then((code) => code.length) + ).to.gt(100) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/debugTx.ts b/packages/hebao_v3/test/account-abstraction/debugTx.ts new file mode 100644 index 000000000..aed7e6343 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/debugTx.ts @@ -0,0 +1,36 @@ +import { ethers } from 'hardhat' + +export interface DebugLog { + pc: number + op: string + gasCost: number + depth: number + stack: string[] + memory: string[] +} + +export interface DebugTransactionResult { + gas: number + failed: boolean + returnValue: string + structLogs: DebugLog[] +} + +export async function debugTransaction( + txHash: string, + disableMemory = true, + disableStorage = true +): Promise { + const debugTx = async ( + hash: string + ): Promise => + await ethers.provider.send('debug_traceTransaction', [ + hash, + { + disableMemory, + disableStorage + } + ]) + + return await debugTx(txHash) +} diff --git a/packages/hebao_v3/test/account-abstraction/deposit-paymaster.test.ts b/packages/hebao_v3/test/account-abstraction/deposit-paymaster.test.ts new file mode 100644 index 000000000..8960a576c --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/deposit-paymaster.test.ts @@ -0,0 +1,356 @@ +import './aa.init' +import { expect } from 'chai' +import { hexConcat, hexZeroPad, parseEther } from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type DepositPaymaster, + DepositPaymaster__factory, + type EntryPoint, + type SimpleAccount, + type TestCounter, + TestCounter__factory, + TestOracle__factory, + type TestToken, + TestToken__factory +} from '../../typechain-types' + +import { fillAndSign } from './UserOp' +import { + AddressZero, + createAccount, + createAccountOwner, + createAddress, + deployEntryPoint, + FIVE_ETH, + ONE_ETH, + simulationResultCatch, + userOpsWithoutAgg +} from './testutils' + +describe('DepositPaymaster', () => { + let entryPoint: EntryPoint + const ethersSigner = ethers.provider.getSigner() + let token: TestToken + let paymaster: DepositPaymaster + before(async function () { + entryPoint = await deployEntryPoint() + + paymaster = await new DepositPaymaster__factory( + ethersSigner + ).deploy(entryPoint.address) + await paymaster.addStake(1, { value: parseEther('2') }) + await entryPoint.depositTo(paymaster.address, { + value: parseEther('1') + }) + + token = await new TestToken__factory(ethersSigner).deploy() + const testOracle = await new TestOracle__factory( + ethersSigner + ).deploy() + await paymaster.addToken(token.address, testOracle.address) + + await token.mint(await ethersSigner.getAddress(), FIVE_ETH) + await token.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + }) + + describe('deposit', () => { + let account: SimpleAccount + + before(async () => { + ;({ proxy: account } = await createAccount( + ethersSigner, + await ethersSigner.getAddress(), + entryPoint.address + )) + }) + it('should deposit and read balance', async () => { + await paymaster.addDepositFor( + token.address, + account.address, + 100 + ) + expect( + await paymaster.depositInfo(token.address, account.address) + ).to.eql({ amount: 100 }) + }) + it('should fail to withdraw without unlock', async () => { + const paymasterWithdraw = await paymaster.populateTransaction + .withdrawTokensTo(token.address, AddressZero, 1) + .then((tx) => tx.data!) + + await expect( + account.execute(paymaster.address, 0, paymasterWithdraw) + ).to.rejectedWith('DepositPaymaster: must unlockTokenDeposit') + }) + it('should fail to withdraw within the same block ', async () => { + const paymasterUnlock = await paymaster.populateTransaction + .unlockTokenDeposit() + .then((tx) => tx.data!) + const paymasterWithdraw = await paymaster.populateTransaction + .withdrawTokensTo(token.address, AddressZero, 1) + .then((tx) => tx.data!) + + await expect( + account.executeBatch( + [paymaster.address, paymaster.address], + [paymasterUnlock, paymasterWithdraw] + ) + ).to.be.rejectedWith( + 'DepositPaymaster: must unlockTokenDeposit' + ) + }) + it('should succeed to withdraw after unlock', async () => { + const paymasterUnlock = await paymaster.populateTransaction + .unlockTokenDeposit() + .then((tx) => tx.data!) + const target = createAddress() + const paymasterWithdraw = await paymaster.populateTransaction + .withdrawTokensTo(token.address, target, 1) + .then((tx) => tx.data!) + await account.execute(paymaster.address, 0, paymasterUnlock) + await account.execute(paymaster.address, 0, paymasterWithdraw) + expect(await token.balanceOf(target)).to.eq(1) + }) + }) + + describe('#validatePaymasterUserOp', () => { + let account: SimpleAccount + const gasPrice = 1e9 + + before(async () => { + ;({ proxy: account } = await createAccount( + ethersSigner, + await ethersSigner.getAddress(), + entryPoint.address + )) + }) + + it('should fail if no token', async () => { + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: paymaster.address + }, + ethersSigner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp) + ).to.be.rejectedWith('paymasterAndData must specify token') + }) + + it('should fail with wrong token', async () => { + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad('0x1234', 20) + ]) + }, + ethersSigner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp, { gasPrice }) + ).to.be.rejectedWith('DepositPaymaster: unsupported token') + }) + + it('should reject if no deposit', async () => { + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]) + }, + ethersSigner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp, { gasPrice }) + ).to.be.rejectedWith('DepositPaymaster: deposit too low') + }) + + it('should reject if deposit is not locked', async () => { + await paymaster.addDepositFor( + token.address, + account.address, + ONE_ETH + ) + + const paymasterUnlock = await paymaster.populateTransaction + .unlockTokenDeposit() + .then((tx) => tx.data!) + await account.execute(paymaster.address, 0, paymasterUnlock) + + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]) + }, + ethersSigner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp, { gasPrice }) + ).to.be.rejectedWith('not locked') + }) + + it('succeed with valid deposit', async () => { + // needed only if previous test did unlock. + const paymasterLockTokenDeposit = + await paymaster.populateTransaction + .lockTokenDeposit() + .then((tx) => tx.data!) + await account.execute( + paymaster.address, + 0, + paymasterLockTokenDeposit + ) + + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]) + }, + ethersSigner, + entryPoint + ) + await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + }) + }) + describe('#handleOps', () => { + let account: SimpleAccount + const accountOwner = createAccountOwner() + let counter: TestCounter + let callData: string + before(async () => { + ;({ proxy: account } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + )) + counter = await new TestCounter__factory(ethersSigner).deploy() + const counterJustEmit = await counter.populateTransaction + .justemit() + .then((tx) => tx.data!) + callData = await account.populateTransaction + .execute(counter.address, 0, counterJustEmit) + .then((tx) => tx.data!) + + await paymaster.addDepositFor( + token.address, + account.address, + ONE_ETH + ) + }) + it("should pay with deposit (and revert user's call) if user can't pay with tokens", async () => { + const beneficiary = createAddress() + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]), + callData + }, + accountOwner, + entryPoint + ) + + await entryPoint.handleAggregatedOps( + userOpsWithoutAgg([userOp]), + beneficiary + ) + + const [log] = await entryPoint.queryFilter( + entryPoint.filters.UserOperationEvent() + ) + expect(log.args.success).to.eq(false) + expect( + await counter.queryFilter(counter.filters.CalledFrom()) + ).to.eql([]) + expect(await ethers.provider.getBalance(beneficiary)).to.be.gt( + 0 + ) + }) + + it('should pay with tokens if available', async () => { + const beneficiary = createAddress() + const beneficiary1 = createAddress() + const initialTokens = parseEther('1') + await token.mint(account.address, initialTokens) + + // need to "approve" the paymaster to use the tokens. we issue a UserOp for that (which uses the deposit to execute) + const tokenApprovePaymaster = await token.populateTransaction + .approve(paymaster.address, ethers.constants.MaxUint256) + .then((tx) => tx.data!) + const execApprove = await account.populateTransaction + .execute(token.address, 0, tokenApprovePaymaster) + .then((tx) => tx.data!) + const userOp1 = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]), + callData: execApprove + }, + accountOwner, + entryPoint + ) + await entryPoint.handleAggregatedOps( + userOpsWithoutAgg([userOp1]), + beneficiary1 + ) + + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + hexZeroPad(token.address, 20) + ]), + callData + }, + accountOwner, + entryPoint + ) + await entryPoint.handleAggregatedOps( + userOpsWithoutAgg([userOp]), + beneficiary + ) + + const [log] = await entryPoint.queryFilter( + entryPoint.filters.UserOperationEvent(), + await ethers.provider.getBlockNumber() + ) + expect(log.args.success).to.eq(true) + const charge = log.args.actualGasCost + expect(await ethers.provider.getBalance(beneficiary)).to.eq( + charge + ) + + const targetLogs = await counter.queryFilter( + counter.filters.CalledFrom() + ) + expect(targetLogs.length).to.eq(1) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/entrypoint.test.ts b/packages/hebao_v3/test/account-abstraction/entrypoint.test.ts new file mode 100644 index 000000000..09a869a86 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/entrypoint.test.ts @@ -0,0 +1,2220 @@ +import './aa.init' +import { type BytesLike } from '@ethersproject/bytes' +import { expect } from 'chai' +import { toChecksumAddress } from 'ethereumjs-util' +import { BigNumber, type Event, type Wallet } from 'ethers' +import { type PopulatedTransaction } from 'ethers/lib/ethers' +import { + arrayify, + defaultAbiCoder, + hexConcat, + hexZeroPad, + parseEther +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type EntryPoint, + MaliciousAccount__factory, + type SimpleAccount, + type SimpleAccountFactory, + type TestAggregatedAccount, + TestAggregatedAccount__factory, + TestAggregatedAccountFactory__factory, + type TestCounter, + TestCounter__factory, + type TestExpirePaymaster, + TestExpirePaymaster__factory, + type TestExpiryAccount, + TestExpiryAccount__factory, + type TestPaymasterAcceptAll, + TestPaymasterAcceptAll__factory, + TestRevertAccount__factory, + type TestSignatureAggregator, + TestSignatureAggregator__factory, + TestWarmColdAccount__factory +} from '../../typechain-types' + +import { + DefaultsForUserOp, + fillAndSign, + getUserOpHash +} from './UserOp' +import { type UserOperation } from './UserOperation' +import { debugTransaction } from './debugTx' +import { + AddressZero, + calcGasUsage, + checkForBannedOps, + checkForGeth, + createAccount, + createAccountOwner, + createAddress, + decodeRevertReason, + deployEntryPoint, + fund, + getAccountAddress, + getAccountInitCode, + getAggregatedAccountInitCode, + getBalance, + HashZero, + ONE_ETH, + rethrow, + simulationResultCatch, + simulationResultWithAggregationCatch, + tostr, + TWO_ETH +} from './testutils' + +describe('EntryPoint', function () { + let entryPoint: EntryPoint + let simpleAccountFactory: SimpleAccountFactory + + let accountOwner: Wallet + const ethersSigner = ethers.provider.getSigner() + let account: SimpleAccount + + const globalUnstakeDelaySec = 2 + const paymasterStake = ethers.utils.parseEther('2') + + before(async function () { + this.timeout(20000) + await checkForGeth() + + const chainId = await ethers.provider + .getNetwork() + .then((net) => net.chainId) + + entryPoint = await deployEntryPoint() + + accountOwner = createAccountOwner() + ;({ proxy: account, accountFactory: simpleAccountFactory } = + await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + )) + await fund(account) + + // sanity: validate helper functions + const sampleOp = await fillAndSign( + { sender: account.address }, + accountOwner, + entryPoint + ) + expect( + getUserOpHash(sampleOp, entryPoint.address, chainId) + ).to.eql(await entryPoint.getUserOpHash(sampleOp)) + }) + + describe('Stake Management', () => { + let addr: string + before(async () => { + addr = await ethersSigner.getAddress() + }) + + it('should deposit for transfer into EntryPoint', async () => { + const signer2 = ethers.provider.getSigner(2) + await signer2.sendTransaction({ + to: entryPoint.address, + value: ONE_ETH + }) + expect( + await entryPoint.balanceOf(await signer2.getAddress()) + ).to.eql(ONE_ETH) + expect( + await entryPoint.getDepositInfo(await signer2.getAddress()) + ).to.eql({ + deposit: ONE_ETH, + staked: false, + stake: 0, + unstakeDelaySec: 0, + withdrawTime: 0 + }) + }) + + describe('without stake', () => { + it('should fail to stake without value', async () => { + await expect(entryPoint.addStake(2)).to.revertedWith( + 'no stake specified' + ) + }) + it('should fail to stake without delay', async () => { + await expect( + entryPoint.addStake(0, { value: ONE_ETH }) + ).to.revertedWith('must specify unstake delay') + }) + it('should fail to unlock', async () => { + await expect(entryPoint.unlockStake()).to.revertedWith( + 'not staked' + ) + }) + }) + describe('with stake of 2 eth', () => { + before(async () => { + await entryPoint.addStake(2, { value: TWO_ETH }) + }) + it('should report "staked" state', async () => { + const { stake, staked, unstakeDelaySec, withdrawTime } = + await entryPoint.getDepositInfo(addr) + expect({ + stake, + staked, + unstakeDelaySec, + withdrawTime + }).to.eql({ + stake: parseEther('2'), + staked: true, + unstakeDelaySec: 2, + withdrawTime: 0 + }) + }) + + it('should succeed to stake again', async () => { + const { stake } = await entryPoint.getDepositInfo(addr) + await entryPoint.addStake(2, { value: ONE_ETH }) + const { stake: stakeAfter } = + await entryPoint.getDepositInfo(addr) + expect(stakeAfter).to.eq(stake.add(ONE_ETH)) + }) + it('should fail to withdraw before unlock', async () => { + await expect( + entryPoint.withdrawStake(AddressZero) + ).to.revertedWith('must call unlockStake() first') + }) + describe('with unlocked stake', () => { + before(async () => { + await entryPoint.unlockStake() + }) + it('should report as "not staked"', async () => { + expect( + await entryPoint + .getDepositInfo(addr) + .then((info) => info.staked) + ).to.eq(false) + }) + it('should report unstake state', async () => { + const withdrawTime1 = + (await ethers.provider + .getBlock('latest') + .then((block) => block.timestamp)) + + globalUnstakeDelaySec + const { stake, staked, unstakeDelaySec, withdrawTime } = + await entryPoint.getDepositInfo(addr) + expect({ + stake, + staked, + unstakeDelaySec, + withdrawTime + }).to.eql({ + stake: parseEther('3'), + staked: false, + unstakeDelaySec: 2, + withdrawTime: withdrawTime1 + }) + }) + it('should fail to withdraw before unlock timeout', async () => { + await expect( + entryPoint.withdrawStake(AddressZero) + ).to.revertedWith('Stake withdrawal is not due') + }) + it('should fail to unlock again', async () => { + await expect(entryPoint.unlockStake()).to.revertedWith( + 'already unstaking' + ) + }) + describe('after unstake delay', () => { + before(async () => { + // dummy transaction and increase time by 2 seconds + await ethers.provider.send('evm_increaseTime', [2]) + await ethersSigner.sendTransaction({ to: addr }) + }) + it('adding stake should reset "unlockStake"', async () => { + let snap + try { + snap = await ethers.provider.send('evm_snapshot', []) + + await ethersSigner.sendTransaction({ to: addr }) + await entryPoint.addStake(2, { value: ONE_ETH }) + const { stake, staked, unstakeDelaySec, withdrawTime } = + await entryPoint.getDepositInfo(addr) + expect({ + stake, + staked, + unstakeDelaySec, + withdrawTime + }).to.eql({ + stake: parseEther('4'), + staked: true, + unstakeDelaySec: 2, + withdrawTime: 0 + }) + } finally { + await ethers.provider.send('evm_revert', [snap]) + } + }) + + it('should fail to unlock again', async () => { + await expect(entryPoint.unlockStake()).to.revertedWith( + 'already unstaking' + ) + }) + it('should succeed to withdraw', async () => { + const { stake } = await entryPoint.getDepositInfo(addr) + const addr1 = createAddress() + await entryPoint.withdrawStake(addr1) + expect(await ethers.provider.getBalance(addr1)).to.eq( + stake + ) + const { + stake: stakeAfter, + withdrawTime, + unstakeDelaySec + } = await entryPoint.getDepositInfo(addr) + + expect({ + stakeAfter, + withdrawTime, + unstakeDelaySec + }).to.eql({ + stakeAfter: BigNumber.from(0), + unstakeDelaySec: 0, + withdrawTime: 0 + }) + }) + }) + }) + }) + describe('with deposit', () => { + let account: SimpleAccount + before(async () => { + ;({ proxy: account } = await createAccount( + ethersSigner, + await ethersSigner.getAddress(), + entryPoint.address, + simpleAccountFactory + )) + await account.addDeposit({ value: ONE_ETH }) + expect(await getBalance(account.address)).to.equal(0) + expect(await account.getDeposit()).to.eql(ONE_ETH) + }) + it('should be able to withdraw', async () => { + const depositBefore = await account.getDeposit() + await account.withdrawDepositTo(account.address, ONE_ETH) + expect(await getBalance(account.address)).to.equal(1e18) + expect(await account.getDeposit()).to.equal( + depositBefore.sub(ONE_ETH) + ) + }) + }) + }) + + describe('#simulateValidation', () => { + const accountOwner1 = createAccountOwner() + let account1: SimpleAccount + + before(async () => { + ;({ proxy: account1 } = await createAccount( + ethersSigner, + await accountOwner1.getAddress(), + entryPoint.address + )) + }) + + it('should fail if validateUserOp fails', async () => { + // using wrong nonce + const op = await fillAndSign( + { sender: account.address, nonce: 1234 }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op) + ).to.rejectedWith('AA25 invalid account nonce') + }) + + it('should report signature failure without revert', async () => { + // (this is actually a feature of the wallet, not the entrypoint) + // using wrong owner for account1 + // (zero gas price so it doesn't fail on prefund) + const op = await fillAndSign( + { sender: account1.address, maxFeePerGas: 0 }, + accountOwner, + entryPoint + ) + const { returnInfo } = await entryPoint.callStatic + .simulateValidation(op) + .catch(simulationResultCatch) + expect(returnInfo.sigFailed).to.be.true + }) + + it('should revert if wallet not deployed (and no initcode)', async () => { + const op = await fillAndSign( + { + sender: createAddress(), + nonce: 0, + verificationGasLimit: 1000 + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op) + ).to.rejectedWith('AA20 account not deployed') + }) + + it('should revert on oog if not enough verificationGas', async () => { + const op = await fillAndSign( + { sender: account.address, verificationGasLimit: 1000 }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op) + ).to.rejectedWith('AA23 reverted (or OOG)') + }) + + it('should succeed if validateUserOp succeeds', async () => { + const op = await fillAndSign( + { sender: account1.address }, + accountOwner1, + entryPoint + ) + await fund(account1) + await entryPoint.callStatic + .simulateValidation(op) + .catch(simulationResultCatch) + }) + + it('should return empty context if no paymaster', async () => { + const op = await fillAndSign( + { sender: account1.address, maxFeePerGas: 0 }, + accountOwner1, + entryPoint + ) + const { returnInfo } = await entryPoint.callStatic + .simulateValidation(op) + .catch(simulationResultCatch) + expect(returnInfo.paymasterContext).to.eql('0x') + }) + + it('should return stake of sender', async () => { + const stakeValue = BigNumber.from(123) + const unstakeDelay = 3 + const { proxy: account2 } = await createAccount( + ethersSigner, + await ethersSigner.getAddress(), + entryPoint.address + ) + await fund(account2) + await account2.execute( + entryPoint.address, + stakeValue, + entryPoint.interface.encodeFunctionData('addStake', [ + unstakeDelay + ]) + ) + const op = await fillAndSign( + { sender: account2.address }, + ethersSigner, + entryPoint + ) + const result = await entryPoint.callStatic + .simulateValidation(op) + .catch(simulationResultCatch) + expect(result.senderInfo).to.eql({ + stake: stakeValue, + unstakeDelaySec: unstakeDelay + }) + }) + + it('should prevent overflows: fail if any numeric value is more than 120 bits', async () => { + const op = await fillAndSign( + { + preVerificationGas: BigNumber.from(2).pow(130), + sender: account1.address + }, + accountOwner1, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op) + ).to.rejectedWith('gas values overflow') + }) + + it('should fail creation for wrong sender', async () => { + const op1 = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner1.address, + simpleAccountFactory + ), + sender: '0x'.padEnd(42, '1'), + verificationGasLimit: 3e6 + }, + accountOwner1, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op1) + ).to.rejectedWith('AA14 initCode must return sender') + }) + + it('should report failure on insufficient verificationGas (OOG) for creation', async () => { + const initCode = getAccountInitCode( + accountOwner1.address, + simpleAccountFactory + ) + const sender = await entryPoint.callStatic + .getSenderAddress(initCode) + .catch((e) => e.errorArgs.sender) + const op0 = await fillAndSign( + { + initCode, + sender, + verificationGasLimit: 5e5, + maxFeePerGas: 0 + }, + accountOwner1, + entryPoint + ) + // must succeed with enough verification gas. + await expect( + entryPoint.callStatic.simulateValidation(op0, { + gasLimit: 1e6 + }) + ).to.rejectedWith('ValidationResult') + + const op1 = await fillAndSign( + { + initCode, + sender, + verificationGasLimit: 1e5, + maxFeePerGas: 0 + }, + accountOwner1, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op1, { + gasLimit: 1e6 + }) + ).to.rejectedWith('AA13 initCode failed or OOG') + }) + + it('should succeed for creating an account', async () => { + const sender = await getAccountAddress( + accountOwner1.address, + simpleAccountFactory + ) + const op1 = await fillAndSign( + { + sender, + initCode: getAccountInitCode( + accountOwner1.address, + simpleAccountFactory + ) + }, + accountOwner1, + entryPoint + ) + await fund(op1.sender) + + await entryPoint.callStatic + .simulateValidation(op1) + .catch(simulationResultCatch) + }) + + it('should not call initCode from entrypoint', async () => { + // a possible attack: call an account's execFromEntryPoint through initCode. This might lead to stolen funds. + const { proxy: account } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + ) + const sender = createAddress() + const op1 = await fillAndSign( + { + initCode: hexConcat([ + account.address, + account.interface.encodeFunctionData('execute', [ + sender, + 0, + '0x' + ]) + ]), + sender + }, + accountOwner, + entryPoint + ) + const error = await entryPoint.callStatic + .simulateValidation(op1) + .catch((e) => e) + expect(error.message).to.match(/initCode failed or OOG/, error) + }) + + it('should not use banned ops during simulateValidation', async () => { + const op1 = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner1.address, + simpleAccountFactory + ), + sender: await getAccountAddress( + accountOwner1.address, + simpleAccountFactory + ) + }, + accountOwner1, + entryPoint + ) + await fund(op1.sender) + await entryPoint + .simulateValidation(op1, { gasLimit: 10e6 }) + .catch((e) => e) + const block = await ethers.provider.getBlock('latest') + const hash = block.transactions[0] + await checkForBannedOps(hash, false) + }) + }) + + describe('#simulateHandleOp', () => { + it('should simulate execution', async () => { + const accountOwner1 = createAccountOwner() + const { proxy: account } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + ) + await fund(account) + const counter = await new TestCounter__factory( + ethersSigner + ).deploy() + + const count = counter.interface.encodeFunctionData('count') + const callData = account.interface.encodeFunctionData( + 'execute', + [counter.address, 0, count] + ) + // deliberately broken signature.. simulate should work with it too. + const userOp = await fillAndSign( + { + sender: account.address, + callData + }, + accountOwner1, + entryPoint + ) + + const ret = await entryPoint.callStatic + .simulateHandleOp( + userOp, + counter.address, + counter.interface.encodeFunctionData('counters', [ + account.address + ]) + ) + .catch((e) => e.errorArgs) + + const [countResult] = counter.interface.decodeFunctionResult( + 'counters', + ret.targetResult + ) + expect(countResult).to.eql(1) + expect(ret.targetSuccess).to.be.true + + // actual counter is zero + expect(await counter.counters(account.address)).to.eql(0) + }) + }) + + describe('flickering account validation', () => { + it('should prevent leakage of basefee', async () => { + const maliciousAccount = await new MaliciousAccount__factory( + ethersSigner + ).deploy(entryPoint.address, { value: parseEther('1') }) + + const snap = await ethers.provider.send('evm_snapshot', []) + await ethers.provider.send('evm_mine', []) + const block = await ethers.provider.getBlock('latest') + await ethers.provider.send('evm_revert', [snap]) + + if (block.baseFeePerGas == null) { + expect.fail(null, null, 'test error: no basefee') + } + + const userOp: UserOperation = { + sender: maliciousAccount.address, + nonce: await entryPoint.getNonce(maliciousAccount.address, 0), + signature: defaultAbiCoder.encode( + ['uint256'], + [block.baseFeePerGas] + ), + initCode: '0x', + callData: '0x', + callGasLimit: '0x' + (1e5).toString(16), + verificationGasLimit: '0x' + (1e5).toString(16), + preVerificationGas: '0x' + (1e5).toString(16), + // we need maxFeeperGas > block.basefee + maxPriorityFeePerGas so requiredPrefund onchain is basefee + maxPriorityFeePerGas + maxFeePerGas: block.baseFeePerGas.mul(3), + maxPriorityFeePerGas: block.baseFeePerGas, + paymasterAndData: '0x' + } + userOp + // TODO(fix bug) + // try { + // await expect( + // entryPoint.simulateValidation(userOp, { gasLimit: 1e6 }) + // ).to.rejectedWith("ValidationResult"); + // console.log("after first simulation"); + // await ethers.provider.send("evm_mine", []); + // await expect( + // entryPoint.simulateValidation(userOp, { gasLimit: 1e6 }) + // ).to.rejectedWith("Revert after first validation"); + // // if we get here, it means the userOp passed first sim and reverted second + // expect.fail(null, null, "should fail on first simulation"); + // } catch (e: any) { + // expect(e.message).to.include("Revert after first validation"); + // } + }) + + it('should limit revert reason length before emitting it', async () => { + const revertLength = 1e5 + const REVERT_REASON_MAX_LEN = 2048 + const testRevertAccount = await new TestRevertAccount__factory( + ethersSigner + ).deploy(entryPoint.address, { value: parseEther('1') }) + const badData = + await testRevertAccount.populateTransaction.revertLong( + revertLength + 1 + ) + const badOp: UserOperation = { + ...DefaultsForUserOp, + sender: testRevertAccount.address, + callGasLimit: 1e5, + maxFeePerGas: 1, + nonce: await entryPoint.getNonce( + testRevertAccount.address, + 0 + ), + verificationGasLimit: 1e5, + callData: badData.data! + } + const beneficiaryAddress = createAddress() + await expect( + entryPoint.simulateValidation(badOp, { gasLimit: 3e5 }) + ).to.rejectedWith('ValidationResult') + const tx = await entryPoint.handleOps( + [badOp], + beneficiaryAddress + ) // { gasLimit: 3e5 }) + const receipt = await tx.wait() + const userOperationRevertReasonEvent = receipt.events?.find( + (event) => event.event === 'UserOperationRevertReason' + ) + expect(userOperationRevertReasonEvent?.event).to.equal( + 'UserOperationRevertReason' + ) + const revertReason = Buffer.from( + arrayify(userOperationRevertReasonEvent?.args?.revertReason) + ) + expect(revertReason.length).to.equal(REVERT_REASON_MAX_LEN) + }) + describe('warm/cold storage detection in simulation vs execution', () => { + const TOUCH_GET_AGGREGATOR = 1 + const TOUCH_PAYMASTER = 2 + it('should prevent detection through getAggregator()', async () => { + const testWarmColdAccount = + await new TestWarmColdAccount__factory(ethersSigner).deploy( + entryPoint.address, + { value: parseEther('1') } + ) + const badOp: UserOperation = { + ...DefaultsForUserOp, + nonce: TOUCH_GET_AGGREGATOR, + sender: testWarmColdAccount.address + } + const beneficiaryAddress = createAddress() + try { + await entryPoint.simulateValidation(badOp, { + gasLimit: 1e6 + }) + } catch (e: any) { + if ((e as Error).message.includes('ValidationResult')) { + const tx = await entryPoint.handleOps( + [badOp], + beneficiaryAddress, + { + gasLimit: 1e6 + } + ) + await tx.wait() + } else { + expect(e.message).to.include( + 'FailedOp(0, "AA23 reverted (or OOG)")' + ) + } + } + }) + + it('should prevent detection through paymaster.code.length', async () => { + const testWarmColdAccount = + await new TestWarmColdAccount__factory(ethersSigner).deploy( + entryPoint.address, + { value: parseEther('1') } + ) + const paymaster = await new TestPaymasterAcceptAll__factory( + ethersSigner + ).deploy(entryPoint.address) + await paymaster.deposit({ value: ONE_ETH }) + const badOp: UserOperation = { + ...DefaultsForUserOp, + nonce: TOUCH_PAYMASTER, + paymasterAndData: paymaster.address, + sender: testWarmColdAccount.address + } + const beneficiaryAddress = createAddress() + try { + await entryPoint.simulateValidation(badOp, { + gasLimit: 1e6 + }) + } catch (e: any) { + if ((e as Error).message.includes('ValidationResult')) { + const tx = await entryPoint.handleOps( + [badOp], + beneficiaryAddress, + { + gasLimit: 1e6 + } + ) + await tx.wait() + } else { + expect(e.message).to.include( + 'FailedOp(0, "AA23 reverted (or OOG)")' + ) + } + } + }) + }) + }) + + describe('2d nonces', () => { + const beneficiaryAddress = createAddress() + let sender: string + const key = 1 + const keyShifted = BigNumber.from(key).shl(64) + + before(async () => { + const { proxy } = await createAccount( + ethersSigner, + accountOwner.address, + entryPoint.address + ) + sender = proxy.address + await fund(sender) + }) + + it('should fail nonce with new key and seq!=0', async () => { + const op = await fillAndSign( + { + sender, + nonce: keyShifted.add(1) + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress) + ).to.rejectedWith('AA25 invalid account nonce') + }) + + describe('with key=1, seq=1', () => { + before(async () => { + const op = await fillAndSign( + { + sender, + nonce: keyShifted + }, + accountOwner, + entryPoint + ) + await entryPoint.handleOps([op], beneficiaryAddress) + }) + + it('should get next nonce value by getNonce', async () => { + expect(await entryPoint.getNonce(sender, key)).to.eql( + keyShifted.add(1) + ) + }) + + it('should allow to increment nonce of different key', async () => { + const op = await fillAndSign( + { + sender, + nonce: await entryPoint.getNonce(sender, key) + }, + accountOwner, + entryPoint + ) + await entryPoint.callStatic.handleOps( + [op], + beneficiaryAddress + ) + }) + + it('should allow manual nonce increment', async () => { + // must be called from account itself + const incNonceKey = 5 + const incrementCallData = + entryPoint.interface.encodeFunctionData('incrementNonce', [ + incNonceKey + ]) + const callData = account.interface.encodeFunctionData( + 'execute', + [entryPoint.address, 0, incrementCallData] + ) + const op = await fillAndSign( + { + sender, + callData, + nonce: await entryPoint.getNonce(sender, key) + }, + accountOwner, + entryPoint + ) + await entryPoint.handleOps([op], beneficiaryAddress) + + expect( + await entryPoint.getNonce(sender, incNonceKey) + ).to.equal(BigNumber.from(incNonceKey).shl(64).add(1)) + }) + it('should fail with nonsequential seq', async () => { + const op = await fillAndSign( + { + sender, + nonce: keyShifted.add(3) + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress) + ).to.rejectedWith('AA25 invalid account nonce') + }) + }) + }) + + describe('without paymaster (account pays in eth)', () => { + describe('#handleOps', () => { + let counter: TestCounter + let accountExecFromEntryPoint: PopulatedTransaction + before(async () => { + counter = await new TestCounter__factory( + ethersSigner + ).deploy() + const count = await counter.populateTransaction.count() + accountExecFromEntryPoint = + await account.populateTransaction.execute( + counter.address, + 0, + count.data! + ) + }) + + it('should revert on signature failure', async () => { + // wallet-reported signature failure should revert in handleOps + const wrongOwner = createAccountOwner() + const op = await fillAndSign( + { + sender: account.address + }, + wrongOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + await expect( + entryPoint.estimateGas.handleOps([op], beneficiaryAddress) + ).to.rejectedWith('AA24 signature error') + }) + + it('account should pay for tx', async function () { + const op = await fillAndSign( + { + sender: account.address, + callData: accountExecFromEntryPoint.data, + verificationGasLimit: 1e6, + callGasLimit: 1e6 + }, + accountOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + const countBefore = await counter.counters(account.address) + // for estimateGas, must specify maxFeePerGas, otherwise our gas check fails + console.log( + ' == est gas=', + await entryPoint.estimateGas + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9 + }) + .then(tostr) + ) + + // must specify at least on of maxFeePerGas, gasLimit + // (gasLimit, to prevent estimateGas to fail on missing maxFeePerGas, see above..) + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 1e7 + }) + .then(async (t) => await t.wait()) + + const countAfter = await counter.counters(account.address) + expect(countAfter.toNumber()).to.equal( + countBefore.toNumber() + 1 + ) + console.log( + 'rcpt.gasUsed=', + rcpt.gasUsed.toString(), + rcpt.transactionHash + ) + + await calcGasUsage(rcpt, entryPoint, beneficiaryAddress) + }) + + it('account should pay for high gas usage tx', async function () { + if (process.env.COVERAGE != null) { + return + } + const iterations = 45 + const count = await counter.populateTransaction.gasWaster( + iterations, + '' + ) + const accountExec = await account.populateTransaction.execute( + counter.address, + 0, + count.data! + ) + const op = await fillAndSign( + { + sender: account.address, + callData: accountExec.data, + verificationGasLimit: 1e5, + callGasLimit: 11e5 + }, + accountOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + const offsetBefore = await counter.offset() + console.log(' == offset before', offsetBefore) + // for estimateGas, must specify maxFeePerGas, otherwise our gas check fails + console.log( + ' == est gas=', + await entryPoint.estimateGas + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9 + }) + .then(tostr) + ) + + // must specify at least on of maxFeePerGas, gasLimit + // (gasLimit, to prevent estimateGas to fail on missing maxFeePerGas, see above..) + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 13e5 + }) + .then(async (t) => await t.wait()) + + console.log( + 'rcpt.gasUsed=', + rcpt.gasUsed.toString(), + rcpt.transactionHash + ) + await calcGasUsage(rcpt, entryPoint, beneficiaryAddress) + + // check that the state of the counter contract is updated + // this ensures that the `callGasLimit` is high enough + // therefore this value can be used as a reference in the test below + console.log(' == offset after', await counter.offset()) + expect(await counter.offset()).to.equal( + offsetBefore.add(iterations) + ) + }) + + it('account should not pay if too low gas limit was set', async function () { + const iterations = 45 + const count = await counter.populateTransaction.gasWaster( + iterations, + '' + ) + const accountExec = await account.populateTransaction.execute( + counter.address, + 0, + count.data! + ) + const op = await fillAndSign( + { + sender: account.address, + callData: accountExec.data, + verificationGasLimit: 1e5, + callGasLimit: 11e5 + }, + accountOwner, + entryPoint + ) + const inititalAccountBalance = await getBalance( + account.address + ) + const beneficiaryAddress = createAddress() + const offsetBefore = await counter.offset() + console.log(' == offset before', offsetBefore) + // for estimateGas, must specify maxFeePerGas, otherwise our gas check fails + console.log( + ' == est gas=', + await entryPoint.estimateGas + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9 + }) + .then(tostr) + ) + + // must specify at least on of maxFeePerGas, gasLimit + // (gasLimit, to prevent estimateGas to fail on missing maxFeePerGas, see above..) + // this transaction should revert as the gasLimit is too low to satisfy the expected `callGasLimit` (see test above) + await expect( + entryPoint.handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 12e5 + }) + ).to.rejectedWith('AA95 out of gas') + + // Make sure that the user did not pay for the transaction + expect(await getBalance(account.address)).to.eq( + inititalAccountBalance + ) + }) + + it('legacy mode (maxPriorityFee==maxFeePerGas) should not use "basefee" opcode', async function () { + const op = await fillAndSign( + { + sender: account.address, + callData: accountExecFromEntryPoint.data, + maxPriorityFeePerGas: 10e9, + maxFeePerGas: 10e9, + verificationGasLimit: 1e6, + callGasLimit: 1e6 + }, + accountOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + + // (gasLimit, to prevent estimateGas to fail on missing maxFeePerGas, see above..) + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 1e7 + }) + .then(async (t) => await t.wait()) + + const ops = await debugTransaction(rcpt.transactionHash).then( + (tx) => tx.structLogs.map((op) => op.op) + ) + expect(ops).to.include('GAS') + expect(ops).to.not.include('BASEFEE') + }) + + it('if account has a deposit, it should use it to pay', async function () { + await account.addDeposit({ value: ONE_ETH }) + const op = await fillAndSign( + { + sender: account.address, + callData: accountExecFromEntryPoint.data, + verificationGasLimit: 1e6, + callGasLimit: 1e6 + }, + accountOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + + const countBefore = await counter.counters(account.address) + // for estimateGas, must specify maxFeePerGas, otherwise our gas check fails + console.log( + ' == est gas=', + await entryPoint.estimateGas + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9 + }) + .then(tostr) + ) + + const balBefore = await getBalance(account.address) + const depositBefore = await entryPoint.balanceOf( + account.address + ) + // must specify at least one of maxFeePerGas, gasLimit + // (gasLimit, to prevent estimateGas to fail on missing maxFeePerGas, see above..) + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 1e7 + }) + .then(async (t) => await t.wait()) + + const countAfter = await counter.counters(account.address) + expect(countAfter.toNumber()).to.equal( + countBefore.toNumber() + 1 + ) + console.log( + 'rcpt.gasUsed=', + rcpt.gasUsed.toString(), + rcpt.transactionHash + ) + + const balAfter = await getBalance(account.address) + const depositAfter = await entryPoint.balanceOf( + account.address + ) + expect(balAfter).to.equal( + balBefore, + 'should pay from stake, not balance' + ) + const depositUsed = depositBefore.sub(depositAfter) + expect( + await ethers.provider.getBalance(beneficiaryAddress) + ).to.equal(depositUsed) + + await calcGasUsage(rcpt, entryPoint, beneficiaryAddress) + }) + + it('should pay for reverted tx', async () => { + const op = await fillAndSign( + { + sender: account.address, + callData: '0xdeadface', + verificationGasLimit: 1e6, + callGasLimit: 1e6 + }, + accountOwner, + entryPoint + ) + const beneficiaryAddress = createAddress() + + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + maxFeePerGas: 1e9, + gasLimit: 1e7 + }) + .then(async (t) => await t.wait()) + + const [log] = await entryPoint.queryFilter( + entryPoint.filters.UserOperationEvent(), + rcpt.blockHash + ) + expect(log.args.success).to.eq(false) + expect(await getBalance(beneficiaryAddress)).to.be.gte(1) + }) + + it('#handleOp (single)', async () => { + const beneficiaryAddress = createAddress() + + const op = await fillAndSign( + { + sender: account.address, + callData: accountExecFromEntryPoint.data + }, + accountOwner, + entryPoint + ) + + const countBefore = await counter.counters(account.address) + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + .then(async (t) => await t.wait()) + const countAfter = await counter.counters(account.address) + expect(countAfter.toNumber()).to.equal( + countBefore.toNumber() + 1 + ) + + console.log( + 'rcpt.gasUsed=', + rcpt.gasUsed.toString(), + rcpt.transactionHash + ) + await calcGasUsage(rcpt, entryPoint, beneficiaryAddress) + }) + + it('should fail to call recursively into handleOps', async () => { + const beneficiaryAddress = createAddress() + + const callHandleOps = entryPoint.interface.encodeFunctionData( + 'handleOps', + [[], beneficiaryAddress] + ) + const execHandlePost = account.interface.encodeFunctionData( + 'execute', + [entryPoint.address, 0, callHandleOps] + ) + const op = await fillAndSign( + { + sender: account.address, + callData: execHandlePost + }, + accountOwner, + entryPoint + ) + + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + .then(async (r) => r.wait()) + + const error = rcpt.events?.find( + (ev) => ev.event === 'UserOperationRevertReason' + ) + expect(decodeRevertReason(error?.args?.revertReason)).to.eql( + 'Error(ReentrancyGuard: reentrant call)', + 'execution of handleOps inside a UserOp should revert' + ) + }) + it('should report failure on insufficient verificationGas after creation', async () => { + const op0 = await fillAndSign( + { + sender: account.address, + verificationGasLimit: 5e5 + }, + accountOwner, + entryPoint + ) + // must succeed with enough verification gas + await expect( + entryPoint.callStatic.simulateValidation(op0) + ).to.rejectedWith('ValidationResult') + + const op1 = await fillAndSign( + { + sender: account.address, + verificationGasLimit: 10000 + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op1) + ).to.rejectedWith('AA23 reverted (or OOG)') + }) + }) + + describe('create account', () => { + if (process.env.COVERAGE != null) { + return + } + let createOp: UserOperation + const beneficiaryAddress = createAddress() // 1 + + it('should reject create if sender address is wrong', async () => { + const op = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner.address, + simpleAccountFactory + ), + verificationGasLimit: 2e6, + sender: '0x'.padEnd(42, '1') + }, + accountOwner, + entryPoint + ) + + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + ).to.rejectedWith('AA14 initCode must return sender') + }) + + it('should reject create if account not funded', async () => { + const op = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner.address, + simpleAccountFactory, + 100 + ), + verificationGasLimit: 2e6 + }, + accountOwner, + entryPoint + ) + + expect(await ethers.provider.getBalance(op.sender)).to.eq(0) + + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress, { + gasLimit: 1e7, + gasPrice: await ethers.provider.getGasPrice() + }) + ).to.rejectedWith("didn't pay prefund") + + // await expect(await ethers.provider.getCode(op.sender).then(x => x.length)).to.equal(2, "account exists before creation") + }) + + it('should succeed to create account after prefund', async () => { + const salt = 20 + const preAddr = await getAccountAddress( + accountOwner.address, + simpleAccountFactory, + salt + ) + await fund(preAddr) + createOp = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner.address, + simpleAccountFactory, + salt + ), + callGasLimit: 1e6, + verificationGasLimit: 2e6 + }, + accountOwner, + entryPoint + ) + + expect( + await ethers.provider.getCode(preAddr).then((x) => x.length) + ).to.equal(2, 'account exists before creation') + const ret = await entryPoint.handleOps( + [createOp], + beneficiaryAddress, + { + gasLimit: 1e7 + } + ) + const rcpt = await ret.wait() + const hash = await entryPoint.getUserOpHash(createOp) + await expect(ret) + .to.emit(entryPoint, 'AccountDeployed') + + .withArgs( + hash, + createOp.sender, + toChecksumAddress( + ethers.utils.hexlify(createOp.initCode).slice(0, 42) + ), + AddressZero + ) + + await calcGasUsage(rcpt!, entryPoint, beneficiaryAddress) + }) + + it('should reject if account already created', async function () { + const preAddr = await getAccountAddress( + accountOwner.address, + simpleAccountFactory + ) + if ( + (await ethers.provider + .getCode(preAddr) + .then((x) => x.length)) === 2 + ) { + this.skip() + } + + await expect( + entryPoint.callStatic.handleOps( + [createOp], + beneficiaryAddress, + { + gasLimit: 1e7 + } + ) + ).to.rejectedWith('sender already constructed') + }) + }) + + describe('batch multiple requests', function () { + this.timeout(20000) + if (process.env.COVERAGE != null) { + return + } + /** + * attempt a batch: + * 1. create account1 + "initialize" (by calling counter.count()) + * 2. account2.exec(counter.count() + * (account created in advance) + */ + let counter: TestCounter + let accountExecCounterFromEntryPoint: PopulatedTransaction + const beneficiaryAddress = createAddress() + const accountOwner1 = createAccountOwner() + let account1: string + const accountOwner2 = createAccountOwner() + let account2: SimpleAccount + + before('before', async () => { + counter = await new TestCounter__factory( + ethersSigner + ).deploy() + const count = await counter.populateTransaction.count() + accountExecCounterFromEntryPoint = + await account.populateTransaction.execute( + counter.address, + 0, + count.data! + ) + account1 = await getAccountAddress( + accountOwner1.address, + simpleAccountFactory + ) + ;({ proxy: account2 } = await createAccount( + ethersSigner, + await accountOwner2.getAddress(), + entryPoint.address + )) + await fund(account1) + await fund(account2.address) + // execute and increment counter + const op1 = await fillAndSign( + { + initCode: getAccountInitCode( + accountOwner1.address, + simpleAccountFactory + ), + callData: accountExecCounterFromEntryPoint.data, + callGasLimit: 2e6, + verificationGasLimit: 2e6 + }, + accountOwner1, + entryPoint + ) + + const op2 = await fillAndSign( + { + callData: accountExecCounterFromEntryPoint.data, + sender: account2.address, + callGasLimit: 2e6, + verificationGasLimit: 76000 + }, + accountOwner2, + entryPoint + ) + + await entryPoint.callStatic + .simulateValidation(op2, { gasPrice: 1e9 }) + .catch(simulationResultCatch) + + await fund(op1.sender) + await fund(account2.address) + await entryPoint + .handleOps([op1!, op2], beneficiaryAddress) + .catch(rethrow()) + .then(async (r) => r!.wait()) + // console.log(ret.events!.map(e=>({ev:e.event, ...objdump(e.args!)}))) + }) + it('should execute', async () => { + expect(await counter.counters(account1)).equal(1) + expect(await counter.counters(account2.address)).equal(1) + }) + it('should pay for tx', async () => { + // const cost1 = prebalance1.sub(await ethers.provider.getBalance(account1)) + // const cost2 = prebalance2.sub(await ethers.provider.getBalance(account2.address)) + // console.log('cost1=', cost1) + // console.log('cost2=', cost2) + }) + }) + + describe('aggregation tests', () => { + const beneficiaryAddress = createAddress() + let aggregator: TestSignatureAggregator + let aggAccount: TestAggregatedAccount + let aggAccount2: TestAggregatedAccount + + before(async () => { + aggregator = await new TestSignatureAggregator__factory( + ethersSigner + ).deploy() + aggAccount = await new TestAggregatedAccount__factory( + ethersSigner + ).deploy(entryPoint.address, aggregator.address) + aggAccount2 = await new TestAggregatedAccount__factory( + ethersSigner + ).deploy(entryPoint.address, aggregator.address) + await ethersSigner.sendTransaction({ + to: aggAccount.address, + value: parseEther('0.1') + }) + await ethersSigner.sendTransaction({ + to: aggAccount2.address, + value: parseEther('0.1') + }) + }) + it('should fail to execute aggregated account without an aggregator', async () => { + const userOp = await fillAndSign( + { + sender: aggAccount.address + }, + accountOwner, + entryPoint + ) + + // no aggregator is kind of "wrong aggregator" + await expect( + entryPoint.handleOps([userOp], beneficiaryAddress) + ).to.rejectedWith('AA24 signature error') + }) + it('should fail to execute aggregated account with wrong aggregator', async () => { + const userOp = await fillAndSign( + { + sender: aggAccount.address + }, + accountOwner, + entryPoint + ) + + const wrongAggregator = + await new TestSignatureAggregator__factory( + ethersSigner + ).deploy() + const sig = HashZero + + await expect( + entryPoint.handleAggregatedOps( + [ + { + userOps: [userOp], + aggregator: wrongAggregator.address, + signature: sig + } + ], + beneficiaryAddress + ) + ).to.rejectedWith('AA24 signature error') + }) + + it('should reject non-contract (address(1)) aggregator', async () => { + // this is just sanity check that the compiler indeed reverts on a call to "validateSignatures()" to nonexistent contracts + const address1 = hexZeroPad('0x1', 20) + const aggAccount1 = await new TestAggregatedAccount__factory( + ethersSigner + ).deploy(entryPoint.address, address1) + + const userOp = await fillAndSign( + { + sender: aggAccount1.address, + maxFeePerGas: 0 + }, + accountOwner, + entryPoint + ) + + const sig = HashZero + + expect( + await entryPoint + .handleAggregatedOps( + [ + { + userOps: [userOp], + aggregator: address1, + signature: sig + } + ], + beneficiaryAddress + ) + .catch((e) => e.reason) + ).to.match(/invalid aggregator/) + // (different error in coverage mode (because of different solidity settings) + }) + + it('should fail to execute aggregated account with wrong agg. signature', async () => { + const userOp = await fillAndSign( + { + sender: aggAccount.address + }, + accountOwner, + entryPoint + ) + + const wrongSig = hexZeroPad('0x123456', 32) + const aggAddress: string = aggregator.address + await expect( + entryPoint.handleAggregatedOps( + [ + { + userOps: [userOp], + aggregator: aggregator.address, + signature: wrongSig + } + ], + beneficiaryAddress + ) + ) + .to.revertedWithCustomError( + entryPoint, + 'SignatureValidationFailed' + ) + .withArgs(aggAddress) + }) + + it('should run with multiple aggregators (and non-aggregated-accounts)', async () => { + const aggregator3 = + await new TestSignatureAggregator__factory( + ethersSigner + ).deploy() + const aggAccount3 = await new TestAggregatedAccount__factory( + ethersSigner + ).deploy(entryPoint.address, aggregator3.address) + await ethersSigner.sendTransaction({ + to: aggAccount3.address, + value: parseEther('0.1') + }) + + const userOp1 = await fillAndSign( + { + sender: aggAccount.address + }, + accountOwner, + entryPoint + ) + const userOp2 = await fillAndSign( + { + sender: aggAccount2.address + }, + accountOwner, + entryPoint + ) + const userOp_agg3 = await fillAndSign( + { + sender: aggAccount3.address + }, + accountOwner, + entryPoint + ) + const userOp_noAgg = await fillAndSign( + { + sender: account.address + }, + accountOwner, + entryPoint + ) + + // extract signature from userOps, and create aggregated signature + // (not really required with the test aggregator, but should work with any aggregator + const sigOp1 = + await aggregator.validateUserOpSignature(userOp1) + const sigOp2 = + await aggregator.validateUserOpSignature(userOp2) + userOp1.signature = sigOp1 + userOp2.signature = sigOp2 + const aggSig = await aggregator.aggregateSignatures([ + userOp1, + userOp2 + ]) + + const aggInfos = [ + { + userOps: [userOp1, userOp2], + aggregator: aggregator.address, + signature: aggSig + }, + { + userOps: [userOp_agg3], + aggregator: aggregator3.address, + signature: HashZero + }, + { + userOps: [userOp_noAgg], + aggregator: AddressZero, + signature: '0x' + } + ] + const rcpt = await entryPoint + .handleAggregatedOps(aggInfos, beneficiaryAddress, { + gasLimit: 3e6 + }) + .then(async (ret) => ret.wait()) + const events = rcpt.events + ?.map((ev: Event) => { + if (ev.event === 'UserOperationEvent') { + return `userOp(${ev.args?.sender as string})` + } + if (ev.event === 'SignatureAggregatorChanged') { + return `agg(${ev.args?.aggregator as string})` + } else return null + }) + .filter((ev) => ev != null) + // expected "SignatureAggregatorChanged" before every switch of aggregator + expect(events).to.eql([ + `agg(${aggregator.address})`, + `userOp(${userOp1.sender})`, + `userOp(${userOp2.sender})`, + `agg(${aggregator3.address})`, + `userOp(${userOp_agg3.sender})`, + `agg(${AddressZero})`, + `userOp(${userOp_noAgg.sender})`, + `agg(${AddressZero})` + ]) + }) + + describe('execution ordering', () => { + let userOp1: UserOperation + let userOp2: UserOperation + before(async () => { + userOp1 = await fillAndSign( + { + sender: aggAccount.address + }, + accountOwner, + entryPoint + ) + userOp2 = await fillAndSign( + { + sender: aggAccount2.address + }, + accountOwner, + entryPoint + ) + userOp1.signature = '0x' + userOp2.signature = '0x' + }) + + context('create account', () => { + let initCode: BytesLike + let addr: string + let userOp: UserOperation + before(async () => { + const factory = + await new TestAggregatedAccountFactory__factory( + ethersSigner + ).deploy(entryPoint.address, aggregator.address) + initCode = await getAggregatedAccountInitCode( + entryPoint.address, + factory + ) + addr = await entryPoint.callStatic + .getSenderAddress(initCode) + .catch((e) => e.errorArgs.sender) + await ethersSigner.sendTransaction({ + to: addr, + value: parseEther('0.1') + }) + userOp = await fillAndSign( + { + initCode + }, + accountOwner, + entryPoint + ) + }) + it('simulateValidation should return aggregator and its stake', async () => { + await aggregator.addStake(entryPoint.address, 3, { + value: TWO_ETH + }) + const { aggregatorInfo } = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultWithAggregationCatch) + expect(aggregatorInfo.aggregator).to.equal( + aggregator.address + ) + expect(aggregatorInfo.stakeInfo.stake).to.equal(TWO_ETH) + expect(aggregatorInfo.stakeInfo.unstakeDelaySec).to.equal( + 3 + ) + }) + it('should create account in handleOps', async () => { + await aggregator.validateUserOpSignature(userOp) + const sig = await aggregator.aggregateSignatures([userOp]) + await entryPoint.handleAggregatedOps( + [ + { + userOps: [{ ...userOp, signature: '0x' }], + aggregator: aggregator.address, + signature: sig + } + ], + beneficiaryAddress, + { gasLimit: 3e6 } + ) + }) + }) + }) + }) + + describe('with paymaster (account with no eth)', () => { + let paymaster: TestPaymasterAcceptAll + let counter: TestCounter + let accountExecFromEntryPoint: PopulatedTransaction + const account2Owner = createAccountOwner() + + before(async () => { + paymaster = await new TestPaymasterAcceptAll__factory( + ethersSigner + ).deploy(entryPoint.address) + await paymaster.addStake(globalUnstakeDelaySec, { + value: paymasterStake + }) + counter = await new TestCounter__factory( + ethersSigner + ).deploy() + const count = await counter.populateTransaction.count() + accountExecFromEntryPoint = + await account.populateTransaction.execute( + counter.address, + 0, + count.data! + ) + }) + + it('should fail with nonexistent paymaster', async () => { + const pm = createAddress() + const op = await fillAndSign( + { + paymasterAndData: pm, + callData: accountExecFromEntryPoint.data, + initCode: getAccountInitCode( + account2Owner.address, + simpleAccountFactory + ), + verificationGasLimit: 3e6, + callGasLimit: 1e6 + }, + account2Owner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(op) + ).to.rejectedWith('"AA30 paymaster not deployed"') + }) + + it('should fail if paymaster has no deposit', async function () { + const op = await fillAndSign( + { + paymasterAndData: paymaster.address, + callData: accountExecFromEntryPoint.data, + initCode: getAccountInitCode( + account2Owner.address, + simpleAccountFactory + ), + + verificationGasLimit: 3e6, + callGasLimit: 1e6 + }, + account2Owner, + entryPoint + ) + const beneficiaryAddress = createAddress() + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress) + ).to.rejectedWith('"AA31 paymaster deposit too low"') + }) + + it('paymaster should pay for tx', async function () { + await paymaster.deposit({ value: ONE_ETH }) + const op = await fillAndSign( + { + paymasterAndData: paymaster.address, + callData: accountExecFromEntryPoint.data, + initCode: getAccountInitCode( + account2Owner.address, + simpleAccountFactory + ) + }, + account2Owner, + entryPoint + ) + const beneficiaryAddress = createAddress() + + const rcpt = await entryPoint + .handleOps([op], beneficiaryAddress) + .then(async (t) => t.wait()) + + const { actualGasCost } = await calcGasUsage( + rcpt, + entryPoint, + beneficiaryAddress + ) + const paymasterPaid = ONE_ETH.sub( + await entryPoint.balanceOf(paymaster.address) + ) + expect(paymasterPaid).to.eql(actualGasCost) + }) + it('simulateValidation should return paymaster stake and delay', async () => { + await paymaster.deposit({ value: ONE_ETH }) + const anOwner = createAccountOwner() + + const op = await fillAndSign( + { + paymasterAndData: paymaster.address, + callData: accountExecFromEntryPoint.data, + initCode: getAccountInitCode( + anOwner.address, + simpleAccountFactory + ) + }, + anOwner, + entryPoint + ) + + const { paymasterInfo } = await entryPoint.callStatic + .simulateValidation(op) + .catch(simulationResultCatch) + const { stake: simRetStake, unstakeDelaySec: simRetDelay } = + paymasterInfo + + expect(simRetStake).to.eql(paymasterStake) + expect(simRetDelay).to.eql(globalUnstakeDelaySec) + }) + }) + + describe('Validation time-range', () => { + const beneficiary = createAddress() + let account: TestExpiryAccount + let now: number + let sessionOwner: Wallet + before('init account with session key', async () => { + // create a test account. The primary owner is the global ethersSigner, so that we can easily add a temporaryOwner, below + account = await new TestExpiryAccount__factory( + ethersSigner + ).deploy(entryPoint.address) + await account.initialize(await ethersSigner.getAddress()) + await ethersSigner.sendTransaction({ + to: account.address, + value: parseEther('0.1') + }) + now = await ethers.provider + .getBlock('latest') + .then((block) => block.timestamp) + sessionOwner = createAccountOwner() + await account.addTemporaryOwner( + sessionOwner.address, + 100, + now + 60 + ) + }) + + describe('validateUserOp time-range', function () { + it('should accept non-expired owner', async () => { + const userOp = await fillAndSign( + { + sender: account.address + }, + sessionOwner, + entryPoint + ) + const ret = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + expect(ret.returnInfo.validUntil).to.eql(now + 60) + expect(ret.returnInfo.validAfter).to.eql(100) + }) + + it('should not reject expired owner', async () => { + const expiredOwner = createAccountOwner() + await account.addTemporaryOwner( + expiredOwner.address, + 123, + now - 60 + ) + const userOp = await fillAndSign( + { + sender: account.address + }, + expiredOwner, + entryPoint + ) + const ret = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + expect(ret.returnInfo.validUntil).eql(now - 60) + expect(ret.returnInfo.validAfter).to.eql(123) + }) + }) + + describe('validatePaymasterUserOp with deadline', function () { + let paymaster: TestExpirePaymaster + let now: number + before('init account with session key', async function () { + this.timeout(20000) + paymaster = await new TestExpirePaymaster__factory( + ethersSigner + ).deploy(entryPoint.address) + await paymaster.addStake(1, { value: paymasterStake }) + await paymaster.deposit({ value: parseEther('0.1') }) + now = await ethers.provider + .getBlock('latest') + .then((block) => block.timestamp) + }) + + it('should accept non-expired paymaster request', async () => { + const timeRange = defaultAbiCoder.encode( + ['uint48', 'uint48'], + [123, now + 60] + ) + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + timeRange + ]) + }, + ethersSigner, + entryPoint + ) + const ret = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + expect(ret.returnInfo.validUntil).to.eql(now + 60) + expect(ret.returnInfo.validAfter).to.eql(123) + }) + + it('should not reject expired paymaster request', async () => { + const timeRange = defaultAbiCoder.encode( + ['uint48', 'uint48'], + [321, now - 60] + ) + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + timeRange + ]) + }, + ethersSigner, + entryPoint + ) + const ret = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + expect(ret.returnInfo.validUntil).to.eql(now - 60) + expect(ret.returnInfo.validAfter).to.eql(321) + }) + + // helper method + async function createOpWithPaymasterParams( + owner: Wallet, + after: number, + until: number + ): Promise { + const timeRange = defaultAbiCoder.encode( + ['uint48', 'uint48'], + [after, until] + ) + return await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + timeRange + ]) + }, + owner, + entryPoint + ) + } + + describe('time-range overlap of paymaster and account should intersect', () => { + let owner: Wallet + before(async () => { + owner = createAccountOwner() + await account.addTemporaryOwner(owner.address, 100, 500) + }) + + async function simulateWithPaymasterParams( + after: number, + until: number + ): Promise { + const userOp = await createOpWithPaymasterParams( + owner, + after, + until + ) + const ret = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + return ret.returnInfo + } + + // sessionOwner has a range of 100.. now+60 + it('should use lower "after" value of paymaster', async () => { + expect( + (await simulateWithPaymasterParams(10, 1000)).validAfter + ).to.eql(100) + }) + it('should use lower "after" value of account', async () => { + expect( + (await simulateWithPaymasterParams(200, 1000)) + .validAfter + ).to.eql(200) + }) + it('should use higher "until" value of paymaster', async () => { + expect( + (await simulateWithPaymasterParams(10, 400)).validUntil + ).to.eql(400) + }) + it('should use higher "until" value of account', async () => { + expect( + (await simulateWithPaymasterParams(200, 600)).validUntil + ).to.eql(500) + }) + + it('handleOps should revert on expired paymaster request', async () => { + const userOp = await createOpWithPaymasterParams( + sessionOwner, + now + 100, + now + 200 + ) + await expect( + entryPoint.handleOps([userOp], beneficiary) + ).to.rejectedWith('AA32 paymaster expired or not due') + }) + }) + }) + describe('handleOps should abort on time-range', () => { + it('should revert on expired account', async () => { + const expiredOwner = createAccountOwner() + await account.addTemporaryOwner(expiredOwner.address, 1, 2) + const userOp = await fillAndSign( + { + sender: account.address + }, + expiredOwner, + entryPoint + ) + await expect( + entryPoint.handleOps([userOp], beneficiary) + ).to.rejectedWith('AA22 expired or not due') + }) + + it('should revert on date owner', async () => { + const futureOwner = createAccountOwner() + await account.addTemporaryOwner( + futureOwner.address, + now + 100, + now + 200 + ) + const userOp = await fillAndSign( + { + sender: account.address + }, + futureOwner, + entryPoint + ) + await expect( + entryPoint.handleOps([userOp], beneficiary) + ).to.rejectedWith('AA22 expired or not due') + }) + }) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/gnosis.test.ts b/packages/hebao_v3/test/account-abstraction/gnosis.test.ts new file mode 100644 index 000000000..6306f40a9 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/gnosis.test.ts @@ -0,0 +1,447 @@ +import './aa.init' +import { expect } from 'chai' +import { type Signer } from 'ethers' +import { + defaultAbiCoder, + hexConcat, + hexZeroPad, + parseEther +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + EIP4337Fallback__factory, + type EIP4337Manager, + EIP4337Manager__factory, + type EntryPoint, + EntryPoint__factory, + type GnosisSafe, + GnosisSafe__factory, + type GnosisSafeAccountFactory, + GnosisSafeAccountFactory__factory, + type GnosisSafeProxy, + GnosisSafeProxyFactory__factory, + type TestCounter, + TestCounter__factory +} from '../../typechain-types' + +import { fillAndSign } from './UserOp' +import { + AddressZero, + createAccountOwner, + createAddress, + deployEntryPoint, + getBalance, + HashZero, + isDeployed +} from './testutils' + +describe('Gnosis Proxy', function () { + this.timeout(30000) + + let ethersSigner: Signer + let safeSingleton: GnosisSafe + let owner: Signer + let ownerAddress: string + let proxy: GnosisSafeProxy + let manager: EIP4337Manager + let entryPoint: EntryPoint + let counter: TestCounter + let proxySafe: GnosisSafe + let safe_execTxCallData: string + + let accountFactory: GnosisSafeAccountFactory + + before('before', async function () { + // EIP4337Manager fails to compile with solc-coverage + if (process.env.COVERAGE != null) { + return this.skip() + } + + const provider = ethers.provider + ethersSigner = provider.getSigner() + + // standard safe singleton contract (implementation) + safeSingleton = await new GnosisSafe__factory( + ethersSigner + ).deploy() + // standard safe proxy factory + const proxyFactory = await new GnosisSafeProxyFactory__factory( + ethersSigner + ).deploy() + entryPoint = await deployEntryPoint() + manager = await new EIP4337Manager__factory(ethersSigner).deploy( + entryPoint.address + ) + owner = createAccountOwner() + ownerAddress = await owner.getAddress() + counter = await new TestCounter__factory(ethersSigner).deploy() + + accountFactory = await new GnosisSafeAccountFactory__factory( + ethersSigner + ).deploy( + proxyFactory.address, + safeSingleton.address, + manager.address + ) + + await accountFactory.createAccount(ownerAddress, 0) + // we use our accountFactory to create and configure the proxy. + // but the actual deployment is done internally by the gnosis factory + const ev = await proxyFactory.queryFilter( + proxyFactory.filters.ProxyCreation() + ) + const addr = ev[0].args.proxy + + proxy = proxySafe = GnosisSafe__factory.connect(addr, owner) + + await ethersSigner.sendTransaction({ + to: proxy.address, + value: parseEther('0.1') + }) + + const counter_countCallData = + counter.interface.encodeFunctionData('count') + safe_execTxCallData = manager.interface.encodeFunctionData( + 'executeAndRevert', + [counter.address, 0, counter_countCallData, 0] + ) + }) + let beneficiary: string + beforeEach(() => { + beneficiary = createAddress() + }) + + it('#getCurrentEIP4337Manager', async () => { + // need some manager to query the current manager of a safe + const tempManager = await new EIP4337Manager__factory( + ethersSigner + ).deploy(AddressZero) + const { manager: curManager } = + await tempManager.getCurrentEIP4337Manager(proxySafe.address) + expect(curManager).to.eq(manager.address) + }) + + it('should validate', async function () { + await manager.callStatic.validateEip4337( + proxySafe.address, + manager.address, + { gasLimit: 10e6 } + ) + }) + + it('should fail from wrong entrypoint', async function () { + const op = await fillAndSign( + { + sender: proxy.address + }, + owner, + entryPoint, + 'getNonce' + ) + + const anotherEntryPoint = await new EntryPoint__factory( + ethersSigner + ).deploy() + + await expect( + anotherEntryPoint.handleOps([op], beneficiary) + ).to.rejectedWith('account: not from entrypoint') + }) + + it('should fail on invalid userop', async function () { + let op = await fillAndSign( + { + sender: proxy.address, + nonce: 1234, + callGasLimit: 1e6, + callData: safe_execTxCallData + }, + owner, + entryPoint, + 'getNonce' + ) + await expect( + entryPoint.handleOps([op], beneficiary) + ).to.rejectedWith('AA25 invalid account nonce') + + op = await fillAndSign( + { + sender: proxy.address, + callGasLimit: 1e6, + callData: safe_execTxCallData + }, + owner, + entryPoint, + 'getNonce' + ) + // invalidate the signature + op.callGasLimit = 1 + await expect(entryPoint.handleOps([op], beneficiary)) + .to.revertedWithCustomError(entryPoint, 'FailedOp') + .withArgs(0, 'AA24 signature error') + }) + + it('should exec', async function () { + const op = await fillAndSign( + { + sender: proxy.address, + callGasLimit: 1e6, + callData: safe_execTxCallData + }, + owner, + entryPoint, + 'getNonce' + ) + const rcpt = await entryPoint + .handleOps([op], beneficiary) + .then(async (r) => r.wait()) + console.log('gasUsed=', rcpt.gasUsed, rcpt.transactionHash) + + const ev = rcpt.events!.find( + (ev) => ev.event === 'UserOperationEvent' + )! + expect(ev.args!.success).to.eq(true) + expect(await getBalance(beneficiary)).to.eq( + ev.args!.actualGasCost + ) + }) + + it('should revert with reason', async function () { + const counter_countFailCallData = + counter.interface.encodeFunctionData('countFail') + const safe_execFailTxCallData = + manager.interface.encodeFunctionData('executeAndRevert', [ + counter.address, + 0, + counter_countFailCallData, + 0 + ]) + + const op = await fillAndSign( + { + sender: proxy.address, + callGasLimit: 1e6, + callData: safe_execFailTxCallData + }, + owner, + entryPoint, + 'getNonce' + ) + + const rcpt = await entryPoint + .handleOps([op], beneficiary) + .then(async (r) => r.wait()) + console.log('gasUsed=', rcpt.gasUsed, rcpt.transactionHash) + + // decode the revertReason + const ev = rcpt.events!.find( + (ev) => ev.event === 'UserOperationRevertReason' + )! + let message: string = ev.args!.revertReason + if (message.startsWith('0x08c379a0')) { + // Error(string) + message = defaultAbiCoder + .decode(['string'], '0x' + message.substring(10)) + .toString() + } + expect(message).to.eq('count failed') + }) + + let counterfactualAddress: string + it('should create account', async function () { + const initCode = hexConcat([ + accountFactory.address, + accountFactory.interface.encodeFunctionData('createAccount', [ + ownerAddress, + 123 + ]) + ]) + + counterfactualAddress = + await accountFactory.callStatic.getAddress(ownerAddress, 123) + expect(!(await isDeployed(counterfactualAddress))) + + await ethersSigner.sendTransaction({ + to: counterfactualAddress, + value: parseEther('0.1') + }) + const op = await fillAndSign( + { + sender: counterfactualAddress, + initCode, + verificationGasLimit: 400000 + }, + owner, + entryPoint, + 'getNonce' + ) + + const rcpt = await entryPoint + .handleOps([op], beneficiary) + .then(async (r) => r.wait()) + console.log('gasUsed=', rcpt.gasUsed, rcpt.transactionHash) + expect(await isDeployed(counterfactualAddress)) + + const newCode = await ethers.provider.getCode( + counterfactualAddress + ) + expect(newCode.length).eq(248) + }) + + it('another op after creation', async function () { + if (counterfactualAddress == null) this.skip() + expect(await isDeployed(counterfactualAddress)) + + const op = await fillAndSign( + { + sender: counterfactualAddress, + callData: safe_execTxCallData + }, + owner, + entryPoint, + 'getNonce' + ) + + const rcpt = await entryPoint + .handleOps([op], beneficiary) + .then(async (r) => r.wait()) + console.log('gasUsed=', rcpt.gasUsed, rcpt.transactionHash) + }) + + it('should validate ERC1271 signatures', async function () { + const safe = EIP4337Fallback__factory.connect( + proxySafe.address, + ethersSigner + ) + + const message = ethers.utils.hexlify( + ethers.utils.toUtf8Bytes('hello erc1271') + ) + const dataHash = ethers.utils.arrayify( + ethers.utils.keccak256(message) + ) + + const sig = await owner.signMessage(dataHash) + expect(await safe.isValidSignature(dataHash, sig)).to.be.eq( + '0x1626ba7e' + ) + + // make an sig invalid + const badWallet = ethers.Wallet.createRandom() + const badSig = await badWallet.signMessage(dataHash) + expect( + await safe.isValidSignature(dataHash, badSig) + ).to.be.not.eq('0x1626ba7e') + }) + + context('#replaceEIP4337', () => { + let signature: string + let newEntryPoint: EntryPoint + let newFallback: string + let newManager: EIP4337Manager + let oldManager: string + let prev: string + + before(async () => { + // sig is r{32}s{32}v{1}. for trusting the caller, r=address, v=1 + signature = hexConcat([ + hexZeroPad(ownerAddress, 32), + HashZero, + '0x01' + ]) + newEntryPoint = await new EntryPoint__factory( + ethersSigner + ).deploy() + + newManager = await new EIP4337Manager__factory( + ethersSigner + ).deploy(newEntryPoint.address) + newFallback = await newManager.eip4337Fallback() + ;[prev, oldManager] = await manager.getCurrentEIP4337Manager( + proxySafe.address + ) + }) + + it('should reject to replace if wrong old manager', async () => { + const replaceManagerCallData = + manager.interface.encodeFunctionData( + 'replaceEIP4337Manager', + [prev, newManager.address, oldManager] + ) + // using call from module, so it return value.. + const proxyFromModule = proxySafe.connect(entryPoint.address) + const ret = + await proxyFromModule.callStatic.execTransactionFromModuleReturnData( + manager.address, + 0, + replaceManagerCallData, + 1 + ) + const [errorStr] = defaultAbiCoder.decode( + ['string'], + ret.returnData.replace(/0x.{8}/, '0x') + ) + expect(errorStr).to.equal( + 'replaceEIP4337Manager: oldManager is not active' + ) + }) + + it('should replace manager', async function () { + const oldFallback = await manager.eip4337Fallback() + expect( + await proxySafe.isModuleEnabled(entryPoint.address) + ).to.equal(true) + expect(await proxySafe.isModuleEnabled(oldFallback)).to.equal( + true + ) + + expect(oldManager.toLowerCase()).to.eq( + manager.address.toLowerCase() + ) + await ethersSigner.sendTransaction({ + to: ownerAddress, + value: parseEther('33') + }) + + const replaceManagerCallData = + manager.interface.encodeFunctionData( + 'replaceEIP4337Manager', + [prev, oldManager, newManager.address] + ) + await proxySafe + .execTransaction( + manager.address, + 0, + replaceManagerCallData, + 1, + 1e6, + 0, + 0, + AddressZero, + AddressZero, + signature + ) + .then(async (r) => r.wait()) + + // console.log(rcpt.events?.slice(-1)[0].event) + + expect( + await proxySafe.isModuleEnabled(newEntryPoint.address) + ).to.equal(true) + expect(await proxySafe.isModuleEnabled(newFallback)).to.equal( + true + ) + expect( + await proxySafe.isModuleEnabled(entryPoint.address) + ).to.equal(false) + expect(await proxySafe.isModuleEnabled(oldFallback)).to.equal( + false + ) + + const { manager: curManager } = + await manager.getCurrentEIP4337Manager(proxySafe.address) + expect(curManager).to.eq(newManager.address) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/helpers.test.ts b/packages/hebao_v3/test/account-abstraction/helpers.test.ts new file mode 100644 index 000000000..92f6bc799 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/helpers.test.ts @@ -0,0 +1,129 @@ +import './aa.init' +import { expect } from 'chai' +import { BigNumber } from 'ethers' +import { hexlify } from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type TestHelpers, + TestHelpers__factory +} from '../../typechain-types' + +import { AddressZero } from './testutils' + +const provider = ethers.provider +const ethersSigner = provider.getSigner() + +describe('#ValidationData helpers', function () { + function pack( + addr: string, + validUntil: number, + validAfter: number + ): BigNumber { + return BigNumber.from(BigNumber.from(addr)) + .add(BigNumber.from(validUntil).mul(BigNumber.from(2).pow(160))) + .add( + BigNumber.from(validAfter).mul( + BigNumber.from(2).pow(160 + 48) + ) + ) + } + + let helpers: TestHelpers + const addr1 = AddressZero.replace(/0$/, '1') + const addr = '0x'.padEnd(42, '9') + const max48 = 2 ** 48 - 1 + + before(async () => { + helpers = await new TestHelpers__factory(ethersSigner).deploy() + }) + + it('#parseValidationData', async () => { + expect(await helpers.parseValidationData(0)).to.eql({ + aggregator: AddressZero, + validAfter: 0, + validUntil: max48 + }) + expect(await helpers.parseValidationData(1)).to.eql({ + aggregator: addr1, + validAfter: 0, + validUntil: max48 + }) + expect( + await helpers.parseValidationData(pack(AddressZero, 0, 10)) + ).to.eql({ + aggregator: AddressZero, + validAfter: 10, + validUntil: max48 + }) + expect( + await helpers.parseValidationData(pack(AddressZero, 10, 0)) + ).to.eql({ + aggregator: AddressZero, + validAfter: 0, + validUntil: 10 + }) + }) + + it('#packValidationData', async () => { + expect(await helpers.packValidationData(false, 0, 0)).to.eql(0) + expect(await helpers.packValidationData(true, 0, 0)).to.eql(1) + expect( + hexlify(await helpers.packValidationData(true, 123, 456)) + ).to.eql(hexlify(pack(addr1, 123, 456))) + }) + + it('#packValidationData with aggregator', async () => { + expect( + hexlify( + await helpers.packValidationDataStruct({ + aggregator: addr, + validUntil: 234, + validAfter: 567 + }) + ) + ).to.eql(hexlify(pack(addr, 234, 567))) + }) + + it('#intersectTimeRange', async () => { + expect( + await helpers.intersectTimeRange( + pack(AddressZero, 0, 0), + pack(AddressZero, 0, 0) + ) + ).to.eql({ + aggregator: AddressZero, + validAfter: 0, + validUntil: max48 + }) + expect( + await helpers.intersectTimeRange( + pack(AddressZero, 100, 10), + pack(AddressZero, 200, 50) + ) + ).to.eql({ + aggregator: AddressZero, + validAfter: 50, + validUntil: 100 + }) + + expect( + await helpers.intersectTimeRange( + pack(addr, 100, 10), + pack(AddressZero, 200, 50) + ) + ).to.eql({ aggregator: addr, validAfter: 50, validUntil: 100 }) + expect( + await helpers.intersectTimeRange( + pack(addr, 100, 10), + pack(addr1, 200, 50) + ) + ).to.eql({ aggregator: addr, validAfter: 50, validUntil: 100 }) + expect( + await helpers.intersectTimeRange( + pack(AddressZero, 100, 10), + pack(addr1, 200, 50) + ) + ).to.eql({ aggregator: addr1, validAfter: 50, validUntil: 100 }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/paymaster.test.ts b/packages/hebao_v3/test/account-abstraction/paymaster.test.ts new file mode 100644 index 000000000..5df3fc048 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/paymaster.test.ts @@ -0,0 +1,445 @@ +import { hexValue } from '@ethersproject/bytes' +import { expect } from 'chai' +import { type Wallet } from 'ethers' +import { hexConcat, parseEther } from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type EntryPoint, + type SimpleAccount, + type SimpleAccountFactory, + SimpleAccountFactory__factory, + TestCounter__factory, + type TokenPaymaster, + TokenPaymaster__factory +} from '../../typechain-types' + +import { fillAndSign } from './UserOp' +import { type UserOperation } from './UserOperation' +import { + AddressZero, + calcGasUsage, + checkForBannedOps, + checkForGeth, + createAccount, + createAccountOwner, + createAddress, + deployEntryPoint, + fund, + getAccountAddress, + getBalance, + getTokenBalance, + ONE_ETH, + rethrow +} from './testutils' + +describe('EntryPoint with paymaster', function () { + let entryPoint: EntryPoint + let accountOwner: Wallet + const ethersSigner = ethers.provider.getSigner() + let account: SimpleAccount + const beneficiaryAddress = '0x'.padEnd(42, '1') + let factory: SimpleAccountFactory + + function getAccountDeployer( + entryPoint: string, + accountOwner: string, + _salt = 0 + ): string { + return hexConcat([ + factory.address, + hexValue( + factory.interface.encodeFunctionData('createAccount', [ + accountOwner, + _salt + ])! + ) + ]) + } + + before(async function () { + this.timeout(20000) + await checkForGeth() + + entryPoint = await deployEntryPoint() + factory = await new SimpleAccountFactory__factory( + ethersSigner + ).deploy(entryPoint.address) + + accountOwner = createAccountOwner() + ;({ proxy: account } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address, + factory + )) + await fund(account) + }) + + describe('#TokenPaymaster', () => { + let paymaster: TokenPaymaster + const otherAddr = createAddress() + let ownerAddr: string + let pmAddr: string + + before(async () => { + paymaster = await new TokenPaymaster__factory( + ethersSigner + ).deploy(factory.address, 'ttt', entryPoint.address) + pmAddr = paymaster.address + ownerAddr = await ethersSigner.getAddress() + }) + + it('owner should have allowance to withdraw funds', async () => { + expect(await paymaster.allowance(pmAddr, ownerAddr)).to.equal( + ethers.constants.MaxUint256 + ) + expect(await paymaster.allowance(pmAddr, otherAddr)).to.equal(0) + }) + + it('should allow only NEW owner to move funds after transferOwnership', async () => { + await paymaster.transferOwnership(otherAddr) + expect(await paymaster.allowance(pmAddr, otherAddr)).to.equal( + ethers.constants.MaxUint256 + ) + expect(await paymaster.allowance(pmAddr, ownerAddr)).to.equal(0) + }) + }) + + describe('using TokenPaymaster (account pays in paymaster tokens)', () => { + let paymaster: TokenPaymaster + before(async () => { + paymaster = await new TokenPaymaster__factory( + ethersSigner + ).deploy(factory.address, 'tst', entryPoint.address) + await entryPoint.depositTo(paymaster.address, { + value: parseEther('1') + }) + await paymaster.addStake(1, { value: parseEther('2') }) + }) + + describe('#handleOps', () => { + let calldata: string + before(async () => { + const updateEntryPoint = await account.populateTransaction + .withdrawDepositTo(AddressZero, 0) + .then((tx) => tx.data!) + calldata = await account.populateTransaction + .execute(account.address, 0, updateEntryPoint) + .then((tx) => tx.data!) + }) + it("paymaster should reject if account doesn't have tokens", async () => { + const op = await fillAndSign( + { + sender: account.address, + paymasterAndData: paymaster.address, + callData: calldata + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + ).to.rejectedWith('AA33 reverted: TokenPaymaster: no balance') + await expect( + entryPoint.handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + ).to.rejectedWith('AA33 reverted: TokenPaymaster: no balance') + }) + }) + + describe('create account', () => { + let createOp: UserOperation + let created = false + const beneficiaryAddress = createAddress() + + it('should reject if account not funded', async () => { + const op = await fillAndSign( + { + initCode: getAccountDeployer( + entryPoint.address, + accountOwner.address, + 1 + ), + verificationGasLimit: 1e7, + paymasterAndData: paymaster.address + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic + .handleOps([op], beneficiaryAddress, { + gasLimit: 1e7 + }) + .catch(rethrow()) + ).to.rejectedWith('TokenPaymaster: no balance') + }) + + it('should succeed to create account with tokens', async () => { + createOp = await fillAndSign( + { + initCode: getAccountDeployer( + entryPoint.address, + accountOwner.address, + 3 + ), + verificationGasLimit: 2e6, + paymasterAndData: paymaster.address, + nonce: 0 + }, + accountOwner, + entryPoint + ) + + const preAddr = createOp.sender + await paymaster.mintTokens(preAddr, parseEther('1')) + // paymaster is the token, so no need for "approve" or any init function... + + await entryPoint + .simulateValidation(createOp, { gasLimit: 5e6 }) + .catch((e) => e.message) + const [tx] = await ethers.provider + .getBlock('latest') + .then((block) => block.transactions) + await checkForBannedOps(tx, true) + + const rcpt = await entryPoint + .handleOps([createOp], beneficiaryAddress, { + gasLimit: 1e7 + }) + .catch(rethrow()) + .then(async (tx) => await tx!.wait()) + console.log('\t== create gasUsed=', rcpt.gasUsed.toString()) + await calcGasUsage(rcpt, entryPoint) + created = true + }) + + it('account should pay for its creation (in tst)', async function () { + if (!created) this.skip() + // TODO: calculate needed payment + const ethRedeemed = await getBalance(beneficiaryAddress) + expect(ethRedeemed).to.above(100000) + + const accountAddr = await getAccountAddress( + accountOwner.address, + factory + ) + const postBalance = await getTokenBalance( + paymaster, + accountAddr + ) + expect(1e18 - postBalance).to.above(10000) + }) + + it('should reject if account already created', async function () { + if (!created) this.skip() + await expect( + entryPoint.callStatic + .handleOps([createOp], beneficiaryAddress, { + gasLimit: 1e7 + }) + .catch(rethrow()) + ).to.rejectedWith('sender already constructed') + }) + + it('batched request should each pay for its share', async function () { + this.timeout(20000) + // validate context is passed correctly to postOp + // (context is the account to pay with) + + const beneficiaryAddress = createAddress() + const testCounter = await new TestCounter__factory( + ethersSigner + ).deploy() + const justEmit = + testCounter.interface.encodeFunctionData('justemit') + const execFromSingleton = + account.interface.encodeFunctionData('execute', [ + testCounter.address, + 0, + justEmit + ]) + + const ops: UserOperation[] = [] + const accounts: SimpleAccount[] = [] + + for (let i = 0; i < 4; i++) { + const { proxy: aAccount } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + ) + await paymaster.mintTokens( + aAccount.address, + parseEther('1') + ) + const op = await fillAndSign( + { + sender: aAccount.address, + callData: execFromSingleton, + paymasterAndData: paymaster.address + }, + accountOwner, + entryPoint + ) + + accounts.push(aAccount) + ops.push(op) + } + + const pmBalanceBefore = await paymaster + .balanceOf(paymaster.address) + .then((b) => b.toNumber()) + await entryPoint + .handleOps(ops, beneficiaryAddress) + .then(async (tx) => tx.wait()) + const totalPaid = + (await paymaster + .balanceOf(paymaster.address) + .then((b) => b.toNumber())) - pmBalanceBefore + for (let i = 0; i < accounts.length; i++) { + const bal = await getTokenBalance( + paymaster, + accounts[i].address + ) + const paid = parseEther('1').sub(bal.toString()).toNumber() + + // roughly each account should pay 1/4th of total price, within 15% + // (first account pays more, for warming up..) + expect(paid).to.be.closeTo(totalPaid / 4, paid * 0.15) + } + }) + + // accounts attempt to grief paymaster: both accounts pass validatePaymasterUserOp (since they have enough balance) + // but the execution of account1 drains account2. + // as a result, the postOp of the paymaster reverts, and cause entire handleOp to revert. + describe('grief attempt', () => { + let account2: SimpleAccount + let approveCallData: string + before(async function () { + this.timeout(20000) + ;({ proxy: account2 } = await createAccount( + ethersSigner, + await accountOwner.getAddress(), + entryPoint.address + )) + await paymaster.mintTokens( + account2.address, + parseEther('1') + ) + await paymaster.mintTokens(account.address, parseEther('1')) + approveCallData = paymaster.interface.encodeFunctionData( + 'approve', + [account.address, ethers.constants.MaxUint256] + ) + // need to call approve from account2. use paymaster for that + const approveOp = await fillAndSign( + { + sender: account2.address, + callData: account2.interface.encodeFunctionData( + 'execute', + [paymaster.address, 0, approveCallData] + ), + paymasterAndData: paymaster.address + }, + accountOwner, + entryPoint + ) + await entryPoint.handleOps([approveOp], beneficiaryAddress) + expect( + await paymaster.allowance( + account2.address, + account.address + ) + ).to.eq(ethers.constants.MaxUint256) + }) + + it('griefing attempt should cause handleOp to revert', async () => { + // account1 is approved to withdraw going to withdraw account2's balance + + const account2Balance = await paymaster.balanceOf( + account2.address + ) + const transferCost = parseEther('1').sub(account2Balance) + const withdrawAmount = account2Balance.sub( + transferCost.mul(0) + ) + const withdrawTokens = + paymaster.interface.encodeFunctionData('transferFrom', [ + account2.address, + account.address, + withdrawAmount + ]) + // const withdrawTokens = paymaster.interface.encodeFunctionData('transfer', [account.address, parseEther('0.1')]) + const execFromEntryPoint = + account.interface.encodeFunctionData('execute', [ + paymaster.address, + 0, + withdrawTokens + ]) + + const userOp1 = await fillAndSign( + { + sender: account.address, + callData: execFromEntryPoint, + paymasterAndData: paymaster.address + }, + accountOwner, + entryPoint + ) + + // account2's operation is unimportant, as it is going to be reverted - but the paymaster will have to pay for it.. + const userOp2 = await fillAndSign( + { + sender: account2.address, + callData: execFromEntryPoint, + paymasterAndData: paymaster.address, + callGasLimit: 1e6 + }, + accountOwner, + entryPoint + ) + + await expect( + entryPoint.handleOps( + [userOp1, userOp2], + beneficiaryAddress + ) + ).to.be.rejectedWith('transfer amount exceeds balance') + }) + }) + }) + describe('withdraw', () => { + const withdrawAddress = createAddress() + it('should fail to withdraw before unstake', async function () { + this.timeout(20000) + await expect( + paymaster.withdrawStake(withdrawAddress) + ).to.rejectedWith('must call unlockStake') + }) + it('should be able to withdraw after unstake delay', async () => { + await paymaster.unlockStake() + const amount = await entryPoint + .getDepositInfo(paymaster.address) + .then((info) => info.stake) + expect(amount).to.be.gte(ONE_ETH.div(2)) + await ethers.provider.send('evm_mine', [ + Math.floor(Date.now() / 1000) + 1000 + ]) + await paymaster.withdrawStake(withdrawAddress) + expect( + await ethers.provider.getBalance(withdrawAddress) + ).to.eql(amount) + expect( + await entryPoint + .getDepositInfo(paymaster.address) + .then((info) => info.stake) + ).to.eq(0) + }) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/simple-wallet.test.ts b/packages/hebao_v3/test/account-abstraction/simple-wallet.test.ts new file mode 100644 index 000000000..ae1a5bf78 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/simple-wallet.test.ts @@ -0,0 +1,178 @@ +import { expect } from 'chai' +import { type Wallet } from 'ethers' +import { parseEther } from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + ERC1967Proxy__factory, + type SimpleAccount, + SimpleAccount__factory, + SimpleAccountFactory__factory, + type TestUtil, + TestUtil__factory +} from '../../typechain-types' + +import { + fillUserOpDefaults, + getUserOpHash, + packUserOp, + signUserOp +} from './UserOp' +import { type UserOperation } from './UserOperation' +import { + createAccount, + createAccountOwner, + createAddress, + deployEntryPoint, + getBalance, + HashZero, + isDeployed, + ONE_ETH +} from './testutils' + +describe('SimpleAccount', function () { + let entryPoint: string + let accounts: string[] + let testUtil: TestUtil + let accountOwner: Wallet + const ethersSigner = ethers.provider.getSigner() + + before(async function () { + entryPoint = await deployEntryPoint().then((e) => e.address) + accounts = await ethers.provider.listAccounts() + // ignore in geth.. this is just a sanity test. should be refactored to use a single-account mode.. + if (accounts.length < 2) this.skip() + testUtil = await new TestUtil__factory(ethersSigner).deploy() + accountOwner = createAccountOwner() + }) + + it('owner should be able to call transfer', async () => { + const { proxy: account } = await createAccount( + ethers.provider.getSigner(), + accounts[0], + entryPoint + ) + await ethersSigner.sendTransaction({ + from: accounts[0], + to: account.address, + value: parseEther('2') + }) + await account.execute(accounts[2], ONE_ETH, '0x') + }) + it('other account should not be able to call transfer', async () => { + const { proxy: account } = await createAccount( + ethers.provider.getSigner(), + accounts[0], + entryPoint + ) + await expect( + account + .connect(ethers.provider.getSigner(1)) + .execute(accounts[2], ONE_ETH, '0x') + ).to.be.revertedWith('account: not Owner or EntryPoint') + }) + + it('should pack in js the same as solidity', async () => { + const op = fillUserOpDefaults({ sender: accounts[0] }) + const packed = packUserOp(op) + expect(await testUtil.packUserOp(op)).to.equal(packed) + }) + + describe('#validateUserOp', () => { + let account: SimpleAccount + let userOp: UserOperation + let userOpHash: string + let preBalance: number + let expectedPay: number + + const actualGasPrice = 1e9 + // for testing directly validateUserOp, we initialize the account with EOA as entryPoint. + let entryPointEoa: string + + before(async () => { + entryPointEoa = accounts[2] + const epAsSigner = await ethers.getSigner(entryPointEoa) + + // cant use "SimpleAccountFactory", since it attempts to increment nonce first + const implementation = await new SimpleAccount__factory( + ethersSigner + ).deploy(entryPointEoa) + const proxy = await new ERC1967Proxy__factory( + ethersSigner + ).deploy(implementation.address, '0x') + account = SimpleAccount__factory.connect( + proxy.address, + epAsSigner + ) + + await ethersSigner.sendTransaction({ + from: accounts[0], + to: account.address, + value: parseEther('0.2') + }) + const callGasLimit = 200000 + const verificationGasLimit = 100000 + const maxFeePerGas = 3e9 + const chainId = await ethers.provider + .getNetwork() + .then((net) => net.chainId) + + userOp = signUserOp( + fillUserOpDefaults({ + sender: account.address, + callGasLimit, + verificationGasLimit, + maxFeePerGas + }), + accountOwner, + entryPointEoa, + chainId + ) + + userOpHash = getUserOpHash(userOp, entryPointEoa, chainId) + + expectedPay = + actualGasPrice * (callGasLimit + verificationGasLimit) + + preBalance = await getBalance(account.address) + const ret = await account.validateUserOp( + userOp, + userOpHash, + expectedPay, + { gasPrice: actualGasPrice } + ) + await ret.wait() + }) + + it('should pay', async () => { + const postBalance = await getBalance(account.address) + expect(preBalance - postBalance).to.eql(expectedPay) + }) + + it('should return NO_SIG_VALIDATION on wrong signature', async () => { + const userOpHash = HashZero + const deadline = await account.callStatic.validateUserOp( + { ...userOp, nonce: 1 }, + userOpHash, + 0 + ) + expect(deadline).to.eq(1) + }) + }) + + context('SimpleAccountFactory', () => { + it('sanity: check deployer', async () => { + const ownerAddr = createAddress() + const deployer = await new SimpleAccountFactory__factory( + ethersSigner + ).deploy(entryPoint) + const target = await deployer.callStatic.createAccount( + ownerAddr, + 1234 + ) + expect(await isDeployed(target)).to.eq(false) + await deployer.createAccount(ownerAddr, 1234) + expect(await isDeployed(target)).to.eq(true) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/solidityTypes.ts b/packages/hebao_v3/test/account-abstraction/solidityTypes.ts new file mode 100644 index 000000000..735f44998 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/solidityTypes.ts @@ -0,0 +1,10 @@ +// define the same export types as used by export typechain/ethers +import { type BytesLike } from '@ethersproject/bytes' +import { type BigNumberish } from 'ethers' + +export type address = string +export type uint256 = BigNumberish +export type uint = BigNumberish +export type uint48 = BigNumberish +export type bytes = BytesLike +export type bytes32 = BytesLike diff --git a/packages/hebao_v3/test/account-abstraction/testutils.ts b/packages/hebao_v3/test/account-abstraction/testutils.ts new file mode 100644 index 000000000..bf345d681 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/testutils.ts @@ -0,0 +1,452 @@ +import { type BytesLike } from '@ethersproject/bytes' +import { expect } from 'chai' +import { + BigNumber, + type BigNumberish, + type Contract, + type ContractReceipt, + type Signer, + type Wallet +} from 'ethers' +import { + arrayify, + hexConcat, + keccak256, + parseEther +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type EntryPoint, + EntryPoint__factory, + type IEntryPoint, + type IERC20, + type SimpleAccount, + SimpleAccount__factory, + type SimpleAccountFactory, + SimpleAccountFactory__factory, + type TestAggregatedAccountFactory +} from '../../typechain-types' +import { Create2Factory } from '../helper/Create2Factory' + +import { type UserOperation } from './UserOperation' +import { debugTransaction } from './debugTx' + +export const AddressZero = ethers.constants.AddressZero +export const HashZero = ethers.constants.HashZero +export const ONE_ETH = parseEther('1') +export const TWO_ETH = parseEther('2') +export const FIVE_ETH = parseEther('5') + +export const tostr = (x: any): string => + x != null ? x.toString() : 'null' + +export function tonumber(x: any): number { + try { + return parseFloat(x.toString()) + } catch (e: any) { + console.log('=== failed to parseFloat:', x, e.message) + return NaN + } +} + +// just throw 1eth from account[0] to the given address (or contract instance) +export async function fund( + contractOrAddress: string | Contract, + amountEth = '1' +): Promise { + let address: string + if (typeof contractOrAddress === 'string') { + address = contractOrAddress + } else { + address = contractOrAddress.address + } + await ethers.provider + .getSigner() + .sendTransaction({ to: address, value: parseEther(amountEth) }) +} + +export async function getBalance(address: string): Promise { + const balance = await ethers.provider.getBalance(address) + return parseInt(balance.toString()) +} + +export async function getTokenBalance( + token: IERC20, + address: string +): Promise { + const balance = await token.balanceOf(address) + return parseInt(balance.toString()) +} + +let counter = 0 + +// create non-random account, so gas calculations are deterministic +export function createAccountOwner(): Wallet { + const privateKey = keccak256( + Buffer.from(arrayify(BigNumber.from(++counter))) + ) + return new ethers.Wallet(privateKey, ethers.provider) + // return new ethers.Wallet('0x'.padEnd(66, privkeyBase), ethers.provider); +} + +export function createAddress(): string { + return createAccountOwner().address +} + +export function callDataCost(data: string): number { + return ethers.utils + .arrayify(data) + .map((x) => (x === 0 ? 4 : 16)) + .reduce((sum, x) => sum + x) +} + +export async function calcGasUsage( + rcpt: ContractReceipt, + entryPoint: EntryPoint, + beneficiaryAddress?: string +): Promise<{ actualGasCost: BigNumberish }> { + const actualGas = rcpt.gasUsed + const logs = await entryPoint.queryFilter( + entryPoint.filters.UserOperationEvent(), + rcpt.blockHash + ) + const { actualGasCost, actualGasUsed } = logs[0].args + console.log( + '\t== actual gasUsed (from tx receipt)=', + actualGas.toString() + ) + console.log( + '\t== calculated gasUsed (paid to beneficiary)=', + actualGasUsed + ) + const tx = await ethers.provider.getTransaction( + rcpt.transactionHash + ) + console.log( + '\t== gasDiff', + actualGas.toNumber() - + actualGasUsed.toNumber() - + callDataCost(tx.data) + ) + if (beneficiaryAddress != null) { + expect(await getBalance(beneficiaryAddress)).to.eq( + actualGasCost.toNumber() + ) + } + return { actualGasCost } +} + +// helper function to create the initCode to deploy the account, using our account factory. +export function getAccountInitCode( + owner: string, + factory: SimpleAccountFactory, + salt = 0 +): BytesLike { + return hexConcat([ + factory.address, + factory.interface.encodeFunctionData('createAccount', [ + owner, + salt + ]) + ]) +} + +export async function getAggregatedAccountInitCode( + entryPoint: string, + factory: TestAggregatedAccountFactory, + salt = 0 +): Promise { + // the test aggregated account doesn't check the owner... + const owner = AddressZero + return hexConcat([ + factory.address, + factory.interface.encodeFunctionData('createAccount', [ + owner, + salt + ]) + ]) +} + +// given the parameters as AccountDeployer, return the resulting "counterfactual address" that it would create. +export async function getAccountAddress( + owner: string, + factory: SimpleAccountFactory, + salt = 0 +): Promise { + return await factory.getAddress(owner, salt) +} + +const panicCodes: Record = { + // from https://docs.soliditylang.org/en/v0.8.0/control-structures.html + 0x01: 'assert(false)', + 0x11: 'arithmetic overflow/underflow', + 0x12: 'divide by zero', + 0x21: 'invalid enum value', + 0x22: 'storage byte array that is incorrectly encoded', + 0x31: '.pop() on an empty array.', + 0x32: 'array sout-of-bounds or negative index', + 0x41: 'memory overflow', + 0x51: 'zero-initialized variable of internal function type' +} + +// rethrow "cleaned up" exception. +// - stack trace goes back to method (or catch) line, not inner provider +// - attempt to parse revert data (needed for geth) +// use with ".catch(rethrow())", so that current source file/line is meaningful. +export function rethrow(): (e: Error) => void { + const callerStack = new Error() + .stack!.replace(/Error.*\n.*at.*\n/, '') + .replace(/.*at.* \(internal[\s\S]*/, '') + + if (arguments[0] != null) { + throw new Error( + 'must use .catch(rethrow()), and NOT .catch(rethrow)' + ) + } + return function (e: Error) { + const solstack = e.stack!.match(/((?:.* at .*\.sol.*\n)+)/) + const stack = (solstack != null ? solstack[1] : '') + callerStack + // const regex = new RegExp('error=.*"data":"(.*?)"').compile() + const found = /error=.*?"data":"(.*?)"/.exec(e.message) + let message: string + if (found != null) { + const data = found[1] + message = + decodeRevertReason(data) ?? + e.message + ' - ' + data.slice(0, 100) + } else { + message = e.message + } + const err = new Error(message) + err.stack = 'Error: ' + message + '\n' + stack + throw err + } +} + +export function decodeRevertReason( + data: string, + nullIfNoMatch = true +): string | null { + const methodSig = data.slice(0, 10) + const dataParams = '0x' + data.slice(10) + + if (methodSig === '0x08c379a0') { + const [err] = ethers.utils.defaultAbiCoder.decode( + ['string'], + dataParams + ) + + return `Error(${err as string})` + } else if (methodSig === '0x00fa072b') { + const [opindex, paymaster, msg] = + ethers.utils.defaultAbiCoder.decode( + ['uint256', 'address', 'string'], + dataParams + ) + + // eslint-disable-next-line + return `FailedOp(${opindex}, ${ + (paymaster as string) !== AddressZero + ? (paymaster as string) + : 'none' + }, ${msg as string})` + } else if (methodSig === '0x4e487b71') { + const [code] = ethers.utils.defaultAbiCoder.decode( + ['uint256'], + dataParams + ) + return `Panic(${panicCodes[code] ?? code} + ')` + } + if (!nullIfNoMatch) { + return data + } + return null +} + +let currentNode = '' + +// basic geth support +// - by default, has a single account. our code needs more. +export async function checkForGeth(): Promise { + // @ts-expect-error nothing + const provider = ethers.provider._hardhatProvider + + currentNode = await provider.request({ + method: 'web3_clientVersion' + }) + + console.log('node version:', currentNode) + // NOTE: must run geth with params: + // --http.api personal,eth,net,web3 + // --allow-insecure-unlock + if (currentNode.match(/geth/i) != null) { + for (let i = 0; i < 2; i++) { + const acc = await provider + .request({ method: 'personal_newAccount', params: ['pass'] }) + .catch(rethrow) + await provider + .request({ + method: 'personal_unlockAccount', + params: [acc, 'pass'] + }) + .catch(rethrow) + await fund(acc, '10') + } + } +} + +// remove "array" members, convert values to strings. +// so Result obj like +// { '0': "a", '1': 20, first: "a", second: 20 } +// becomes: +// { first: "a", second: "20" } +export function objdump(obj: Record): any { + return Object.keys(obj) + .filter((key) => key.match(/^[\d_]/) == null) + .reduce( + (set, key) => ({ + ...set, + [key]: decodeRevertReason(obj[key].toString(), false) + }), + {} + ) +} + +export async function checkForBannedOps( + txHash: string, + checkPaymaster: boolean +): Promise { + const tx = await debugTransaction(txHash) + const logs = tx.structLogs + const blockHash = logs + .map((op, index) => ({ op: op.op, index })) + .filter((op) => op.op === 'NUMBER') + expect(blockHash.length).to.equal( + 2, + 'expected exactly 2 call to NUMBER (Just before and after validateUserOperation)' + ) + const validateAccountOps = logs.slice(0, blockHash[0].index - 1) + const validatePaymasterOps = logs.slice(blockHash[0].index + 1) + const ops = validateAccountOps + .filter((log) => log.depth > 1) + .map((log) => log.op) + const paymasterOps = validatePaymasterOps + .filter((log) => log.depth > 1) + .map((log) => log.op) + + expect(ops).to.include( + 'POP', + 'not a valid ops list: ' + JSON.stringify(ops) + ) // sanity + const bannedOpCodes = new Set([ + 'GAS', + 'BASEFEE', + 'GASPRICE', + 'NUMBER' + ]) + expect( + ops.filter((op, index) => { + // don't ban "GAS" op followed by "*CALL" + if (op === 'GAS' && ops[index + 1].match(/CALL/) != null) { + return false + } + return bannedOpCodes.has(op) + }) + ).to.eql([]) + if (checkPaymaster) { + expect(paymasterOps).to.include( + 'POP', + 'not a valid ops list: ' + JSON.stringify(paymasterOps) + ) // sanity + expect(paymasterOps).to.not.include('BASEFEE') + expect(paymasterOps).to.not.include('GASPRICE') + expect(paymasterOps).to.not.include('NUMBER') + } +} + +/** + * process exception of ValidationResult + * usage: entryPoint.simulationResult(..).catch(simulationResultCatch) + */ +export function simulationResultCatch(e: any): any { + if (e.errorName !== 'ValidationResult') { + throw e + } + return e.errorArgs +} + +/** + * process exception of ValidationResultWithAggregation + * usage: entryPoint.simulationResult(..).catch(simulationResultWithAggregation) + */ +export function simulationResultWithAggregationCatch(e: any): any { + if (e.errorName !== 'ValidationResultWithAggregation') { + throw e + } + return e.errorArgs +} + +export async function deployEntryPoint( + provider = ethers.provider +): Promise { + const create2factory = new Create2Factory(provider) + const epf = new EntryPoint__factory(provider.getSigner()) + const addr = await create2factory.deploy( + epf.bytecode, + 0, + process.env.COVERAGE != null ? 20e6 : 8e6 + ) + return EntryPoint__factory.connect(addr, provider.getSigner()) +} + +export async function isDeployed(addr: string): Promise { + const code = await ethers.provider.getCode(addr) + return code.length > 2 +} + +// internal helper function: create a UserOpsPerAggregator structure, with no aggregator or signature +export function userOpsWithoutAgg( + userOps: UserOperation[] +): IEntryPoint.UserOpsPerAggregatorStruct[] { + return [ + { + userOps, + aggregator: AddressZero, + signature: '0x' + } + ] +} + +// Deploys an implementation and a proxy pointing to this implementation +export async function createAccount( + ethersSigner: Signer, + accountOwner: string, + entryPoint: string, + _factory?: SimpleAccountFactory +): Promise<{ + proxy: SimpleAccount + accountFactory: SimpleAccountFactory + implementation: string +}> { + const accountFactory = + _factory ?? + (await new SimpleAccountFactory__factory(ethersSigner).deploy( + entryPoint + )) + const implementation = await accountFactory.accountImplementation() + await accountFactory.createAccount(accountOwner, 0) + const accountAddress = await accountFactory.getAddress( + accountOwner, + 0 + ) + const proxy = SimpleAccount__factory.connect( + accountAddress, + ethersSigner + ) + return { + implementation, + accountFactory, + proxy + } +} diff --git a/packages/hebao_v3/test/account-abstraction/verifying_paymaster.test.ts b/packages/hebao_v3/test/account-abstraction/verifying_paymaster.test.ts new file mode 100644 index 000000000..7290597f1 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/verifying_paymaster.test.ts @@ -0,0 +1,219 @@ +import { expect } from 'chai' +import { type Wallet } from 'ethers' +import { + arrayify, + defaultAbiCoder, + hexConcat, + parseEther +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type EntryPoint, + type SimpleAccount, + type VerifyingPaymaster, + VerifyingPaymaster__factory +} from '../../typechain-types' + +import { fillAndSign } from './UserOp' +import { type UserOperation } from './UserOperation' +import { + createAccount, + createAccountOwner, + createAddress, + deployEntryPoint, + simulationResultCatch +} from './testutils' + +const MOCK_VALID_UNTIL = '0x00000000deadbeef' +const MOCK_VALID_AFTER = '0x0000000000001234' +const MOCK_SIG = '0x1234' + +describe('EntryPoint with VerifyingPaymaster', function () { + let entryPoint: EntryPoint + let accountOwner: Wallet + const ethersSigner = ethers.provider.getSigner() + let account: SimpleAccount + let offchainSigner: Wallet + + let paymaster: VerifyingPaymaster + before(async function () { + this.timeout(20000) + entryPoint = await deployEntryPoint() + + offchainSigner = createAccountOwner() + accountOwner = createAccountOwner() + + paymaster = await new VerifyingPaymaster__factory( + ethersSigner + ).deploy(entryPoint.address, offchainSigner.address) + await paymaster.addStake(1, { value: parseEther('2') }) + await entryPoint.depositTo(paymaster.address, { + value: parseEther('1') + }) + ;({ proxy: account } = await createAccount( + ethersSigner, + accountOwner.address, + entryPoint.address + )) + }) + + describe('#parsePaymasterAndData', () => { + it('should parse data properly', async () => { + const paymasterAndData = hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + MOCK_SIG + ]) + console.log(paymasterAndData) + const res = + await paymaster.parsePaymasterAndData(paymasterAndData) + expect(res.validUntil).to.be.equal( + ethers.BigNumber.from(MOCK_VALID_UNTIL) + ) + expect(res.validAfter).to.be.equal( + ethers.BigNumber.from(MOCK_VALID_AFTER) + ) + expect(res.signature).equal(MOCK_SIG) + }) + }) + + describe('#validatePaymasterUserOp', () => { + it('should reject on no signature', async () => { + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + '0x1234' + ]) + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp) + ).to.be.rejectedWith( + 'invalid signature length in paymasterAndData' + ) + }) + + it('should reject on invalid signature', async () => { + const userOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + '0x' + '00'.repeat(65) + ]) + }, + accountOwner, + entryPoint + ) + await expect( + entryPoint.callStatic.simulateValidation(userOp) + ).to.be.rejectedWith('ECDSA: invalid signature') + }) + + describe('with wrong signature', () => { + let wrongSigUserOp: UserOperation + const beneficiaryAddress = createAddress() + before(async () => { + const sig = await offchainSigner.signMessage( + arrayify('0xdead') + ) + wrongSigUserOp = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + sig + ]) + }, + accountOwner, + entryPoint + ) + }) + + it('should return signature error (no revert) on wrong signer signature', async () => { + const ret = await entryPoint.callStatic + .simulateValidation(wrongSigUserOp) + .catch(simulationResultCatch) + expect(ret.returnInfo.sigFailed).to.be.true + }) + + it('handleOp revert on signature failure in handleOps', async () => { + await expect( + entryPoint.estimateGas.handleOps( + [wrongSigUserOp], + beneficiaryAddress + ) + ).to.rejectedWith('AA34 signature error') + }) + }) + + it('succeed with valid signature', async () => { + const userOp1 = await fillAndSign( + { + sender: account.address, + paymasterAndData: hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + '0x' + '00'.repeat(65) + ]) + }, + accountOwner, + entryPoint + ) + const hash = await paymaster.getHash( + userOp1, + MOCK_VALID_UNTIL, + MOCK_VALID_AFTER + ) + const sig = await offchainSigner.signMessage(arrayify(hash)) + const userOp = await fillAndSign( + { + ...userOp1, + paymasterAndData: hexConcat([ + paymaster.address, + defaultAbiCoder.encode( + ['uint48', 'uint48'], + [MOCK_VALID_UNTIL, MOCK_VALID_AFTER] + ), + sig + ]) + }, + accountOwner, + entryPoint + ) + const res = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + expect(res.returnInfo.sigFailed).to.be.false + expect(res.returnInfo.validAfter).to.be.equal( + ethers.BigNumber.from(MOCK_VALID_AFTER) + ) + expect(res.returnInfo.validUntil).to.be.equal( + ethers.BigNumber.from(MOCK_VALID_UNTIL) + ) + }) + }) +}) diff --git a/packages/hebao_v3/test/account-abstraction/y.bls.test.ts b/packages/hebao_v3/test/account-abstraction/y.bls.test.ts new file mode 100644 index 000000000..d0fbc8eb4 --- /dev/null +++ b/packages/hebao_v3/test/account-abstraction/y.bls.test.ts @@ -0,0 +1,339 @@ +import { type BytesLike, hexValue } from '@ethersproject/bytes' +import { hashToPoint } from '@thehubbleproject/bls/dist/mcl' +import { + aggregate, + BlsSignerFactory, + BlsVerifier +} from '@thehubbleproject/bls/dist/signer' +import { expect } from 'chai' +import { keccak256 } from 'ethereumjs-util' +import { type BigNumber, type Signer } from 'ethers' +import { + arrayify, + defaultAbiCoder, + hexConcat +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' + +import { + type BLSAccount, + BLSAccount__factory, + type BLSAccountFactory, + BLSAccountFactory__factory, + BLSOpen__factory, + type BLSSignatureAggregator, + BLSSignatureAggregator__factory, + BrokenBLSAccountFactory__factory, + type EntryPoint +} from '../../typechain-types' + +import { DefaultsForUserOp, fillUserOp } from './UserOp' +import { + createAddress, + deployEntryPoint, + fund, + ONE_ETH, + simulationResultWithAggregationCatch +} from './testutils' + +async function deployBlsAccount( + ethersSigner: Signer, + factoryAddr: string, + blsSigner: any +): Promise { + const factory = BLSAccountFactory__factory.connect( + factoryAddr, + ethersSigner + ) + const addr = await factory.callStatic.createAccount( + 0, + blsSigner.pubkey + ) + await factory.createAccount(0, blsSigner.pubkey) + return BLSAccount__factory.connect(addr, ethersSigner) +} + +describe('bls account', function () { + this.timeout(20000) + const BLS_DOMAIN = arrayify( + keccak256(Buffer.from('eip4337.bls.domain')) + ) + const etherSigner = ethers.provider.getSigner() + let fact: BlsSignerFactory + let signer1: any + let signer2: any + let blsAgg: BLSSignatureAggregator + let entrypoint: EntryPoint + let account1: BLSAccount + let account2: BLSAccount + let accountDeployer: BLSAccountFactory + before(async () => { + entrypoint = await deployEntryPoint() + const BLSOpenLib = await new BLSOpen__factory( + ethers.provider.getSigner() + ).deploy() + blsAgg = await new BLSSignatureAggregator__factory( + { + 'contracts/account-abstraction/samples/bls/lib/BLSOpen.sol:BLSOpen': + BLSOpenLib.address + }, + ethers.provider.getSigner() + ).deploy() + + await blsAgg.addStake(entrypoint.address, 2, { value: ONE_ETH }) + fact = await BlsSignerFactory.new() + signer1 = fact.getSigner(arrayify(BLS_DOMAIN), '0x01') + signer2 = fact.getSigner(arrayify(BLS_DOMAIN), '0x02') + + accountDeployer = await new BLSAccountFactory__factory( + etherSigner + ).deploy(entrypoint.address, blsAgg.address) + + account1 = await deployBlsAccount( + etherSigner, + accountDeployer.address, + signer1 + ) + account2 = await deployBlsAccount( + etherSigner, + accountDeployer.address, + signer2 + ) + }) + + it('#getTrailingPublicKey', async () => { + const data = defaultAbiCoder.encode( + ['uint[6]'], + [[1, 2, 3, 4, 5, 6]] + ) + const last4 = await blsAgg.getTrailingPublicKey(data) + expect(last4.map((x) => x.toNumber())).to.eql([3, 4, 5, 6]) + }) + it('#aggregateSignatures', async () => { + const sig1 = signer1.sign('0x1234') + const sig2 = signer2.sign('0x5678') + const offChainSigResult = hexConcat(aggregate([sig1, sig2])) + const userOp1 = { + ...DefaultsForUserOp, + signature: hexConcat(sig1) + } + const userOp2 = { + ...DefaultsForUserOp, + signature: hexConcat(sig2) + } + const solidityAggResult = await blsAgg.aggregateSignatures([ + userOp1, + userOp2 + ]) + expect(solidityAggResult).to.equal(offChainSigResult) + }) + + it('#userOpToMessage', async () => { + const userOp1 = await fillUserOp( + { + sender: account1.address + }, + entrypoint + ) + const requestHash = await blsAgg.getUserOpHash(userOp1) + const solPoint: BigNumber[] = + await blsAgg.userOpToMessage(userOp1) + const messagePoint = hashToPoint(requestHash, BLS_DOMAIN) + expect( + `1 ${solPoint[0].toString()} ${solPoint[1].toString()}` + ).to.equal(messagePoint.getStr()) + }) + + it('#validateUserOpSignature', async () => { + const userOp1 = await fillUserOp( + { + sender: account1.address + }, + entrypoint + ) + const requestHash = await blsAgg.getUserOpHash(userOp1) + + const sigParts = signer1.sign(requestHash) + userOp1.signature = hexConcat(sigParts) + expect(userOp1.signature.length).to.equal(130) // 64-byte hex value + + const verifier = new BlsVerifier(BLS_DOMAIN) + expect( + verifier.verify(sigParts, signer1.pubkey, requestHash) + ).to.equal(true) + + const ret = await blsAgg.validateUserOpSignature(userOp1) + expect(ret).to.equal('0x') + }) + + it('aggregated sig validation must succeed if off-chain UserOp sig succeeds', async () => { + // regression AA-119: prevent off-chain signature success and on-chain revert. + // "broken account" uses different public-key during construction and runtime. + const brokenAccountFactory = + await new BrokenBLSAccountFactory__factory(etherSigner).deploy( + entrypoint.address, + blsAgg.address + ) + // const brokenAccountFactory = await new BLSAccountFactory__factory(etherSigner).deploy(entrypoint.address, blsAgg.address) + const deployTx = + await brokenAccountFactory.populateTransaction.createAccount( + 0, + signer1.pubkey + ) + const res = await brokenAccountFactory.provider.call(deployTx) + const acc = brokenAccountFactory.interface.decodeFunctionResult( + 'createAccount', + res + )[0] + await fund(acc) + const userOp = await fillUserOp( + { + sender: acc, + initCode: hexConcat([ + brokenAccountFactory.address, + deployTx.data! + ]) + }, + entrypoint + ) + const requestHash = await blsAgg.getUserOpHash(userOp) + const signature = (userOp.signature = hexConcat( + signer1.sign(requestHash) + )) + + // and sig validation should fail: + const singleOpSigCheck = (await blsAgg + .validateUserOpSignature(userOp) + .then( + () => 'ok', + (e) => e.message + )) as string + + // above account should fail on-chain: + const beneficiary = createAddress() + const handleRet = (await entrypoint.callStatic + .handleAggregatedOps( + [ + { + userOps: [userOp], + aggregator: blsAgg.address, + signature + } + ], + beneficiary + ) + .then( + () => 'ok', + (e) => e.errorName + )) as string + + expect(`${singleOpSigCheck},${handleRet}`).to.eq('ok,ok') + }) + + it('validateSignatures', async function () { + // yes, it does take long on hardhat, but quick on geth. + this.timeout(30000) + const userOp1 = await fillUserOp( + { + sender: account1.address + }, + entrypoint + ) + const requestHash = await blsAgg.getUserOpHash(userOp1) + const sig1 = signer1.sign(requestHash) + userOp1.signature = hexConcat(sig1) + + const userOp2 = await fillUserOp( + { + sender: account2.address + }, + entrypoint + ) + const requestHash2 = await blsAgg.getUserOpHash(userOp2) + const sig2 = signer2.sign(requestHash2) + userOp2.signature = hexConcat(sig2) + + const aggSig = aggregate([sig1, sig2]) + const aggregatedSig = await blsAgg.aggregateSignatures([ + userOp1, + userOp2 + ]) + expect(hexConcat(aggSig)).to.equal(aggregatedSig) + + const pubkeys = [signer1.pubkey, signer2.pubkey] + const v = new BlsVerifier(BLS_DOMAIN) + // off-chain check + const now = Date.now() + expect( + v.verifyMultiple(aggSig, pubkeys, [requestHash, requestHash2]) + ).to.equal(true) + console.log('verifyMultiple (mcl code)', Date.now() - now, 'ms') + const now2 = Date.now() + console.log( + 'validateSignatures gas= ', + await blsAgg.estimateGas.validateSignatures( + [userOp1, userOp2], + aggregatedSig + ) + ) + console.log( + 'validateSignatures (on-chain)', + Date.now() - now2, + 'ms' + ) + }) + + describe('#EntryPoint.simulateValidation with aggregator', () => { + let initCode: BytesLike + let signer3: any + before(async () => { + signer3 = fact.getSigner(arrayify(BLS_DOMAIN), '0x03') + initCode = hexConcat([ + accountDeployer.address, + accountDeployer.interface.encodeFunctionData( + 'createAccount', + [0, signer3.pubkey] + ) + ]) + }) + + it('validate after simulation returns ValidationResultWithAggregation', async () => { + const verifier = new BlsVerifier(BLS_DOMAIN) + const senderAddress = await entrypoint.callStatic + .getSenderAddress(initCode) + .catch((e) => e.errorArgs.sender) + await fund(senderAddress, '0.01') + const userOp = await fillUserOp( + { + sender: senderAddress, + initCode + }, + entrypoint + ) + const requestHash = await blsAgg.getUserOpHash(userOp) + const sigParts = signer3.sign(requestHash) + userOp.signature = hexConcat(sigParts) + + const { aggregatorInfo } = await entrypoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultWithAggregationCatch) + expect(aggregatorInfo.aggregator).to.eq(blsAgg.address) + expect(aggregatorInfo.stakeInfo.stake).to.eq(ONE_ETH) + expect(aggregatorInfo.stakeInfo.unstakeDelaySec).to.eq(2) + + const [signature] = defaultAbiCoder.decode( + ['bytes32[2]'], + userOp.signature + ) + const pubkey = (await blsAgg.getUserOpPublicKey(userOp)).map( + (n) => hexValue(n) + ) // TODO: returns uint256[4], verify needs bytes32[4] + const requestHash1 = await blsAgg.getUserOpHash(userOp) + + expect( + // @ts-expect-error nothing + verifier.verify(signature, pubkey, requestHash1) + ).to.equal(true) + }) + }) +}) diff --git a/packages/hebao_v3/test/automation/automation.test.ts b/packages/hebao_v3/test/automation/automation.test.ts new file mode 100644 index 000000000..e4f3f7a84 --- /dev/null +++ b/packages/hebao_v3/test/automation/automation.test.ts @@ -0,0 +1,878 @@ +import { ethers } from 'hardhat' +import { expect } from 'chai' +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { + faucetToken, + fixtureForAutoMation, + CONSTANTS, + userOpCast, + makeAnExecutor, + unApproveExecutor, + encodeSpells, + encodeFlashcastData, + approveExecutor +} from './automation_utils' + +describe('automation test', () => { + describe('connectorRegistry test', () => { + it('connector management', async () => { + const { connectorRegistry, deployer } = await loadFixture( + fixtureForAutoMation + ) + const role = await connectorRegistry.MANAGER() + // deployer is default manager + expect(await connectorRegistry.hasRole(role, deployer.address)) + .to.be.true + + const mockConnectors = [ethers.constants.AddressZero] + expect(await connectorRegistry.isConnectors(mockConnectors)).to + .be.false + await connectorRegistry.addConnectors(mockConnectors) + expect(await connectorRegistry.isConnectors(mockConnectors)).to + .be.true + await connectorRegistry.removeConnectors(mockConnectors) + expect(await connectorRegistry.isConnectors(mockConnectors)).to + .be.false + + // add already valid connectors again + await expect(connectorRegistry.addConnectors(mockConnectors)) + .not.to.reverted + }) + + it('permission test', async () => { + const { connectorRegistry, somebody } = await loadFixture( + fixtureForAutoMation + ) + const role = await connectorRegistry.MANAGER() + + expect(await connectorRegistry.hasRole(role, somebody.address)) + .to.be.false + const mockConnectors = [ethers.constants.AddressZero] + // only manager can add new connector + await expect( + connectorRegistry + .connect(somebody) + .addConnectors(mockConnectors) + ).to.revertedWith('not a manager') + await expect( + connectorRegistry + .connect(somebody) + .removeConnectors(mockConnectors) + ).to.revertedWith('not a manager') + + await connectorRegistry.grantRole(role, somebody.address) + expect(await connectorRegistry.hasRole(role, somebody.address)) + .to.be.true + await expect( + connectorRegistry + .connect(somebody) + .addConnectors(mockConnectors) + ).not.to.reverted + }) + }) + describe('permission test', () => { + it('approve test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + await expect( + approveExecutor(loadedFixture, ethers.constants.AddressZero) + ).to.revertedWith('LRC#104') + const executor = ethers.Wallet.createRandom() + await approveExecutor(loadedFixture, executor.address) + // check it is a valid executor + const { smartWallet } = loadedFixture + expect(await smartWallet.isExecutorOrOwner(executor.address)).to + .be.true + await expect( + unApproveExecutor(loadedFixture, ethers.constants.AddressZero) + ).to.revertedWith('LRC#309') + await unApproveExecutor(loadedFixture, executor.address) + }) + it('not approved executor should be rejected', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet } = loadedFixture + const wethConnector = loadedFixture.wethConnector + const data = wethConnector.interface.encodeFunctionData( + 'deposit', + [CONSTANTS.ONE_FOR_ETH, 0, 0] + ) + const someone = ethers.Wallet.createRandom() + + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: someone }, + loadedFixture + ) + ) + .to.revertedWithCustomError( + loadedFixture.entrypoint, + 'FailedOp' + ) + .withArgs(0, 'AA24 signature error') + + const executor = await makeAnExecutor(loadedFixture) + + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + + // prepare eth for executor + await loadedFixture.deployer.sendTransaction({ + to: executor.address, + value: CONSTANTS.ONE_FOR_ETH + }) + await expect( + smartWallet + .connect(executor) + .castFromExecutor([wethConnector.address], [data]) + ).not.to.reverted + + // cannot automation after unapprove + await unApproveExecutor(loadedFixture, executor.address) + + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: someone }, + loadedFixture + ) + ) + .to.revertedWithCustomError( + loadedFixture.entrypoint, + 'FailedOp' + ) + .withArgs(0, 'AA24 signature error') + }) + it('use contract as a executor', async () => { + // create a official guardian + const loadedFixture = await loadFixture(fixtureForAutoMation) + // prepare a contract as executor + const someone = ethers.Wallet.createRandom().connect( + ethers.provider + ) + await loadedFixture.deployer.sendTransaction({ + to: someone.address, + value: CONSTANTS.ONE_FOR_ETH + }) + const officialGuardian = await ( + await ethers.getContractFactory('OfficialGuardian') + ).deploy() + await officialGuardian + .connect(loadedFixture.deployer) + .addManager(someone.address) + // smartwallet approve the officialGuardian first + await approveExecutor(loadedFixture, officialGuardian.address) + + const wethConnector = loadedFixture.wethConnector + const data = wethConnector.interface.encodeFunctionData( + 'deposit', + [CONSTANTS.ONE_FOR_ETH, 0, 0] + ) + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: someone, contract: officialGuardian.address }, + loadedFixture + ) + ).not.to.reverted + }) + it('executor call directly', async () => {}) + it('cant cast when wallet is locked', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, wethConnector, entrypoint } = loadedFixture + const executor = await makeAnExecutor(loadedFixture) + await (await smartWallet.lock()).wait() + + const data = wethConnector.interface.encodeFunctionData( + 'deposit', + [CONSTANTS.ONE_FOR_ETH, 0, 0] + ) + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: wallet is locked') + }) + }) + + describe('basic connectors test', () => { + it('weth connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, wethConnector } = loadedFixture + const weth = await ethers.getContractAt( + 'TokenInterface', + CONSTANTS.WETH_ADDRESS + ) + const executor = await makeAnExecutor(loadedFixture) + + const balance1 = await weth.balanceOf(smartWallet.address) + const data = wethConnector.interface.encodeFunctionData( + 'deposit', + [CONSTANTS.ONE_FOR_ETH, 0, 0] + ) + await expect( + userOpCast( + [wethConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balance2 = await weth.balanceOf(smartWallet.address) + expect(balance2.sub(balance1)).eq(CONSTANTS.ONE_FOR_ETH) + }) + + it('compound connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, compoundConnector } = loadedFixture + const executor = await makeAnExecutor(loadedFixture) + + // USDC-A + const cTokenAddr = '0x39AA39c021dfbaE8faC545936693aC917d5E7563' + const cERC20 = await ethers.getContractAt( + 'IERC20Metadata', + cTokenAddr + ) + const cToken = await ethers.getContractAt( + 'CTokenInterface', + cTokenAddr + ) + const tokenAddr = await cToken.underlying() + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + '1' + ) + + // deposit + { + const data = compoundConnector.interface.encodeFunctionData( + 'deposit', + [tokenAddr, cTokenAddr, CONSTANTS.ONE_FOR_USDC, 0, 0] + ) + const balanceBefore = await cERC20.balanceOf( + smartWallet.address + ) + await expect( + userOpCast( + [compoundConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balanceAfter = await cERC20.balanceOf( + smartWallet.address + ) + expect(balanceAfter.sub(balanceBefore)).gt(0) + } + + // borrow + { + // "USDT-A" + const cToken = await ethers.getContractAt( + 'CTokenInterface', + '0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9' + ) + const tokenAddr = await cToken.underlying() + const token = await ethers.getContractAt( + 'IERC20Metadata', + tokenAddr + ) + const balanceBefore = await token.balanceOf( + smartWallet.address + ) + const data = compoundConnector.interface.encodeFunctionData( + 'borrow', + [ + tokenAddr, + cToken.address, + CONSTANTS.ONE_FOR_USDC.div(2), + 0, + 0 + ] + ) + await expect( + userOpCast( + [compoundConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balanceAfter = await token.balanceOf( + smartWallet.address + ) + expect(balanceAfter.sub(balanceBefore)).eq( + CONSTANTS.ONE_FOR_USDC.div(2) + ) + + // repay + const data2 = compoundConnector.interface.encodeFunctionData( + 'payback', + [ + tokenAddr, + cToken.address, + ethers.constants.MaxUint256, // repay all borrowed tokens + 0, + 0 + ] + ) + + await expect( + userOpCast( + [compoundConnector.address], + [data2], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + } + + // withdraw + const data = compoundConnector.interface.encodeFunctionData( + 'withdraw', + [tokenAddr, cTokenAddr, ethers.constants.MaxUint256, 0, 0] + ) + + await expect( + userOpCast( + [compoundConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + }) + it('aaveV3 connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, aaveV3Connector } = loadedFixture + const data = aaveV3Connector.interface.encodeFunctionData( + 'deposit', + [ + CONSTANTS.WSTETH_ADDRESS, + CONSTANTS.ONE_FOR_ETH.mul(10), + 0, + 0 + ] + ) + await faucetToken( + CONSTANTS.WSTETH_ADDRESS, + smartWallet.address, + '100' + ) + const wstETH = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.WSTETH_ADDRESS + ) + const wstETHBalanceBefore = await wstETH.balanceOf( + smartWallet.address + ) + const executor = await makeAnExecutor(loadedFixture) + await expect( + userOpCast( + [aaveV3Connector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const wstETHBalanceAfter = await wstETH.balanceOf( + smartWallet.address + ) + expect(wstETHBalanceBefore.sub(wstETHBalanceAfter)).eq( + CONSTANTS.ONE_FOR_ETH.mul(10) + ) + + // borrow weth from aavev3 + const borrowData = aaveV3Connector.interface.encodeFunctionData( + 'borrow', + [CONSTANTS.USDC_ADDRESS, CONSTANTS.ONE_FOR_USDC, 2, 0, 0] + ) + await expect( + userOpCast( + [aaveV3Connector.address], + [borrowData], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + + // payback all debts + // need some weth token to pay for interests + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + '10' + ) + const paybackData = + aaveV3Connector.interface.encodeFunctionData('payback', [ + CONSTANTS.USDC_ADDRESS, + ethers.constants.MaxUint256, + 2, + 0, + 0 + ]) + await expect( + userOpCast( + [aaveV3Connector.address], + [paybackData], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + // withdraw + const withdrawData = + aaveV3Connector.interface.encodeFunctionData('withdraw', [ + CONSTANTS.WSTETH_ADDRESS, + ethers.constants.MaxUint256, + 0, + 0 + ]) + await expect( + userOpCast( + [aaveV3Connector.address], + [withdrawData], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + }) + + it('lido connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, lidoConnector, deployer } = loadedFixture + const data = lidoConnector.interface.encodeFunctionData( + 'deposit', + [CONSTANTS.ONE_FOR_ETH, 0, 0] + ) + + // deposit eth to smartWallet first + await deployer.sendTransaction({ + to: smartWallet.address, + value: CONSTANTS.ONE_FOR_ETH.mul(3) + }) + + const ethBalanceBefore = await ethers.provider.getBalance( + smartWallet.address + ) + + const executor = await makeAnExecutor(loadedFixture) + await expect( + userOpCast( + [lidoConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const ethBalanceAfter = await ethers.provider.getBalance( + smartWallet.address + ) + // check ETH and stETH balance + expect(ethBalanceBefore.sub(ethBalanceAfter)).eq( + CONSTANTS.ONE_FOR_ETH + ) + + const stETH = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.STETH_ADDRESS + ) + const stETHBalance = await stETH.balanceOf(smartWallet.address) + expect(stETHBalance).to.gt(0) + // wrapAndStaking test + const wrapAndStakingData = + lidoConnector.interface.encodeFunctionData('wrapAndStaking', [ + CONSTANTS.ONE_FOR_ETH, + 0, + 0 + ]) + + const wstETH = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.WSTETH_ADDRESS + ) + const wstETHBalanceBefore = await wstETH.balanceOf( + smartWallet.address + ) + await expect( + userOpCast( + [lidoConnector.address], + [wrapAndStakingData], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const wstETHBalanceAfter = await wstETH.balanceOf( + smartWallet.address + ) + expect(wstETHBalanceAfter.sub(wstETHBalanceBefore)).gt(0) + // unwrap all wstETH + const unwrapData = lidoConnector.interface.encodeFunctionData( + 'unwrap', + [ethers.constants.MaxUint256, 0, 0] + ) + await expect( + userOpCast( + [lidoConnector.address], + [unwrapData], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + expect(await wstETH.balanceOf(smartWallet.address)).eq(0) + }) + + it('1inchv5 connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const executor = await makeAnExecutor(loadedFixture) + const { smartWallet, oneInchV5Connector } = loadedFixture + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + '100' + ) + const UNI = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.UNI_ADDRESS + ) + // TODO(get a valid calldata from 1inch swap api) + const callData = '0x' + const data = oneInchV5Connector.interface.encodeFunctionData( + 'sell', + [ + CONSTANTS.UNI_ADDRESS, + CONSTANTS.USDC_ADDRESS, + 3000, + 0, + callData, + 0 + ] + ) + + const balanceBefore = await UNI.balanceOf(smartWallet.address) + await expect( + userOpCast( + [oneInchV5Connector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balanceAfter = await UNI.balanceOf(smartWallet.address) + // TODO(fix it when using a valid calldata) + expect(balanceAfter.sub(balanceBefore).gt(0)).false + }) + + it('uniswapv3 connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, uniswapv3Connector } = loadedFixture + const UNI = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.UNI_ADDRESS + ) + const balance1 = await UNI.balanceOf(smartWallet.address) + const executor = await makeAnExecutor(loadedFixture) + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + '100' + ) + + // buy uni with usdc + const data2 = uniswapv3Connector.interface.encodeFunctionData( + 'sell', + [ + CONSTANTS.UNI_ADDRESS, + CONSTANTS.USDC_ADDRESS, + 3000, + 0, + CONSTANTS.ONE_FOR_USDC, + 0, + 0 + ] + ) + await expect( + userOpCast( + [uniswapv3Connector.address], + [data2], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balance2 = await UNI.balanceOf(smartWallet.address) + expect(balance2.sub(balance1).gt(0)).true + + // sell uni + const data = uniswapv3Connector.interface.encodeFunctionData( + 'buy', + [ + CONSTANTS.UNI_ADDRESS, + CONSTANTS.USDC_ADDRESS, + 3000, + ethers.utils.parseEther('1000'), // ratio + ethers.utils.parseEther('1'), // 1 UNI + 0, + 0 + ] + ) + await expect( + userOpCast( + [uniswapv3Connector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balance3 = await UNI.balanceOf(smartWallet.address) + expect(balance3.sub(balance2).gt(0)).true + }) + + it('uniswapv2 connector test', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { smartWallet, uniswapConnector } = loadedFixture + const UNI = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.UNI_ADDRESS + ) + const balance1 = await UNI.balanceOf(smartWallet.address) + const executor = await makeAnExecutor(loadedFixture) + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + '100' + ) + + // buy uni with usdc + const data2 = uniswapConnector.interface.encodeFunctionData( + 'sell', + [ + CONSTANTS.UNI_ADDRESS, + CONSTANTS.USDC_ADDRESS, + CONSTANTS.ONE_FOR_USDC, + 0, + 0, + 0 + ] + ) + await expect( + userOpCast( + [uniswapConnector.address], + [data2], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balance2 = await UNI.balanceOf(smartWallet.address) + expect(balance2.sub(balance1).gt(0)).true + + // sell uni + const data = uniswapConnector.interface.encodeFunctionData( + 'buy', + [ + CONSTANTS.UNI_ADDRESS, + CONSTANTS.USDC_ADDRESS, + ethers.utils.parseEther('1'), // 1 UNI + ethers.utils.parseEther('1000'), // ratio + 0, + 0 + ] + ) + await expect( + userOpCast( + [uniswapConnector.address], + [data], + { wallet: executor }, + loadedFixture + ) + ).not.to.reverted + const balance3 = await UNI.balanceOf(smartWallet.address) + expect(balance3.sub(balance2).gt(0)).true + }) + + // add liquidity + // remove liquidity + }) + + describe('flashloan test', () => { + it('margin trading', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { + uniswapConnector, + compoundConnector, + flashLoanConnector, + smartWallet, + usdc + } = loadedFixture + const ratio = 3 + const collateral = 200 + const decimal = await usdc.decimals() + const total = ethers.utils.parseUnits( + (collateral * ratio).toString(), + decimal + ) + const loan = ethers.utils.parseUnits( + (collateral * (ratio - 1)).toString(), + decimal + ) + await faucetToken( + CONSTANTS.USDC_ADDRESS, + smartWallet.address, + collateral.toString() + ) + const IdOne = '2878734423' + const spells = [ + { + connectorName: 'UNISWAP', + connectorAddr: uniswapConnector.address, + method: 'sell', + args: [ + CONSTANTS.ETH_ADDRESS, + CONSTANTS.USDC_ADDRESS, + total, + 0, + 0, + IdOne + ] // margin trade + }, + { + connectorName: 'COMPOUND', + connectorAddr: compoundConnector.address, + method: 'deposit', + args: [ + CONSTANTS.ETH_ADDRESS, + '0x4ddc2d193948926d02f9b1fe9e1daa0718270ed5', + 0, + IdOne, + 0 + ] + }, + { + connectorName: 'COMPOUND', + connectorAddr: compoundConnector.address, + method: 'borrow', + args: [ + CONSTANTS.USDC_ADDRESS, + '0x39aa39c021dfbae8fac545936693ac917d5e7563', + loan, + 0, + 0 + ] // borrow usdt, note use token id here + }, + { + connectorName: 'FLASHLOAN', + connectorAddr: flashLoanConnector.address, + method: 'flashPayback', + args: [CONSTANTS.USDC_ADDRESS, loan, 0, 0] + } + ] + + const calldata = encodeFlashcastData(spells) + const spells2 = [ + { + connectorName: 'FLASHLOAN', + connectorAddr: flashLoanConnector.address, + method: 'flashBorrowAndCast', + args: [CONSTANTS.USDC_ADDRESS, loan, calldata] + } + ] + + const executor = await makeAnExecutor(loadedFixture) + const balanceBefore = await usdc.balanceOf(smartWallet.address) + await userOpCast( + ...encodeSpells(spells2), + { wallet: executor }, + loadedFixture + ) + const balanceAfter = await usdc.balanceOf(smartWallet.address) + expect(balanceBefore.sub(balanceAfter)).eq( + ethers.utils.parseUnits(collateral.toString(), decimal) + ) + }) + it('leverage staking', async () => { + const loadedFixture = await loadFixture(fixtureForAutoMation) + const { + flashLoanConnector, + aaveV3Connector, + lidoConnector, + wethConnector, + smartWallet, + deployer + } = loadedFixture + + const ratio = 3 + const collateral = CONSTANTS.ONE_FOR_ETH + const total = collateral.mul(ratio) + const loan = total.sub(collateral) + + // prepare init eth for smart wallet + await deployer.sendTransaction({ + to: smartWallet.address, + value: collateral + }) + const wstETH = CONSTANTS.WSTETH_ADDRESS + const spells = [ + { + connectorName: 'WETH', + connectorAddr: wethConnector.address, + method: 'withdraw', + args: [loan, 0, 0] + }, + { + connectorName: 'LIDO', + connectorAddr: lidoConnector.address, + method: 'wrapAndStaking', + args: [total, 0, 0] + }, + { + connectorName: 'AAVEV3', + connectorAddr: aaveV3Connector.address, + method: 'deposit', + args: [wstETH, ethers.constants.MaxUint256, 0, 0] // margin trade + }, + { + connectorName: 'AAVEV3', + connectorAddr: aaveV3Connector.address, + method: 'borrow', + args: [CONSTANTS.WETH_ADDRESS, loan, 2, 0, 0] + }, + { + connectorName: 'FLASHLOAN', + connectorAddr: flashLoanConnector.address, + method: 'flashPayback', + args: [CONSTANTS.WETH_ADDRESS, loan, 0, 0] + } + ] + + const calldata = encodeFlashcastData(spells) + const spells2 = [ + { + connectorName: 'FLASHLOAN', + connectorAddr: flashLoanConnector.address, + method: 'flashBorrowAndCast', + args: [CONSTANTS.WETH_ADDRESS, loan, calldata] + } + ] + + const executor = await makeAnExecutor(loadedFixture) + await userOpCast( + ...encodeSpells(spells2), + { wallet: executor }, + loadedFixture + ) + }) + }) +}) diff --git a/packages/hebao_v3/test/automation/automation_utils.ts b/packages/hebao_v3/test/automation/automation_utils.ts new file mode 100644 index 000000000..ad553d23b --- /dev/null +++ b/packages/hebao_v3/test/automation/automation_utils.ts @@ -0,0 +1,342 @@ +import { ethers } from 'hardhat' +import { fixture } from '../../test/helper/fixture' +import { type Wallet, type BigNumberish } from 'ethers' +import { type Interface } from '@ethersproject/abi' +import { type TransactionReceipt } from '@ethersproject/providers' +import { + CompoundConnector__factory, + UniswapConnector__factory, + WETHConnector__factory, + FlashLoanConnector__factory, + LidoConnector__factory, + AaveV3Connector__factory +} from '../../typechain-types' + +import { + type SendUserOp, + type UserOperation, + fillUserOp, + getUserOpHash +} from '../../test/helper/AASigner' + +import { + type EntryPoint, + type LoopringCreate2Deployer, + type SmartWalletV3 +} from '../../typechain-types' + +export const CONSTANTS = { + RICH_ADDRESS: '0x176F3DAb24a159341c0509bB36B833E7fdd0a132', + USDC_ADDRESS: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + UNI_ADDRESS: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', + USDT_ADDRESS: '0xdAC17F958D2ee523a2206206994597C13D831ec7', + cUSDT_ADDRESS: '0xf650C3d88D12dB855b8bf7D11Be6C55A4e07dCC9', + WETH_ADDRESS: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + WBT_ADDRESS: '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599', + DAI_ADDRESS: '0x6B175474E89094C44Da98b954EedeAC495271d0F', + ETH_ADDRESS: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', + STETH_ADDRESS: '0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84', + WSTETH_ADDRESS: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0', + ONE_FOR_ETH: ethers.utils.parseEther('1'), + ONE_FOR_USDC: ethers.utils.parseUnits('1', 6) +} + +export const tokenMapping = { + BAT: { + cToken: '0x6c8c6b02e7b2be14d4fa6022dfd6d75921d90e4e', + token: '' + }, + COMP: { + cToken: '0x70e36f6bf80a52b3b46b3af8e106cc0ed743e8e4', + token: '' + }, + DAI: '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643', + REP: '0x158079ee67fce2f58472a96584a73c7ab9ac95c1', + UNI: '0x35a18000230da775cac24873d00ff85bccded550', + USDC: '0x39aa39c021dfbae8fac545936693ac917d5e7563', + USDT: '0xf650c3d88d12db855b8bf7d11be6c55a4e07dcc9', + WBTC: '0xc11b1268c1a384e55c48c2391d8d480264a3a7f4', + ZRX: '0xb3319f5d18bc0d84dd1b4825dcde5d5f7266d407', + TUSD: '0x12392F67bdf24faE0AF363c24aC620a2f67DAd86', + LINK: '0xFAce851a4921ce59e912d19329929CE6da6EB0c7' +} + +// eslint-disable-next-line +export async function fixtureForAutoMation() { + const initFixture = await fixture() + const { connectorRegistry } = initFixture + const ownedMemory = await ( + await ethers.getContractFactory('OwnedMemory') + ).deploy() + const wethConnector = await ( + await ethers.getContractFactory('WETHConnector') + ).deploy(ownedMemory.address) + const uniswapConnector = await ( + await ethers.getContractFactory('UniswapConnector') + ).deploy(ownedMemory.address) + const uniswapv3Connector = await ( + await ethers.getContractFactory('UniswapV3Connector') + ).deploy(ownedMemory.address) + const oneInchV5Connector = await ( + await ethers.getContractFactory('OneInchV5Connector') + ).deploy(ownedMemory.address) + const compoundConnector = await ( + await ethers.getContractFactory('CompoundConnector') + ).deploy(ownedMemory.address) + + const vaultAddr = '0xBA12222222228d8Ba445958a75a0704d566BF2C8' + const flashLoanPool = await ( + await ethers.getContractFactory('BalancerFlashLoan') + ).deploy(vaultAddr) + + const flashLoanConnector = await ( + await ethers.getContractFactory('FlashLoanConnector') + ).deploy(ownedMemory.address, flashLoanPool.address) + + const lidoConnector = await ( + await ethers.getContractFactory('LidoConnector') + ).deploy(ownedMemory.address) + + const aaveV3Connector = await ( + await ethers.getContractFactory('AaveV3Connector') + ).deploy(ownedMemory.address) + + await ( + await connectorRegistry.addConnectors([ + wethConnector.address, + flashLoanConnector.address, + uniswapConnector.address, + compoundConnector.address, + lidoConnector.address, + aaveV3Connector.address, + uniswapv3Connector.address, + oneInchV5Connector.address + ]) + ).wait() + + // can only be used in forknet test + const usdc = await ethers.getContractAt( + 'IERC20Metadata', + CONSTANTS.USDC_ADDRESS + ) + return { + ...initFixture, + wethConnector, + uniswapConnector, + oneInchV5Connector, + compoundConnector, + flashLoanConnector, + lidoConnector, + aaveV3Connector, + uniswapv3Connector, + flashLoanPool, + usdc + } +} + +interface Fixture { + smartWallet: SmartWalletV3 + smartWalletOwner: Wallet + create2: LoopringCreate2Deployer + entrypoint: EntryPoint + sendUserOp: SendUserOp +} + +const getSignedUserOp = async ( + callData: string, + nonce: BigNumberish, + smartWalletAddr: string, + signer: { wallet: Wallet; contract?: string }, + create2Addr: string, + entrypoint: EntryPoint, + byExecutor: boolean +): Promise => { + const partialUserOp: Partial = { + sender: smartWalletAddr, + nonce, + callData + } + const provider = entrypoint.provider + const op2 = await fillUserOp(partialUserOp, create2Addr, entrypoint) + const { chainId } = await provider!.getNetwork() + const message = ethers.utils.arrayify( + getUserOpHash(op2, entrypoint.address, chainId) + ) + + const rawSignature = await signer.wallet.signMessage(message) + const signature = byExecutor + ? ethers.utils.defaultAbiCoder.encode( + ['address', 'bytes'], + [signer.contract ?? signer.wallet.address, rawSignature] + ) + : rawSignature + const signedUserOp = { + ...op2, + signature + } + return signedUserOp +} + +export const faucetToken = async ( + tokenAddress: string | 0, + myAddress: string, + amount: string +): Promise => { + const impersonatedRichAddr = await ethers.getImpersonatedSigner( + CONSTANTS.RICH_ADDRESS + ) + if (tokenAddress === 0) { + return impersonatedRichAddr + .sendTransaction({ + to: myAddress, + value: ethers.utils.parseEther(amount) + }) + .then(async (tx) => tx.wait()) + } else { + const token = await ethers.getContractAt( + 'IERC20Metadata', + tokenAddress, + impersonatedRichAddr + ) + const dc = await token.decimals() + return token + .transfer(myAddress, ethers.utils.parseUnits(amount, dc)) + .then(async (tx) => tx.wait()) + } +} + +export const userOpCast = async ( + addresses: string[], + datas: string[], + signer: { wallet: Wallet; contract?: string }, + loadedFixture: Fixture +): Promise => { + const { smartWallet, create2, entrypoint, sendUserOp } = + loadedFixture + const nonce = await smartWallet.getNonce() + + const data = smartWallet.interface.encodeFunctionData( + 'castFromEntryPoint', + [addresses, datas] + ) + const signedUserOp = await getSignedUserOp( + data, + nonce, + smartWallet.address, + signer, + create2.address, + entrypoint, + true + ) + return await sendUserOp(signedUserOp) +} + +export const approveExecutor = async ( + loadedFixture: Fixture, + executorAddr: string +): Promise => { + const { + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + } = loadedFixture + const nonce = await smartWallet.getNonce() + const validUntil = Math.floor( + Date.now() / 1000 + 24 * 60 * 60 + ).toString() + const data = smartWallet.interface.encodeFunctionData( + 'approveExecutor', + [executorAddr, validUntil] + ) + const signedUserOp = await getSignedUserOp( + data, + nonce, + smartWallet.address, + { wallet: smartWalletOwner }, + create2.address, + entrypoint, + false + ) + await sendUserOp(signedUserOp) +} + +export const makeAnExecutor = async ( + loadedFixture: Fixture +): Promise => { + const executor = ethers.Wallet.createRandom().connect( + ethers.provider + ) + await approveExecutor(loadedFixture, executor.address) + return executor +} + +export const unApproveExecutor = async ( + loadedFixture: Fixture, + executor: string +): Promise => { + const { + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + } = loadedFixture + const nonce = await smartWallet.getNonce() + const data = smartWallet.interface.encodeFunctionData( + 'unApproveExecutor', + [executor] + ) + const signedUserOp = await getSignedUserOp( + data, + nonce, + smartWallet.address, + { wallet: smartWalletOwner }, + create2.address, + entrypoint, + false + ) + return sendUserOp(signedUserOp) +} + +export const connectMapping: Record = { + COMPOUND: CompoundConnector__factory.createInterface(), + UNISWAP: UniswapConnector__factory.createInterface(), + WETH: WETHConnector__factory.createInterface(), + FLASHLOAN: FlashLoanConnector__factory.createInterface(), + AAVEV3: AaveV3Connector__factory.createInterface(), + LIDO: LidoConnector__factory.createInterface() +} + +interface SpellType { + connectorName: string + connectorAddr: string + method: string + args: any[] +} + +export const encodeSpells = ( + spells: SpellType[] +): [string[], string[]] => { + const targets = spells.map((a) => a.connectorAddr) + const calldatas = spells.map((a) => { + if (!(a.connectorName in connectMapping)) { + throw new Error(`Couldn't find connector: ${a.connectorName}`) + } + return connectMapping[a.connectorName].encodeFunctionData( + a.method, + a.args + ) + }) + return [targets, calldatas] +} + +export function encodeFlashcastData(spells: SpellType[]): string { + const encodeSpellsData = encodeSpells(spells) + const argTypes = ['address[]', 'bytes[]'] + return ethers.utils.defaultAbiCoder.encode(argTypes, [ + encodeSpellsData[0], + encodeSpellsData[1] + ]) +} diff --git a/packages/hebao_v3/test/change_entrypoint.test.ts b/packages/hebao_v3/test/change_entrypoint.test.ts new file mode 100644 index 000000000..e0c5700f1 --- /dev/null +++ b/packages/hebao_v3/test/change_entrypoint.test.ts @@ -0,0 +1,88 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { localUserOpSender } from './helper/AASigner' +import { fixture } from './helper/fixture' +import { sendTx } from './helper/utils' +import { ErrorCodes } from './helper/error_codes' + +describe('change entrypoint', () => { + it('basic usecase', async () => { + const { + smartWallet, + smartWalletOwner, + entrypoint, + usdtToken, + paymaster, + create2, + deployer + } = await loadFixture(fixture) + // check old entrypoint address + const entryPointAddr = await smartWallet.entryPoint() + expect(entryPointAddr).eq(entrypoint.address) + + // deploy new entrypoint + const newEntryPoint = await ( + await ethers.getContractFactory('EntryPoint') + ).deploy() + await smartWallet.changeEntryPoint(newEntryPoint.address) + expect(await smartWallet.entryPoint()).eq(newEntryPoint.address) + + // send userop using new entrypoint + // approve first + const approveToken = await usdtToken.populateTransaction.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + + const sendUserOp = localUserOpSender( + newEntryPoint.address, + deployer + ) + await expect( + sendTx( + [approveToken], + smartWallet, + smartWalletOwner, + create2, + newEntryPoint, + sendUserOp + ) + ).not.to.reverted + + // cannot send userop from old entrypoint + await expect( + sendTx( + [approveToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + ).to.rejectedWith( + `${ErrorCodes.NOT_OWNER_SELF_OR_ENTRYPOINT_OR_LOCKED}` + ) + }) + + it('failure cases', async () => { + const { smartWallet } = await loadFixture(fixture) + await expect( + smartWallet.changeEntryPoint(ethers.constants.AddressZero) + ).to.rejectedWith(`${ErrorCodes.ZERO_ADDRESS}`) + await expect( + smartWallet.changeEntryPoint(await smartWallet.entryPoint()) + ).to.rejectedWith(`${ErrorCodes.INVALID_SAME_ENTRYPOINT}`) + + const other = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const newEntryPoint = '0x' + '11'.repeat(20) + await expect( + smartWallet.connect(other).changeEntryPoint(newEntryPoint) + ).to.rejectedWith( + `${ErrorCodes.NOT_OWNER_SELF_OR_ENTRYPOINT_OR_LOCKED}` + ) + }) +}) diff --git a/packages/hebao_v3/test/eip4337.test.ts b/packages/hebao_v3/test/eip4337.test.ts new file mode 100644 index 000000000..421b78f49 --- /dev/null +++ b/packages/hebao_v3/test/eip4337.test.ts @@ -0,0 +1,536 @@ +import { + loadFixture, + setBalance +} from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { + BigNumber, + type BigNumberish, + type PopulatedTransaction, + type Wallet +} from 'ethers' +import { ethers } from 'hardhat' + +import { + type EntryPoint, + type LoopringCreate2Deployer, + type SmartWalletV3, + SmartWalletV3__factory +} from '../typechain-types' + +import { + fillAndMultiSign, + fillAndSign, + type UserOperation +} from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { + createSmartWallet, + getCurrentQuota, + sendTx, + simulationResultCatch +} from './helper/utils' + +describe('eip4337 test', () => { + // execute tx from entrypoint instead of `execute` or `executebatch` + async function getSignedUserOp( + tx: PopulatedTransaction, + nonce: BigNumberish, + smartWallet: SmartWalletV3, + smartWalletOwner: Wallet, + create2: LoopringCreate2Deployer, + entrypoint: EntryPoint + ): Promise { + const partialUserOp: Partial = { + sender: smartWallet.address, + nonce, + callData: tx.data, + callGasLimit: '126880' + } + const signedUserOp = await fillAndSign( + partialUserOp, + smartWalletOwner, + create2.address, + entrypoint + ) + return signedUserOp + } + + it('empty calldata', async () => { + const { + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + entrypoint + } = await loadFixture(fixture) + const tx = { to: smartWallet.address, data: '0x' } + const nonce = await smartWallet.getNonce() + const signedUserOp = await getSignedUserOp( + tx, + nonce, + smartWallet, + smartWalletOwner, + create2, + entrypoint + ) + await entrypoint.callStatic + .simulateValidation(signedUserOp) + .catch(simulationResultCatch) + await sendUserOp(signedUserOp) + }) + + it('invalid nonce', async () => { + const { smartWallet, smartWalletOwner, create2, entrypoint } = + await loadFixture(fixture) + const changeDailyQuota = + await smartWallet.populateTransaction.changeDailyQuota(100) + // too small or too larger, neither of them is valid + const invalidNonces = [ethers.constants.MaxUint256] + for (let i = 0; i < invalidNonces.length; ++i) { + const signedUserOp = await getSignedUserOp( + changeDailyQuota, + invalidNonces[i], + smartWallet, + smartWalletOwner, + create2, + entrypoint + ) + await expect( + entrypoint.callStatic.simulateValidation(signedUserOp) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA25 invalid account nonce') + } + }) + it('execute tx directly from entrypoint', async () => { + const { + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + entrypoint + } = await loadFixture(fixture) + const addGuardian = + await smartWallet.populateTransaction.addGuardian( + ethers.constants.AddressZero + ) + const nonce = await smartWallet.getNonce() + const signedUserOp = await getSignedUserOp( + addGuardian, + nonce, + smartWallet, + smartWalletOwner, + create2, + entrypoint + ) + await sendUserOp(signedUserOp) + + // replay it using the same nonce + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA25 invalid account nonce') + }) + it('cannot execute changeDailyQuota tx when wallet is locked', async () => { + const { + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + entrypoint + } = await loadFixture(fixture) + await smartWallet.lock() + const changeDailyQuota = + await smartWallet.populateTransaction.changeDailyQuota(100) + const nonce = await smartWallet.getNonce() + const signedUserOp = await getSignedUserOp( + changeDailyQuota, + nonce, + smartWallet, + smartWalletOwner, + create2, + entrypoint + ) + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: wallet is locked') + }) + + it('check valid until', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + + const newQuota = 100 + let validUntil = 1 + const approvalOption = { + validUntil, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeDailyQuota + } + const callData = smartWallet.interface.encodeFunctionData( + 'changeDailyQuotaWA', + [newQuota] + ) + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + // new salt + approvalOption.salt = ethers.utils.randomBytes(32) + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA22 expired or not due') + const block = await ethers.provider.getBlock('latest') + validUntil = block.timestamp + 3600 + + const signedUserOp2 = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await entrypoint.callStatic + .simulateValidation(signedUserOp2) + .catch(simulationResultCatch) + }) + it('transfer token from wallet owner', async () => { + const { smartWallet, deployer, usdtToken } = + await loadFixture(fixture) + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + const receiver = deployer.address + const usdtTokenBalanceBefore = await usdtToken.balanceOf(receiver) + const tokenAmount = ethers.utils.parseUnits('100', 6) + await smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + false + ) + const usdtTokenBalanceAfter = await usdtToken.balanceOf(receiver) + expect(usdtTokenBalanceAfter.sub(usdtTokenBalanceBefore)).to.eq( + tokenAmount + ) + }) + it('transfer token with eth using entrypoint', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + deployer, + sendUserOp, + usdtToken + } = await loadFixture(fixture) + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + const tokenAmount = ethers.utils.parseUnits('100', 6) + const transferToken = + await usdtToken.populateTransaction.transfer( + deployer.address, + tokenAmount + ) + + { + const preDeposit = await smartWallet.getDeposit() + const ethBalanceBefore = await ethers.provider.getBalance( + deployer.address + ) + const usdtTokenBalanceBefore = await usdtToken.balanceOf( + deployer.address + ) + // pay for gas using prefund eth + const recipt = await sendTx( + [transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + const postDeposit = await smartWallet.getDeposit() + const ethBalanceAfter = await ethers.provider.getBalance( + deployer.address + ) + const usdtTokenBalanceAfter = await usdtToken.balanceOf( + deployer.address + ) + const gasCost = recipt.effectiveGasPrice.mul(recipt.gasUsed) + // relayer balance after = relayer balance before + ethReceived - gasCost + expect(preDeposit.sub(postDeposit)).eq( + ethBalanceAfter.sub(ethBalanceBefore).add(gasCost) + ) + + // check usdt token balance of receiver + expect(usdtTokenBalanceAfter.sub(usdtTokenBalanceBefore)).to.eq( + tokenAmount + ) + } + + { + // execute batch + const usdtTokenBalanceBefore = await usdtToken.balanceOf( + deployer.address + ) + const transferToken = + await smartWallet.populateTransaction.transferToken( + usdtToken.address, + deployer.address, + tokenAmount, + '0x', + false + ) + await expect( + sendTx( + [transferToken, transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + ).not.to.reverted + const usdtTokenBalanceAfter = await usdtToken.balanceOf( + deployer.address + ) + // transfer tokens for two times + expect(usdtTokenBalanceAfter.sub(usdtTokenBalanceBefore)).to.eq( + tokenAmount.mul(2) + ) + } + + // pay for gas using eth in smartwallet, transfer eth during userop execution + // use up all prefund eth + { + await smartWallet.withdrawDepositTo( + ethers.constants.AddressZero, + await smartWallet.getDeposit() + ) + const walletEthBalanceBefore = await ethers.provider.getBalance( + smartWallet.address + ) + const relayerEthBalanceBefore = + await ethers.provider.getBalance(deployer.address) + const recipt = await sendTx( + [transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + const walletEthBalanceAfter = await ethers.provider.getBalance( + smartWallet.address + ) + const relayerEthBalanceAfter = await ethers.provider.getBalance( + deployer.address + ) + // relayer balance after = relayer balance before + ethReceived - gasCost + const gasCost = recipt.effectiveGasPrice.mul(recipt.gasUsed) + // left gas will remain in entrypoint for the next usage + const prefund = await smartWallet.getDeposit() + expect( + walletEthBalanceBefore.sub(walletEthBalanceAfter).sub(prefund) + ).eq( + relayerEthBalanceAfter + .sub(relayerEthBalanceBefore) + .add(gasCost) + ) + } + }) + + it('deposit and withdraw eth in entrypoint', async () => { + const { smartWallet, deployer } = await loadFixture(fixture) + const preDeposit = await smartWallet.getDeposit() + const amount = ethers.utils.parseEther('1') + await smartWallet.addDeposit({ value: amount }) + const postDeposit = await smartWallet.getDeposit() + expect(postDeposit.sub(preDeposit)).to.eq(amount) + // withdraw deposited eth + const receiver = deployer.address + const preBalance = await ethers.provider.getBalance(receiver) + await smartWallet.withdrawDepositTo(receiver, postDeposit) + const postBalance = await ethers.provider.getBalance(receiver) + expect(await smartWallet.getDeposit()).to.eq(0) + expect(postBalance.sub(preBalance)).to.eq(postDeposit) + }) + + it('skip nonce success when changing dailyquota with approval even if wallet is locked', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + // lock wallet first + await smartWallet.lock() + + const newQuota = 100 + // skip nonce by using new key + const key = 1 + const keyShifted = BigNumber.from(key).shl(64) + const callData = smartWallet.interface.encodeFunctionData( + 'changeDailyQuotaWA', + [newQuota] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeDailyQuota + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint, + { nonce: keyShifted } + ) + const recipt = await sendUserOp(signedUserOp) + const quotaInfo = (await smartWallet.wallet()).quota + const currentQuota = await getCurrentQuota( + quotaInfo, + recipt.blockNumber + ) + expect(currentQuota).to.equal(newQuota) + expect(quotaInfo.pendingUntil.toString()).to.equal('0') + + // replay it when using the same aproval hash + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: HASH_EXIST') + }) + + describe('read methods', () => { + it('quota', async () => { + const { smartWallet } = await loadFixture(fixture) + const walletData = await smartWallet.wallet() + const quotaInfo = walletData.quota + // TODO(add check for quota info) + quotaInfo + }) + + it('guardians', async () => { + const { smartWallet } = await loadFixture(fixture) + const actualGuardians = await smartWallet.getGuardians(true) + // TODO(add check here) + actualGuardians + }) + + it('isWhitelisted', async () => { + const { smartWallet } = await loadFixture(fixture) + const isWhitelisted = await smartWallet.isWhitelisted( + '0x' + '22'.repeat(20) + ) + // TODO(add check here) + isWhitelisted + }) + + it('getNonce', async () => { + const { smartWallet } = await loadFixture(fixture) + const walletData = await smartWallet.wallet() + expect(walletData.nonce).to.eq(0) + }) + }) + + describe('owner setter', () => { + it('should be able to set owner for a blank wallet', async () => { + const { walletFactory, blankOwner, guardians } = + await loadFixture(fixture) + const ownerSetter = blankOwner.address + const other = ethers.Wallet.createRandom().connect( + ethers.provider + ) + // prepare gas fee + await setBalance(other.address, ethers.utils.parseEther('1')) + + const salt = ethers.utils.formatBytes32String('0x5') + await createSmartWallet( + blankOwner, + guardians.map((g) => g.address.toLowerCase()).sort(), + walletFactory, + salt + ) + + const smartWalletAddr = + await walletFactory.computeWalletAddress( + blankOwner.address, + salt + ) + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + blankOwner + ) + + // check owner before: + const ownerBefore = (await smartWallet.wallet()).owner + expect(ownerBefore.toLowerCase()).to.equal( + ownerSetter.toLowerCase() + ) + + const newOwner = '0x' + '12'.repeat(20) + // other accounts can not set owner: + await expect( + smartWallet.connect(other).transferOwnership(newOwner) + ).to.rejectedWith('NOT_ALLOWED_TO_SET_OWNER') + + // ownerSetter should be able to set owner if owner is blankOwner + await smartWallet + .connect(blankOwner) + .transferOwnership(newOwner) + const ownerAfter = (await smartWallet.wallet()).owner + expect(ownerAfter.toLowerCase()).to.equal( + newOwner.toLowerCase() + ) + + // ownerSetter should not be able to set owner again + const newOwner2 = '0x' + '34'.repeat(20) + await expect( + smartWallet.connect(blankOwner).transferOwnership(newOwner2) + ).to.rejectedWith('NOT_ALLOWED_TO_SET_OWNER') + }) + }) +}) diff --git a/packages/hebao_v3/test/erc20.test.ts b/packages/hebao_v3/test/erc20.test.ts new file mode 100644 index 000000000..35eed4458 --- /dev/null +++ b/packages/hebao_v3/test/erc20.test.ts @@ -0,0 +1,299 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { expect, assert } from 'chai' +import { ethers } from 'hardhat' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { getFirstEvent, sendTx } from './helper/utils' + +describe('erc20 test', () => { + it('basic success test', async () => { + // execute approve, transfer and call contract using batch way + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + deployer, + sendUserOp, + usdtToken, + testTarget + } = await loadFixture(fixture) + // prepare usdt tokens + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + const tokenAmount = ethers.utils.parseUnits('100', 6) + const receiver = deployer.address + const approve = + await smartWallet.populateTransaction.approveToken( + usdtToken.address, + receiver, + tokenAmount, + false + ) + const transferToken = + await smartWallet.populateTransaction.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + false + ) + + const functionDefault = + await testTarget.populateTransaction.functionDefault(0) + const callcontract = + await smartWallet.populateTransaction.callContract( + receiver, + 0, + functionDefault.data!, + false + ) + + const callData = testTarget.interface.encodeFunctionData( + 'functionPayable', + [10] + ) + const approveThenCall = + await smartWallet.populateTransaction.approveThenCallContract( + usdtToken.address, + testTarget.address, + ethers.utils.parseEther('10000'), + ethers.utils.parseEther('0.01'), + callData, + false + ) + + await sendTx( + [approve, transferToken, callcontract, approveThenCall], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect(await usdtToken.balanceOf(receiver)).to.eq(tokenAmount) + }) + + it('execute from wallet owner', async () => { + const { smartWallet, deployer, usdtToken, testTarget } = + await loadFixture(fixture) + // prepare usdt tokens + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + const tokenAmount = ethers.utils.parseUnits('100', 6) + const receiver = deployer.address + // approve first + await smartWallet.populateTransaction.approveToken( + usdtToken.address, + receiver, + tokenAmount, + false + ) + // then transfer token + await smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + false + ) + expect(await usdtToken.balanceOf(receiver)).to.eq(tokenAmount) + // finally call contract + const functionDefault = + await testTarget.populateTransaction.functionDefault(0) + await expect( + smartWallet.populateTransaction.callContract( + receiver, + 0, + functionDefault.data!, + false + ) + ).not.to.reverted + + // approvethencall + const callData = testTarget.interface.encodeFunctionData( + 'functionPayable', + [10] + ) + const tx = await smartWallet.approveThenCallContract( + usdtToken.address, + testTarget.address, + ethers.utils.parseEther('10000'), + ethers.utils.parseEther('0.01'), + callData, + false + ) + const event = await getFirstEvent( + testTarget, + tx.blockNumber!, + 'Invoked' + ) + assert(event.args) + expect(event.args.sender).to.equal(smartWallet.address) + }) + + describe('execute tx with approval', () => { + it('approve token test', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + deployer, + sendUserOp, + smartWalletImpl, + guardians, + usdtToken + } = await loadFixture(fixture) + + const toAddr = deployer.address + const amount = 100 + const callData = smartWallet.interface.encodeFunctionData( + 'approveTokenWA', + [usdtToken.address, toAddr, amount] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ApproveToken + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await sendUserOp(signedUserOp) + // check allowance + const allowance = await usdtToken.allowance( + smartWallet.address, + toAddr + ) + expect(allowance).to.eq(amount) + }) + + it('callcontract test', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + smartWalletImpl, + guardians, + testTarget + } = await loadFixture(fixture) + + const functionDefault = + await testTarget.populateTransaction.functionDefault(0) + const callData = smartWallet.interface.encodeFunctionData( + 'callContractWA', + [testTarget.address, 0, functionDefault.data] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.CallContract + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + const recipt = await sendUserOp(signedUserOp) + const event = await getFirstEvent( + testTarget, + recipt.blockNumber, + 'Invoked' + ) + assert(event.args) + expect(event.args.sender).to.equal(smartWallet.address) + }) + + it('approveThenCallContract test', async () => { + const { + sendUserOp, + entrypoint, + create2, + guardians, + testTarget, + usdtToken, + smartWallet: wallet, + smartWalletOwner, + smartWalletImpl, + smartWallet + } = await loadFixture(fixture) + const innerCallData = testTarget.interface.encodeFunctionData( + 'functionPayable', + [10] + ) + const amount = ethers.utils.parseEther('10000') + const value = ethers.utils.parseEther('50') + const callData = smartWallet.interface.encodeFunctionData( + 'approveThenCallContractWA', + [ + usdtToken.address, + testTarget.address, + amount.toString(), + value, + innerCallData + ] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ApproveThenCallContract + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + const recipt = await sendUserOp(signedUserOp) + const event = await getFirstEvent( + testTarget, + recipt.blockNumber, + 'Invoked' + ) + assert(event.args) + expect(event.args.sender).to.equal(wallet.address) + }) + }) +}) diff --git a/packages/hebao_v3/test/guardian.test.ts b/packages/hebao_v3/test/guardian.test.ts new file mode 100644 index 000000000..71d0e39ba --- /dev/null +++ b/packages/hebao_v3/test/guardian.test.ts @@ -0,0 +1,645 @@ +import { + loadFixture, + setBalance, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { increase } from '@nomicfoundation/hardhat-network-helpers/dist/src/helpers/time' +import { expect, assert } from 'chai' +import { ethers } from 'hardhat' +import { type Wallet } from 'ethers' + +import { + GuardianLib__factory, + SmartWalletV3__factory, + type WalletFactory, + type EntryPoint, + type SmartWalletV3 +} from '../typechain-types' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { + createSmartWallet, + getBlockTimestamp, + sendTx +} from './helper/utils' + +describe('guardian test', () => { + const three_days = 3 * 3600 * 24 + const guardianInterfact = GuardianLib__factory.createInterface() + async function createRandomWallet( + smartWalletOwner: Wallet, + guardians: Wallet[], + walletFactory: WalletFactory + ): Promise { + const salt = ethers.utils.formatBytes32String('0x1') + await createSmartWallet( + smartWalletOwner, + guardians.map((g) => g.address.toLowerCase()).sort(), + walletFactory, + salt + ) + + const smartWalletAddr = await walletFactory.computeWalletAddress( + smartWalletOwner.address, + salt + ) + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + return smartWallet + } + it('basic testcase', async () => { + const { smartWallet } = await loadFixture(fixture) + const guardian1 = '0x' + '12'.repeat(20) + await expect( + smartWallet.addGuardian(ethers.constants.AddressZero) + ).to.rejectedWith('LRC#104') + + const tx1 = await smartWallet.addGuardian(guardian1) + const receipt1 = await tx1.wait() + // console.log("receipt1:", receipt1); + + assert( + receipt1.events !== undefined && receipt1.events.length > 0 + ) + const eventData = receipt1.events[0].data + const eventTopics = receipt1.events[0].topics + const addEvent = guardianInterfact.decodeEventLog( + 'GuardianAdded(address,uint256)', + eventData, + eventTopics + ) + // console.log("addEvent:", addEvent.guardian); + expect(addEvent.guardian).to.equal(guardian1) + const blockTime = await getBlockTimestamp(tx1.blockNumber!) + // first guardian should be effective immediately: + expect(addEvent.effectiveTime.toNumber()).to.equal( + blockTime + three_days + ) + }) + + it('first two guardian additions should be effective immediately', async () => { + const guardian1 = '0x' + '12'.repeat(20) + const { smartWalletOwner, walletFactory } = + await loadFixture(fixture) + const wallet = await createRandomWallet( + smartWalletOwner, + [], + walletFactory + ) + const tx1 = await wallet.addGuardian(guardian1) + const receipt1 = await tx1.wait() + + // console.log("GuardianLib:", GuardianLib); + assert( + receipt1.events !== undefined && receipt1.events.length > 0 + ) + const eventData1 = receipt1.events[0].data + const eventTopics1 = receipt1.events[0].topics + const addEvent1 = guardianInterfact.decodeEventLog( + 'GuardianAdded(address,uint256)', + eventData1, + eventTopics1 + ) + // console.log("addEvent:", addEvent.guardian); + expect(addEvent1.guardian).to.equal(guardian1) + const blockTime1 = await getBlockTimestamp(tx1.blockNumber!) + // first guardian should be effective immediately: + expect(addEvent1.effectiveTime.toNumber()).to.equal( + blockTime1 + 1 + ) + + const guardian2 = '0x' + '22'.repeat(20) + const tx2 = await wallet.addGuardian(guardian2) + const receipt2 = await tx2.wait() + + // console.log("GuardianLib:", GuardianLib); + assert( + receipt2.events !== undefined && receipt2.events.length > 0 + ) + const eventData2 = receipt2.events[0].data + const eventTopics2 = receipt2.events[0].topics + const addEvent2 = guardianInterfact.decodeEventLog( + 'GuardianAdded(address,uint256)', + eventData2, + eventTopics2 + ) + expect(addEvent2.guardian).to.equal(guardian2) + const blockTime2 = await getBlockTimestamp(tx2.blockNumber!) + // second guardian should be effective immediately: + expect(addEvent2.effectiveTime.toNumber()).to.equal( + blockTime2 + 1 + ) + }) + + it('the third guardian addition will be effective in 3 days', async () => { + const guardian3 = '0x' + '33'.repeat(20) + const { smartWallet: wallet } = await loadFixture(fixture) + const tx1 = await wallet.addGuardian(guardian3) + const receipt1 = await tx1.wait() + + // console.log("GuardianLib:", GuardianLib); + assert( + receipt1.events !== undefined && receipt1.events.length > 0 + ) + const eventData1 = receipt1.events[0].data + const eventTopics1 = receipt1.events[0].topics + const addEvent1 = guardianInterfact.decodeEventLog( + 'GuardianAdded(address,uint256)', + eventData1, + eventTopics1 + ) + // console.log("addEvent:", addEvent.guardian); + expect(addEvent1.guardian).to.equal(guardian3) + const blockTime1 = await getBlockTimestamp(tx1.blockNumber) + // third guardian will be effective in 3 days. + expect(addEvent1.effectiveTime.toNumber()).to.equal( + blockTime1 + three_days + ) + }) + it('guardian deletion will be effective in 3 days', async () => { + const { smartWallet: wallet, guardians } = + await loadFixture(fixture) + const guardian1 = guardians[0].address + // await wallet.addGuardian(guardian1); + const tx1 = await wallet.removeGuardian(guardian1) + const receipt1 = await tx1.wait() + + assert( + receipt1.events !== undefined && receipt1.events.length > 0 + ) + const eventData = receipt1.events[0].data + const eventTopics = receipt1.events[0].topics + const removeEvent = guardianInterfact.decodeEventLog( + 'GuardianRemoved(address,uint256)', + eventData, + eventTopics + ) + + expect(removeEvent.guardian).to.equal(guardian1) + const blockTime = await getBlockTimestamp(tx1.blockNumber!) + expect(removeEvent.effectiveTime.toNumber()).to.equal( + blockTime + three_days + ) + }) + + it('guardian can not be owner', async () => { + const { smartWalletOwner, guardians, walletFactory } = + await loadFixture(fixture) + await expect( + createRandomWallet( + smartWalletOwner, + [smartWalletOwner, guardians[0]], + walletFactory + ) + ).to.revertedWith('LRC#418') + + const wallet = await createRandomWallet( + smartWalletOwner, + [guardians[0]], + walletFactory + ) + + await expect( + wallet.addGuardian(smartWalletOwner.address) + ).to.rejectedWith('LRC#418') + }) + + it('guardian can be smartwallet', async () => { + const { + sendUserOp, + create2, + entrypoint, + smartWalletOwner, + smartWallet, + guardians, + walletFactory, + usdtToken, + deployer, + smartWalletImpl + } = await loadFixture(fixture) + const guardianOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const guardian = await createRandomWallet( + guardianOwner, + [], + walletFactory + ) + await smartWallet.addGuardian(guardian.address) + await time.increase(three_days) + + // use new guardian signature to approve token + const receiver = deployer.address + const tokenAmount = ethers.utils.parseUnits('100', 6) + const callData = smartWallet.interface.encodeFunctionData( + 'approveTokenWA', + [usdtToken.address, receiver, tokenAmount] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ApproveToken + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { signer: guardians[0] }, + { + signer: guardianOwner, + smartWalletAddress: guardian.address + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + expect( + await usdtToken.allowance(smartWallet.address, receiver) + ).to.eq(tokenAmount) + }) + + describe('execute tx from entrypoint with nonce', () => { + it('add and remove guardian test', async () => { + const { smartWallet } = await loadFixture(fixture) + const guardian = ethers.Wallet.createRandom().connect( + ethers.provider + ) + await smartWallet.addGuardian(guardian.address) + expect(await smartWallet.isGuardian(guardian.address, true)).to + .be.true + // during pending period + expect(await smartWallet.isGuardian(guardian.address, false)).to + .be.false + await time.increase(three_days) + expect(await smartWallet.isGuardian(guardian.address, false)).to + .be.true + + // remove + await smartWallet.removeGuardian(guardian.address) + await time.increase(three_days) + expect(await smartWallet.isGuardian(guardian.address, true)).to + .be.false + + // TODO(add test case that remove before pending adding period) + }) + }) + + describe('execute tx with approval(skip nonce)', () => { + it('add guardian test', async () => { + const { + sendUserOp, + smartWalletOwner, + guardians, + create2, + entrypoint, + smartWallet, + smartWalletImpl + } = await loadFixture(fixture) + + // add new guardian + const guardian3 = '0x' + '12'.repeat(20) + const callData = smartWallet.interface.encodeFunctionData( + 'addGuardianWA', + [guardian3] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.AddGuardian + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [{ signer: smartWalletOwner }, { signer: guardians[0] }], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + const receipt = await sendUserOp(signedUserOp) + assert( + receipt.events !== undefined && receipt.events.length > 0 + ) + // skip BeforeExecutionEvent + const eventData = receipt.events[1].data + const eventTopics = receipt.events[1].topics + const addEvent = guardianInterfact.decodeEventLog( + 'GuardianAdded(address,uint256)', + eventData, + eventTopics + ) + + expect(addEvent.guardian).to.equal(guardian3) + const blockTime = await getBlockTimestamp(receipt.blockNumber) + expect(addEvent.effectiveTime.toNumber()).to.equal(blockTime) + }) + it('reset guardian test', async () => { + const { + sendUserOp, + smartWalletOwner, + guardians, + create2, + entrypoint, + smartWallet, + smartWalletImpl + } = await loadFixture(fixture) + const newGuardians: Wallet[] = [] + for (let i = 0; i < 2; i++) { + newGuardians.push( + ethers.Wallet.createRandom().connect(ethers.provider) + ) + } + newGuardians.sort((a, b) => + a.address.toLowerCase() < b.address.toLowerCase() ? -1 : 1 + ) + const newGuardianAddrs = newGuardians.map((g) => g.address) + + const callData = smartWallet.interface.encodeFunctionData( + 'resetGuardiansWA', + [newGuardianAddrs] + ) + + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ResetGuardians + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [{ signer: smartWalletOwner }, { signer: guardians[0] }], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + await time.increase(three_days) + // check all old guardians and new guardians + for (const newGuardianAddr of newGuardianAddrs) { + expect(await smartWallet.isGuardian(newGuardianAddr, false)) + .to.be.true + } + + for (const guardian of guardians) { + expect(await smartWallet.isGuardian(guardian.address, false)) + .to.be.false + } + }) + it('remove guardian test', async () => { + const { + sendUserOp, + smartWalletOwner, + guardians, + create2, + entrypoint, + smartWallet, + smartWalletImpl + } = await loadFixture(fixture) + const removedGuardian = guardians[1].address + const callData = smartWallet.interface.encodeFunctionData( + 'removeGuardianWA', + [removedGuardian] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.RemoveGuardian + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [{ signer: smartWalletOwner }, { signer: guardians[0] }], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await sendUserOp(signedUserOp) + await time.increase(three_days) + expect(await smartWallet.isGuardian(removedGuardian, false)).to + .be.false + }) + }) + describe('wallet test when no guardians', () => { + it('wa operation', async () => { + const { + smartWalletOwner, + walletFactory, + create2, + smartWalletImpl, + entrypoint, + usdtToken, + sendUserOp + } = await loadFixture(fixture) + // create wallet with empty guardians list + const wallet = await createRandomWallet( + smartWalletOwner, + [], + walletFactory + ) + + // recover test + const newOwner = ethers.Wallet.createRandom() + const newGuardians: string[] = [] + const callData = wallet.interface.encodeFunctionData( + 'recover', + [newOwner.address, newGuardians] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.Recover + } + const signedUserOp = await fillAndMultiSign( + callData, + wallet, + smartWalletOwner, + [{ signer: smartWalletOwner }], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: LRC#400') + + // approveTokenWA test + { + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ApproveToken + } + const toAddr = ethers.constants.AddressZero + const amount = 100 + const callData = wallet.interface.encodeFunctionData( + 'approveTokenWA', + [usdtToken.address, toAddr, amount] + ) + const signedUserOp = await fillAndMultiSign( + callData, + wallet, + smartWalletOwner, + [{ signer: smartWalletOwner }], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: LRC#400') + } + // approveToken test + { + const toAddr = ethers.constants.AddressZero + const amount = 100 + const approve = await wallet.populateTransaction.approveToken( + usdtToken.address, + toAddr, + amount, + false + ) + await expect( + sendTx( + [approve], + wallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + ).not.to.reverted + } + }) + }) + describe('smart wallet guardians approval', () => { + it('add guardian with smart wallet guardian approval', async () => { + const { + sendUserOp, + create2, + entrypoint, + walletFactory, + smartWalletImpl + } = await loadFixture(fixture) + async function createRandomWalletAndFundingIt( + guardians: Wallet[], + walletFactory: WalletFactory, + entrypoint: EntryPoint + ): Promise<{ + smartWalletOwner: Wallet + smartWallet: SmartWalletV3 + }> { + const smartWalletOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const smartWallet = await createRandomWallet( + smartWalletOwner, + guardians, + walletFactory + ) + await setBalance( + smartWalletOwner.address, + ethers.utils.parseEther('100') + ) + await setBalance( + smartWallet.address, + ethers.utils.parseEther('100') + ) + await entrypoint.depositTo(smartWallet.address, { + value: ethers.utils.parseEther('100') + }) + return { smartWalletOwner, smartWallet } + } + const { smartWalletOwner, smartWallet } = + await createRandomWalletAndFundingIt( + [], + walletFactory, + entrypoint + ) + const { smartWallet: smartGuardian0 } = + await createRandomWalletAndFundingIt( + [], + walletFactory, + entrypoint + ) + const { + smartWalletOwner: smartGuardianOwner1, + smartWallet: smartGuardian1 + } = await createRandomWalletAndFundingIt( + [], + walletFactory, + entrypoint + ) + const guardianToAdd = ethers.Wallet.createRandom().connect( + ethers.provider + ) + await ( + await smartWallet.addGuardian(smartGuardian0.address) + ).wait() + await ( + await smartWallet.addGuardian(smartGuardian1.address) + ).wait() + await increase(3 * 24 * 60 * 60 + 1) // wait for 3 days; + const guardiansBefore = await smartWallet.getGuardians(false) + expect( + guardiansBefore.some((g) => g.addr === smartGuardian0.address) + ).to.equal(true) // contains smartGuardian0 + expect( + guardiansBefore.some((g) => g.addr === smartGuardian1.address) + ).to.equal(true) // contains smartGuardian1 + expect( + guardiansBefore.some((g) => g.addr === guardianToAdd.address) + ).to.equal(false) // not contains guardianToAdd + const callData = smartWallet.interface.encodeFunctionData( + 'addGuardianWA', + [guardianToAdd.address] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.AddGuardian + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: smartGuardianOwner1, + smartWalletAddress: smartGuardian1.address + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + const guardiansAfter = await smartWallet.getGuardians(false) + expect( + guardiansAfter.some((g) => g.addr === guardianToAdd.address) + ).to.equal(true) // contains guardianToAdd + }) + }) +}) diff --git a/packages/hebao_v3/test/helper/AASigner.ts b/packages/hebao_v3/test/helper/AASigner.ts new file mode 100644 index 000000000..51d4cfcc4 --- /dev/null +++ b/packages/hebao_v3/test/helper/AASigner.ts @@ -0,0 +1,417 @@ +import { type ContractReceipt } from '@ethersproject/contracts' +import { + BigNumber, + type BigNumberish, + constants, + Contract, + type Signer, + type Wallet +} from 'ethers' +import { + arrayify, + defaultAbiCoder, + getCreate2Address, + hexDataSlice, + keccak256 +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' +import _ from 'lodash' + +import { + type EntryPoint, + EntryPoint__factory, + type SmartWalletV3 +} from '../../typechain-types' + +import { + type ApprovalOption, + signTypedData +} from './LoopringGuardianAPI' +import type * as typ from './solidityTypes' + +export const HashZero = ethers.constants.HashZero + +export interface UserOperation { + sender: typ.address + nonce: typ.uint256 + initCode: typ.bytes + callData: typ.bytes + callGasLimit: typ.uint256 + verificationGasLimit: typ.uint256 + preVerificationGas: typ.uint256 + maxFeePerGas: typ.uint256 + maxPriorityFeePerGas: typ.uint256 + paymasterAndData: typ.bytes + signature: typ.bytes +} +export function packUserOp( + op: UserOperation, + forSignature = true +): string { + if (forSignature) { + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes32', + 'bytes32', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes32' + ], + [ + op.sender, + op.nonce, + keccak256(op.initCode), + keccak256(op.callData), + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + keccak256(op.paymasterAndData) + ] + ) + } else { + // for the purpose of calculating gas cost encode also signature (and no keccak of bytes) + return defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes', + 'bytes', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'bytes', + 'bytes' + ], + [ + op.sender, + op.nonce, + op.initCode, + op.callData, + op.callGasLimit, + op.verificationGasLimit, + op.preVerificationGas, + op.maxFeePerGas, + op.maxPriorityFeePerGas, + op.paymasterAndData, + op.signature + ] + ) + } +} + +export function getUserOpHash( + op: UserOperation, + entryPoint: string, + chainId: number +): string { + const userOpHash = keccak256(packUserOp(op, true)) + const enc = defaultAbiCoder.encode( + ['bytes32', 'address', 'uint256'], + [userOpHash, entryPoint, chainId] + ) + return keccak256(enc) +} + +export const DefaultsForUserOp: UserOperation = { + sender: constants.AddressZero, + nonce: 0, + initCode: '0x', + callData: '0x', + callGasLimit: 0, + verificationGasLimit: 200000, // default verification gas. will add create2 cost (3200+200*length) if initCode exists + preVerificationGas: 21000, // should also cover calldata cost. + maxFeePerGas: 0, + maxPriorityFeePerGas: 1e9, + paymasterAndData: '0x', + signature: '0x' +} + +export function fillUserOpDefaults( + op: Partial, + defaults = DefaultsForUserOp +): UserOperation { + const partial: any = { ...op } + // we want "item:undefined" to be used from defaults, and not override defaults, so we must explicitly + // remove those so "merge" will succeed. + for (const key in partial) { + if (partial[key] == null) { + // eslint-disable-next-line + delete partial[key] + } + } + const filled = { ...defaults, ...partial } + return filled +} + +export function callDataCost(data: string): number { + return ethers.utils + .arrayify(data) + .map((x) => (x === 0 ? 4 : 16)) + .reduce((sum, x) => sum + x) +} + +// helper to fill structure: +// - default callGasLimit to estimate call from entryPoint to account (TODO: add overhead) +// if there is initCode: +// - calculate sender by eth_call the deployment code +// - default verificationGasLimit estimateGas of deployment code plus default 100000 +// no initCode: +// - update nonce from account.nonce() +// entryPoint param is only required to fill in "sender address when specifying "initCode" +// nonce: assume contract as "nonce()" function, and fill in. +// sender - only in case of construction: fill sender from initCode. +// callGasLimit: VERY crude estimation (by estimating call to account, and add rough entryPoint overhead +// verificationGasLimit: hard-code default at 100k. should add "create2" cost +export async function fillUserOp( + op: Partial, + walletFactoryAddress: string, + entryPoint?: EntryPoint +): Promise { + const op1 = { ...op } + const provider = entryPoint?.provider + if (op.initCode != null) { + const initAddr = hexDataSlice(op1.initCode!, 0, 20) + const initCallData = hexDataSlice(op1.initCode!, 20) + if (op1.nonce == null) op1.nonce = 0 + if (op1.sender == null) { + // hack: if the init contract is our known deployer, then we know what the address would be, without a view call + if ( + initAddr.toLowerCase() === walletFactoryAddress.toLowerCase() + ) { + const ctr = hexDataSlice(initCallData, 32) + const salt = hexDataSlice(initCallData, 0, 32) + op1.sender = getCreate2Address( + walletFactoryAddress, + salt, + ctr + ) + } else { + if (provider == null) { + throw new Error('no entrypoint/provider') + } + op1.sender = await entryPoint!.callStatic + .getSenderAddress(op1.initCode!) + .catch((e) => e.errorArgs.sender) + } + } + if (op1.verificationGasLimit == null) { + if (provider == null) throw new Error('no entrypoint/provider') + const initEstimate = await provider.estimateGas({ + from: entryPoint?.address, + to: initAddr, + data: initCallData, + gasLimit: 10e6 + }) + op1.verificationGasLimit = BigNumber.from( + DefaultsForUserOp.verificationGasLimit + ).add(initEstimate) + } + } + if (op1.nonce == null) { + if (provider == null) { + throw new Error('must have entryPoint to autofill nonce') + } + const c = new Contract( + op.sender!, + ['function getNonce() view returns(uint256)'], + provider + ) + op1.nonce = await c.getNonce() + } + if (op1.callGasLimit == null && op.callData != null) { + if (provider == null) { + throw new Error( + 'must have entryPoint for callGasLimit estimate' + ) + } + const gasEtimated = await provider.estimateGas({ + from: entryPoint?.address, + to: op1.sender, + data: op1.callData + }) + + // estimateGas assumes direct call from entryPoint. add wrapper cost. + op1.callGasLimit = gasEtimated.add(55000) + } + if (op1.maxFeePerGas == null) { + if (provider == null) { + throw new Error('must have entryPoint to autofill maxFeePerGas') + } + const block = await provider.getBlock('latest') + op1.maxFeePerGas = block.baseFeePerGas!.add( + op1.maxPriorityFeePerGas ?? + DefaultsForUserOp.maxPriorityFeePerGas + ) + } + // TODO: this is exactly what fillUserOp below should do - but it doesn't. + // adding this manually + if (op1.maxPriorityFeePerGas == null) { + op1.maxPriorityFeePerGas = DefaultsForUserOp.maxPriorityFeePerGas + } + const op2 = fillUserOpDefaults(op1) + + if (BigNumber.from(op2.preVerificationGas).eq(0)) { + // TODO: we don't add overhead, which is ~21000 for a single TX, but much lower in a batch. + op2.preVerificationGas = callDataCost(packUserOp(op2, false)) + } + return op2 +} + +export async function fillAndMultiSign( + callData: string, + smartWallet: SmartWalletV3, + smartWalletOwner: Wallet, + smartWalletOrEOASigners: Array<{ + signer: Wallet + smartWalletAddress?: string + }>, + walletFactoryAddress: string, + verifyingContract: string, + approvalOption: ApprovalOption, + entryPoint?: EntryPoint, + option?: Partial<{ + nonce: BigNumberish + callGasLimit: BigNumberish + }> +): Promise { + const provider = entryPoint?.provider + const nonce = await smartWallet.getNonce() + const op = { + sender: smartWallet.address, + nonce, + callData, + ...option + } + const op2 = await fillUserOp(op, walletFactoryAddress, entryPoint) + const chainId = await provider! + .getNetwork() + .then((net) => net.chainId) + const userOpHash = getUserOpHash(op2, entryPoint!.address, chainId) + const calldata = ethers.utils.hexDataSlice(op.callData, 4) + const domain = { + name: 'LoopringWallet', + version: '2.0.0', + chainId, + verifyingContract + } + + const signatures = await Promise.all( + smartWalletOrEOASigners.map( + async (g) => + await signTypedData( + calldata, + g.signer, + approvalOption, + domain, + { + wallet: smartWallet.address, + validUntil: approvalOption.validUntil, + salt: approvalOption.salt + } + ) + ) + ) + const [sortedSigners, sortedSignatures] = _.unzip( + _.sortBy( + _.zip( + smartWalletOrEOASigners.map((g) => + g.smartWalletAddress !== undefined + ? g.smartWalletAddress.toLowerCase() + : g.signer.address.toLowerCase() + ), + signatures + ), + (item) => item[0] + ) + ) + + const approval = { + signers: sortedSigners, + signatures: sortedSignatures, + validUntil: approvalOption.validUntil, + salt: approvalOption.salt + } + const ownerSignature = await smartWalletOwner.signMessage( + arrayify(userOpHash) + ) + const signature = ethers.utils.defaultAbiCoder.encode( + [ + 'tuple(address[] signers,bytes[] signatures,uint256 validUntil,bytes32 salt)', + 'bytes' + ], + [approval, ownerSignature] + ) + return { + ...op2, + signature + } +} + +export async function fillAndSign( + op: Partial, + signer: Wallet | Signer, + walletFactoryAddress: string, + entryPoint?: EntryPoint +): Promise { + const provider = entryPoint?.provider + const op2 = await fillUserOp(op, walletFactoryAddress, entryPoint) + const chainId = await provider! + .getNetwork() + .then((net) => net.chainId) + const message = arrayify( + getUserOpHash(op2, entryPoint!.address, chainId) + ) + + return { + ...op2, + signature: await signer.signMessage(message) + } +} + +export type SendUserOp = ( + userOp: UserOperation +) => Promise + +/** + * send UserOp using handleOps, but locally. + * for testing: instead of connecting through RPC to a remote host, directly send the transaction + * @param entryPointAddress the entryPoint address to use. + * @param signer ethers provider to send the request (must have eth balance to send) + * @param beneficiary the account to receive the payment (from account/paymaster). defaults to the signer's address + */ +export function localUserOpSender( + entryPointAddress: string, + signer: Signer, + beneficiary?: string +): SendUserOp { + const entryPoint = EntryPoint__factory.connect( + entryPointAddress, + signer + ) + return async function (userOp) { + const gasLimit = BigNumber.from(userOp.preVerificationGas) + .add(userOp.verificationGasLimit) + .add(userOp.callGasLimit) + // TODO(handle gasLimit) + gasLimit + const ret = await entryPoint.handleOps( + [userOp], + beneficiary ?? (await signer.getAddress()), + { + maxPriorityFeePerGas: userOp.maxPriorityFeePerGas, + maxFeePerGas: userOp.maxFeePerGas + } + ) + const recipt = await ret.wait() + return recipt + } +} diff --git a/packages/hebao_v3/test/helper/Create2Factory.ts b/packages/hebao_v3/test/helper/Create2Factory.ts new file mode 100644 index 000000000..714487f7c --- /dev/null +++ b/packages/hebao_v3/test/helper/Create2Factory.ts @@ -0,0 +1,172 @@ +// from: https://github.com/Arachnid/deterministic-deployment-proxy +import { type TransactionRequest } from '@ethersproject/abstract-provider' +import { type Provider } from '@ethersproject/providers' +import { + BigNumber, + type BigNumberish, + type ethers, + type Signer +} from 'ethers' +import { + arrayify, + hexConcat, + hexlify, + hexZeroPad, + keccak256 +} from 'ethers/lib/utils' + +export class Create2Factory { + factoryDeployed = false + + // from: https://github.com/Arachnid/deterministic-deployment-proxy + static readonly contractAddress = + '0x4e59b44847b379578588920ca78fbf26c0b4956c' + + static readonly factoryTx = + '0xf8a58085174876e800830186a08080b853604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf31ba02222222222222222222222222222222222222222222222222222222222222222a02222222222222222222222222222222222222222222222222222222222222222' + + static readonly factoryDeployer = + '0x3fab184622dc19b6109349b94811493bf2a45362' + + static readonly deploymentGasPrice = 100e9 + static readonly deploymentGasLimit = 100000 + static readonly factoryDeploymentFee = ( + Create2Factory.deploymentGasPrice * + Create2Factory.deploymentGasLimit + ).toString() + + constructor( + readonly provider: Provider, + readonly signer = ( + provider as ethers.providers.JsonRpcProvider + ).getSigner() + ) {} + + /** + * deploy a contract using our deterministic deployer. + * The deployer is deployed (unless it is already deployed) + * NOTE: this transaction will fail if already deployed. use getDeployedAddress to check it first. + * @param initCode delpoyment code. can be a hex string or factory.getDeploymentTransaction(..) + * @param salt specific salt for deployment + * @param gasLimit gas limit or 'estimate' to use estimateGas. by default, calculate gas based on data size. + */ + async deploy( + initCode: string | TransactionRequest, + salt: BigNumberish = 0, + gasLimit?: BigNumberish | 'estimate' + ): Promise { + await this.deployFactory() + if (typeof initCode !== 'string') { + initCode = ( + (initCode as TransactionRequest).data as string + ).toString() + } + + const addr = Create2Factory.getDeployedAddress(initCode, salt) + if ( + (await this.provider + .getCode(addr) + .then((code) => code.length)) > 2 + ) { + return addr + } + + const deployTx = { + to: Create2Factory.contractAddress, + data: this.getDeployTransactionCallData(initCode, salt) + } + if (gasLimit === 'estimate') { + gasLimit = await this.signer.estimateGas(deployTx) + } + + // manual estimation (its bit larger: we don't know actual deployed code size) + if (gasLimit === undefined) { + gasLimit = + arrayify(initCode) + .map((x) => (x === 0 ? 4 : 16)) + .reduce((sum, x) => sum + x) + + (200 * initCode.length) / 2 + // actual is usually somewhat smaller (only deposited code, not entire constructor) + 6 * Math.ceil(initCode.length / 64) + // hash price. very minor compared to deposit costs + 32000 + + 21000 + + // deployer requires some extra gas + gasLimit = Math.floor((gasLimit * 64) / 63) + } + + const ret = await this.signer.sendTransaction({ + ...deployTx, + gasLimit + }) + await ret.wait() + if ( + (await this.provider + .getCode(addr) + .then((code) => code.length)) === 2 + ) { + throw new Error('failed to deploy') + } + return addr + } + + getDeployTransactionCallData( + initCode: string, + salt: BigNumberish = 0 + ): string { + const saltBytes32 = hexZeroPad(hexlify(salt), 32) + return hexConcat([saltBytes32, initCode]) + } + + /** + * return the deployed address of this code. + * (the deployed address to be used by deploy() + * @param initCode + * @param salt + */ + static getDeployedAddress( + initCode: string, + salt: BigNumberish + ): string { + const saltBytes32 = hexZeroPad(hexlify(salt), 32) + return ( + '0x' + + keccak256( + hexConcat([ + '0xff', + Create2Factory.contractAddress, + saltBytes32, + keccak256(initCode) + ]) + ).slice(-40) + ) + } + + // deploy the factory, if not already deployed. + async deployFactory(signer?: Signer): Promise { + if (await this._isFactoryDeployed()) { + return + } + await (signer ?? this.signer).sendTransaction({ + to: Create2Factory.factoryDeployer, + value: BigNumber.from(Create2Factory.factoryDeploymentFee) + }) + await this.provider.sendTransaction(Create2Factory.factoryTx) + if (!(await this._isFactoryDeployed())) { + throw new Error( + 'fatal: failed to deploy deterministic deployer' + ) + } + } + + async _isFactoryDeployed(): Promise { + if (!this.factoryDeployed) { + const deployed = await this.provider.getCode( + Create2Factory.contractAddress + ) + if (deployed.length > 2) { + this.factoryDeployed = true + } + } + return this.factoryDeployed + } +} diff --git a/packages/hebao_v3/test/helper/LoopringGuardianAPI.ts b/packages/hebao_v3/test/helper/LoopringGuardianAPI.ts new file mode 100644 index 000000000..d27562e7a --- /dev/null +++ b/packages/hebao_v3/test/helper/LoopringGuardianAPI.ts @@ -0,0 +1,353 @@ +import { + type BigNumberish, + type BytesLike, + utils, + type Wallet +} from 'ethers' + +export interface GuardianParams { + guardians: Wallet[] + owner: Wallet + wallet: string + verifyingContract: string +} + +export enum ActionType { + ApproveToken, + TransferToken, + CallContract, + ApproveThenCallContract, + Recover, + Unlock, + AddToWhitelist, + ChangeMasterCopy, + ChangeDailyQuota, + AddGuardian, + RemoveGuardian, + ResetGuardians +} + +export interface ApprovalOption { + validUntil: BigNumberish + // validAfter: BigNumberish + // salt: BytesLike + action_type: ActionType +} + +export interface Approval { + signers: string[] + signatures: string[] + validUntil: BigNumberish + // salt: BytesLike +} + +export async function signTypedData( + data: BytesLike, + signer: Wallet, + approvalOption: ApprovalOption, + domain: any, + initValue: { + wallet: string + validUntil: BigNumberish + // salt: BytesLike + } +): Promise { + let message: any + switch (approvalOption.action_type) { + case ActionType.ApproveToken: { + const result = utils.defaultAbiCoder.decode( + ['address', 'address', 'uint256'], + data + ) + const types = { + approveToken: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'token', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'approveToken', + value: { + ...initValue, + token: result[0], + to: result[1], + amount: result[2] + } + } + break + } + case ActionType.TransferToken: { + const result = utils.defaultAbiCoder.decode( + ['address', 'address', 'uint256', 'bytes'], + data + ) + + const types = { + transferToken: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'token', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'logdata', type: 'bytes' } + // { name: 'salt', type: 'bytes32' } + ] + } + + message = { + types, + domain, + primaryType: 'transferToken', + value: { + ...initValue, + token: result[0], + to: result[1], + amount: result[2], + logdata: result[3] + } + } + break + } + case ActionType.CallContract: { + const result = utils.defaultAbiCoder.decode( + ['address', 'uint256', 'bytes'], + data + ) + const types = { + callContract: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'to', type: 'address' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'callContract', + value: { + ...initValue, + to: result[0], + value: result[1], + data: result[2] + } + } + break + } + case ActionType.ApproveThenCallContract: { + const result = utils.defaultAbiCoder.decode( + ['address', 'address', 'uint256', 'uint256', 'bytes'], + data + ) + const types = { + approveThenCallContract: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'token', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' }, + { name: 'value', type: 'uint256' }, + { name: 'data', type: 'bytes' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'approveThenCallContract', + value: { + ...initValue, + token: result[0], + to: result[1], + amount: result[2], + value: result[3], + data: result[4] + } + } + break + } + case ActionType.AddGuardian: { + const result = utils.defaultAbiCoder.decode(['address'], data) + const types = { + addGuardian: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'guardian', type: 'address' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'addGuardian', + value: { + ...initValue, + guardian: result[0] + } + } + break + } + case ActionType.RemoveGuardian: { + const result = utils.defaultAbiCoder.decode(['address'], data) + const types = { + removeGuardian: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'guardian', type: 'address' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'removeGuardian', + value: { + ...initValue, + guardian: result[0] + } + } + break + } + case ActionType.ResetGuardians: { + const result = utils.defaultAbiCoder.decode(['address[]'], data) + const types = { + resetGuardians: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'guardians', type: 'address[]' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'resetGuardians', + value: { + ...initValue, + guardians: result[0] + } + } + break + } + case ActionType.AddToWhitelist: { + const result = utils.defaultAbiCoder.decode(['address'], data) + const types = { + addToWhitelist: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'addr', type: 'address' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'addToWhitelist', + value: { + ...initValue, + addr: result[0] + } + } + break + } + case ActionType.ChangeDailyQuota: { + const result = utils.defaultAbiCoder.decode(['uint256'], data) + const types = { + changeDailyQuota: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'newQuota', type: 'uint256' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'changeDailyQuota', + value: { + ...initValue, + newQuota: result[0] + } + } + break + } + case ActionType.ChangeMasterCopy: { + const result = utils.defaultAbiCoder.decode(['address'], data) + const types = { + changeMasterCopy: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'masterCopy', type: 'address' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'changeMasterCopy', + value: { + ...initValue, + masterCopy: result[0] + } + } + break + } + case ActionType.Recover: { + const result = utils.defaultAbiCoder.decode( + ['address', 'address[]'], + data + ) + const types = { + recover: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'newOwner', type: 'address' }, + { name: 'newGuardians', type: 'address[]' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'recover', + value: { + ...initValue, + newOwner: result[0], + newGuardians: result[1] + } + } + break + } + case ActionType.Unlock: { + const types = { + unlock: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' } + // { name: 'salt', type: 'bytes32' } + ] + } + message = { + types, + domain, + primaryType: 'unlock', + value: { + ...initValue + } + } + break + } + } + return await signer._signTypedData( + message.domain, + message.types, + message.value + ) +} diff --git a/packages/hebao_v3/test/helper/error_codes.ts b/packages/hebao_v3/test/helper/error_codes.ts new file mode 100644 index 000000000..2534132c1 --- /dev/null +++ b/packages/hebao_v3/test/helper/error_codes.ts @@ -0,0 +1,42 @@ +export enum ErrorCodes { + ZERO_ADDRESS = 104, + INVALID_VALID_SINCE = 105, + ZERO_TOKEN = 106, + MASTER_COPY_ZERO_ADDRESS = 107, + + BATCHED_CALL_FAILED = 300, + DISALLOWED_ON_IMPLEMENTATION_CONTRACT = 301, + NOT_ALLOWED_TO_SET_OWNER = 302, + ONLY_FROM_ENTRYPOINT = 303, + NOT_OWNER_SELF_OR_ENTRYPOINT_OR_LOCKED = 304, + INVALID_OWNER = 305, + INITIALIZED_ALREADY = 306, + INVALID_SAME_ENTRYPOINT = 307, + NOT_ENTRYPOINT_OR_INHERITOR = 308, + NOT_EXECUTOR = 309, + OFFICIALGUARDIAN_CALL_FAILED = 310, + NOT_FROM_BALANCER_VAULT = 311, + INVALID_SAME_MASTER_COPY = 312, + MEMORY_NOT_MASTER = 313, + + NO_GUARDIANS = 400, + INVALID_SIGNERS_ORDER = 401, + SIGNER_NOT_GUARDIAN = 402, + WALLET_OWNER_SIGNATURE_NOT_ALLOWED = 403, + WALLET_OWNER_SIGNATURE_REQUIRED = 404, + INVALID_ORDERING = 405, + NO_GUARDIAN_SIGNED_BESIDES_OWNER = 406, + INVALID_GUARDIAN_ADDRESS = 407, + NOT_FROM_WALLET_OR_OWNER_OR_GUARDIAN = 408, + QUOTA_EXCEEDED = 409, + INVALID_QUOTA = 410, + IS_SAME_OWNER = 411, + INVALID_NEW_WALLET_OWNER = 412, + INVALID_NEW_WALLET_GUARDIAN = 413, + UNEXPECTED_RESULT = 414, + INVALID_VALID_UNTIL = 415, + GUARDIAN_NOT_EXISTS = 416, + TOO_MANY_GUARDIANS = 417, + GUARDIAN_CAN_NOT_BE_OWNER = 418, + INVALID_MASTER_COPY = 419 +} diff --git a/packages/hebao_v3/test/helper/fixture.ts b/packages/hebao_v3/test/helper/fixture.ts new file mode 100644 index 000000000..bc525f37c --- /dev/null +++ b/packages/hebao_v3/test/helper/fixture.ts @@ -0,0 +1,203 @@ +import * as helpers from '@nomicfoundation/hardhat-network-helpers' +import { type Wallet } from 'ethers' +import { ethers } from 'hardhat' + +import { + DelayedImplementationManager__factory, + EntryPoint__factory, + LoopringPaymaster__factory, + SmartWalletV3__factory, + USDT__factory, + WalletFactory__factory, + LRC__factory +} from '../../typechain-types' + +import { localUserOpSender } from './AASigner' +import { + createSmartWallet, + deploySingle, + deployWalletImpl +} from './utils' + +// eslint-disable-next-line +export async function fixture() { + const signers = await ethers.getSigners() + const deployer = signers[0] + const paymasterOwner = signers[1] + const somebody = signers[2] + const blankOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + await helpers.setBalance( + blankOwner.address, + ethers.utils.parseEther('100') + ) + + // create2 factory + + const create2 = await ( + await ethers.getContractFactory('LoopringCreate2Deployer') + ).deploy() + + // entrypoint and paymaster + const entrypoint = EntryPoint__factory.connect( + (await deploySingle(create2, 'EntryPoint')).address, + deployer + ) + // const entrypointAddr = "0x515aC6B1Cd51BcFe88334039cC32e3919D13b35d"; + // const entrypoint = await ethers.getContractAt("EntryPoint", entrypointAddr); + + const paymaster = LoopringPaymaster__factory.connect( + ( + await deploySingle(create2, 'LoopringPaymaster', [ + entrypoint.address, + paymasterOwner.address + ]) + ).address, + paymasterOwner + ) + + // TODO(add some pre-registered connectors here) + const connectorRegistry = await ( + await ethers.getContractFactory('ConnectorRegistry') + ).deploy() + + const smartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + blankOwner.address, + ethers.constants.AddressZero, + connectorRegistry.address + ) + + const implStorage = DelayedImplementationManager__factory.connect( + ( + await deploySingle( + create2, + 'DelayedImplementationManager', + // deployer as implementation manager + [smartWalletImpl.address] + ) + ).address, + deployer + ) + + const forwardProxy = await deploySingle(create2, 'ForwardProxy', [ + implStorage.address + ]) + + const walletFactory = WalletFactory__factory.connect( + ( + await deploySingle(create2, 'WalletFactory', [ + forwardProxy.address + ]) + ).address, + deployer + ) + // transfer wallet factory ownership to deployer + await create2.setTarget(walletFactory.address) + const transferWalletFactoryOwnership = + await walletFactory.populateTransaction.transferOwnership( + deployer.address + ) + await create2.transact(transferWalletFactoryOwnership.data!) + await walletFactory.addOperator(deployer.address) + + // transfer DelayedImplementationManager ownership to deployer + await create2.setTarget(implStorage.address) + const transferImplStorageOwnership = + await implStorage.populateTransaction.transferOwnership( + deployer.address + ) + await create2.transact(transferImplStorageOwnership.data!) + + // create demo wallet + const smartWalletOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + // prepare eth for walletowner + await helpers.setBalance( + smartWalletOwner.address, + ethers.utils.parseEther('100') + ) + const sendUserOp = localUserOpSender(entrypoint.address, deployer) + + const guardians: Wallet[] = [] + for (let i = 0; i < 2; i++) { + guardians.push( + ethers.Wallet.createRandom().connect(ethers.provider) + ) + } + guardians.sort((a, b) => + a.address.toLowerCase() < b.address.toLowerCase() ? -1 : 1 + ) + + const salt = ethers.utils.formatBytes32String('0x5') + await createSmartWallet( + smartWalletOwner, + guardians.map((g) => g.address.toLowerCase()), + walletFactory, + salt + ) + + const smartWalletAddr = await walletFactory.computeWalletAddress( + smartWalletOwner.address, + salt + ) + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + // prepare eth for smartwallet + await helpers.setBalance( + smartWallet.address, + ethers.utils.parseEther('100') + ) + + // predeposit for smartwallet and paymaster in entrypoint + await entrypoint.depositTo(smartWallet.address, { + value: ethers.utils.parseEther('100') + }) + await entrypoint.depositTo(paymaster.address, { + value: ethers.utils.parseEther('100') + }) + + // deploy mock usdt token for test. + const usdtToken = USDT__factory.connect( + (await deploySingle(create2, 'USDT')).address, + deployer + ) + // usdt token is supported by paymaster + await paymaster.addToken(usdtToken.address) + const lrcToken = LRC__factory.connect( + (await deploySingle(create2, 'LRC')).address, + deployer + ) + + // used for any call contract test + const testTarget = await ( + await ethers.getContractFactory('TestTargetContract') + ).deploy() + + return { + entrypoint, + paymaster, + forwardProxy, + smartWallet, + create2, + deployer, + paymasterOwner, + blankOwner, + smartWalletOwner, + usdtToken, + sendUserOp, + smartWalletImpl, + guardians, + lrcToken, + walletFactory, + implStorage, + testTarget, + somebody, + connectorRegistry + } +} diff --git a/packages/hebao_v3/test/helper/signatureUtils.ts b/packages/hebao_v3/test/helper/signatureUtils.ts new file mode 100644 index 000000000..6df51d8ec --- /dev/null +++ b/packages/hebao_v3/test/helper/signatureUtils.ts @@ -0,0 +1,55 @@ +import { type BigNumberish, type Wallet } from 'ethers' + +export async function signCreateWallet( + moduleAddress: string, + owner: Wallet, + guardians: string[], + quota: BigNumberish, + inheritor: string, + feeRecipient: string, + feeToken: string, + maxFeeAmount: BigNumberish, + salt: BigNumberish, + chainId: number +): Promise { + const domain = { + name: 'WalletFactory', + version: '2.0.0', + chainId, + verifyingContract: moduleAddress + } + + const types = { + createWallet: [ + { name: 'owner', type: 'address' }, + { name: 'guardians', type: 'address[]' }, + { name: 'quota', type: 'uint256' }, + { name: 'inheritor', type: 'address' }, + { name: 'feeRecipient', type: 'address' }, + { name: 'feeToken', type: 'address' }, + { name: 'maxFeeAmount', type: 'uint256' }, + { name: 'salt', type: 'uint256' } + ] + } + const message = { + types, + domain, + primaryType: 'createWallet', + value: { + owner: owner.address, + guardians, + quota, + inheritor, + feeRecipient, + feeToken, + maxFeeAmount, + salt + } + } + + return await owner._signTypedData( + message.domain, + message.types, + message.value + ) +} diff --git a/packages/hebao_v3/test/helper/solidityTypes.ts b/packages/hebao_v3/test/helper/solidityTypes.ts new file mode 100644 index 000000000..508076452 --- /dev/null +++ b/packages/hebao_v3/test/helper/solidityTypes.ts @@ -0,0 +1,10 @@ +// define the same export types as used by export typechain/ethers +import { type BytesLike } from '@ethersproject/bytes' +import { type BigNumberish } from 'ethers' + +export type address = string +export type uint256 = BigNumberish +export type uint = BigNumberish +export type uint64 = BigNumberish +export type bytes = BytesLike +export type bytes32 = BytesLike diff --git a/packages/hebao_v3/test/helper/utils.ts b/packages/hebao_v3/test/helper/utils.ts new file mode 100644 index 000000000..a84fd4906 --- /dev/null +++ b/packages/hebao_v3/test/helper/utils.ts @@ -0,0 +1,631 @@ +import { + type Event, + type ContractReceipt +} from '@ethersproject/contracts' +import { type BytesLike } from '@ethersproject/bytes' +import { + type Deferrable, + resolveProperties +} from '@ethersproject/properties' +import { + type BaseProvider, + type TransactionReceipt, + type TransactionRequest +} from '@ethersproject/providers' +import { + type Contract, + BigNumber, + type BigNumberish, + type Signer, + type Wallet +} from 'ethers' +import { + arrayify, + defaultAbiCoder, + hexConcat, + keccak256 +} from 'ethers/lib/utils' +import { ethers } from 'hardhat' +import * as hre from 'hardhat' + +import { + type EntryPoint, + type LoopringCreate2Deployer, + type LoopringPaymaster, + type SmartWalletV3, + type WalletFactory +} from '../../typechain-types' + +import { + fillAndSign, + type SendUserOp, + type UserOperation +} from './AASigner' +import { signCreateWallet } from './signatureUtils' +import type * as typ from './solidityTypes' + +export interface WalletConfig { + accountOwner: typ.address + guardians: typ.address[] + quota: typ.uint + inheritor: typ.address +} + +function getPaymasterHash(userOp: UserOperation): string { + return keccak256( + defaultAbiCoder.encode( + [ + 'address', + 'uint256', + 'bytes32', + 'bytes32', + 'uint256', + 'uint256', + 'uint256', + 'uint256', + 'uint256' + ], + [ + userOp.sender, + userOp.nonce, + keccak256(userOp.initCode), + keccak256(userOp.callData), + userOp.callGasLimit, + userOp.verificationGasLimit, + userOp.preVerificationGas, + userOp.maxFeePerGas, + userOp.maxPriorityFeePerGas + ] + ) + ) +} + +export async function getPaymasterData( + userOp: UserOperation, + payMasterAddress: string, + paymasterOwner: Signer, + token: string, + valueOfEth: BigNumberish +): Promise { + const message = arrayify(getPaymasterHash(userOp)) + const signature = await paymasterOwner.signMessage(message) + + const enc = + payMasterAddress.toLowerCase() + + defaultAbiCoder + .encode( + ['address', 'uint256', 'bytes'], + [token, valueOfEth, signature] + ) + .substring(2) + return enc +} + +export async function getPaymasterAndData( + payMasterAddress: string, + paymasterOwner: Signer, + hash: string, + usdcToken: string, + valueOfEth: BigNumberish, + validUntil: BigNumberish +): Promise { + const sig = await paymasterOwner.signMessage(arrayify(hash)) + const paymasterCalldata = ethers.utils.defaultAbiCoder.encode( + ['address', 'uint48', 'uint256', 'bytes'], + [usdcToken, validUntil, valueOfEth, sig] + ) + return hexConcat([payMasterAddress, paymasterCalldata]) +} + +/** + * process exception of ValidationResult + * usage: entryPoint.simulationResult(..).catch(simulationResultCatch) + */ +export function simulationResultCatch(e: any): any { + if (e.errorName !== 'ValidationResult') { + throw e + } + return e.errorArgs +} + +export async function evInfo( + entryPoint: EntryPoint, + rcpt: TransactionReceipt +): Promise< + Array<{ + nonce: BigNumber + gasUsed: BigNumber + actualGasCost: BigNumber + actualGasUsed: BigNumber + }> +> { + // TODO: checking only latest block... + const block = rcpt.blockNumber + const ev = await entryPoint.queryFilter( + entryPoint.filters.UserOperationEvent(), + block + ) + // if (ev.length === 0) return {} + return ev.map((event) => { + const { nonce, actualGasUsed, actualGasCost } = event.args + return { + nonce, + gasUsed: rcpt.gasUsed, + actualGasUsed, + actualGasCost + } + }) +} + +export async function evRevertInfo( + entryPoint: EntryPoint, + rcpt: TransactionReceipt +): Promise< + Array<{ + nonce: BigNumber + gasUsed: BigNumber + revertReason: string + }> +> { + // TODO: checking only latest block... + const block = rcpt.blockNumber + const ev = await entryPoint.queryFilter( + entryPoint.filters.UserOperationRevertReason(), + block + ) + // if (ev.length === 0) return {} + return ev.map((event) => { + const { nonce, revertReason } = event.args + return { + nonce, + gasUsed: rcpt.gasUsed, + revertReason + } + }) +} + +export function computeRequiredPreFund( + userOp: UserOperation, + usePaymaster = false +): BigNumber { + // get required fund + const requiredGas = BigNumber.from(userOp.verificationGasLimit) + .mul(usePaymaster ? 3 : 1) + .add(userOp.callGasLimit) + .add(userOp.preVerificationGas) + + const requiredPrefund = requiredGas.mul(userOp.maxFeePerGas) + return requiredPrefund +} + +export async function deploySingle( + deployFactory: Contract, + contractName: string, + args?: any[], + libs?: Map, + verifiedContract?: string +): Promise { + // use same salt for all deployments: + const salt = ethers.utils.formatBytes32String('0x5') + + const libraries: Record = {} + libs?.forEach((value, key) => (libraries[key] = value)) + + const contract = await ethers.getContractFactory(contractName, { + libraries + }) + + let deployableCode = contract.bytecode + if (args != null && args.length > 0) { + deployableCode = ethers.utils.hexConcat([ + deployableCode, + contract.interface.encodeDeploy(args) + ]) + } + + const deployedAddress = ethers.utils.getCreate2Address( + deployFactory.address, + salt, + ethers.utils.keccak256(deployableCode) + ) + const forTest = hre.network.name === 'hardhat' + // check if it is deployed already + if ((await ethers.provider.getCode(deployedAddress)) === '0x') { + const gasLimit = await deployFactory.estimateGas.deploy( + deployableCode, + salt + ) + const tx = await deployFactory.deploy(deployableCode, salt, { + gasLimit + }) + await tx.wait() + if (!forTest) { + console.log(contractName, 'deployed address: ', deployedAddress) + } + } else { + if (!forTest) { + console.log( + contractName, + ' is deployed already at: ', + deployedAddress + ) + } + + // NOTE(may throw error when contract code verification too quickly.) + // so only verify contract after it is deployed already for several minutes + if ( + hre.network.name === 'goerli' || + hre.network.name === 'sepolia' || + hre.network.name === 'ethereum' + ) { + await hre.run('verify:verify', { + contract: verifiedContract, + address: deployedAddress, + constructorArguments: args, + libraries + }) + } + } + + return contract.attach(deployedAddress) +} + +export async function deployWalletImpl( + deployFactory: LoopringCreate2Deployer, + entryPointAddr: string, + blankOwner: string, + priceOracleAddr = ethers.constants.AddressZero, + connectorRegistryAddr = ethers.constants.AddressZero +): Promise { + const ERC1271Lib = await deploySingle(deployFactory, 'ERC1271Lib') + const ERC20Lib = await deploySingle(deployFactory, 'ERC20Lib') + const GuardianLib = await deploySingle(deployFactory, 'GuardianLib') + const InheritanceLib = await deploySingle( + deployFactory, + 'InheritanceLib', + undefined, + new Map([['GuardianLib', GuardianLib.address]]) + ) + const QuotaLib = await deploySingle(deployFactory, 'QuotaLib') + const UpgradeLib = await deploySingle(deployFactory, 'UpgradeLib') + const WhitelistLib = await deploySingle( + deployFactory, + 'WhitelistLib' + ) + const LockLib = await deploySingle( + deployFactory, + 'LockLib', + undefined, + new Map([['GuardianLib', GuardianLib.address]]) + ) + const RecoverLib = await deploySingle( + deployFactory, + 'RecoverLib', + undefined, + new Map([['GuardianLib', GuardianLib.address]]) + ) + const ApprovalLib = await deploySingle( + deployFactory, + 'ApprovalLib', + undefined, + new Map([ + ['ERC20Lib', ERC20Lib.address], + ['GuardianLib', GuardianLib.address], + ['LockLib', LockLib.address], + ['RecoverLib', RecoverLib.address], + ['UpgradeLib', UpgradeLib.address], + ['WhitelistLib', WhitelistLib.address] + ]) + ) + if (connectorRegistryAddr === ethers.constants.AddressZero) { + const connectorRegistry = await ( + await ethers.getContractFactory('ConnectorRegistry') + ).deploy() + connectorRegistryAddr = connectorRegistry.address + } + + const smartWallet = await deploySingle( + deployFactory, + 'SmartWalletV3', + [ + priceOracleAddr, + blankOwner, + entryPointAddr, + connectorRegistryAddr + ], + new Map([ + ['ERC1271Lib', ERC1271Lib.address], + ['ERC20Lib', ERC20Lib.address], + ['GuardianLib', GuardianLib.address], + ['InheritanceLib', InheritanceLib.address], + ['LockLib', LockLib.address], + ['QuotaLib', QuotaLib.address], + ['RecoverLib', RecoverLib.address], + ['UpgradeLib', UpgradeLib.address], + ['WhitelistLib', WhitelistLib.address], + ['ApprovalLib', ApprovalLib.address] + ]) + ) + return smartWallet +} + +export async function createSmartWallet( + owner: Wallet, + guardians: string[], + walletFactory: WalletFactory, + salt: string +): Promise { + const feeRecipient = ethers.constants.AddressZero + const { chainId } = await ethers.provider.getNetwork() + // create smart wallet + const signature = await signCreateWallet( + walletFactory.address, + owner, + guardians, + BigNumber.from(0), + ethers.constants.AddressZero, + feeRecipient, + ethers.constants.AddressZero, + BigNumber.from(0), + salt, + chainId + ) + + const walletConfig: any = { + owner: owner.address, + guardians, + quota: 0, + inheritor: ethers.constants.AddressZero, + feeRecipient, + feeToken: ethers.constants.AddressZero, + maxFeeAmount: 0, + salt, + signature + } + + const tx = await walletFactory.createWallet(walletConfig, 0) + return tx.wait() +} + +export interface PaymasterOption { + paymaster: LoopringPaymaster + payToken: Contract + paymasterOwner: Signer + valueOfEth: BigNumberish + validUntil: BigNumberish +} + +export async function generateSignedUserOp( + txs: Array>, + smartWallet: SmartWalletV3, + smartWalletOwner: Signer, + contractFactory: Contract, + entrypoint: EntryPoint, + paymasterOption?: PaymasterOption, + useExecuteApi = true +): Promise { + const ethSent = txs.reduce( + (acc, tx) => acc.add(BigNumber.from(tx.value ?? 0)), + BigNumber.from(0) + ) + const partialUserOp = await createBatchTransactions( + txs, + ethers.provider, + smartWallet, + useExecuteApi // wrap raw calldata with callcontract api + ) + // first call to fill userop + let signedUserOp = await fillAndSign( + partialUserOp, + smartWalletOwner, + contractFactory.address, + entrypoint + ) + + // handle paymaster + if (paymasterOption != null) { + const paymaster = paymasterOption.paymaster + const payToken = paymasterOption.payToken + const valueOfEth = paymasterOption.valueOfEth + const validUntil = paymasterOption.validUntil + + const hash = await paymaster.getHash( + signedUserOp, + ethers.utils.solidityKeccak256( + ['address', 'uint48', 'uint256'], + [payToken.address, validUntil, valueOfEth] + ) + ) + + const paymasterAndData = await getPaymasterAndData( + paymaster.address, + paymasterOption.paymasterOwner, + hash, + payToken.address, + valueOfEth, + validUntil + ) + signedUserOp.paymasterAndData = paymasterAndData + signedUserOp = await fillAndSign( + signedUserOp, + smartWalletOwner, + contractFactory.address, + entrypoint + ) + } + + // prepare gas before send userop + const requiredPrefund = computeRequiredPreFund( + signedUserOp, + paymasterOption !== undefined + ).add(ethSent) + // only consider deposited balance in entrypoint contract when using paymaster + const currentBalance = + paymasterOption != null + ? await entrypoint.balanceOf(paymasterOption.paymaster.address) + : await getEthBalance(smartWallet) + + if (requiredPrefund.gt(currentBalance)) { + const missingValue = requiredPrefund.sub(currentBalance) + const payer = + paymasterOption != null + ? paymasterOption.paymaster.address + : smartWallet.address + await ( + await entrypoint.depositTo(payer, { + value: missingValue + }) + ).wait() + } + return signedUserOp +} + +export async function sendTx( + txs: Array>, + smartWallet: SmartWalletV3, + smartWalletOwner: Signer, + contractFactory: Contract, + entrypoint: EntryPoint, + sendUserOp: SendUserOp, + paymasterOption?: PaymasterOption, + useExecuteApi = true +): Promise { + const signedUserOp = await generateSignedUserOp( + txs, + smartWallet, + smartWalletOwner, + contractFactory, + entrypoint, + paymasterOption, + useExecuteApi + ) + + // get details if throw error + await entrypoint.callStatic + .simulateValidation(signedUserOp) + .catch(simulationResultCatch) + const receipt = await sendUserOp(signedUserOp) + return receipt +} + +export async function createBatchTransactions( + transactions: Array>, + ethersProvider: BaseProvider, + wallet: SmartWalletV3, + useExecuteApi: boolean, + initCode?: BytesLike +): Promise> { + const txs: TransactionRequest[] = await Promise.all( + transactions.map(async (tx) => resolveProperties(tx)) + ) + + let execFromEntryPoint + if (txs.length === 1) { + const tx = txs[0] + if (useExecuteApi) { + execFromEntryPoint = + await wallet.populateTransaction.callContract( + tx.to!, + tx.value ?? 0, + tx.data ?? '0x', + false + ) + } else { + execFromEntryPoint = tx + } + } else { + let datas: BytesLike[] = txs.map((tx) => tx.data ?? '0x') + + if (useExecuteApi) { + const wrappedTxs = await Promise.all( + txs.map(async (tx) => + wallet.populateTransaction.callContract( + tx.to!, + tx.value ?? 0, + tx.data ?? '0x', + false + ) + ) + ) + datas = wrappedTxs.map((wtx) => wtx.data!) + } else { + datas = txs.map((tx) => tx.data ?? '0x') + } + execFromEntryPoint = + await wallet.populateTransaction.selfBatchCall(datas) + } + + let { gasPrice, maxPriorityFeePerGas, maxFeePerGas } = + execFromEntryPoint + // gasPrice is legacy, and overrides eip1559 values: + + if (gasPrice !== undefined) { + maxPriorityFeePerGas = gasPrice + maxFeePerGas = gasPrice + } + const nonce = await wallet.getNonce() + return { + sender: wallet.address, + initCode, + nonce, + callData: execFromEntryPoint.data!, + callGasLimit: execFromEntryPoint.gasLimit, + maxPriorityFeePerGas, + maxFeePerGas + } +} + +async function getEthBalance( + smartWallet: SmartWalletV3 +): Promise { + const ethBalance = await ethers.provider.getBalance( + smartWallet.address + ) + const depositBalance = await smartWallet.getDeposit() + const totalBalance = ethBalance.add(depositBalance) + return totalBalance +} + +// eslint-disable-next-line +export function getErrorMessage(revertReason: string) { + return ethers.utils.defaultAbiCoder.decode( + ['string'], + '0x' + revertReason.slice(10) + )[0] +} + +export async function getBlockTimestamp( + blockNumber: number +): Promise { + const block = await ethers.provider.getBlock(blockNumber) + return block.timestamp +} + +export async function getCurrentQuota( + quotaInfo: any, + blockNumber: number +): Promise { + const blockTime = await getBlockTimestamp(blockNumber) + const pendingUntil = quotaInfo.pendingUntil.toNumber() + + return pendingUntil <= blockTime + ? quotaInfo.pendingQuota + : quotaInfo.currentQuota +} + +export async function getFirstEvent( + contract: Contract, + fromBlock: number, + eventName: string +): Promise { + const events = await contract.queryFilter( + { address: contract.address }, + fromBlock + ) + + for (const e of events) { + if (e.event === eventName) return e + } + + throw new Error() +} diff --git a/packages/hebao_v3/test/inheritor.test.ts b/packages/hebao_v3/test/inheritor.test.ts new file mode 100644 index 000000000..ff5e45a59 --- /dev/null +++ b/packages/hebao_v3/test/inheritor.test.ts @@ -0,0 +1,285 @@ +import { + loadFixture, + setBalance, + takeSnapshot, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { SmartWalletV3__factory } from '../typechain-types' + +import { fixture } from './helper/fixture' +import { createSmartWallet, sendTx } from './helper/utils' + +describe('inheritor test', () => { + it('basic success testcase', async () => { + const { smartWallet, create2, entrypoint, sendUserOp } = + await loadFixture(fixture) + const inheritor = ethers.Wallet.createRandom().connect( + ethers.provider + ) + + // check before + const walletDataBefore = await smartWallet.wallet() + expect(walletDataBefore.inheritor).to.eq( + ethers.constants.AddressZero + ) + expect(walletDataBefore.inheritWaitingPeriod).to.eq(0) + + const waitingPeriod = 3600 * 24 * 30 + await smartWallet.setInheritor(inheritor.address, waitingPeriod) + + const walletData = await smartWallet.wallet() + expect(walletData.inheritor).to.eq(inheritor.address) + expect(walletData.inheritWaitingPeriod).to.eq(waitingPeriod) + + // advance time + const validBlockTime = walletData.lastActive.add( + walletData.inheritWaitingPeriod + ) + await time.increaseTo(validBlockTime) + + // inherit + const newOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const tx = await smartWallet.populateTransaction.inherit( + newOwner.address, + [] /* keep all guardians */ + ) + // check emitted event + void expect(tx) + .to.emit(smartWallet, 'Inherited') + .withArgs(inheritor.address, newOwner.address) + + const snapshotRestorer = await takeSnapshot() + await sendTx( + [tx], + smartWallet, + inheritor, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + + // inherit successfully from inheritor directly + { + // reset inheritor + await snapshotRestorer.restore() + const walletDataBefore = await smartWallet.wallet() + expect(walletDataBefore.inheritor).to.eq(inheritor.address) + + await setBalance( + inheritor.address, + ethers.utils.parseEther('100') + ) + await smartWallet + .connect(inheritor) + .inherit(newOwner.address, []) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + } + }) + + it('inherit from other smart wallet', async () => { + const { + smartWallet, + create2, + entrypoint, + sendUserOp, + walletFactory + } = await loadFixture(fixture) + // create new smart wallet as inheritor + const inheritorOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const salt = ethers.utils.formatBytes32String('0x5') + await createSmartWallet(inheritorOwner, [], walletFactory, salt) + const smartWalletAddr = await walletFactory.computeWalletAddress( + inheritorOwner.address, + salt + ) + const inheritor = SmartWalletV3__factory.connect( + smartWalletAddr, + inheritorOwner + ) + + // set new inheritor for smartwallet + const waitingPeriod = 3600 * 24 * 30 + void expect( + await smartWallet.setInheritor(inheritor.address, waitingPeriod) + ) + .to.emit(smartWallet, 'InheritorChanged') + .withArgs(inheritor.address, waitingPeriod) + const walletData = await smartWallet.wallet() + const validBlockTime = walletData.lastActive.add( + walletData.inheritWaitingPeriod + ) + + await time.increaseTo(validBlockTime) + + // inherit + const newOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const tx = await smartWallet.populateTransaction.inherit( + newOwner.address, + [] /* keep all guardians */ + ) + + const snapshotRestorer = await takeSnapshot() + await sendTx( + [tx], + smartWallet, + inheritorOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + + // inherit successfully from inheritor directly (send inherit userop from inheritor smart wallet) + await snapshotRestorer.restore() + // prepare gas for inheritor smartwallet + await setBalance( + inheritor.address, + ethers.utils.parseEther('100') + ) + // use execute api + await sendTx( + [tx], + inheritor, + inheritorOwner, + create2, + entrypoint, + sendUserOp + ) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + }) + + it('fail without waiting period', async () => { + const { smartWallet, create2, entrypoint, sendUserOp } = + await loadFixture(fixture) + const inheritor = ethers.Wallet.createRandom().connect( + ethers.provider + ) + + const walletDataBefore = await smartWallet.wallet() + expect(walletDataBefore.inheritor).to.eq( + ethers.constants.AddressZero + ) + expect(walletDataBefore.inheritWaitingPeriod).to.eq(0) + + const waitingPeriod = 3600 * 24 * 30 + await smartWallet.setInheritor(inheritor.address, waitingPeriod) + + const walletData = await smartWallet.wallet() + expect(walletData.inheritor).to.eq(inheritor.address) + expect(walletData.inheritWaitingPeriod).to.eq(waitingPeriod) + + const validBlockTime = walletData.lastActive.add( + walletData.inheritWaitingPeriod + ) + await time.increaseTo(validBlockTime.sub(1)) + + const newOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const tx = await smartWallet.populateTransaction.inherit( + newOwner.address, + [] /* keep all guardians */ + ) + await expect( + sendTx( + [tx], + smartWallet, + inheritor, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + ).to.be.revertedWith('TOO_EARLY') + }) + + it('inherit with a owner in guardians group', async () => { + const test = async (removeGuardians: boolean): Promise => { + const { smartWallet, create2, entrypoint, sendUserOp } = + await loadFixture(fixture) + const inheritor = ethers.Wallet.createRandom().connect( + ethers.provider + ) + // check before + const walletDataBefore = await smartWallet.wallet() + expect(walletDataBefore.inheritor).to.eq( + ethers.constants.AddressZero + ) + expect(walletDataBefore.inheritWaitingPeriod).to.eq(0) + + const newOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + // add newOwner to guardians group + await smartWallet + .addGuardian(newOwner.address) + .then(async (tx) => tx.wait()) + const guardians = await smartWallet.getGuardians(true) + // expect newOwner is on guardians group + expect( + guardians.some((g) => g.addr === newOwner.address) + ).to.eq(true) + + const waitingPeriod = 3600 * 24 * 30 + await smartWallet.setInheritor(inheritor.address, waitingPeriod) + await time.increase(waitingPeriod + 1) + + { + const tx = await smartWallet.populateTransaction.inherit( + newOwner.address, + [newOwner.address] /* keep all guardians */ + ) + await expect( + sendTx( + [tx], + smartWallet, + inheritor, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + ).to.rejectedWith('INVALID_NEW_WALLET_GUARDIAN') + } + + const tx = await smartWallet.populateTransaction.inherit( + newOwner.address, + [] /* keep all guardians */ + ) + await sendTx( + [tx], + smartWallet, + inheritor, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + const guardians2 = await smartWallet.getGuardians(true) + // expect newOwner is not on guardians group + expect( + guardians2.some((g) => g.addr === newOwner.address) + ).to.eq(false) + } + await test(true) // removeGuardians: true + await test(false) // removeGuardians: false + }) +}) diff --git a/packages/hebao_v3/test/lock.test.ts b/packages/hebao_v3/test/lock.test.ts new file mode 100644 index 000000000..7df4ade19 --- /dev/null +++ b/packages/hebao_v3/test/lock.test.ts @@ -0,0 +1,218 @@ +import { + loadFixture, + setBalance, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { SmartWalletV3__factory } from '../typechain-types' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { createSmartWallet, sendTx } from './helper/utils' +import { ErrorCodes } from './helper/error_codes' + +describe('lock test', () => { + it('basic success testcase', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + // lock wallet from owner first + await smartWallet.lock() + expect((await smartWallet.wallet()).locked).to.equal(true) + // TODO(allow to double lock?) + await expect(smartWallet.lock()).not.to.reverted + const callData = + smartWallet.interface.encodeFunctionData('unlock') + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.Unlock + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: guardians[0] }, + { + signer: smartWalletOwner + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + + // check + expect((await smartWallet.wallet()).locked).to.equal(false) + + // replay test + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: HASH_EXIST') + }) + describe('lock test', () => { + it('lock success from guardian', async () => { + const { smartWallet, deployer, guardians } = + await loadFixture(fixture) + await setBalance( + guardians[0].address, + ethers.utils.parseEther('100') + ) + await expect(smartWallet.connect(guardians[0]).lock()).not.to + .reverted + // check wallet is lock + expect((await smartWallet.wallet()).locked).to.equal(true) + // others cannot lock wallet + await expect( + smartWallet.connect(deployer).lock() + ).to.revertedWith( + `LRC#${ErrorCodes.NOT_FROM_WALLET_OR_OWNER_OR_GUARDIAN}` + ) + }) + + it('lock success directly from entrypoint', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp + } = await loadFixture(fixture) + const lock = await smartWallet.populateTransaction.lock() + + await sendTx( + [lock], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect((await smartWallet.wallet()).locked).to.equal(true) + }) + + it('lock wallet by guardian(smart wallet)', async () => { + // create new smart wallet as guardian then add it + const { + entrypoint, + smartWallet, + create2, + sendUserOp, + walletFactory + } = await loadFixture(fixture) + const guardianOwner = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const salt = ethers.utils.formatBytes32String('0x5') + await createSmartWallet(guardianOwner, [], walletFactory, salt) + const smartWalletAddr = + await walletFactory.computeWalletAddress( + guardianOwner.address, + salt + ) + const guardian = SmartWalletV3__factory.connect( + smartWalletAddr, + guardianOwner + ) + // add guardian + expect(await smartWallet.isGuardian(guardian.address, true)).to + .be.false + await smartWallet.addGuardian(guardian.address) + expect(await smartWallet.isGuardian(guardian.address, true)).to + .be.true + await time.increase(3600 * 24 * 3) + expect(await smartWallet.isGuardian(guardian.address, false)).to + .be.true + + expect((await smartWallet.wallet()).locked).to.equal(false) + const lock = await smartWallet.populateTransaction.lock() + await setBalance( + guardian.address, + ethers.utils.parseEther('100') + ) + // note that user op here is signed by guardian owner + // instead of guardian when it is smart wallet rather than EOA + await sendTx( + [lock], + guardian, + guardianOwner, + create2, + entrypoint, + sendUserOp + ) + // check if it is locked by the new guardian + expect((await smartWallet.wallet()).locked).to.equal(true) + }) + it('cannot lock when no any guardians', async () => { + const { smartWalletOwner, walletFactory } = + await loadFixture(fixture) + // create wallet with empty guardians list + + const salt = ethers.utils.formatBytes32String('0x1') + await createSmartWallet( + smartWalletOwner, + [], + walletFactory, + salt + ) + + const smartWalletAddr = + await walletFactory.computeWalletAddress( + smartWalletOwner.address, + salt + ) + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + + // cannot lock + await expect(smartWallet.lock()).to.rejectedWith('LRC#400') + }) + }) + describe('unlock test', () => { + it('cannot unlock directly from wallet owner', async () => { + const { smartWallet } = await loadFixture(fixture) + await expect(smartWallet.unlock()).to.rejectedWith( + `${ErrorCodes.ONLY_FROM_ENTRYPOINT}` + ) + }) + + it('cannot unlock from entrypoint using `execute` api', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp + } = await loadFixture(fixture) + const unlock = await smartWallet.populateTransaction.unlock() + + // NOTE cannot allow unlock using callcontract api + await expect( + sendTx( + [unlock], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + ).to.revertedWith('SELF_CALL_DISALLOWED') + }) + }) +}) diff --git a/packages/hebao_v3/test/loopring_create2.test.ts b/packages/hebao_v3/test/loopring_create2.test.ts new file mode 100644 index 000000000..9c9dcfc24 --- /dev/null +++ b/packages/hebao_v3/test/loopring_create2.test.ts @@ -0,0 +1,107 @@ +import { expect } from 'chai' +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { ethers } from 'hardhat' +import { type SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { type LoopringCreate2Deployer } from '../typechain-types' + +describe('loopring create test', () => { + async function fixture(): Promise<{ + deployFactory: LoopringCreate2Deployer + salt: string + deployer: SignerWithAddress + other: SignerWithAddress + }> { + const create2 = await ( + await ethers.getContractFactory('LoopringCreate2Deployer') + ).deploy() + const salt = ethers.utils.formatBytes32String('0x5') + + const [deployer, other] = await ethers.getSigners() + return { deployFactory: create2, salt, deployer, other } + } + + it('deploy contracts', async () => { + const { deployFactory, salt } = await loadFixture(fixture) + const contract = await ethers.getContractFactory('LRC') + const tx = contract.getDeployTransaction() + await deployFactory.deploy(tx.data!, salt) + + const deployedAddress = ethers.utils.getCreate2Address( + deployFactory.address, + salt, + ethers.utils.keccak256(tx.data!) + ) + // test deployed contract + const lrc = contract.attach(deployedAddress) + expect(await lrc.name()).to.eq('LRC_TEST') + }) + + it('deploy complex contract', async () => { + const { deployFactory, salt, deployer } = + await loadFixture(fixture) + const contract = await ethers.getContractFactory('WalletFactory') + const deployableCode = contract.getDeployTransaction( + // as fake wallet implementation + deployFactory.address + ).data! + await deployFactory.deploy(deployableCode, salt) + + const deployedAddress = ethers.utils.getCreate2Address( + deployFactory.address, + salt, + ethers.utils.keccak256(deployableCode) + ) + + const walletFactory = contract.attach(deployedAddress) + + await deployFactory.setTarget(walletFactory.address) + const transferOwnership = + walletFactory.interface.encodeFunctionData( + 'transferOwnership', + [deployer.address] + ) + + expect(await walletFactory.owner()).to.eq(deployFactory.address) + await deployFactory.transact(transferOwnership) + expect(await walletFactory.owner()).to.eq(deployer.address) + }) + + it('transfer ownership', async () => { + const { deployFactory, deployer, other } = + await loadFixture(fixture) + expect(await deployFactory.owner()).to.eq(deployer.address) + await deployFactory.transferOwnership(other.address) + await deployFactory.connect(other).claimOwnership() + expect(await deployFactory.owner()).to.eq(other.address) + }) + + it('permission checks', async () => { + const { deployFactory, deployer, other } = + await loadFixture(fixture) + const bytes4 = '0x12345678' + expect(await deployFactory.hasAccessTo(deployer.address, bytes4)) + .to.be.true + expect(await deployFactory.hasAccessTo(other.address, bytes4)).to + .be.false + + await expect(deployFactory.setTarget(other.address)).not.to + .reverted + await expect( + deployFactory.connect(other).setTarget(other.address) + ).to.revertedWith('UNAUTHORIZED') + + await expect(deployFactory.transact(bytes4)).not.to.reverted + await expect( + deployFactory.connect(other).transact(bytes4) + ).to.revertedWith('PERMISSION_DENIED') + + await deployFactory.grantAccess(other.address, bytes4, true) + await expect(deployFactory.connect(other).transact(bytes4)).not.to + .reverted + + await deployFactory.grantAccess(other.address, bytes4, false) + await expect( + deployFactory.connect(other).transact(bytes4) + ).to.revertedWith('PERMISSION_DENIED') + }) +}) diff --git a/packages/hebao_v3/test/loopring_paymaster.test.ts b/packages/hebao_v3/test/loopring_paymaster.test.ts new file mode 100644 index 000000000..27c086652 --- /dev/null +++ b/packages/hebao_v3/test/loopring_paymaster.test.ts @@ -0,0 +1,502 @@ +import { + loadFixture, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { anyValue } from '@nomicfoundation/hardhat-chai-matchers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { fixture } from './helper/fixture' +import { type PaymasterOption, sendTx } from './helper/utils' +// import { LoopringPaymaster__factory } from '../typechain-types' + +describe('LoopringPaymaster test', () => { + describe('admin operation success', () => { + it('deploy test', async () => { + const entryPointAddr = ethers.Wallet.createRandom().address + const deployFactory = await ethers.getContractFactory( + 'LoopringPaymaster' + ) + await expect( + deployFactory.deploy( + entryPointAddr, + ethers.constants.AddressZero + ) + ).to.revertedWith('LRC#104') + const paymasterOwnerAddr = ethers.Wallet.createRandom().address + const paymaster = await deployFactory.deploy( + entryPointAddr, + paymasterOwnerAddr + ) + expect(await paymaster.owner()).to.eq(paymasterOwnerAddr) + expect( + await paymaster.hasRole( + await paymaster.SIGNER(), + paymasterOwnerAddr + ) + ).to.be.true + expect( + await paymaster.hasRole( + await paymaster.DEFAULT_ADMIN_ROLE(), + paymasterOwnerAddr + ) + ).to.be.true + expect(await paymaster.entryPoint()).to.eq(entryPointAddr) + }) + it('adjust paramster params by owner', async () => { + const { paymaster, somebody, lrcToken } = + await loadFixture(fixture) + + await expect( + paymaster.connect(somebody).addToken(lrcToken.address) + ).to.revertedWith('Ownable: caller is not the owner') + // cannot add zero as token address + await expect( + paymaster.addToken(ethers.constants.AddressZero) + ).to.revertedWith('LRC#104') + await paymaster.addToken(lrcToken.address) + await expect( + paymaster.addToken(lrcToken.address) + ).to.revertedWith('LRC#522') + expect(await paymaster.registeredToken(lrcToken.address)).to.be + .true + // cannot add zero as token address + await expect( + paymaster.removeToken(ethers.constants.AddressZero) + ).to.revertedWith('LRC#104') + await paymaster.removeToken(lrcToken.address) + await expect( + paymaster.removeToken(lrcToken.address) + ).to.revertedWith('LRC#521') + expect(await paymaster.registeredToken(lrcToken.address)).to.be + .false + }) + + it('roles management', async () => { + const { paymaster, paymasterOwner: owner } = + await loadFixture(fixture) + // expect owner to be admin + expect( + await paymaster.hasRole(paymaster.SIGNER(), owner.address) + ).to.be.true + // add other to be admin + const other = ethers.Wallet.createRandom() + expect( + await paymaster.hasRole(paymaster.SIGNER(), other.address) + ).to.be.false + await paymaster.grantRole(paymaster.SIGNER(), other.address) + expect( + await paymaster.hasRole(paymaster.SIGNER(), other.address) + ).to.be.true + }) + }) + + describe('send userOp with paymaster', () => { + it('transfer usdtToken with paymaster', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + lrcToken, + deployer, + sendUserOp, + create2, + paymaster, + paymasterOwner + } = await loadFixture(fixture) + // prepare mock usdt token first + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + /// /////////////////////////////////////// + // usdt token transfer test + const tokenAmount = ethers.utils.parseUnits('100', 6) + // approve paymaster before using usdt paymaster service + const approveToken = + await usdtToken.populateTransaction.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + const transferToken = + await usdtToken.populateTransaction.transfer( + deployer.address, + tokenAmount + ) + const valueOfEth = ethers.utils.parseUnits('625', 12) + const paymasterOption: PaymasterOption = { + paymaster, + payToken: lrcToken, + paymasterOwner, + valueOfEth, + validUntil: 0 + } + + await paymaster.addToken(lrcToken.address) + await expect( + sendTx( + [approveToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA33 reverted: LRC#525') + paymasterOption.payToken = usdtToken + + expect(await usdtToken.balanceOf(deployer.address)).to.eq(0) + + // approve token and transfer at the same time + const ethBalanceBefore = await ethers.provider.getBalance( + smartWallet.address + ) + await sendTx( + [approveToken, transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + + expect(await usdtToken.balanceOf(deployer.address)).to.eq( + tokenAmount + ) + // no any gas used by smart wallet + expect( + await ethers.provider.getBalance(smartWallet.address) + ).to.eq(ethBalanceBefore) + + const afterBalance = await usdtToken.balanceOf( + smartWallet.address + ) + // fee is transfered to paymaster contract + expect(await usdtToken.balanceOf(paymaster.address)).to.eq( + initTokenAmount.sub(afterBalance).sub(tokenAmount) + ) + // TODO(check eth balance for paymaster) + + // sendtx for free + paymasterOption.valueOfEth = 0 + + // eslint-disable-next-line + expect( + await sendTx( + [transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ) + .to.emit(paymaster, 'PaymasterEvent') + .withArgs( + anyValue, + anyValue, + anyValue, + anyValue, + ethers.constants.Zero + ) + // no fee for sending tx + expect(await usdtToken.balanceOf(smartWallet.address)).to.eq( + afterBalance.sub(tokenAmount) + ) + + // if usdt token is unregistered, user cannot pay the tokens to paymaster any more + await paymaster.removeToken(usdtToken.address) + await expect( + sendTx( + [transferToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA33 reverted: LRC#521') + }) + + it('check valid until', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + sendUserOp, + create2, + paymaster, + paymasterOwner + } = await loadFixture(fixture) + // prepare mock usdt token first + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + const value = ethers.utils.parseEther('10') + const to = ethers.constants.AddressZero + const transferEth = { value, to } + const valueOfEth = ethers.utils.parseUnits('625', 12) + const block = await ethers.provider.getBlock('latest') + const paymasterOption: PaymasterOption = { + paymaster, + payToken: usdtToken, + paymasterOwner, + valueOfEth, + validUntil: 1 + } + // approve first + const approveToken = + await usdtToken.populateTransaction.approve( + paymaster.address, + ethers.constants.MaxUint256 + ) + + await expect( + sendTx( + [approveToken], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + ).not.to.reverted + + await expect( + sendTx( + [transferEth], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA32 paymaster expired or not due') + paymasterOption.validUntil = 3600 + block.timestamp + await expect( + sendTx( + [transferEth], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ).not.to.reverted + }) + + it('deposit and withdraw eth for paymaster in entrypoint', async () => { + const { deployer, paymaster } = await loadFixture(fixture) + const amount = ethers.utils.parseEther('1') + const depositAmountBefore = await paymaster.getDeposit() + await paymaster.deposit({ value: amount }) + const depositAmountAfter = await paymaster.getDeposit() + expect(depositAmountAfter.sub(depositAmountBefore)).to.eq( + amount + ) + + // withdraw eth to deployer + const withdrawer = deployer.address + const balanceBefore = + await ethers.provider.getBalance(withdrawer) + await paymaster.withdrawTo(withdrawer, depositAmountAfter) + const balanceAfter = + await ethers.provider.getBalance(withdrawer) + expect(balanceAfter.sub(balanceBefore)).eq(depositAmountAfter) + }) + + it('stake and unstake eth for paymaster in entrypoint', async () => { + const { deployer, paymaster } = await loadFixture(fixture) + const amount = ethers.utils.parseEther('1') + const unstakeDelaySec = 10 + await paymaster.addStake(unstakeDelaySec, { value: amount }) + + // withdraw eth to deployer + await paymaster.unlockStake() + // advance time after unlock + await time.increase(unstakeDelaySec) + const withdrawer = deployer.address + const balanceBefore = + await ethers.provider.getBalance(withdrawer) + await paymaster.withdrawStake(withdrawer) + const balanceAfter = + await ethers.provider.getBalance(withdrawer) + expect(balanceAfter.sub(balanceBefore)).eq(amount) + }) + + it('reject eth and any erc20 token directly', async () => { + const { deployer, paymaster } = await loadFixture(fixture) + const value = ethers.utils.parseEther('1') + await expect( + deployer.sendTransaction({ to: paymaster.address, value }) + ).to.revertedWith('eth rejected') + }) + }) + + describe('gas tank', () => { + it('deposit and withdraw for user', async () => { + const { deployer, paymaster, lrcToken } = + await loadFixture(fixture) + const amount = ethers.utils.parseUnits( + '1000', + await lrcToken.decimals() + ) + await lrcToken.setBalance(deployer.address, amount) + await lrcToken.approve(paymaster.address, amount) + await expect( + paymaster + .connect(deployer) + .addDepositFor(lrcToken.address, deployer.address, amount) + ).to.revertedWith('LRC#521') + + // add token before deposit + await paymaster.addToken(lrcToken.address) + await paymaster + .connect(deployer) + .addDepositFor(lrcToken.address, deployer.address, amount) + // check deposit info + const depositInfo = await paymaster.depositInfo( + lrcToken.address, + deployer.address + ) + // token is already locked in paymaster contract + expect(depositInfo._unlockBlock).to.eq(0) + expect(depositInfo.amount).to.eq(amount) + + // unlock and withdraw token + await expect( + paymaster + .connect(deployer) + .withdrawTokensTo( + lrcToken.address, + deployer.address, + amount + ) + ).to.revertedWith('LRC#523') + await paymaster.connect(deployer).unlockTokenDeposit() + await paymaster + .connect(deployer) + .withdrawTokensTo(lrcToken.address, deployer.address, amount) + expect(await lrcToken.balanceOf(deployer.address)).to.eq(amount) + }) + + it('transfer usdtToken with gastank', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + usdtToken, + deployer, + sendUserOp, + create2, + paymaster, + paymasterOwner + } = await loadFixture(fixture) + // prepare enviroment first + const initAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(deployer.address, initAmount) + await usdtToken.approve(paymaster.address, initAmount) + + // predeposit usdt token to paymaster for smartwallet + await paymaster + .connect(deployer) + .addDepositFor( + usdtToken.address, + smartWallet.address, + initAmount + ) + + const value = ethers.utils.parseEther('10') + const to = ethers.constants.AddressZero + const transferEth = { value, to } + const valueOfEth = ethers.utils.parseUnits('625', 12) + const paymasterOption: PaymasterOption = { + paymaster, + payToken: usdtToken, + paymasterOwner, + valueOfEth, + validUntil: 0 + } + const unlock = + await paymaster.populateTransaction.unlockTokenDeposit() + + await sendTx( + [unlock], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + await expect( + sendTx( + [transferEth], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + ) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA33 reverted: LRC#525') + + // only locked fund can be used for gas fee. so lock it again here. + // note that cannot lock fund using paymaster service + const lock = + await paymaster.populateTransaction.lockTokenDeposit() + await sendTx( + [lock], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + await sendTx( + [transferEth], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + paymasterOption + ) + + // withdraw token by paymaster owner + const receiver = paymasterOwner.address + const depositInfo = await paymaster.depositInfo( + usdtToken.address, + paymasterOwner.address + ) + expect(depositInfo.amount).to.gt(0) + // unlock before withdraw + await paymaster.unlockTokenDeposit() + await paymaster.withdrawTokensTo( + usdtToken.address, + receiver, + depositInfo.amount + ) + expect(await usdtToken.balanceOf(receiver)).to.eq( + depositInfo.amount + ) + }) + }) + describe('failure cases checks', () => { + it('check revert reasons', async () => {}) + }) +}) diff --git a/packages/hebao_v3/test/official_guardian.test.ts b/packages/hebao_v3/test/official_guardian.test.ts new file mode 100644 index 000000000..2cac07ca7 --- /dev/null +++ b/packages/hebao_v3/test/official_guardian.test.ts @@ -0,0 +1,92 @@ +import { expect } from 'chai' +import { type SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers' +import { ethers } from 'hardhat' +import { + loadFixture, + setBalance +} from '@nomicfoundation/hardhat-network-helpers' +import { type OfficialGuardian } from '../typechain-types' +import { type Wallet } from 'ethers' + +describe('official guardian test', () => { + async function fixture(): Promise<{ + officialGuardian: OfficialGuardian + someone: Wallet + deployer: SignerWithAddress + }> { + const deployer = (await ethers.getSigners())[0] + const officialGuardian = await ( + await ethers.getContractFactory('OfficialGuardian') + ).deploy() + const someone = ethers.Wallet.createRandom().connect( + ethers.provider + ) + // prepare gas fee + await setBalance(someone.address, ethers.utils.parseEther('10')) + return { someone, officialGuardian, deployer } + } + + it('basic usage test', async () => { + const { deployer, officialGuardian, someone } = + await loadFixture(fixture) + expect(await officialGuardian.owner()).to.eq(deployer.address) + + // call transact + await officialGuardian.addManager(someone.address) + await setBalance( + officialGuardian.address, + ethers.utils.parseEther('10') + ) + const amount = ethers.utils.parseEther('1') + // new address is ok + const receiver = ethers.constants.AddressZero + await expect( + officialGuardian + .connect(deployer) + .transact(receiver, amount, '0x') + ).to.revertedWith('NOT_MANAGER') + await officialGuardian + .connect(someone) + .transact(receiver, amount, '0x') + expect(await ethers.provider.getBalance(receiver)).to.eq(amount) + + // call init owner + await expect( + officialGuardian.initOwner(ethers.constants.AddressZero) + ).to.revertedWith('LRC#104') + await expect( + officialGuardian.initOwner(someone.address) + ).to.revertedWith('LRC#306') + + // TODO(call initOwner when using proxy contract) + }) + it('ownership management', async () => { + const { officialGuardian, someone, deployer } = + await loadFixture(fixture) + await expect( + officialGuardian + .connect(someone) + .transferOwnership(someone.address) + ).to.revertedWith('UNAUTHORIZED') + await officialGuardian + .connect(deployer) + .transferOwnership(someone.address) + await officialGuardian.connect(someone).claimOwnership() + expect(await officialGuardian.owner()).to.eq(someone.address) + }) + + it('manager management', async () => { + const { officialGuardian, someone } = await loadFixture(fixture) + expect(await officialGuardian.numManagers()).to.eq(0) + expect(await officialGuardian.isManager(someone.address)).to.be + .false + await officialGuardian.addManager(someone.address) + expect(await officialGuardian.isManager(someone.address)).to.be + .true + expect(await officialGuardian.numManagers()).to.eq(1) + await officialGuardian.removeManager(someone.address) + expect(await officialGuardian.isManager(someone.address)).to.be + .false + expect(await officialGuardian.numManagers()).to.eq(0) + }) +}) diff --git a/packages/hebao_v3/test/price_oracle.test.ts b/packages/hebao_v3/test/price_oracle.test.ts new file mode 100644 index 000000000..49648f732 --- /dev/null +++ b/packages/hebao_v3/test/price_oracle.test.ts @@ -0,0 +1,169 @@ +import { expect } from 'chai' +import { ethers } from 'hardhat' + +describe('price oracle test', () => { + // only valid price(should be positive number) is considered + function getTokenValue( + tokenPrices: number[], + amount: number + ): number { + tokenPrices = tokenPrices.filter((tp) => tp > 0) + return ( + tokenPrices.reduce((acc, cur) => acc + cur * amount, 0) / + tokenPrices.length + ) + } + + it('aggregational price oracle', async () => { + const testPriceOraclesAddr = [] + // const num = 2; + const prices = [1, 10, 0] + for (let i = 0; i < prices.length; ++i) { + const testPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(prices[i]) + testPriceOraclesAddr.push(testPriceOracle.address) + } + + const aggregationalPriceOracle = await ( + await ethers.getContractFactory('AggregationalPriceOracle') + ).deploy(testPriceOraclesAddr) + const token = ethers.constants.AddressZero + const amount = 1000 + const tokenValue = await aggregationalPriceOracle.tokenValue( + token, + amount + ) + expect(tokenValue).to.eq(getTokenValue(prices, amount)) + }) + + it('cached price oracle', async () => { + const signers = await ethers.getSigners() + const manager = signers[1] + const oraclePrice = 1 + const testPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(oraclePrice) + + const cachedPriceOracle = await ( + await ethers.getContractFactory('CachedPriceOracle') + ).deploy(testPriceOracle.address) + + const token = ethers.constants.AddressZero + const amount = 1000 + expect(await cachedPriceOracle.tokenValue(token, amount)).to.eq(0) + + await expect( + cachedPriceOracle.updateTokenPrice(token, amount) + ).to.revertedWith('NOT_MANAGER') + await cachedPriceOracle.addManager(manager.address) + + const initPrice = 10 + await cachedPriceOracle + .connect(manager) + .setTokenPrice(token, amount, amount * initPrice) + expect(await cachedPriceOracle.tokenValue(token, amount)).to.eq( + amount * initPrice + ) + // calculate token value using the fixed ratio(fixed token price as to say) + expect( + await cachedPriceOracle.tokenValue(token, 2 * amount) + ).to.eq(2 * amount * initPrice) + expect( + await cachedPriceOracle.tokenValue(token, 0.5 * amount) + ).to.eq(0.5 * amount * initPrice) + + // update token price by price oracle + await cachedPriceOracle + .connect(manager) + .updateTokenPrice(token, amount) + expect(await cachedPriceOracle.tokenValue(token, amount)).to.eq( + amount * oraclePrice + ) + + // change oracle price + const newOraclePrice = 20 + const newPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(newOraclePrice) + await cachedPriceOracle + .connect(manager) + .setOracle(newPriceOracle.address) + // token value is not changed before oracle update price + expect(await cachedPriceOracle.tokenValue(token, amount)).to.eq( + amount * oraclePrice + ) + + // change to new oracle price + await cachedPriceOracle + .connect(manager) + .updateTokenPrice(token, amount) + expect(await cachedPriceOracle.tokenValue(token, amount)).to.eq( + amount * newOraclePrice + ) + }) + + it('uniswapv2 price oracle test', async () => { + const uniswapv2Factory = await ( + await ethers.getContractFactory('TestUniswapV2Factory') + ).deploy() + const wethAddr = '0x' + '01'.repeat(20) + const uniswapV2PriceOracle = await ( + await ethers.getContractFactory('UniswapV2PriceOracle') + ).deploy(uniswapv2Factory.address, wethAddr) + const nativeTokenAddr = ethers.constants.AddressZero + const erc20Addr = '0x' + '02'.repeat(20) + const amount = 1000 + + // token value of eth/weth + expect( + await uniswapV2PriceOracle.tokenValue(nativeTokenAddr, amount) + ).to.eq(amount * 1) + expect( + await uniswapV2PriceOracle.tokenValue(wethAddr, amount) + ).to.eq(amount * 1) + // token value of common erc20 + expect( + await uniswapV2PriceOracle.tokenValue(erc20Addr, amount) + ).to.eq(amount * 0) + + // create a mocked token pair and add it to uniswapv2 factory + const testUniswapV2Pair = await ( + await ethers.getContractFactory('TestUniswapV2Pair') + ).deploy(1 /* weth reserves */, 10 /* erc20 reserves */) + await uniswapv2Factory.addPair( + erc20Addr, + wethAddr, + testUniswapV2Pair.address + ) + expect( + await uniswapV2PriceOracle.tokenValue(erc20Addr, amount) + ).to.eq(amount / 10) + }) + + it('kyber price oracle test', async () => { + const price = 10 + const kyberFactory = await ( + await ethers.getContractFactory('TestKyberNetworkProxy') + ).deploy(price) + const kyberPriceOracle = await ( + await ethers.getContractFactory('KyberNetworkPriceOracle') + ).deploy(kyberFactory.address) + + const nativeTokenAddr = ethers.constants.AddressZero + const erc20Addr = '0x' + '02'.repeat(20) + const wethAddr = '0x' + 'ee'.repeat(20) + const amount = 1000 + + // token value of eth/weth + expect( + await kyberPriceOracle.tokenValue(nativeTokenAddr, amount) + ).to.eq(amount * 1) + expect(await kyberPriceOracle.tokenValue(wethAddr, amount)).to.eq( + amount * 1 + ) + expect( + await kyberPriceOracle.tokenValue(erc20Addr, amount) + ).to.eq(amount * price) + }) +}) diff --git a/packages/hebao_v3/test/quota.test.ts b/packages/hebao_v3/test/quota.test.ts new file mode 100644 index 000000000..ba3559c01 --- /dev/null +++ b/packages/hebao_v3/test/quota.test.ts @@ -0,0 +1,474 @@ +import { + loadFixture, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { Wallet } from 'ethers' +import { ethers } from 'hardhat' +import { ErrorCodes } from './helper/error_codes' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { + deployWalletImpl, + getBlockTimestamp, + getCurrentQuota, + sendTx +} from './helper/utils' + +describe('quota test', () => { + it('change daily quota from entrypoint directly', async () => { + const { + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + } = await loadFixture(fixture) + const quotaAmount = ethers.utils.parseEther('20') + const tx = + await smartWallet.populateTransaction.changeDailyQuota( + quotaAmount + ) + await sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + undefined, + false + ) + expect((await smartWallet.wallet()).quota.pendingQuota).to.eq( + quotaAmount + ) + + await expect( + sendTx( + [tx], + smartWallet, + smartWalletOwner, + create2, + entrypoint, + sendUserOp + ) + ).to.revertedWith('SELF_CALL_DISALLOWED') + }) + it('change daily quota from wallet owner', async () => { + const { smartWallet: wallet } = await loadFixture(fixture) + const quotaAmount = ethers.utils.parseEther('10') + await wallet.changeDailyQuota(quotaAmount) + const quotaInfo = (await wallet.wallet()).quota + + expect(quotaInfo.pendingQuota).to.equal(quotaAmount) + expect(quotaInfo.pendingUntil).to.equal(0) + }) + + it('changeDailyQuota extra test', async () => { + const { smartWallet: wallet } = await loadFixture(fixture) + + const quotaAmount = ethers.utils.parseEther('10') + const tx = await wallet.changeDailyQuota(quotaAmount) + const quotaInfo = (await wallet.wallet()).quota + // 0 (MAX_AMOUNT) => quotaAmount, become effective immediately. + const currentQuota = await getCurrentQuota( + quotaInfo, + tx.blockNumber! + ) + expect(currentQuota).to.equal(quotaAmount) + expect(quotaInfo.pendingQuota).to.equal(quotaAmount) + expect(quotaInfo.pendingUntil).to.equal(0) + + await time.increase(3600 * 24) + const quotaAmount2 = ethers.utils.parseEther('20') + const tx2 = await wallet.changeDailyQuota(quotaAmount2) + const blockTime2 = await getBlockTimestamp(tx2.blockNumber!) + const quotaInfo2 = (await wallet.wallet()).quota + const currentQuota2 = await getCurrentQuota( + quotaInfo2, + tx2.blockNumber! + ) + expect(currentQuota2).to.equal(quotaAmount) + expect(quotaInfo2.pendingQuota).to.equal(quotaAmount2) + expect(quotaInfo2.pendingUntil).to.equal(blockTime2 + 3600 * 24) + + await time.increase(3600 * 24) + const quotaAmount3 = ethers.utils.parseEther('50') + const tx3 = await wallet.changeDailyQuota(quotaAmount3) + const blockTime3 = await getBlockTimestamp(tx3.blockNumber!) + const quotaInfo3 = (await wallet.wallet()).quota + const currentQuota3 = await getCurrentQuota( + quotaInfo3, + tx3.blockNumber! + ) + expect(currentQuota3).to.equal(quotaAmount2) + expect(quotaInfo3.pendingQuota).to.equal(quotaAmount3) + expect(quotaInfo3.pendingUntil).to.equal(blockTime3 + 3600 * 24) + + await time.increase(3600 * 24) + + // newQuota < currentQuota, newQuota will become effective immediately. + const quotaAmount4 = ethers.utils.parseEther('49') + const tx4 = await wallet.changeDailyQuota(quotaAmount4) + const quotaInfo4 = (await wallet.wallet()).quota + const currentQuota4 = await getCurrentQuota( + quotaInfo4, + tx4.blockNumber! + ) + expect(currentQuota4).to.equal(quotaAmount4) + expect(quotaInfo4.pendingQuota).to.equal(quotaAmount4) + expect(quotaInfo4.pendingUntil).to.equal(0) + }) + + it('changeDailyQuotaWA', async () => { + const { + smartWallet, + smartWalletOwner, + guardians, + create2, + entrypoint, + sendUserOp, + smartWalletImpl + } = await loadFixture(fixture) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeDailyQuota + } + const newQuota = '1' + '0'.repeat(20) + const callData = smartWallet.interface.encodeFunctionData( + 'changeDailyQuotaWA', + [newQuota] + ) + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + const recipt = await sendUserOp(signedUserOp) + + const quotaInfo = (await smartWallet.wallet()).quota + const currentQuota = await getCurrentQuota( + quotaInfo, + recipt.blockNumber + ) + expect(currentQuota).to.equal(newQuota) + expect(quotaInfo.pendingUntil).to.equal(0) + }) + + describe('quota check test', () => { + const ONE_DAY = 3600 * 24 + it('will failed when usage excess daily quota', async () => { + const { + smartWallet, + smartWalletOwner, + guardians, + create2, + entrypoint, + sendUserOp, + blankOwner, + usdtToken, + smartWalletImpl + } = await loadFixture(fixture) + + const oraclePrice = 1 + const testPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(oraclePrice) + // create new smart wallet implementation with valid price oracle + const newSmartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + blankOwner.address, + testPriceOracle.address + ) + const callData = smartWallet.interface.encodeFunctionData( + 'changeMasterCopy', + [newSmartWalletImpl.address] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeMasterCopy + } + // update to new implementation + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await sendUserOp(signedUserOp) + const masterCopyOfWallet = await smartWallet.getMasterCopy() + expect(masterCopyOfWallet).to.equal(newSmartWalletImpl.address) + expect(await smartWallet.priceOracle()).to.eq( + testPriceOracle.address + ) + + // spent daily quota using approving token + const tokenAmount = ethers.utils.parseUnits('100', 6) + const quotaAmount = ethers.utils.parseUnits('200', 6) + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + await smartWallet.changeDailyQuota(quotaAmount) + // advance time to make it valid immediately + await time.increase(ONE_DAY) + const receiver = ethers.constants.AddressZero + await smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + true + ) + const quotaInfo = (await smartWallet.wallet()).quota + const tokenValue = await testPriceOracle.tokenValue( + usdtToken.address, + tokenAmount + ) + expect(quotaInfo.spentAmount).to.equal(tokenValue) + + // will fail when spent too much tokens + await expect( + smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount.mul(2), + '0x', + true + ) + ).to.rejectedWith('QUOTA_EXCEEDED') + }) + it('will reset quota after one day', async () => { + const { + smartWallet, + smartWalletOwner, + guardians, + create2, + entrypoint, + sendUserOp, + blankOwner, + usdtToken, + smartWalletImpl + } = await loadFixture(fixture) + + const oraclePrice = 1 + const testPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(oraclePrice) + // create new smart wallet implementation with valid price oracle + const newSmartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + blankOwner.address, + testPriceOracle.address + ) + const callData = smartWallet.interface.encodeFunctionData( + 'changeMasterCopy', + [newSmartWalletImpl.address] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeMasterCopy + } + // update to new implementation + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + const masterCopyOfWallet = await smartWallet.getMasterCopy() + expect(masterCopyOfWallet).to.equal(newSmartWalletImpl.address) + expect(await smartWallet.priceOracle()).to.eq( + testPriceOracle.address + ) + + // spent daily quota using approving token + const tokenAmount = ethers.utils.parseUnits('100', 6) + const quotaAmount = ethers.utils.parseUnits('200', 6) + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + await smartWallet.changeDailyQuota(quotaAmount) + // advance time to make it valid immediately + await time.increase(ONE_DAY) + const receiver = ethers.constants.AddressZero + await smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + true + ) + const quotaInfo = (await smartWallet.wallet()).quota + const tokenValue = await testPriceOracle.tokenValue( + usdtToken.address, + tokenAmount + ) + expect(quotaInfo.spentAmount).to.equal(tokenValue) + + // will fail when spent too much tokens + await expect( + smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount.mul(2), + '0x', + true + ) + ).to.rejectedWith('QUOTA_EXCEEDED') + + await time.increase(ONE_DAY) + await expect( + smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount.mul(2), + '0x', + false + ) + ).not.to.reverted + }) + it('whitelist address can excess daily quota', async () => { + const { + smartWallet, + smartWalletOwner, + guardians, + create2, + entrypoint, + sendUserOp, + smartWalletImpl, + blankOwner, + usdtToken + } = await loadFixture(fixture) + + const oraclePrice = 1 + const testPriceOracle = await ( + await ethers.getContractFactory('TestPriceOracle') + ).deploy(oraclePrice) + // create new smart wallet implementation with valid price oracle + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeMasterCopy + } + const newSmartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + blankOwner.address, + testPriceOracle.address + ) + // update to new implementation + const callData = smartWallet.interface.encodeFunctionData( + 'changeMasterCopy', + [newSmartWalletImpl.address] + ) + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + const masterCopyOfWallet = await smartWallet.getMasterCopy() + expect(masterCopyOfWallet).to.equal(newSmartWalletImpl.address) + expect(await smartWallet.priceOracle()).to.eq( + testPriceOracle.address + ) + + // spent daily quota using approving token + const tokenAmount = ethers.utils.parseUnits('100', 6) + const quotaAmount = ethers.utils.parseUnits('200', 6) + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + + await smartWallet.changeDailyQuota(quotaAmount) + // advance time to make it valid immediately + await time.increase(ONE_DAY) + const receiver1 = Wallet.createRandom().address + const receiver2 = Wallet.createRandom().address + await smartWallet.addToWhitelist(receiver2) + await time.increase(ONE_DAY) + await smartWallet.transferToken( + usdtToken.address, + receiver1, + tokenAmount, + '0x', + false + ) + const quotaInfo = (await smartWallet.wallet()).quota + const tokenValue = await testPriceOracle.tokenValue( + usdtToken.address, + tokenAmount + ) + expect(quotaInfo.spentAmount).to.equal(tokenValue) + + // will fail send to unwhitelisted address + await expect( + smartWallet.transferToken( + usdtToken.address, + receiver1, + tokenAmount.mul(2), + '0x', + false + ) + ).to.rejectedWith(`LRC#${ErrorCodes.QUOTA_EXCEEDED}`) + + // will success send to whitelisted address + await expect( + smartWallet.transferToken( + usdtToken.address, + receiver2, + tokenAmount.mul(2), + '0x', + false + ) + ).not.to.reverted + }) + }) +}) diff --git a/packages/hebao_v3/test/recover.test.ts b/packages/hebao_v3/test/recover.test.ts new file mode 100644 index 000000000..4a854debc --- /dev/null +++ b/packages/hebao_v3/test/recover.test.ts @@ -0,0 +1,194 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { evInfo, evRevertInfo, getErrorMessage } from './helper/utils' +import { ErrorCodes } from './helper/error_codes' + +describe('recover test', () => { + it('recover success', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + deployer, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + + const newOwner = ethers.Wallet.createRandom() + const newGuardians: string[] = [] + const callData = smartWallet.interface.encodeFunctionData( + 'recover', + [newOwner.address, newGuardians] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.Recover + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + newOwner, + [ + { signer: guardians[0] }, + { + signer: guardians[1] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + expect(await smartWallet.getOwner()).to.eq( + smartWalletOwner.address + ) + const preDeposit = await smartWallet.getDeposit() + const preBalance = await ethers.provider.getBalance( + deployer.address + ) + const recipt = await sendUserOp(signedUserOp) + const postDeposit = await smartWallet.getDeposit() + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + const postBalance = await ethers.provider.getBalance( + deployer.address + ) + const events = await evInfo(entrypoint, recipt) + expect(events.length).to.eq(1) + // check relayer balance + expect( + preBalance + .sub(recipt.gasUsed.mul(recipt.effectiveGasPrice)) + .add(events[0].actualGasCost) + ).to.eq(postBalance) + // check sender balance + expect(preDeposit.sub(postDeposit)).to.eq(events[0].actualGasCost) + + // it will not take any cost to execute both of the following txs + // no fee charged if validation failed + await expect(sendUserOp({ ...signedUserOp, signature: '0x' })) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted (or OOG)') + + // replay test + await expect(sendUserOp(signedUserOp)) + .to.revertedWithCustomError(entrypoint, 'FailedOp') + .withArgs(0, 'AA23 reverted: HASH_EXIST') + expect(await smartWallet.getDeposit()).to.eq(postDeposit) + }) + + it('new owner should not be the same as before', async () => { + const { + entrypoint, + smartWallet, + smartWalletOwner, + create2, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + + const newGuardians: string[] = [] + const callData = smartWallet.interface.encodeFunctionData( + 'recover', + [smartWalletOwner.address, newGuardians] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.Recover + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: guardians[0] }, + { + signer: guardians[1] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint, + { callGasLimit: '1000000' } + ) + const preDeposit = await smartWallet.getDeposit() + const recipt = await sendUserOp(signedUserOp) + const postDeposit = await smartWallet.getDeposit() + const revertInfo = await evRevertInfo(entrypoint, recipt) + // is same owner + expect(getErrorMessage(revertInfo[0].revertReason)).to.eq( + `LRC#${ErrorCodes.IS_SAME_OWNER}` + ) + // fee charged even if userop execution failed + expect(postDeposit).to.lt(preDeposit) + }) + + it('will fail when recover from owner', async () => { + const { smartWallet } = await loadFixture(fixture) + const newOwner = ethers.Wallet.createRandom() + await expect( + smartWallet.recover(newOwner.address, []) + ).to.rejectedWith(`${ErrorCodes.ONLY_FROM_ENTRYPOINT}`) + }) + it('will fail when recover from execute', async () => {}) + it('recover success even if wallet is locked', async () => { + const { + entrypoint, + smartWallet, + create2, + sendUserOp, + smartWalletImpl, + guardians + } = await loadFixture(fixture) + + // lock wallet first + await smartWallet.lock() + + const newOwner = ethers.Wallet.createRandom() + const newGuardians: string[] = [] + const callData = smartWallet.interface.encodeFunctionData( + 'recover', + [newOwner.address, newGuardians] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.Recover + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + newOwner, + [ + { signer: guardians[0] }, + { + signer: guardians[1] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await sendUserOp(signedUserOp) + expect(await smartWallet.getOwner()).to.eq(newOwner.address) + }) + + describe('guardians test', () => { + it('recover with new guardians', async () => {}) + + it('recover with empty guardians', async () => {}) + }) +}) diff --git a/packages/hebao_v3/test/upgrade.test.ts b/packages/hebao_v3/test/upgrade.test.ts new file mode 100644 index 000000000..b9de0aef1 --- /dev/null +++ b/packages/hebao_v3/test/upgrade.test.ts @@ -0,0 +1,245 @@ +import { + loadFixture, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { expect, assert } from 'chai' + +import { ethers } from 'hardhat' + +import { + DummySmartWallet__factory, + type DummySmartWallet +} from '../typechain-types' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { deployWalletImpl, getBlockTimestamp } from './helper/utils' + +describe('wallet', () => { + describe('upgrade', () => { + it('wallet owner should be able to upgrade impl with enough approvals', async () => { + const { + smartWallet: wallet, + guardians, + smartWalletOwner, + create2, + entrypoint, + sendUserOp, + smartWalletImpl, + smartWallet + } = await loadFixture(fixture) + const GuardianLib = await ( + await ethers.getContractFactory('GuardianLib') + ).deploy() + // deploy impl of new verision + const newSmartWalletImpl: DummySmartWallet = await ( + await ethers.getContractFactory('DummySmartWallet', { + libraries: { GuardianLib: GuardianLib.address } + }) + ).deploy() + + const callData = smartWallet.interface.encodeFunctionData( + 'changeMasterCopy', + [newSmartWalletImpl.address] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.ChangeMasterCopy + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + await sendUserOp(signedUserOp) + + const masterCopyOfWallet = await wallet.getMasterCopy() + expect(masterCopyOfWallet).to.equal(newSmartWalletImpl.address) + + // test new impl + + const dummyWallet = DummySmartWallet__factory.connect( + wallet.address, + smartWalletOwner + ) + await expect(dummyWallet.emitSomething()) + .to.emit(dummyWallet, 'Invoked') + .withArgs('hello world') + const newGuardians = await dummyWallet.getGuardians(true) + // guardians data is the same as before + guardians.forEach((g, i) => + expect(g.address).to.eq(newGuardians[i].addr) + ) + }) + }) + + describe('DelayedImplementationManager', () => { + it('only owner is able to set nextImpl & effectiveTime', async () => { + const { deployer, implStorage } = await loadFixture(fixture) + const otherSigner = (await ethers.getSigners())[1] + const owner = await implStorage.owner() + expect(owner).to.equal(deployer.address) + + await expect(implStorage.executeUpgrade()).to.revertedWith( + 'NOT_IN_EFFECT' + ) + + const newImpl = '0x' + '11'.repeat(20) + const tx = await implStorage.delayedUpgradeTo(newImpl, 1) + const blockTime = await getBlockTimestamp(tx.blockNumber!) + const receipt = await tx.wait() + + assert( + receipt.events !== undefined && receipt.events.length > 0 + ) + + const upgradeScheduledEvent = receipt.events[0].args! + expect(upgradeScheduledEvent.nextImpl).to.equal(newImpl) + expect(upgradeScheduledEvent.effectiveTime.toNumber()).to.equal( + blockTime + 3600 * 24 + ) + + const storageWithAnotherSigner = + implStorage.connect(otherSigner) + const signer2 = + await storageWithAnotherSigner.signer.getAddress() + expect(owner).not.to.equal(signer2) + const newImpl2 = '0x' + '22'.repeat(20) + await expect( + storageWithAnotherSigner.delayedUpgradeTo(newImpl2, 1) + ).to.revertedWith('UNAUTHORIZED') + + // execute upgrade before nexeEffectiveTime: + await expect( + storageWithAnotherSigner.executeUpgrade() + ).to.revertedWith('NOT_IN_EFFECT') + + await time.increase(3600 * 24) + const executeTx = + await storageWithAnotherSigner.executeUpgrade() + const executeReceipt = await executeTx.wait() + assert( + executeReceipt.events !== undefined && + executeReceipt.events.length > 0 + ) + const implementationChangedEvent = + executeReceipt.events[0].args! + expect(implementationChangedEvent.newImpl).to.equal(newImpl) + + // // upgrade can not be executed agin: + await expect(implStorage.executeUpgrade()).to.revertedWith( + 'NOT_IN_EFFECT' + ) + }) + + it('upgrade for user wallet', async () => { + const { + forwardProxy, + smartWallet, + smartWalletOwner, + implStorage, + create2, + guardians, + sendUserOp, + entrypoint, + blankOwner, + usdtToken, + deployer + } = await loadFixture(fixture) + const currentImpl = await smartWallet.getMasterCopy() + expect(currentImpl).to.eq(forwardProxy.address) + expect(await smartWallet.blankOwner()).to.eq(blankOwner.address) + + // random blankowner + const ownerSetter = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const newSmartWalletImpl = await deployWalletImpl( + create2, + entrypoint.address, + ownerSetter.address + ) + await implStorage.delayedUpgradeTo( + newSmartWalletImpl.address, + 1 + ) + await time.increase(3600 * 24) + await implStorage.executeUpgrade() + // check immutable data + expect(await smartWallet.blankOwner()).to.eq( + ownerSetter.address + ) + + // transfer token + const receiver = deployer.address + const initTokenAmount = ethers.utils.parseUnits('1000', 6) + await usdtToken.setBalance(smartWallet.address, initTokenAmount) + const tokenAmount = ethers.utils.parseUnits('100', 6) + { + const usdtTokenBalanceBefore = + await usdtToken.balanceOf(receiver) + await smartWallet.transferToken( + usdtToken.address, + receiver, + tokenAmount, + '0x', + false + ) + const usdtTokenBalanceAfter = + await usdtToken.balanceOf(receiver) + expect( + usdtTokenBalanceAfter.sub(usdtTokenBalanceBefore) + ).to.eq(tokenAmount) + } + + // transfer token with approval(guardians is the same as before so that multisig is still valid) + { + const usdtTokenBalanceBefore = + await usdtToken.balanceOf(receiver) + const callData = smartWallet.interface.encodeFunctionData( + 'transferTokenWA', + [usdtToken.address, receiver, tokenAmount, '0x'] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.TransferToken + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { signer: smartWalletOwner }, + { + signer: guardians[0] + } + ], + create2.address, + newSmartWalletImpl.address, + approvalOption, + entrypoint + ) + await sendUserOp(signedUserOp) + const usdtTokenBalanceAfter = + await usdtToken.balanceOf(receiver) + expect( + usdtTokenBalanceAfter.sub(usdtTokenBalanceBefore) + ).to.eq(tokenAmount) + } + }) + }) +}) diff --git a/packages/hebao_v3/test/verification_gas.test.ts b/packages/hebao_v3/test/verification_gas.test.ts new file mode 100644 index 000000000..d662f845b --- /dev/null +++ b/packages/hebao_v3/test/verification_gas.test.ts @@ -0,0 +1,269 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { BigNumber, type BigNumberish, type Wallet } from 'ethers' +import { arrayify } from 'ethers/lib/utils' +import { ethers } from 'hardhat' +import _ from 'lodash' + +import { type EntryPoint } from '../typechain-types' + +import { + callDataCost, + getUserOpHash, + packUserOp, + type UserOperation +} from './helper/AASigner' +import { type Approval } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { simulationResultCatch } from './helper/utils' + +describe('verification gaslimit test', () => { + async function generateApprovals( + smartWalletOrEOASigners: Array<{ + signer: Wallet + smartWalletAddress?: string + }>, + smartWalletAddr: string, + verifyingContract: string, + token: string, + to: string, + amount: BigNumberish, + validUntil: number, + chainId: number + // salt: BytesLike + ): Promise { + // use typedData hash instead + const types = { + approveToken: [ + { name: 'wallet', type: 'address' }, + { name: 'validUntil', type: 'uint256' }, + { name: 'token', type: 'address' }, + { name: 'to', type: 'address' }, + { name: 'amount', type: 'uint256' } + // { name: 'salt', type: 'bytes32' } + ] + } + + const domain = { + name: 'LoopringWallet', + version: '2.0.0', + chainId, + verifyingContract + } + const message = { + types, + domain, + primaryType: 'approveToken', + value: { + validUntil, + wallet: smartWalletAddr, + token, + to, + amount + // salt + } + } + + const signatures = await Promise.all( + smartWalletOrEOASigners.map(async (g) => + g.signer._signTypedData( + message.domain, + message.types, + message.value + ) + ) + ) + const [sortedSigners, sortedSignatures] = _.unzip( + _.sortBy( + _.zip( + smartWalletOrEOASigners.map((g) => + g.smartWalletAddress !== undefined + ? g.smartWalletAddress.toLowerCase() + : g.signer.address.toLowerCase() + ), + signatures + ), + (item) => item[0] + ) + ) + + const approval = { + signers: sortedSigners as string[], + signatures: sortedSignatures as string[], + validUntil + // salt + } + return approval + } + + async function estimateUserOpGas( + entryPoint: EntryPoint, + userOp1: UserOperation + ): Promise<{ + preVerificationGas: BigNumber + callGasLimit: BigNumber + verificationGasLimit: BigNumber + }> { + const userOp = { + ...userOp1, + // default values for missing fields. + paymasterAndData: '0x', + maxFeePerGas: 0, + maxPriorityFeePerGas: 0, + preVerificationGas: 0, + verificationGasLimit: 10e6 + } + + const { returnInfo } = await entryPoint.callStatic + .simulateValidation(userOp) + .catch(simulationResultCatch) + const verificationGasLimit = returnInfo.preOpGas + + const callGasLimit = await ethers.provider.estimateGas({ + from: entryPoint.address, + to: userOp.sender, + data: userOp.callData + }) + const rate = BigNumber.from(12) + const base = 10 + + const preVerificationGas = BigNumber.from( + callDataCost(packUserOp(userOp, false)) + ) + return { + preVerificationGas: preVerificationGas.mul(rate).div(base), + callGasLimit: callGasLimit.mul(rate).div(base), + verificationGasLimit: verificationGasLimit.mul(rate).div(base) + } + } + + async function getEIP1559GasPrice( + maxPriorityFeePerGas1?: BigNumber + ): Promise<{ + maxPriorityFeePerGas: BigNumber + maxFeePerGas: BigNumber + }> { + const block = await ethers.provider.getBlock('latest') + const maxPriorityFeePerGas = + maxPriorityFeePerGas1 ?? BigNumber.from(1e9) // default + const maxFeePerGas = block.baseFeePerGas!.add( + maxPriorityFeePerGas + ) + return { + maxPriorityFeePerGas, + maxFeePerGas + } + } + + function encodeSignature( + approval: Approval, + ownerSignature: string + ): string { + const signature = ethers.utils.defaultAbiCoder.encode( + [ + 'tuple(address[] signers,bytes[] signatures,uint256 validUntil)', + 'bytes' + ], + [approval, ownerSignature] + ) + return signature + } + + it('approvals of multiple guardians', async () => { + const { + sendUserOp, + entrypoint, + smartWalletOwner, + smartWallet, + guardians, + usdtToken, + deployer, + smartWalletImpl + } = await loadFixture(fixture) + const chainId = await ethers.provider + .getNetwork() + .then((net) => net.chainId) + + // use new guardian signature to approve token + const receiver = deployer.address + const tokenAmount = ethers.utils.parseUnits('100', 6) + const validUntil = 0 + const nonce = 0 + // prepare userOp first + const approveTokenWA = + await smartWallet.populateTransaction.approveTokenWA( + usdtToken.address, + receiver, + tokenAmount + ) + // generate approvals of guardian + const approval = await generateApprovals( + [ + { signer: smartWalletOwner }, + { signer: guardians[0] }, + { signer: guardians[1] } + ], + smartWallet.address, + smartWalletImpl.address, + usdtToken.address, + receiver, + tokenAmount, + validUntil, + chainId + // ethers.utils.randomBytes(32) + ) + const gasPriceData = await getEIP1559GasPrice() + + // only used to estimate gas + const fakeSignature = encodeSignature( + approval, + '0x' + '0'.repeat(130) + ) + const userOp: UserOperation = { + sender: smartWallet.address, + nonce, + callData: approveTokenWA.data!, + paymasterAndData: '0x', + initCode: '0x', + callGasLimit: 0, + verificationGasLimit: 0, + preVerificationGas: 0, + ...gasPriceData, + // use truly guardian signatures + signature: fakeSignature + } + + // estimate all kinds of gas + const gas = await estimateUserOpGas(entrypoint, userOp) + const finalUserOp = { + ...userOp, + ...gas + } + + // get owner signature + const userOpHash = getUserOpHash( + finalUserOp, + entrypoint.address, + chainId + ) + const ownerSignature = await smartWalletOwner.signMessage( + arrayify(userOpHash) + ) + const signature = encodeSignature(approval, ownerSignature) + const signedUserOp = { ...finalUserOp, signature } + + const { returnInfo } = await entrypoint.callStatic + .simulateValidation(signedUserOp) + .catch(simulationResultCatch) + // check estimated verificationGasLimit is greater than actual used verification gas + expect(gas.verificationGasLimit).gt( + returnInfo.preOpGas.sub(signedUserOp.preVerificationGas) + ) + + await sendUserOp(signedUserOp) + expect( + await usdtToken.allowance(smartWallet.address, receiver) + ).to.eq(tokenAmount) + }) + it('estimate gas when using paymaster', async () => {}) +}) diff --git a/packages/hebao_v3/test/walletFactory.test.ts b/packages/hebao_v3/test/walletFactory.test.ts new file mode 100644 index 000000000..c278d1137 --- /dev/null +++ b/packages/hebao_v3/test/walletFactory.test.ts @@ -0,0 +1,143 @@ +import { loadFixture } from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { SmartWalletV3__factory } from '../typechain-types' + +import { fixture } from './helper/fixture' +import { + createSmartWallet, + getBlockTimestamp, + getFirstEvent +} from './helper/utils' + +describe('walletFactory', () => { + describe('A EOA', () => { + it("should be able to create a new wallet with owner's signature", async () => { + const { smartWalletOwner, guardians, walletFactory } = + await loadFixture(fixture) + + const salt = ethers.utils.formatBytes32String('0x1') + const recipt = await createSmartWallet( + smartWalletOwner, + guardians.map((g) => g.address.toLowerCase()).sort(), + walletFactory, + salt + ) + + // get WalletCreated event: + const fromBlock = recipt.blockNumber + const walletCreatedEvent = await getFirstEvent( + walletFactory, + fromBlock, + 'WalletCreated' + ) + + const smartWalletAddr = + await walletFactory.computeWalletAddress( + smartWalletOwner.address, + salt + ) + expect(smartWalletOwner.address).to.equal( + walletCreatedEvent.args!.owner + ) + expect(smartWalletAddr).to.equal( + walletCreatedEvent.args!.wallet + ) + + const smartWallet = SmartWalletV3__factory.connect( + smartWalletAddr, + smartWalletOwner + ) + + // Check creation timestamp + const blockTime = await getBlockTimestamp(recipt.blockNumber) + const creationTimestamp = + await smartWallet.getCreationTimestamp() + expect(creationTimestamp.toNumber()).to.equal(blockTime) + + // Check owner + const walletOwner = await smartWallet.getOwner() + expect(walletOwner).to.equal(smartWalletOwner.address) + }) + + it('should be able to charge fees when creating a new wallet', async () => { + // const { walletFactory, smartWalletOwner } = await loadFixture(fixture) + }) + + it('require(feeAmount <= maxFeeAmount) when creating a new wallet', async () => { + // const { walletFactory, smartWalletOwner } = await loadFixture(fixture) + }) + }) + + describe('operator management', () => { + it('only owner can add operators', async () => { + const { walletFactory } = await loadFixture(fixture) + const account2 = ethers.Wallet.createRandom().connect( + ethers.provider + ) + const account3 = ethers.Wallet.createRandom().connect( + ethers.provider + ) + expect(await walletFactory.isOperator(account2.address)).to.be + .false + await walletFactory.addOperator(account2.address) + expect(await walletFactory.isOperator(account2.address)).to.be + .true + + // others cannot add operators + await expect( + walletFactory.connect(account2).addOperator(account3.address) + ).to.rejectedWith('UNAUTHORIZED') + }) + + it('can create wallet only by operator', async () => { + const { smartWalletOwner, walletFactory } = + await loadFixture(fixture) + const [, account2] = await ethers.getSigners() + const account2Addr = await account2.getAddress() + // create wallet + const owner = account2Addr + const salt = 1 + + const walletConfig: any = { + owner, + initOwner: owner, + guardians: [], + quota: 0, + inheritor: ethers.constants.AddressZero, + feeRecipient: ethers.constants.AddressZero, + feeToken: ethers.constants.AddressZero, + maxFeeAmount: 0, + salt + } + + const walletAddrComputed = + await walletFactory.computeWalletAddress(owner, salt) + + await expect( + walletFactory + .connect(account2) + .createWalletByOperator(walletConfig, 0) + ).to.revertedWith('NOT A OPERATOR') + await walletFactory.addOperator(account2Addr) + await walletFactory + .connect(account2) + .createWalletByOperator(walletConfig, 0) + + // check wallet is created successfully + const smartWallet = SmartWalletV3__factory.connect( + walletAddrComputed, + smartWalletOwner + ) + expect(await smartWallet.getOwner()).to.eq(account2Addr) + + await walletFactory.removeOperator(account2Addr) + await expect( + walletFactory + .connect(account2) + .createWalletByOperator(walletConfig, 0) + ).to.revertedWith('NOT A OPERATOR') + }) + }) +}) diff --git a/packages/hebao_v3/test/whitelist.test.ts b/packages/hebao_v3/test/whitelist.test.ts new file mode 100644 index 000000000..835b5912f --- /dev/null +++ b/packages/hebao_v3/test/whitelist.test.ts @@ -0,0 +1,90 @@ +import { + loadFixture, + time +} from '@nomicfoundation/hardhat-network-helpers' +import { expect } from 'chai' +import { ethers } from 'hardhat' + +import { fillAndMultiSign } from './helper/AASigner' +import { ActionType } from './helper/LoopringGuardianAPI' +import { fixture } from './helper/fixture' +import { getBlockTimestamp } from './helper/utils' + +describe('whitelist test', () => { + const ONE_DAY = 3600 * 24 + it('owner should be able to add address to its whitelist', async () => { + const whiteListedAddr = '0x' + '11'.repeat(20) + const { smartWallet } = await loadFixture(fixture) + await expect( + smartWallet.addToWhitelist(ethers.constants.AddressZero) + ).to.rejectedWith('LRC#104') + const tx = await smartWallet.addToWhitelist(whiteListedAddr) + const effectiveTime = + await smartWallet.getWhitelistEffectiveTime(whiteListedAddr) + const blockTime = await getBlockTimestamp(tx.blockNumber!) + expect(effectiveTime.toNumber()).to.equal(blockTime + 3600 * 24) + + // advance one day + await time.increase(ONE_DAY) + expect(await smartWallet.isWhitelisted(whiteListedAddr)).to.be + .true + + // remove it from whitelist + await expect( + smartWallet.removeFromWhitelist(ethers.constants.AddressZero) + ).to.rejectedWith('LRC#104') + await smartWallet.removeFromWhitelist(whiteListedAddr) + expect( + await smartWallet.getWhitelistEffectiveTime(whiteListedAddr) + ).to.eq(0) + expect(await smartWallet.isWhitelisted(whiteListedAddr)).to.be + .false + }) + + it('majority(owner required) should be able to whitelist address immediately', async () => { + const { + smartWallet, + smartWalletImpl, + smartWalletOwner, + guardians, + create2, + entrypoint, + sendUserOp + } = await loadFixture(fixture) + const addr = '0x' + '12'.repeat(20) + const callData = smartWallet.interface.encodeFunctionData( + 'addToWhitelistWA', + [addr] + ) + const approvalOption = { + validUntil: 0, + salt: ethers.utils.randomBytes(32), + action_type: ActionType.AddToWhitelist + } + const signedUserOp = await fillAndMultiSign( + callData, + smartWallet, + smartWalletOwner, + [ + { + signer: guardians[0] + }, + { signer: smartWalletOwner } + ], + create2.address, + smartWalletImpl.address, + approvalOption, + entrypoint + ) + + const recipt = await sendUserOp(signedUserOp) + const effectiveTime = + await smartWallet.getWhitelistEffectiveTime(addr) + const blockTime = await getBlockTimestamp(recipt.blockNumber) + expect(effectiveTime.toNumber()).to.equal(blockTime) + + // advance one day + await time.increase(ONE_DAY) + expect(await smartWallet.isWhitelisted(addr)).to.be.true + }) +}) diff --git a/packages/hebao_v3/tsconfig.json b/packages/hebao_v3/tsconfig.json new file mode 100644 index 000000000..0998f0cd1 --- /dev/null +++ b/packages/hebao_v3/tsconfig.json @@ -0,0 +1,25 @@ +{ + "exclude": [".eslintrc.js"], + "compilerOptions": { + "target": "es2020", + "lib": ["dom", "dom.iterable", "esnext"], + "strictPropertyInitialization": false, + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noFallthroughCasesInSwitch": true, + "module": "commonjs", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "jsx": "react-jsx" + } +} diff --git a/packages/hebao_v3/yarn.lock b/packages/hebao_v3/yarn.lock new file mode 100644 index 000000000..e1b0bdb42 --- /dev/null +++ b/packages/hebao_v3/yarn.lock @@ -0,0 +1,5636 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmmirror.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@babel/code-frame@^7.0.0": + version "7.23.5" + resolved "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.npmmirror.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@chainsafe/as-sha256@^0.3.1": + version "0.3.1" + resolved "https://registry.npmmirror.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" + integrity sha512-hldFFYuf49ed7DAakWVXSJODuq3pzJEguD8tQ7h+sGkM18vja+OFoJI9krnGmgzyuZC2ETX0NOIcCTy31v2Mtg== + +"@chainsafe/persistent-merkle-tree@^0.4.2": + version "0.4.2" + resolved "https://registry.npmmirror.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.4.2.tgz#4c9ee80cc57cd3be7208d98c40014ad38f36f7ff" + integrity sha512-lLO3ihKPngXLTus/L7WHKaw9PnNJWizlOF1H9NNzHP6Xvh82vzg9F2bzkXhYIFshMZ2gTCEz8tq6STe7r5NDfQ== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + +"@chainsafe/persistent-merkle-tree@^0.5.0": + version "0.5.0" + resolved "https://registry.npmmirror.com/@chainsafe/persistent-merkle-tree/-/persistent-merkle-tree-0.5.0.tgz#2b4a62c9489a5739dedd197250d8d2f5427e9f63" + integrity sha512-l0V1b5clxA3iwQLXP40zYjyZYospQLZXzBVIhhr9kDg/1qHZfzzHw0jj4VPBijfYCArZDlPkRi1wZaV2POKeuw== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + +"@chainsafe/ssz@^0.10.0": + version "0.10.2" + resolved "https://registry.npmmirror.com/@chainsafe/ssz/-/ssz-0.10.2.tgz#c782929e1bb25fec66ba72e75934b31fd087579e" + integrity sha512-/NL3Lh8K+0q7A3LsiFq09YXS9fPE+ead2rr7vM2QK8PLzrNsw3uqrif9bpRX5UxgeRjM+vYi+boCM3+GM4ovXg== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + "@chainsafe/persistent-merkle-tree" "^0.5.0" + +"@chainsafe/ssz@^0.9.2": + version "0.9.4" + resolved "https://registry.npmmirror.com/@chainsafe/ssz/-/ssz-0.9.4.tgz#696a8db46d6975b600f8309ad3a12f7c0e310497" + integrity sha512-77Qtg2N1ayqs4Bg/wvnWfg5Bta7iy7IRh8XqXh7oNMeP2HBbBwx8m6yTpA8p0EHItWPEBkgZd5S5/LSlp3GXuQ== + dependencies: + "@chainsafe/as-sha256" "^0.3.1" + "@chainsafe/persistent-merkle-tree" "^0.4.2" + case "^1.6.3" + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmmirror.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + 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" + +"@eslint/js@8.56.0": + version "8.56.0" + resolved "https://registry.npmmirror.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b" + integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== + +"@ethereumjs/rlp@^4.0.1": + version "4.0.1" + resolved "https://registry.npmmirror.com/@ethereumjs/rlp/-/rlp-4.0.1.tgz#626fabfd9081baab3d0a3074b0c7ecaf674aaa41" + integrity sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw== + +"@ethereumjs/util@^8.1.0": + version "8.1.0" + resolved "https://registry.npmmirror.com/@ethereumjs/util/-/util-8.1.0.tgz#299df97fb6b034e0577ce9f94c7d9d1004409ed4" + integrity sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA== + dependencies: + "@ethereumjs/rlp" "^4.0.1" + ethereum-cryptography "^2.0.0" + micro-ftch "^0.3.1" + +"@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.0.9", "@ethersproject/abi@^5.1.2", "@ethersproject/abi@^5.4.7", "@ethersproject/abi@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + 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" + +"@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@5.7.0", "@ethersproject/address@^5.0.2", "@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.npmmirror.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2", "@ethersproject/providers@^5.4.7", "@ethersproject/providers@^5.7.1", "@ethersproject/providers@^5.7.2": + version "5.7.2" + resolved "https://registry.npmmirror.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.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" + +"@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + 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" + +"@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.npmmirror.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": + version "5.7.0" + resolved "https://registry.npmmirror.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@fastify/busboy@^2.0.0": + version "2.1.0" + resolved "https://registry.npmmirror.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" + integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + +"@gnosis.pm/safe-contracts@^1.3.0": + version "1.3.0" + resolved "https://registry.npmmirror.com/@gnosis.pm/safe-contracts/-/safe-contracts-1.3.0.tgz#316741a7690d8751a1f701538cfc9ec80866eedc" + integrity sha512-1p+1HwGvxGUVzVkFjNzglwHrLNA67U/axP0Ct85FzzH8yhGJb4t9jDjPYocVMzLorDoWAfKicGy1akPY9jXRVw== + +"@humanwhocodes/config-array@^0.11.13": + version "0.11.13" + resolved "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297" + integrity sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ== + dependencies: + "@humanwhocodes/object-schema" "^2.0.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.1": + version "2.0.1" + resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" + integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.15" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@metamask/eth-sig-util@^4.0.0": + version "4.0.1" + resolved "https://registry.npmmirror.com/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz#3ad61f6ea9ad73ba5b19db780d40d9aae5157088" + integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== + dependencies: + ethereumjs-abi "^0.6.8" + ethereumjs-util "^6.2.1" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + +"@noble/curves@1.1.0", "@noble/curves@~1.1.0": + version "1.1.0" + resolved "https://registry.npmmirror.com/@noble/curves/-/curves-1.1.0.tgz#f13fc667c89184bc04cccb9b11e8e7bae27d8c3d" + integrity sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA== + dependencies: + "@noble/hashes" "1.3.1" + +"@noble/hashes@1.2.0", "@noble/hashes@~1.2.0": + version "1.2.0" + resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" + integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== + +"@noble/hashes@1.3.1": + version "1.3.1" + resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" + integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== + +"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": + version "1.3.3" + resolved "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== + +"@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": + version "1.7.1" + resolved "https://registry.npmmirror.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" + integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nomicfoundation/ethereumjs-block@5.0.1": + version "5.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-block/-/ethereumjs-block-5.0.1.tgz#6f89664f55febbd723195b6d0974773d29ee133d" + integrity sha512-u1Yioemi6Ckj3xspygu/SfFvm8vZEO8/Yx5a1QLzi6nVU0jz3Pg2OmHKJ5w+D9Ogk1vhwRiqEBAqcb0GVhCyHw== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-trie" "6.0.1" + "@nomicfoundation/ethereumjs-tx" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + ethereum-cryptography "0.1.3" + ethers "^5.7.1" + +"@nomicfoundation/ethereumjs-blockchain@7.0.1": + version "7.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-blockchain/-/ethereumjs-blockchain-7.0.1.tgz#80e0bd3535bfeb9baa29836b6f25123dab06a726" + integrity sha512-NhzndlGg829XXbqJEYrF1VeZhAwSPgsK/OB7TVrdzft3y918hW5KNd7gIZ85sn6peDZOdjBsAXIpXZ38oBYE5A== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-ethash" "3.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-trie" "6.0.1" + "@nomicfoundation/ethereumjs-tx" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + abstract-level "^1.0.3" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + level "^8.0.0" + lru-cache "^5.1.1" + memory-level "^1.0.0" + +"@nomicfoundation/ethereumjs-common@4.0.1": + version "4.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.1.tgz#4702d82df35b07b5407583b54a45bf728e46a2f0" + integrity sha512-OBErlkfp54GpeiE06brBW/TTbtbuBJV5YI5Nz/aB2evTDo+KawyEzPjBlSr84z/8MFfj8wS2wxzQX1o32cev5g== + dependencies: + "@nomicfoundation/ethereumjs-util" "9.0.1" + crc-32 "^1.2.0" + +"@nomicfoundation/ethereumjs-ethash@3.0.1": + version "3.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-ethash/-/ethereumjs-ethash-3.0.1.tgz#65ca494d53e71e8415c9a49ef48bc921c538fc41" + integrity sha512-KDjGIB5igzWOp8Ik5I6QiRH5DH+XgILlplsHR7TEuWANZA759G6krQ6o8bvj+tRUz08YygMQu/sGd9mJ1DYT8w== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + abstract-level "^1.0.3" + bigint-crypto-utils "^3.0.23" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-evm@2.0.1": + version "2.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-evm/-/ethereumjs-evm-2.0.1.tgz#f35681e203363f69ce2b3d3bf9f44d4e883ca1f1" + integrity sha512-oL8vJcnk0Bx/onl+TgQOQ1t/534GKFaEG17fZmwtPFeH8S5soiBYPCLUrvANOl4sCp9elYxIMzIiTtMtNNN8EQ== + dependencies: + "@ethersproject/providers" "^5.7.1" + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-tx" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/ethereumjs-rlp@5.0.1": + version "5.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.1.tgz#0b30c1cf77d125d390408e391c4bb5291ef43c28" + integrity sha512-xtxrMGa8kP4zF5ApBQBtjlSbN5E2HI8m8FYgVSYAnO6ssUoY5pVPGy2H8+xdf/bmMa22Ce8nWMH3aEW8CcqMeQ== + +"@nomicfoundation/ethereumjs-statemanager@2.0.1": + version "2.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-statemanager/-/ethereumjs-statemanager-2.0.1.tgz#8824a97938db4471911e2d2f140f79195def5935" + integrity sha512-B5ApMOnlruVOR7gisBaYwFX+L/AP7i/2oAahatssjPIBVDF6wTX1K7Qpa39E/nzsH8iYuL3krkYeUFIdO3EMUQ== + dependencies: + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + ethers "^5.7.1" + js-sdsl "^4.1.4" + +"@nomicfoundation/ethereumjs-trie@6.0.1": + version "6.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-trie/-/ethereumjs-trie-6.0.1.tgz#662c55f6b50659fd4b22ea9f806a7401cafb7717" + integrity sha512-A64It/IMpDVODzCgxDgAAla8jNjNtsoQZIzZUfIV5AY6Coi4nvn7+VReBn5itlxMiL2yaTlQr9TRWp3CSI6VoA== + dependencies: + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + "@types/readable-stream" "^2.3.13" + ethereum-cryptography "0.1.3" + readable-stream "^3.6.0" + +"@nomicfoundation/ethereumjs-tx@5.0.1": + version "5.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.1.tgz#7629dc2036b4a33c34e9f0a592b43227ef4f0c7d" + integrity sha512-0HwxUF2u2hrsIM1fsasjXvlbDOq1ZHFV2dd1yGq8CA+MEYhaxZr8OTScpVkkxqMwBcc5y83FyPl0J9MZn3kY0w== + dependencies: + "@chainsafe/ssz" "^0.9.2" + "@ethersproject/providers" "^5.7.2" + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-util@9.0.1": + version "9.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.1.tgz#530cda8bae33f8b5020a8f199ed1d0a2ce48ec89" + integrity sha512-TwbhOWQ8QoSCFhV/DDfSmyfFIHjPjFBj957219+V3jTZYZ2rf9PmDtNOeZWAE3p3vlp8xb02XGpd0v6nTUPbsA== + dependencies: + "@chainsafe/ssz" "^0.10.0" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + ethereum-cryptography "0.1.3" + +"@nomicfoundation/ethereumjs-vm@7.0.1": + version "7.0.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/ethereumjs-vm/-/ethereumjs-vm-7.0.1.tgz#7d035e0993bcad10716c8b36e61dfb87fa3ca05f" + integrity sha512-rArhyn0jPsS/D+ApFsz3yVJMQ29+pVzNZ0VJgkzAZ+7FqXSRtThl1C1prhmlVr3YNUlfpZ69Ak+RUT4g7VoOuQ== + dependencies: + "@nomicfoundation/ethereumjs-block" "5.0.1" + "@nomicfoundation/ethereumjs-blockchain" "7.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-evm" "2.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-statemanager" "2.0.1" + "@nomicfoundation/ethereumjs-trie" "6.0.1" + "@nomicfoundation/ethereumjs-tx" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + debug "^4.3.3" + ethereum-cryptography "0.1.3" + mcl-wasm "^0.7.1" + rustbn.js "~0.2.0" + +"@nomicfoundation/hardhat-chai-matchers@^1.0.0": + version "1.0.6" + resolved "https://registry.npmmirror.com/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-1.0.6.tgz#72a2e312e1504ee5dd73fe302932736432ba96bc" + integrity sha512-f5ZMNmabZeZegEfuxn/0kW+mm7+yV7VNDxLpMOMGXWFJ2l/Ct3QShujzDRF9cOkK9Ui/hbDeOWGZqyQALDXVCQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@types/chai-as-promised" "^7.1.3" + chai-as-promised "^7.1.1" + deep-eql "^4.0.1" + ordinal "^1.0.3" + +"@nomicfoundation/hardhat-network-helpers@^1.0.0": + version "1.0.10" + resolved "https://registry.npmmirror.com/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.10.tgz#c61042ceb104fdd6c10017859fdef6529c1d6585" + integrity sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ== + dependencies: + ethereumjs-util "^7.1.4" + +"@nomicfoundation/hardhat-verify@^2.0.3": + version "2.0.3" + resolved "https://registry.npmmirror.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.3.tgz#173557f8cfa53c8c9da23a326f54d24fe459ae68" + integrity sha512-ESbRu9by53wu6VvgwtMtm108RSmuNsVqXtzg061D+/4R7jaWh/Wl/8ve+p6SdDX7vA1Z3L02hDO1Q3BY4luLXQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + chalk "^2.4.2" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" + +"@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz#4c858096b1c17fe58a474fe81b46815f93645c15" + integrity sha512-KcTodaQw8ivDZyF+D76FokN/HdpgGpfjc/gFCImdLUyqB6eSWVaZPazMbeAjmfhx3R0zm/NYVzxwAokFKgrc0w== + +"@nomicfoundation/solidity-analyzer-darwin-x64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-darwin-x64/-/solidity-analyzer-darwin-x64-0.1.1.tgz#6e25ccdf6e2d22389c35553b64fe6f3fdaec432c" + integrity sha512-XhQG4BaJE6cIbjAVtzGOGbK3sn1BO9W29uhk9J8y8fZF1DYz0Doj8QDMfpMu+A6TjPDs61lbsmeYodIDnfveSA== + +"@nomicfoundation/solidity-analyzer-freebsd-x64@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-freebsd-x64/-/solidity-analyzer-freebsd-x64-0.1.1.tgz#0a224ea50317139caeebcdedd435c28a039d169c" + integrity sha512-GHF1VKRdHW3G8CndkwdaeLkVBi5A9u2jwtlS7SLhBc8b5U/GcoL39Q+1CSO3hYqePNP+eV5YI7Zgm0ea6kMHoA== + +"@nomicfoundation/solidity-analyzer-linux-arm64-gnu@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-arm64-gnu/-/solidity-analyzer-linux-arm64-gnu-0.1.1.tgz#dfa085d9ffab9efb2e7b383aed3f557f7687ac2b" + integrity sha512-g4Cv2fO37ZsUENQ2vwPnZc2zRenHyAxHcyBjKcjaSmmkKrFr64yvzeNO8S3GBFCo90rfochLs99wFVGT/0owpg== + +"@nomicfoundation/solidity-analyzer-linux-arm64-musl@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-arm64-musl/-/solidity-analyzer-linux-arm64-musl-0.1.1.tgz#c9e06b5d513dd3ab02a7ac069c160051675889a4" + integrity sha512-WJ3CE5Oek25OGE3WwzK7oaopY8xMw9Lhb0mlYuJl/maZVo+WtP36XoQTb7bW/i8aAdHW5Z+BqrHMux23pvxG3w== + +"@nomicfoundation/solidity-analyzer-linux-x64-gnu@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-x64-gnu/-/solidity-analyzer-linux-x64-gnu-0.1.1.tgz#8d328d16839e52571f72f2998c81e46bf320f893" + integrity sha512-5WN7leSr5fkUBBjE4f3wKENUy9HQStu7HmWqbtknfXkkil+eNWiBV275IOlpXku7v3uLsXTOKpnnGHJYI2qsdA== + +"@nomicfoundation/solidity-analyzer-linux-x64-musl@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-linux-x64-musl/-/solidity-analyzer-linux-x64-musl-0.1.1.tgz#9b49d0634b5976bb5ed1604a1e1b736f390959bb" + integrity sha512-KdYMkJOq0SYPQMmErv/63CwGwMm5XHenEna9X9aB8mQmhDBrYrlAOSsIPgFCUSL0hjxE3xHP65/EPXR/InD2+w== + +"@nomicfoundation/solidity-analyzer-win32-arm64-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-arm64-msvc/-/solidity-analyzer-win32-arm64-msvc-0.1.1.tgz#e2867af7264ebbcc3131ef837878955dd6a3676f" + integrity sha512-VFZASBfl4qiBYwW5xeY20exWhmv6ww9sWu/krWSesv3q5hA0o1JuzmPHR4LPN6SUZj5vcqci0O6JOL8BPw+APg== + +"@nomicfoundation/solidity-analyzer-win32-ia32-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-ia32-msvc/-/solidity-analyzer-win32-ia32-msvc-0.1.1.tgz#0685f78608dd516c8cdfb4896ed451317e559585" + integrity sha512-JnFkYuyCSA70j6Si6cS1A9Gh1aHTEb8kOTBApp/c7NRTFGNMH8eaInKlyuuiIbvYFhlXW4LicqyYuWNNq9hkpQ== + +"@nomicfoundation/solidity-analyzer-win32-x64-msvc@0.1.1": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer-win32-x64-msvc/-/solidity-analyzer-win32-x64-msvc-0.1.1.tgz#c9a44f7108646f083b82e851486e0f6aeb785836" + integrity sha512-HrVJr6+WjIXGnw3Q9u6KQcbZCtk0caVWhCdFADySvRyUxJ8PnzlaP+MhwNE8oyT8OZ6ejHBRrrgjSqDCFXGirw== + +"@nomicfoundation/solidity-analyzer@^0.1.0": + version "0.1.1" + resolved "https://registry.npmmirror.com/@nomicfoundation/solidity-analyzer/-/solidity-analyzer-0.1.1.tgz#f5f4d36d3f66752f59a57e7208cd856f3ddf6f2d" + integrity sha512-1LMtXj1puAxyFusBgUIy5pZk3073cNXYnXUpuNKFghHbIit/xZgbk0AokpUADbNm3gyD6bFWl3LRFh3dhVdREg== + optionalDependencies: + "@nomicfoundation/solidity-analyzer-darwin-arm64" "0.1.1" + "@nomicfoundation/solidity-analyzer-darwin-x64" "0.1.1" + "@nomicfoundation/solidity-analyzer-freebsd-x64" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-arm64-gnu" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-arm64-musl" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-x64-gnu" "0.1.1" + "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-arm64-msvc" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1" + "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1" + +"@nomiclabs/hardhat-ethers@^2.0.0": + version "2.2.3" + resolved "https://registry.npmmirror.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0" + integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg== + +"@openzeppelin/contracts@^4.8.1": + version "4.9.5" + resolved "https://registry.npmmirror.com/@openzeppelin/contracts/-/contracts-4.9.5.tgz#1eed23d4844c861a1835b5d33507c1017fa98de8" + integrity sha512-ZK+W5mVhRppff9BE6YdR8CC52C8zAvsVAiWhEtQ5+oNxFE6h1WdeWo+FJSF8KKvtxxVYZ7MTP/5KoVpAU3aSWg== + +"@pnpm/config.env-replace@^1.1.0": + version "1.1.0" + resolved "https://registry.npmmirror.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c" + integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w== + +"@pnpm/network.ca-file@^1.0.1": + version "1.0.2" + resolved "https://registry.npmmirror.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983" + integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA== + dependencies: + graceful-fs "4.2.10" + +"@pnpm/npm-conf@^2.1.0": + version "2.2.2" + resolved "https://registry.npmmirror.com/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz#0058baf1c26cbb63a828f0193795401684ac86f0" + integrity sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA== + dependencies: + "@pnpm/config.env-replace" "^1.1.0" + "@pnpm/network.ca-file" "^1.0.1" + config-chain "^1.1.11" + +"@prettier/sync@^0.3.0": + version "0.3.0" + resolved "https://registry.npmmirror.com/@prettier/sync/-/sync-0.3.0.tgz#91f2cfc23490a21586d1cf89c6f72157c000ca1e" + integrity sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw== + +"@scure/base@~1.1.0": + version "1.1.5" + resolved "https://registry.npmmirror.com/@scure/base/-/base-1.1.5.tgz#1d85d17269fe97694b9c592552dd9e5e33552157" + integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== + +"@scure/bip32@1.1.5": + version "1.1.5" + resolved "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.1.5.tgz#d2ccae16dcc2e75bc1d75f5ef3c66a338d1ba300" + integrity sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw== + dependencies: + "@noble/hashes" "~1.2.0" + "@noble/secp256k1" "~1.7.0" + "@scure/base" "~1.1.0" + +"@scure/bip32@1.3.1": + version "1.3.1" + resolved "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.3.1.tgz#7248aea723667f98160f593d621c47e208ccbb10" + integrity sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A== + dependencies: + "@noble/curves" "~1.1.0" + "@noble/hashes" "~1.3.1" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.1.1": + version "1.1.1" + resolved "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.1.1.tgz#b54557b2e86214319405db819c4b6a370cf340c5" + integrity sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg== + dependencies: + "@noble/hashes" "~1.2.0" + "@scure/base" "~1.1.0" + +"@scure/bip39@1.2.1": + version "1.2.1" + resolved "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a" + integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg== + dependencies: + "@noble/hashes" "~1.3.0" + "@scure/base" "~1.1.0" + +"@sentry/core@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/core/-/core-5.30.0.tgz#6b203664f69e75106ee8b5a2fe1d717379b331f3" + integrity sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/hub@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/hub/-/hub-5.30.0.tgz#2453be9b9cb903404366e198bd30c7ca74cdc100" + integrity sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ== + dependencies: + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/minimal@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/minimal/-/minimal-5.30.0.tgz#ce3d3a6a273428e0084adcb800bc12e72d34637b" + integrity sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sentry/node@^5.18.1": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/node/-/node-5.30.0.tgz#4ca479e799b1021285d7fe12ac0858951c11cd48" + integrity sha512-Br5oyVBF0fZo6ZS9bxbJZG4ApAjRqAnqFFurMVJJdunNb80brh7a5Qva2kjhm+U6r9NJAB5OmDyPkA1Qnt+QVg== + dependencies: + "@sentry/core" "5.30.0" + "@sentry/hub" "5.30.0" + "@sentry/tracing" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^1.9.3" + +"@sentry/tracing@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/tracing/-/tracing-5.30.0.tgz#501d21f00c3f3be7f7635d8710da70d9419d4e1f" + integrity sha512-dUFowCr0AIMwiLD7Fs314Mdzcug+gBVo/+NCMyDw8tFxJkwWAKl7Qa2OZxLQ0ZHjakcj1hNKfCQJ9rhyfOl4Aw== + dependencies: + "@sentry/hub" "5.30.0" + "@sentry/minimal" "5.30.0" + "@sentry/types" "5.30.0" + "@sentry/utils" "5.30.0" + tslib "^1.9.3" + +"@sentry/types@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/types/-/types-5.30.0.tgz#19709bbe12a1a0115bc790b8942917da5636f402" + integrity sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw== + +"@sentry/utils@5.30.0": + version "5.30.0" + resolved "https://registry.npmmirror.com/@sentry/utils/-/utils-5.30.0.tgz#9a5bd7ccff85ccfe7856d493bffa64cabc41e980" + integrity sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww== + dependencies: + "@sentry/types" "5.30.0" + tslib "^1.9.3" + +"@sindresorhus/is@^5.2.0": + version "5.6.0" + resolved "https://registry.npmmirror.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + +"@solidity-parser/parser@^0.14.0": + version "0.14.5" + resolved "https://registry.npmmirror.com/@solidity-parser/parser/-/parser-0.14.5.tgz#87bc3cc7b068e08195c219c91cd8ddff5ef1a804" + integrity sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@solidity-parser/parser@^0.16.0": + version "0.16.2" + resolved "https://registry.npmmirror.com/@solidity-parser/parser/-/parser-0.16.2.tgz#42cb1e3d88b3e8029b0c9befff00b634cd92d2fa" + integrity sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg== + dependencies: + antlr4ts "^0.5.0-alpha.4" + +"@solidity-parser/parser@^0.17.0": + version "0.17.0" + resolved "https://registry.npmmirror.com/@solidity-parser/parser/-/parser-0.17.0.tgz#52a2fcc97ff609f72011014e4c5b485ec52243ef" + integrity sha512-Nko8R0/kUo391jsEHHxrGM07QFdnPGvlmox4rmH0kNiNAashItAilhy4Mv4pK5gQmW5f4sXAF58fwJbmlkGcVw== + +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + +"@thehubbleproject/bls@^0.5.1": + version "0.5.1" + resolved "https://registry.npmmirror.com/@thehubbleproject/bls/-/bls-0.5.1.tgz#6b0565f56fc9c8896dcf3c8f0e2214b69a06167f" + integrity sha512-g5zeMZ8js/yg6MjFoC+pt0eqfCL2jC46yLY1LbKNriyqftB1tE3jpG/FMMDIW3x9/yRg/AgUb8Nluqj15tQs+A== + dependencies: + ethers "^5.5.3" + mcl-wasm "^1.0.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.npmmirror.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmmirror.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmmirror.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmmirror.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@typechain/ethers-v5@^10.1.0": + version "10.2.1" + resolved "https://registry.npmmirror.com/@typechain/ethers-v5/-/ethers-v5-10.2.1.tgz#50241e6957683281ecfa03fb5a6724d8a3ce2391" + integrity sha512-n3tQmCZjRE6IU4h6lqUGiQ1j866n5MTCBJreNEHHVWXa2u9GJTaeYyU1/k+1qLutkyw+sS6VAN+AbeiTqsxd/A== + dependencies: + lodash "^4.17.15" + ts-essentials "^7.0.1" + +"@typechain/hardhat@^6.1.2": + version "6.1.6" + resolved "https://registry.npmmirror.com/@typechain/hardhat/-/hardhat-6.1.6.tgz#1a749eb35e5054c80df531cf440819cb347c62ea" + integrity sha512-BiVnegSs+ZHVymyidtK472syodx1sXYlYJJixZfRstHVGYTi8V1O7QG4nsjyb0PC/LORcq7sfBUcHto1y6UgJA== + dependencies: + fs-extra "^9.1.0" + +"@types/bn.js@^4.11.3": + version "4.11.6" + resolved "https://registry.npmmirror.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + +"@types/bn.js@^5.1.0": + version "5.1.5" + resolved "https://registry.npmmirror.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" + integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== + dependencies: + "@types/node" "*" + +"@types/chai-as-promised@^7.1.3": + version "7.1.8" + resolved "https://registry.npmmirror.com/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz#f2b3d82d53c59626b5d6bbc087667ccb4b677fe9" + integrity sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw== + dependencies: + "@types/chai" "*" + +"@types/chai@*", "@types/chai@^4.2.0": + version "4.3.11" + resolved "https://registry.npmmirror.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + +"@types/concat-stream@^1.6.0": + version "1.6.1" + resolved "https://registry.npmmirror.com/@types/concat-stream/-/concat-stream-1.6.1.tgz#24bcfc101ecf68e886aaedce60dfd74b632a1b74" + integrity sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA== + dependencies: + "@types/node" "*" + +"@types/form-data@0.0.33": + version "0.0.33" + resolved "https://registry.npmmirror.com/@types/form-data/-/form-data-0.0.33.tgz#c9ac85b2a5fd18435b8c85d9ecb50e6d6c893ff8" + integrity sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw== + dependencies: + "@types/node" "*" + +"@types/glob@^7.1.1": + version "7.2.0" + resolved "https://registry.npmmirror.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/http-cache-semantics@^4.0.2": + version "4.0.4" + resolved "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4" + integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== + +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmmirror.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/lodash@^4.14.194": + version "4.14.202" + resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.202.tgz#f09dbd2fb082d507178b2f2a5c7e74bd72ff98f8" + integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + +"@types/lru-cache@^5.1.0": + version "5.1.1" + resolved "https://registry.npmmirror.com/@types/lru-cache/-/lru-cache-5.1.1.tgz#c48c2e27b65d2a153b19bfc1a317e30872e01eef" + integrity sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.npmmirror.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/mocha@>=9.1.0": + version "10.0.6" + resolved "https://registry.npmmirror.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" + integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== + +"@types/node@*", "@types/node@>=12.0.0", "@types/node@^20.2.5": + version "20.10.7" + resolved "https://registry.npmmirror.com/@types/node/-/node-20.10.7.tgz#40fe8faf25418a75de9fe68a8775546732a3a901" + integrity sha512-fRbIKb8C/Y2lXxB5eVMj4IU7xpdox0Lh8bUPEdtLysaylsml1hOOx1+STloRs/B9nf7C6kPRmmg/V7aQW7usNg== + dependencies: + undici-types "~5.26.4" + +"@types/node@^10.0.3": + version "10.17.60" + resolved "https://registry.npmmirror.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" + integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== + +"@types/node@^8.0.0": + version "8.10.66" + resolved "https://registry.npmmirror.com/@types/node/-/node-8.10.66.tgz#dd035d409df322acc83dff62a602f12a5783bbb3" + integrity sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw== + +"@types/pbkdf2@^3.0.0": + version "3.1.2" + resolved "https://registry.npmmirror.com/@types/pbkdf2/-/pbkdf2-3.1.2.tgz#2dc43808e9985a2c69ff02e2d2027bd4fe33e8dc" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== + dependencies: + "@types/node" "*" + +"@types/prettier@^2.1.1": + version "2.7.3" + resolved "https://registry.npmmirror.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + +"@types/qs@^6.2.31": + version "6.9.11" + resolved "https://registry.npmmirror.com/@types/qs/-/qs-6.9.11.tgz#208d8a30bc507bd82e03ada29e4732ea46a6bbda" + integrity sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ== + +"@types/readable-stream@^2.3.13": + version "2.3.15" + resolved "https://registry.npmmirror.com/@types/readable-stream/-/readable-stream-2.3.15.tgz#3d79c9ceb1b6a57d5f6e6976f489b9b5384321ae" + integrity sha512-oM5JSKQCcICF1wvGgmecmHldZ48OZamtMxcGGVICOJA8o8cahXC1zEVAif8iwoc5j8etxFaRFnf095+CDsuoFQ== + dependencies: + "@types/node" "*" + safe-buffer "~5.1.1" + +"@types/secp256k1@^4.0.1": + version "4.0.6" + resolved "https://registry.npmmirror.com/@types/secp256k1/-/secp256k1-4.0.6.tgz#d60ba2349a51c2cbc5e816dcd831a42029d376bf" + integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== + dependencies: + "@types/node" "*" + +"@types/semver@^7.5.0": + version "7.5.6" + resolved "https://registry.npmmirror.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + +"@typescript-eslint/eslint-plugin@^6.11.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz#94b86f3c25b468c714a04bd490017ecec2fd3746" + integrity sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/type-utils" "6.18.0" + "@typescript-eslint/utils" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.11.0", "@typescript-eslint/parser@^6.4.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-6.18.0.tgz#d494161d64832e869f0a6acc6000a2cdff858383" + integrity sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA== + dependencies: + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/typescript-estree" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.18.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz#24ca6fc1f4a2afa71122dcfca9282878687d9997" + integrity sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA== + dependencies: + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + +"@typescript-eslint/type-utils@6.18.0", "@typescript-eslint/type-utils@^6.0.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz#a492da599da5c38c70aa9ff9bfb473961b8ae663" + integrity sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ== + dependencies: + "@typescript-eslint/typescript-estree" "6.18.0" + "@typescript-eslint/utils" "6.18.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@6.18.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/types/-/types-6.18.0.tgz#ffce610a1540c17cf7d8ecf2bb34b8b0e2e77101" + integrity sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA== + +"@typescript-eslint/typescript-estree@6.18.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz#1c357c3ca435c3cfa2af6b9daf45ca0bc2bb059a" + integrity sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg== + dependencies: + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/visitor-keys" "6.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@6.18.0", "@typescript-eslint/utils@^6.2.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-6.18.0.tgz#4d07c9c08f84b9939a1aca7aef98c8f378936142" + integrity sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.18.0" + "@typescript-eslint/types" "6.18.0" + "@typescript-eslint/typescript-estree" "6.18.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.18.0": + version "6.18.0" + resolved "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz#3c8733737786fa6c78a347b4fa306ae7155b560f" + integrity sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA== + dependencies: + "@typescript-eslint/types" "6.18.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.npmmirror.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +abbrev@1: + version "1.1.1" + resolved "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abbrev@1.0.x: + version "1.0.9" + resolved "https://registry.npmmirror.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + integrity sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q== + +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +abstract-level@^1.0.0, abstract-level@^1.0.2, abstract-level@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/abstract-level/-/abstract-level-1.0.3.tgz#78a67d3d84da55ee15201486ab44c09560070741" + integrity sha512-t6jv+xHy+VYwc4xqZMn2Pa9DjcdzvzZmQGRjTFc8spIbRGHgBrEKbPq+rYXc7CCo0lxgYvSgKVg9qZAhpVQSjA== + dependencies: + buffer "^6.0.3" + catering "^2.1.0" + is-buffer "^2.0.5" + level-supports "^4.0.0" + level-transcoder "^1.0.1" + module-error "^1.0.1" + queue-microtask "^1.2.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.1" + resolved "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-8.3.1.tgz#2f10f5b69329d90ae18c58bf1fa8fccd8b959a43" + integrity sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw== + +acorn@^8.4.1, acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.npmmirror.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +address@^1.0.1: + version "1.2.2" + resolved "https://registry.npmmirror.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" + integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA== + +adm-zip@^0.4.16: + version "0.4.16" + resolved "https://registry.npmmirror.com/adm-zip/-/adm-zip-0.4.16.tgz#cf4c508fdffab02c269cbc7f471a875f05570365" + integrity sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== + +agent-base@6: + version "6.0.2" + resolved "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.4, ajv@^6.12.6: + version "6.12.6" + resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + 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" + +ajv@^8.0.1: + version "8.12.0" + resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.npmmirror.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg== + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.npmmirror.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" + integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +antlr4@^4.11.0: + version "4.13.1" + resolved "https://registry.npmmirror.com/antlr4/-/antlr4-4.13.1.tgz#1e0a1830a08faeb86217cb2e6c34716004e4253d" + integrity sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA== + +antlr4ts@^0.5.0-alpha.4: + version "0.5.0-alpha.4" + resolved "https://registry.npmmirror.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a" + integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ== + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmmirror.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmmirror.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-back@^3.0.1, array-back@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + +array-back@^4.0.1, array-back@^4.0.2: + version "4.0.2" + resolved "https://registry.npmmirror.com/array-back/-/array-back-4.0.2.tgz#8004e999a6274586beeb27342168652fdb89fa1e" + integrity sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg== + +array-buffer-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" + integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== + dependencies: + call-bind "^1.0.2" + is-array-buffer "^3.0.1" + +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.npmmirror.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== + +array.prototype.findlastindex@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz#b37598438f97b579166940814e2c0493a4f50207" + integrity sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + get-intrinsic "^1.2.1" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.npmmirror.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.npmmirror.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== + dependencies: + array-buffer-byte-length "^1.0.0" + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-array-buffer "^3.0.2" + is-shared-array-buffer "^1.0.2" + +asap@~2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +ast-parents@^0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/ast-parents/-/ast-parents-0.0.1.tgz#508fd0f05d0c48775d9eccda2e174423261e8dd3" + integrity sha512-XHusKxKz3zoYk1ic8Un640joHbFMhbqneyoZfoKnEGtf2ey9Uh/IdpcQplODdO/kENaMIWsD0nJm4+wX3UNLHA== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@1.x: + version "1.5.2" + resolved "https://registry.npmmirror.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^1.5.1: + version "1.6.5" + resolved "https://registry.npmmirror.com/axios/-/axios-1.6.5.tgz#2c090da14aeeab3770ad30c3a1461bc970fb0cd8" + integrity sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg== + dependencies: + follow-redirects "^1.15.4" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.9" + resolved "https://registry.npmmirror.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bigint-crypto-utils@^3.0.23: + version "3.3.0" + resolved "https://registry.npmmirror.com/bigint-crypto-utils/-/bigint-crypto-utils-3.3.0.tgz#72ad00ae91062cf07f2b1def9594006c279c1d77" + integrity sha512-jOTSb+drvEDxEq6OuUybOAv/xxoh3cuYRUIPyu8sSHQNKM303UQ2R1DAo45o1AkcIXw6fzbaFI1+xGGdaXs2lg== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.npmmirror.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.npmmirror.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-level@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/browser-level/-/browser-level-1.0.1.tgz#36e8c3183d0fe1c405239792faaab5f315871011" + integrity sha512-XECYKJ+Dbzw0lbydyQuJzwNXtOpbMSq737qxJN11sIRTErOMShvDpbzTlgju7orJKvx4epULolZAuJGLzCmWRQ== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.1" + module-error "^1.0.2" + run-parallel-limit "^1.1.0" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.npmmirror.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" + integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== + dependencies: + function-bind "^1.1.2" + get-intrinsic "^1.2.1" + set-function-length "^1.1.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.npmmirror.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +case@^1.6.3: + version "1.6.3" + resolved "https://registry.npmmirror.com/case/-/case-1.6.3.tgz#0a4386e3e9825351ca2e6216c60467ff5f1ea1c9" + integrity sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ== + +caseless@^0.12.0, caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +catering@^2.1.0, catering@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" + integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== + +cbor@^8.1.0: + version "8.1.0" + resolved "https://registry.npmmirror.com/cbor/-/cbor-8.1.0.tgz#cfc56437e770b73417a2ecbfc9caf6b771af60d5" + integrity sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg== + dependencies: + nofilter "^3.1.0" + +chai-as-promised@^7.1.1: + version "7.1.1" + resolved "https://registry.npmmirror.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" + integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== + dependencies: + check-error "^1.0.2" + +chai@^4.2.0: + version "4.4.0" + resolved "https://registry.npmmirror.com/chai/-/chai-4.4.0.tgz#f9ac79f26726a867ac9d90a9b382120479d5f55b" + integrity sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +"charenc@>= 0.0.1": + version "0.0.2" + resolved "https://registry.npmmirror.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + +check-error@^1.0.2, check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@3.5.3, chokidar@^3.4.0: + version "3.5.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +classic-level@^1.2.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/classic-level/-/classic-level-1.3.0.tgz#5e36680e01dc6b271775c093f2150844c5edd5c8" + integrity sha512-iwFAJQYtqRTRM0F6L8h4JCt00ZSGdOyqh7yVrhhjrOpFhmBjNlRUey64MCiyo6UmQHMJ+No3c81nujPv+n9yrg== + dependencies: + abstract-level "^1.0.2" + catering "^2.1.0" + module-error "^1.0.1" + napi-macros "^2.2.2" + node-gyp-build "^4.3.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-table3@^0.5.0: + version "0.5.1" + resolved "https://registry.npmmirror.com/cli-table3/-/cli-table3-0.5.1.tgz#0252372d94dfc40dbd8df06005f48f31f656f202" + integrity sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw== + dependencies: + object-assign "^4.1.0" + string-width "^2.1.1" + optionalDependencies: + colors "^1.1.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colors@1.4.0, colors@^1.1.2: + version "1.4.0" + resolved "https://registry.npmmirror.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +combined-stream@^1.0.6, combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +command-exists@^1.2.8: + version "1.2.9" + resolved "https://registry.npmmirror.com/command-exists/-/command-exists-1.2.9.tgz#c50725af3808c8ab0260fd60b01fbfa25b954f69" + integrity sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w== + +command-line-args@^5.1.1: + version "5.2.1" + resolved "https://registry.npmmirror.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" + integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg== + dependencies: + array-back "^3.1.0" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + +command-line-usage@^6.1.0: + version "6.1.3" + resolved "https://registry.npmmirror.com/command-line-usage/-/command-line-usage-6.1.3.tgz#428fa5acde6a838779dfa30e44686f4b6761d957" + integrity sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw== + dependencies: + array-back "^4.0.2" + chalk "^2.4.2" + table-layout "^1.0.2" + typical "^5.2.0" + +commander@3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/commander/-/commander-3.0.2.tgz#6837c3fb677ad9933d1cfba42dd14d5117d6b39e" + integrity sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow== + +commander@^10.0.0: + version "10.0.1" + resolved "https://registry.npmmirror.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^11.1.0: + version "11.1.0" + resolved "https://registry.npmmirror.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +concat-stream@^1.6.0, concat-stream@^1.6.2: + version "1.6.2" + resolved "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@^1.1.11: + version "1.1.13" + resolved "https://registry.npmmirror.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" + integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +cookie@^0.4.1: + version "0.4.2" + resolved "https://registry.npmmirror.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmiconfig@^8.0.0: + version "8.3.6" + resolved "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== + dependencies: + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" + path-type "^4.0.0" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmmirror.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +"crypt@>= 0.0.1": + version "0.0.2" + resolved "https://registry.npmmirror.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + +death@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/death/-/death-1.1.0.tgz#01aa9c401edd92750514470b8266390c66c67318" + integrity sha512-vsV6S4KVHvTGxbEcij7hkWRv0It+sGGWVOM67dQde/o5Xjnr+KmLjxWJii2uEObIrt1CcM9w0Yaovx+iOlIL+w== + +debug@4, debug@4.3.4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + +deep-eql@^4.0.1, deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.npmmirror.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + +deep-extend@^0.6.0, deep-extend@~0.6.0: + version "0.6.0" + resolved "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge-ts@^5.1.0: + version "5.1.0" + resolved "https://registry.npmmirror.com/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz#c55206cc4c7be2ded89b9c816cf3608884525d7a" + integrity sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw== + +defer-to-connect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" + integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== + +define-data-property@^1.0.1, define-data-property@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.1.tgz#c35f7cd0ab09883480d12ac5cb213715587800b3" + integrity sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +detect-port@^1.3.0: + version "1.5.1" + resolved "https://registry.npmmirror.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b" + integrity sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ== + dependencies: + address "^1.0.1" + debug "4" + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmmirror.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +difflib@^0.2.4: + version "0.2.4" + resolved "https://registry.npmmirror.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e" + integrity sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w== + dependencies: + heap ">= 0.2.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dotenv@^8.0.0: + version "8.6.0" + resolved "https://registry.npmmirror.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.npmmirror.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + 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" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enquirer@^2.3.0: + version "2.4.1" + resolved "https://registry.npmmirror.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.22.1: + version "1.22.3" + resolved "https://registry.npmmirror.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-shim-unscopables@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escodegen@1.8.x: + version "1.8.1" + resolved "https://registry.npmmirror.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + integrity sha512-yhi5S+mNTOuRvyW4gWlg5W1byMaQGWWSYHXsuFZ7GBo7tpyOwi2EdzMP/QWxh9hwkD2m+wDVHJsxhRIj+v/b/A== + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +eslint-compat-utils@^0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz#f45e3b5ced4c746c127cf724fb074cd4e730d653" + integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== + +eslint-config-prettier@^9.0.0: + version "9.1.0" + resolved "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-config-standard-with-typescript@^40.0.0: + version "40.0.0" + resolved "https://registry.npmmirror.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-40.0.0.tgz#6501601dc35e378e6b16e22257e80b7bd276119d" + integrity sha512-GXUJcwIXiTQaS3H4etv8a1lejVVdZYaxZNz3g7vt6GoJosQqMTurbmSC4FVGyHiGT/d1TjFr3+47A3xsHhsG+Q== + dependencies: + "@typescript-eslint/parser" "^6.4.0" + eslint-config-standard "17.1.0" + +eslint-config-standard@17.1.0, eslint-config-standard@^17.1.0: + version "17.1.0" + resolved "https://registry.npmmirror.com/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz#40ffb8595d47a6b242e07cbfd49dc211ed128975" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.npmmirror.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.npmmirror.com/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz#e439fee65fc33f6bba630ff621efc38ec0375c49" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-es-x@^7.5.0: + version "7.5.0" + resolved "https://registry.npmmirror.com/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz#d08d9cd155383e35156c48f736eb06561d07ba92" + integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.6.0" + eslint-compat-utils "^0.1.2" + +eslint-plugin-es@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz#75a7cdfdccddc0589934aeeb384175f221c57893" + integrity sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ== + dependencies: + eslint-utils "^2.0.0" + regexpp "^3.0.0" + +eslint-plugin-eslint-comments@^3.2.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + +eslint-plugin-functional@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/eslint-plugin-functional/-/eslint-plugin-functional-6.0.0.tgz#37c32dd78443f156bb0b45febaa5d19f596cd7e7" + integrity sha512-jOUHUMA9cN2CIpgPj93fW1vTI3c95ZYUHMPJxEJL4KAtFkJDcT/9/YlfyrLOBxHkAcwBhJ29HSmeC/CUnN0k3g== + dependencies: + "@typescript-eslint/utils" "^6.2.0" + deepmerge-ts "^5.1.0" + escape-string-regexp "^4.0.0" + is-immutable-type "^2.0.1" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +eslint-plugin-import@^2.28.1: + version "2.29.1" + resolved "https://registry.npmmirror.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +eslint-plugin-n@^16.3.1: + version "16.6.1" + resolved "https://registry.npmmirror.com/eslint-plugin-n/-/eslint-plugin-n-16.6.1.tgz#b16e0033bc9ce592b1c3512cb1cee24f84ecb5ae" + integrity sha512-M1kE5bVQRLBMDYRZwDhWzlzbp370SRRRC1MHqq4I3L2Tatey+9/2csc5mwLDPlmhJaDvkojbrNUME5/llpRyDg== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + globals "^13.24.0" + ignore "^5.2.4" + is-builtin-module "^3.2.1" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" + +eslint-plugin-node@^11.1.0: + version "11.1.0" + resolved "https://registry.npmmirror.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" + integrity sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g== + dependencies: + eslint-plugin-es "^3.0.0" + eslint-utils "^2.0.0" + ignore "^5.1.1" + minimatch "^3.0.4" + resolve "^1.10.1" + semver "^6.1.0" + +eslint-plugin-promise@^6.1.1: + version "6.1.1" + resolved "https://registry.npmmirror.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816" + integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.54.0: + version "8.56.0" + resolved "https://registry.npmmirror.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15" + integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + 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" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.npmmirror.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@2.7.x, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.npmmirror.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + integrity sha512-OarPfz0lFCiW4/AV2Oy1Rp9qu0iusTKqykwTspGCZtPxmF81JR4MmIebvF1F9+UOKth2ZubLQ4XGGaU+hSn99A== + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + integrity sha512-25w1fMXQrGdoquWnScXZGckOv+Wes+JDnuN/+7ex3SauFRS72r2lFDec0EKPt2YD1wUJ/IrfEex+9yp4hfSOJA== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eth-gas-reporter@^0.2.25: + version "0.2.27" + resolved "https://registry.npmmirror.com/eth-gas-reporter/-/eth-gas-reporter-0.2.27.tgz#928de8548a674ed64c7ba0bf5795e63079150d4e" + integrity sha512-femhvoAM7wL0GcI8ozTdxfuBtBFJ9qsyIAsmKVjlWAHUbdnnXHt+lKzz/kmldM5lA9jLuNHGwuIxorNpLbR1Zw== + dependencies: + "@solidity-parser/parser" "^0.14.0" + axios "^1.5.1" + cli-table3 "^0.5.0" + colors "1.4.0" + ethereum-cryptography "^1.0.3" + ethers "^5.7.2" + fs-readdir-recursive "^1.1.0" + lodash "^4.17.14" + markdown-table "^1.1.3" + mocha "^10.2.0" + req-cwd "^2.0.0" + sha1 "^1.1.1" + sync-request "^6.0.0" + +ethereum-bloom-filters@^1.0.6: + version "1.0.10" + resolved "https://registry.npmmirror.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" + integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + dependencies: + js-sha3 "^0.8.0" + +ethereum-cryptography@0.1.3, ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereum-cryptography@^1.0.3: + version "1.2.0" + resolved "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" + integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== + dependencies: + "@noble/hashes" "1.2.0" + "@noble/secp256k1" "1.7.1" + "@scure/bip32" "1.1.5" + "@scure/bip39" "1.1.1" + +ethereum-cryptography@^2.0.0, ethereum-cryptography@^2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz#18fa7108622e56481157a5cb7c01c0c6a672eb67" + integrity sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug== + dependencies: + "@noble/curves" "1.1.0" + "@noble/hashes" "1.3.1" + "@scure/bip32" "1.3.1" + "@scure/bip39" "1.2.1" + +ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.npmmirror.com/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz#71bc152db099f70e62f108b7cdfca1b362c6fcae" + integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: + version "6.2.1" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz#fcb4e4dd5ceacb9d2305426ab1a5cd93e3163b69" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethereumjs-util@^7.1.4: + version "7.1.5" + resolved "https://registry.npmmirror.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethers@^5.4.7, ethers@^5.5.3, ethers@^5.7.1, ethers@^5.7.2: + version "5.7.2" + resolved "https://registry.npmmirror.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + 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" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +ethjs-util@0.1.6, ethjs-util@^0.1.6: + version "0.1.6" + resolved "https://registry.npmmirror.com/ethjs-util/-/ethjs-util-0.1.6.tgz#f308b62f185f9fe6237132fb2a9818866a5cd536" + integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2, fast-diff@^1.2.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.0.3, fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.16.0" + resolved "https://registry.npmmirror.com/fastq/-/fastq-1.16.0.tgz#83b9a9375692db77a822df081edb6a9cf6839320" + integrity sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + +find-up@5.0.0, find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== + dependencies: + locate-path "^2.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmmirror.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +follow-redirects@^1.12.1, follow-redirects@^1.15.4: + version "1.15.4" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" + integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.npmmirror.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + +form-data@^2.2.0: + version "2.5.1" + resolved "https://registry.npmmirror.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" + integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +fp-ts@1.19.3: + version "1.19.3" + resolved "https://registry.npmmirror.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" + integrity sha512-H5KQDspykdHuztLTg+ajGN0Z2qUjcEf3Ybxc6hLt0k7/zPkn29XnKnxlBPyW2XIddWrGaJBzBl4VLYOtk39yZg== + +fp-ts@^1.0.0: + version "1.19.5" + resolved "https://registry.npmmirror.com/fp-ts/-/fp-ts-1.19.5.tgz#3da865e585dfa1fdfd51785417357ac50afc520a" + integrity sha512-wDNqTimnzs8QqpldiId9OavWK2NptormjXnRJTQecNjzwfyp6P/8s/zG8e4h3ja3oqkKaY72UlTjQYt/1yXf9A== + +fs-extra@^0.30.0: + version "0.30.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-0.30.0.tgz#f233ffcc08d4da7d432daa449776989db1df93f0" + integrity sha512-UvSPKyhMn6LEd/WpUaV9C9t3zATuqoqfWc3QdPhPLb58prN9tqYPlPWi8Krxi44loBoUzlobqZ3+8tGpxxSzwA== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs-extra@^7.0.0, fs-extra@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.npmmirror.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-port@^3.1.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/get-port/-/get-port-3.2.0.tgz#dd7ce7de187c06c8bf353796ac71e099f0980ebc" + integrity sha512-x5UJKlgeUiNT8nyo/AcnwLnZuZNcSjSw0kogRB+Whd1fjjFq4B1hySFxSFWWSn4mIBzg3sRNUDFYc4g5gjPoLg== + +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-tsconfig@^4.7.0: + version "4.7.2" + resolved "https://registry.npmmirror.com/get-tsconfig/-/get-tsconfig-4.7.2.tgz#0dcd6fb330391d46332f4c6c1bf89a6514c2ddce" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + dependencies: + resolve-pkg-maps "^1.0.0" + +ghost-testrpc@^0.0.2: + version "0.0.2" + resolved "https://registry.npmmirror.com/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz#c4de9557b1d1ae7b2d20bbe474a91378ca90ce92" + integrity sha512-i08dAEgJ2g8z5buJIrCTduwPIhih3DP+hOCTyyryikfV8T0bNvHnGXO67i0DD1H4GBDETTclPy9njZbfluQYrQ== + dependencies: + chalk "^2.4.2" + node-emoji "^1.10.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@7.1.7: + version "7.1.7" + resolved "https://registry.npmmirror.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.15: + version "5.0.15" + resolved "https://registry.npmmirror.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA== + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.1.3, glob@^7.1.6: + version "7.2.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +glob@^8.0.3: + version "8.1.0" + resolved "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + +globals@^13.19.0, globals@^13.24.0: + version "13.24.0" + resolved "https://registry.npmmirror.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^10.0.1: + version "10.0.2" + resolved "https://registry.npmmirror.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +got@^12.1.0: + version "12.6.1" + resolved "https://registry.npmmirror.com/got/-/got-12.6.1.tgz#8869560d1383353204b5a9435f782df9c091f549" + integrity sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + +graceful-fs@4.2.10: + version "4.2.10" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +handlebars@^4.0.1: + version "4.7.8" + resolved "https://registry.npmmirror.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + +hardhat-gas-reporter@^1.0.8: + version "1.0.9" + resolved "https://registry.npmmirror.com/hardhat-gas-reporter/-/hardhat-gas-reporter-1.0.9.tgz#9a2afb354bc3b6346aab55b1c02ca556d0e16450" + integrity sha512-INN26G3EW43adGKBNzYWOlI3+rlLnasXTwW79YNnUhXPDa+yHESgt639dJEs37gCjhkbNKcRRJnomXEuMFBXJg== + dependencies: + array-uniq "1.0.3" + eth-gas-reporter "^0.2.25" + sha1 "^1.1.1" + +hardhat@2.14.0: + version "2.14.0" + resolved "https://registry.npmmirror.com/hardhat/-/hardhat-2.14.0.tgz#b60c74861494aeb1b50803cf04cc47865a42b87a" + integrity sha512-73jsInY4zZahMSVFurSK+5TNCJTXMv+vemvGia0Ac34Mm19fYp6vEPVGF3sucbumszsYxiTT2TbS8Ii2dsDSoQ== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@metamask/eth-sig-util" "^4.0.0" + "@nomicfoundation/ethereumjs-block" "5.0.1" + "@nomicfoundation/ethereumjs-blockchain" "7.0.1" + "@nomicfoundation/ethereumjs-common" "4.0.1" + "@nomicfoundation/ethereumjs-evm" "2.0.1" + "@nomicfoundation/ethereumjs-rlp" "5.0.1" + "@nomicfoundation/ethereumjs-statemanager" "2.0.1" + "@nomicfoundation/ethereumjs-trie" "6.0.1" + "@nomicfoundation/ethereumjs-tx" "5.0.1" + "@nomicfoundation/ethereumjs-util" "9.0.1" + "@nomicfoundation/ethereumjs-vm" "7.0.1" + "@nomicfoundation/solidity-analyzer" "^0.1.0" + "@sentry/node" "^5.18.1" + "@types/bn.js" "^5.1.0" + "@types/lru-cache" "^5.1.0" + abort-controller "^3.0.0" + adm-zip "^0.4.16" + aggregate-error "^3.0.0" + ansi-escapes "^4.3.0" + chalk "^2.4.2" + chokidar "^3.4.0" + ci-info "^2.0.0" + debug "^4.1.1" + enquirer "^2.3.0" + env-paths "^2.2.0" + ethereum-cryptography "^1.0.3" + ethereumjs-abi "^0.6.8" + find-up "^2.1.0" + fp-ts "1.19.3" + fs-extra "^7.0.1" + glob "7.2.0" + immutable "^4.0.0-rc.12" + io-ts "1.10.4" + keccak "^3.0.2" + lodash "^4.17.11" + mnemonist "^0.38.0" + mocha "^10.0.0" + p-map "^4.0.0" + qs "^6.7.0" + raw-body "^2.4.1" + resolve "1.17.0" + semver "^6.3.0" + solc "0.7.3" + source-map-support "^0.5.13" + stacktrace-parser "^0.1.10" + tsort "0.0.1" + undici "^5.14.0" + uuid "^8.3.2" + ws "^7.4.6" + +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz#52ba30b6c5ec87fd89fa574bc1c39125c6f65340" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +"heap@>= 0.2.0": + version "0.2.7" + resolved "https://registry.npmmirror.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" + integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +http-basic@^8.1.1: + version "8.1.3" + resolved "https://registry.npmmirror.com/http-basic/-/http-basic-8.1.3.tgz#a7cabee7526869b9b710136970805b1004261bbf" + integrity sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw== + dependencies: + caseless "^0.12.0" + concat-stream "^1.6.2" + http-response-object "^3.0.1" + parse-cache-control "^1.0.1" + +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-response-object@^3.0.1: + version "3.0.2" + resolved "https://registry.npmmirror.com/http-response-object/-/http-response-object-3.0.2.tgz#7f435bb210454e4360d074ef1f989d5ea8aa9810" + integrity sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA== + dependencies: + "@types/node" "^10.0.3" + +http2-wrapper@^2.1.10: + version "2.2.1" + resolved "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.0.5, ignore@^5.1.1, ignore@^5.2.0, ignore@^5.2.4: + version "5.3.0" + resolved "https://registry.npmmirror.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" + integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== + +immutable@^4.0.0-rc.12: + version "4.3.4" + resolved "https://registry.npmmirror.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f" + integrity sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA== + +import-fresh@^3.2.1, import-fresh@^3.3.0: + version "3.3.0" + resolved "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmmirror.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +internal-slot@^1.0.5: + version "1.0.6" + resolved "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== + dependencies: + get-intrinsic "^1.2.2" + hasown "^2.0.0" + side-channel "^1.0.4" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +io-ts@1.10.4: + version "1.10.4" + resolved "https://registry.npmmirror.com/io-ts/-/io-ts-1.10.4.tgz#cd5401b138de88e4f920adbcb7026e2d1967e6e2" + integrity sha512-b23PteSnYXSONJ6JQXRAlvJhuw8KOtkqa87W4wDtvMrud/DTJd5X+NpOOI+O/zZwVq6v0VLAaJ+1EDViKEuN9g== + dependencies: + fp-ts "^1.0.0" + +is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" + integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.0" + is-typed-array "^1.1.10" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.npmmirror.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +is-immutable-type@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/is-immutable-type/-/is-immutable-type-2.0.1.tgz#5a968a045689d5094d553802d2282a83cfa2ba13" + integrity sha512-SNO0yWLzSN+oYb8adM4AvsPYSCqElmjcXUNemryDLo0r5M54oMs/6R4cvKLc9QtIs/nRuc3ahlgJoMdGfcHLwQ== + dependencies: + "@typescript-eslint/type-utils" "^6.0.0" + ts-api-utils "^1.0.1" + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: + version "1.1.12" + resolved "https://registry.npmmirror.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-sdsl@^4.1.4: + version "4.4.2" + resolved "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.2.tgz#2e3c031b1f47d3aca8b775532e3ebb0818e7f847" + integrity sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w== + +js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.npmmirror.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@3.x: + version "3.14.1" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@4.1.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + integrity sha512-PKllAqbgLgxHaj8TElYymKCAgrASebJrWpTnEkOaTowt23VKXXN0sUeriJ+eh7y6ufb/CC5ap11pz71/cM0hUw== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonschema@^1.2.4: + version "1.4.1" + resolved "https://registry.npmmirror.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab" + integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== + +keccak@^3.0.0, keccak@^3.0.2: + version "3.0.4" + resolved "https://registry.npmmirror.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.npmmirror.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + integrity sha512-TED5xi9gGQjGpNnvRWknrwAB1eL5GciPfVFOt3Vk1OJCVDQbzuSfrF3hkUQKlsgKrG1F+0t5W0m+Fje1jIt8rw== + optionalDependencies: + graceful-fs "^4.1.9" + +latest-version@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/latest-version/-/latest-version-7.0.0.tgz#843201591ea81a4d404932eeb61240fe04e9e5da" + integrity sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg== + dependencies: + package-json "^8.1.0" + +level-supports@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/level-supports/-/level-supports-4.0.1.tgz#431546f9d81f10ff0fea0e74533a0e875c08c66a" + integrity sha512-PbXpve8rKeNcZ9C1mUicC9auIYFyGpkV9/i6g76tLgANwWhtG2v7I4xNBUlkn3lE2/dZF3Pi0ygYGtLc4RXXdA== + +level-transcoder@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/level-transcoder/-/level-transcoder-1.0.1.tgz#f8cef5990c4f1283d4c86d949e73631b0bc8ba9c" + integrity sha512-t7bFwFtsQeD8cl8NIoQ2iwxA0CL/9IFw7/9gAjOonH0PWTTiRfY7Hq+Ejbsxh86tXobDQ6IOiddjNYIfOBs06w== + dependencies: + buffer "^6.0.3" + module-error "^1.0.1" + +level@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/level/-/level-8.0.0.tgz#41b4c515dabe28212a3e881b61c161ffead14394" + integrity sha512-ypf0jjAk2BWI33yzEaaotpq7fkOPALKAgDBxggO6Q9HGX2MRXn0wbP1Jn/tJv1gtL867+YOjOB49WaUF3UoJNQ== + dependencies: + browser-level "^1.0.1" + classic-level "^1.2.0" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.npmmirror.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +lru_map@^0.3.3: + version "0.3.3" + resolved "https://registry.npmmirror.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" + integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmmirror.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +markdown-table@^1.1.3: + version "1.1.3" + resolved "https://registry.npmmirror.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" + integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== + +mcl-wasm@^0.7.1: + version "0.7.9" + resolved "https://registry.npmmirror.com/mcl-wasm/-/mcl-wasm-0.7.9.tgz#c1588ce90042a8700c3b60e40efb339fc07ab87f" + integrity sha512-iJIUcQWA88IJB/5L15GnJVnSQJmf/YaxxV6zRavv83HILHaJQb6y0iFyDMdDO0gN8X37tdxmAOrH/P8B6RB8sQ== + +mcl-wasm@^1.0.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/mcl-wasm/-/mcl-wasm-1.4.0.tgz#28ad8f4c0a1260c1f8c44b072060153b7bf4da99" + integrity sha512-90Tvmg2NXwnKMgTafA01PRELsYNNRb/F2bj3nzdByTLLMUmgkgL8H/oeWcjZtVVffnBJyNjDcYxY7cdOE/WoHg== + dependencies: + "@types/node" "^20.2.5" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmmirror.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +memory-level@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" + integrity sha512-UXzwewuWeHBz5krr7EvehKcmLFNoXxGcvuYhC41tRnkrTbJohtS7kVn9akmgirtRygg+f7Yjsfi8Uu5SGSQ4Og== + dependencies: + abstract-level "^1.0.0" + functional-red-black-tree "^1.0.1" + module-error "^1.0.1" + +memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.npmmirror.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw== + +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micro-ftch@^0.3.1: + version "0.3.1" + resolved "https://registry.npmmirror.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" + integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +"minimatch@2 || 3", minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@0.5.x: + version "0.5.6" + resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mnemonist@^0.38.0: + version "0.38.5" + resolved "https://registry.npmmirror.com/mnemonist/-/mnemonist-0.38.5.tgz#4adc7f4200491237fe0fa689ac0b86539685cade" + integrity sha512-bZTFT5rrPKtPJxj8KSV0WkPyNxl72vQepqqVUAW2ARUpUSF2qXMB6jZj7hW5/k7C1rtpzqbD/IIbJwLXUjCHeg== + dependencies: + obliterator "^2.0.0" + +mocha@10.2.0, mocha@^10.0.0, mocha@^10.2.0: + version "10.2.0" + resolved "https://registry.npmmirror.com/mocha/-/mocha-10.2.0.tgz#1fd4a7c32ba5ac372e03a17eef435bd00e5c68b8" + integrity sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +module-error@^1.0.1, module-error@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/module-error/-/module-error-1.0.2.tgz#8d1a48897ca883f47a45816d4fb3e3c6ba404d86" + integrity sha512-0yuvsqSCv8LbaOKhnsQ/T5JhyFlCYLPXK3U2sgV10zoKQwzs/MyfuQUOZQ1V/6OCOJsK/TRgNVrPuPDqtdMFtA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + +napi-macros@^2.2.2: + version "2.2.2" + resolved "https://registry.npmmirror.com/napi-macros/-/napi-macros-2.2.2.tgz#817fef20c3e0e40a963fbf7b37d1600bd0201044" + integrity sha512-hmEVtAGYzVQpCKdbQea4skABsdXW4RUh5t5mJ2zzqowJS2OyXZTU1KhDVFhx+NlWZ4ap9mqR9TcDO3LTTttd+g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-emoji@^1.10.0: + version "1.11.0" + resolved "https://registry.npmmirror.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" + integrity sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A== + dependencies: + lodash "^4.17.21" + +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.8.0" + resolved "https://registry.npmmirror.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + +nofilter@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/nofilter/-/nofilter-3.1.0.tgz#c757ba68801d41ff930ba2ec55bab52ca184aa66" + integrity sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g== + +nopt@3.x: + version "3.0.6" + resolved "https://registry.npmmirror.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg== + dependencies: + abbrev "1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-url@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/normalize-url/-/normalize-url-8.0.0.tgz#593dbd284f743e8dcf6a5ddf8fadff149c82701a" + integrity sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw== + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.npmmirror.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1, object-inspect@^1.9.0: + version "1.13.1" + resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.npmmirror.com/object.fromentries/-/object.fromentries-2.0.7.tgz#71e95f441e9a0ea6baf682ecaaf37fa2a8d7e616" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/object.groupby/-/object.groupby-1.0.1.tgz#d41d9f3c8d6c778d9cbac86b4ee9f5af103152ee" + integrity sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.npmmirror.com/object.values/-/object.values-1.1.7.tgz#617ed13272e7e1071b43973aa1655d9291b8442a" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +obliterator@^2.0.0: + version "2.0.4" + resolved "https://registry.npmmirror.com/obliterator/-/obliterator-2.0.4.tgz#fa650e019b2d075d745e44f1effeb13a2adbe816" + integrity sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ== + +once@1.x, once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.npmmirror.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.npmmirror.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + 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" + +ordinal@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/ordinal/-/ordinal-1.0.3.tgz#1a3c7726a61728112f50944ad7c35c06ae3a0d4d" + integrity sha512-cMddMgb2QElm8G7vdaa02jhUNbTSrhsgAGUz1OokD83uJTwSUn+nKoNoKVVaRa08yF6sgfO7Maou1+bgLd9rdQ== + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== + dependencies: + p-limit "^1.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== + +package-json@^8.1.0: + version "8.1.1" + resolved "https://registry.npmmirror.com/package-json/-/package-json-8.1.1.tgz#3e9948e43df40d1e8e78a85485f1070bf8f03dc8" + integrity sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA== + dependencies: + got "^12.1.0" + registry-auth-token "^5.0.1" + registry-url "^6.0.0" + semver "^7.3.7" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-cache-control@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/parse-cache-control/-/parse-cache-control-1.0.1.tgz#8eeab3e54fa56920fe16ba38f77fa21aacc2d74e" + integrity sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg== + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +pbkdf2@^3.0.17: + version "3.1.2" + resolved "https://registry.npmmirror.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pluralize@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" + integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier-plugin-solidity@^1.0.0-beta.13: + version "1.3.1" + resolved "https://registry.npmmirror.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.3.1.tgz#59944d3155b249f7f234dee29f433524b9a4abcf" + integrity sha512-MN4OP5I2gHAzHZG1wcuJl0FsLS3c4Cc5494bbg+6oQWBPuEamjwDvmGfFMZ6NFzsh3Efd9UUxeT7ImgjNH4ozA== + dependencies: + "@solidity-parser/parser" "^0.17.0" + semver "^7.5.4" + solidity-comments-extractor "^0.0.8" + +prettier@^2.3.1, prettier@^2.8.3: + version "2.8.8" + resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +prettier@^3.2.4: + version "3.2.4" + resolved "https://registry.npmmirror.com/prettier/-/prettier-3.2.4.tgz#4723cadeac2ce7c9227de758e5ff9b14e075f283" + integrity sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +promise@^8.0.0: + version "8.3.0" + resolved "https://registry.npmmirror.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a" + integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg== + dependencies: + asap "~2.0.6" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.npmmirror.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA== + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qs@^6.4.0, qs@^6.7.0: + version "6.11.2" + resolved "https://registry.npmmirror.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" + integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== + dependencies: + side-channel "^1.0.4" + +queue-microtask@^1.2.2, queue-microtask@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +raw-body@^2.4.1: + version "2.5.2" + resolved "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@1.2.8: + version "1.2.8" + resolved "https://registry.npmmirror.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.2.2: + version "2.3.8" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.npmmirror.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +recursive-readdir@^2.2.2: + version "2.2.3" + resolved "https://registry.npmmirror.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372" + integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA== + dependencies: + minimatch "^3.0.5" + +reduce-flatten@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/reduce-flatten/-/reduce-flatten-2.0.0.tgz#734fd84e65f375d7ca4465c69798c25c9d10ae27" + integrity sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w== + +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +regexpp@^3.0.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +registry-auth-token@^5.0.1: + version "5.0.2" + resolved "https://registry.npmmirror.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756" + integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ== + dependencies: + "@pnpm/npm-conf" "^2.1.0" + +registry-url@^6.0.0: + version "6.0.1" + resolved "https://registry.npmmirror.com/registry-url/-/registry-url-6.0.1.tgz#056d9343680f2f64400032b1e199faa692286c58" + integrity sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q== + dependencies: + rc "1.2.8" + +req-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/req-cwd/-/req-cwd-2.0.0.tgz#d4082b4d44598036640fb73ddea01ed53db49ebc" + integrity sha512-ueoIoLo1OfB6b05COxAA9UpeoscNpYyM+BqYlA7H6LVF4hKGPXQQSSaD2YmvDVJMkk4UDpAHIeU1zG53IqjvlQ== + dependencies: + req-from "^2.0.0" + +req-from@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/req-from/-/req-from-2.0.0.tgz#d74188e47f93796f4aa71df6ee35ae689f3e0e70" + integrity sha512-LzTfEVDVQHBRfjOUMgNBA+V6DWsSnoeKzf42J7l0xa/B4jyPOuuF5MlNSmomLNGemWTnV2TIdjSSLnEn95fOQA== + dependencies: + resolve-from "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.0, require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-alpn@^1.2.0: + version "1.2.1" + resolved "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9" + integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@1.1.x: + version "1.1.7" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== + +resolve@1.17.0: + version "1.17.0" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== + dependencies: + path-parse "^1.0.6" + +resolve@^1.1.6, resolve@^1.10.1, resolve@^1.22.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.2.8: + version "2.7.1" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.2.3, rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.npmmirror.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + +run-parallel-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/run-parallel-limit/-/run-parallel-limit-1.1.0.tgz#be80e936f5768623a38a963262d6bef8ff11e7ba" + integrity sha512-jJA7irRNM91jaKc3Hcl1npHsFLOXOoTkPCUL1JEa1R82O2miplXXRaGdjW/KM/98YQWDhJLiSs793CnXfblJUw== + dependencies: + queue-microtask "^1.2.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rustbn.js@~0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/rustbn.js/-/rustbn.js-0.2.0.tgz#8082cb886e707155fd1cb6f23bd591ab8d55d0ca" + integrity sha512-4VlvkRUuCJvr2J6Y0ImW7NvTCriMi7ErOAqWk1y69vAdoNIzCF3yPmgeNzx+RQTLEDFq5sHfscn1MwHxP9hNfA== + +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex-test@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" + integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.3" + is-regex "^1.1.4" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sc-istanbul@^0.4.5: + version "0.4.6" + resolved "https://registry.npmmirror.com/sc-istanbul/-/sc-istanbul-0.4.6.tgz#cf6784355ff2076f92d70d59047d71c13703e839" + integrity sha512-qJFF/8tW/zJsbyfh/iT/ZM5QNHE3CXxtLJbZsL+CzdJLBsPD7SedJZoUA4d8iAcN2IoMp/Dx80shOOd2x96X/g== + dependencies: + abbrev "1.0.x" + async "1.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" + handlebars "^4.0.1" + js-yaml "3.x" + mkdirp "0.5.x" + nopt "3.x" + once "1.x" + resolve "1.1.x" + supports-color "^3.1.0" + which "^1.1.1" + wordwrap "^1.0.0" + +scrypt-js@3.0.1, scrypt-js@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +semver@^5.5.0: + version "5.7.2" + resolved "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.1.0, semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.0.0, semver@^7.3.4, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: + version "7.5.4" + resolved "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +set-function-length@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.1.1.tgz#4bc39fafb0307224a33e106a7d35ca1218d659ed" + integrity sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ== + dependencies: + define-data-property "^1.1.1" + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.npmmirror.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha1@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/sha1/-/sha1-1.1.1.tgz#addaa7a93168f393f19eb2b15091618e2700f848" + integrity sha512-dZBS6OrMjtgVkopB1Gmo4RQCDKiZsqcpAQpkV/aaj+FCrCg8r4I4qMkDPQjBgLIxlmu9k4nUbWq6ohXahOneYA== + dependencies: + charenc ">= 0.0.1" + crypt ">= 0.0.1" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shelljs@^0.8.3: + version "0.8.5" + resolved "https://registry.npmmirror.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +solc@0.7.3: + version "0.7.3" + resolved "https://registry.npmmirror.com/solc/-/solc-0.7.3.tgz#04646961bd867a744f63d2b4e3c0701ffdc7d78a" + integrity sha512-GAsWNAjGzIDg7VxzP6mPjdurby3IkGCjQcM8GFYZT6RyaoUZKmMU6Y7YwG+tFGhv7dwZ8rmR4iwFDrrD99JwqA== + dependencies: + command-exists "^1.2.8" + commander "3.0.2" + follow-redirects "^1.12.1" + fs-extra "^0.30.0" + js-sha3 "0.8.0" + memorystream "^0.3.1" + require-from-string "^2.0.0" + semver "^5.5.0" + tmp "0.0.33" + +solhint-community@^3.7.0: + version "3.7.0" + resolved "https://registry.npmmirror.com/solhint-community/-/solhint-community-3.7.0.tgz#5d8bd4a2137d44dd636272edce93cb754184c09b" + integrity sha512-8nfdaxVll+IIaEBHFz3CzagIZNNTGp4Mrr+6O4m7c9Bs/L8OcgR/xzZJFwROkGAhV8Nbiv4gqJ42nEXZPYl3Qw== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^11.1.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^6.3.0" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + +solhint-plugin-prettier@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz#2f46999e26d6c6bc80281c22a7a21e381175bef7" + integrity sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw== + dependencies: + "@prettier/sync" "^0.3.0" + prettier-linter-helpers "^1.0.0" + +solhint@^4.1.1: + version "4.1.1" + resolved "https://registry.npmmirror.com/solhint/-/solhint-4.1.1.tgz#137c935ef028f01ba13687a1f237288d94dae1bf" + integrity sha512-7G4iF8H5hKHc0tR+/uyZesSKtfppFIMvPSW+Ku6MSL25oVRuyFeqNhOsXHfkex64wYJyXs4fe+pvhB069I19Tw== + dependencies: + "@solidity-parser/parser" "^0.16.0" + ajv "^6.12.6" + antlr4 "^4.11.0" + ast-parents "^0.0.1" + chalk "^4.1.2" + commander "^10.0.0" + cosmiconfig "^8.0.0" + fast-diff "^1.2.0" + glob "^8.0.3" + ignore "^5.2.4" + js-yaml "^4.1.0" + latest-version "^7.0.0" + lodash "^4.17.21" + pluralize "^8.0.0" + semver "^7.5.2" + strip-ansi "^6.0.1" + table "^6.8.1" + text-table "^0.2.0" + optionalDependencies: + prettier "^2.8.3" + +solidity-comments-extractor@^0.0.8: + version "0.0.8" + resolved "https://registry.npmmirror.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.8.tgz#f6e148ab0c49f30c1abcbecb8b8df01ed8e879f8" + integrity sha512-htM7Vn6LhHreR+EglVMd2s+sZhcXAirB1Zlyrv5zBuTxieCvjfnRpd7iZk75m/u6NOlEyQ94C6TWbBn2cY7w8g== + +solidity-coverage@^0.8.0: + version "0.8.5" + resolved "https://registry.npmmirror.com/solidity-coverage/-/solidity-coverage-0.8.5.tgz#64071c3a0c06a0cecf9a7776c35f49edc961e875" + integrity sha512-6C6N6OV2O8FQA0FWA95FdzVH+L16HU94iFgg5wAFZ29UpLFkgNI/DRR2HotG1bC0F4gAc/OMs2BJI44Q/DYlKQ== + dependencies: + "@ethersproject/abi" "^5.0.9" + "@solidity-parser/parser" "^0.16.0" + chalk "^2.4.2" + death "^1.1.0" + detect-port "^1.3.0" + difflib "^0.2.4" + fs-extra "^8.1.0" + ghost-testrpc "^0.0.2" + global-modules "^2.0.0" + globby "^10.0.1" + jsonschema "^1.2.4" + lodash "^4.17.15" + mocha "10.2.0" + node-emoji "^1.10.0" + pify "^4.0.1" + recursive-readdir "^2.2.2" + sc-istanbul "^0.4.5" + semver "^7.3.4" + shelljs "^0.8.3" + web3-utils "^1.3.6" + +source-map-support@^0.5.13: + version "0.5.21" + resolved "https://registry.npmmirror.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + integrity sha512-CBdZ2oa/BHhS4xj5DlhjWNHcan57/5YuvfdLf17iVmIpd9KRm+DFLmC6nBNj+6Ua7Kt3TmOjDpQT1aTYOQtoUA== + dependencies: + amdefine ">=0.0.4" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stacktrace-parser@^0.1.10: + version "0.1.10" + resolved "https://registry.npmmirror.com/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" + integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== + dependencies: + type-fest "^0.7.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string-format@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b" + integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA== + +string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.npmmirror.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^3.1.0: + version "3.2.3" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A== + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +sync-request@^6.0.0: + version "6.1.0" + resolved "https://registry.npmmirror.com/sync-request/-/sync-request-6.1.0.tgz#e96217565b5e50bbffe179868ba75532fb597e68" + integrity sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw== + dependencies: + http-response-object "^3.0.1" + sync-rpc "^1.2.1" + then-request "^6.0.0" + +sync-rpc@^1.2.1: + version "1.3.6" + resolved "https://registry.npmmirror.com/sync-rpc/-/sync-rpc-1.3.6.tgz#b2e8b2550a12ccbc71df8644810529deb68665a7" + integrity sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw== + dependencies: + get-port "^3.1.0" + +table-layout@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/table-layout/-/table-layout-1.0.2.tgz#c4038a1853b0136d63365a734b6931cf4fad4a04" + integrity sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A== + dependencies: + array-back "^4.0.1" + deep-extend "~0.6.0" + typical "^5.2.0" + wordwrapjs "^4.0.0" + +table@^6.8.0, table@^6.8.1: + version "6.8.1" + resolved "https://registry.npmmirror.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +then-request@^6.0.0: + version "6.0.2" + resolved "https://registry.npmmirror.com/then-request/-/then-request-6.0.2.tgz#ec18dd8b5ca43aaee5cb92f7e4c1630e950d4f0c" + integrity sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA== + dependencies: + "@types/concat-stream" "^1.6.0" + "@types/form-data" "0.0.33" + "@types/node" "^8.0.0" + "@types/qs" "^6.2.31" + caseless "~0.12.0" + concat-stream "^1.6.0" + form-data "^2.2.0" + http-basic "^8.1.1" + http-response-object "^3.0.1" + promise "^8.0.0" + qs "^6.4.0" + +tmp@0.0.33: + version "0.0.33" + resolved "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +ts-api-utils@^1.0.1: + version "1.0.3" + resolved "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-1.0.3.tgz#f12c1c781d04427313dbac808f453f050e54a331" + integrity sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg== + +ts-command-line-args@^2.2.0: + version "2.5.1" + resolved "https://registry.npmmirror.com/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz#e64456b580d1d4f6d948824c274cf6fa5f45f7f0" + integrity sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw== + dependencies: + chalk "^4.1.0" + command-line-args "^5.1.1" + command-line-usage "^6.1.0" + string-format "^2.0.0" + +ts-essentials@^7.0.1: + version "7.0.3" + resolved "https://registry.npmmirror.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" + integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== + +ts-node@>=8.0.0: + version "10.9.2" + resolved "https://registry.npmmirror.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.npmmirror.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsort@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" + integrity sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw== + +tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.npmmirror.com/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz#b80fcdb5c97bcc508be18c44a4be50f022eea00b" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + +tweetnacl@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmmirror.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.npmmirror.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.7.1: + version "0.7.1" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" + integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== + +typechain@^8.1.0: + version "8.3.2" + resolved "https://registry.npmmirror.com/typechain/-/typechain-8.3.2.tgz#1090dd8d9c57b6ef2aed3640a516bdbf01b00d73" + integrity sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q== + dependencies: + "@types/prettier" "^2.1.1" + debug "^4.3.1" + fs-extra "^7.0.0" + glob "7.1.7" + js-sha3 "^0.8.0" + lodash "^4.17.15" + mkdirp "^1.0.4" + prettier "^2.3.1" + ts-command-line-args "^2.2.0" + ts-essentials "^7.0.1" + +typed-array-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" + integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + is-typed-array "^1.1.10" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== + +typescript@^5.1.6: + version "5.3.3" + resolved "https://registry.npmmirror.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== + +typical@^5.2.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/typical/-/typical-5.2.0.tgz#4daaac4f2b5315460804f0acf6cb69c52bb93066" + integrity sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg== + +uglify-js@^3.1.4: + version "3.17.4" + resolved "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici@^5.14.0: + version "5.28.2" + resolved "https://registry.npmmirror.com/undici/-/undici-5.28.2.tgz#fea200eac65fc7ecaff80a023d1a0543423b4c91" + integrity sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w== + dependencies: + "@fastify/busboy" "^2.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.npmmirror.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +web3-utils@^1.3.6: + version "1.10.3" + resolved "https://registry.npmmirror.com/web3-utils/-/web3-utils-1.10.3.tgz#f1db99c82549c7d9f8348f04ffe4e0188b449714" + integrity sha512-OqcUrEE16fDBbGoQtZXWdavsPzbGIDc5v3VrRTZ0XrIpefC/viZ1ZU9bGEemazyS0catk/3rkOOxpzTfY+XsyQ== + dependencies: + "@ethereumjs/util" "^8.1.0" + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereum-cryptography "^2.1.2" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.11, which-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" + integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.4" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.0" + +which@^1.1.1, which@^1.3.1: + version "1.3.1" + resolved "https://registry.npmmirror.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +wordwrapjs@^4.0.0: + version "4.0.1" + resolved "https://registry.npmmirror.com/wordwrapjs/-/wordwrapjs-4.0.1.tgz#d9790bccfb110a0fc7836b5ebce0937b37a8b98f" + integrity sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA== + dependencies: + reduce-flatten "^2.0.0" + typical "^5.2.0" + +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.npmmirror.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@7.4.6: + version "7.4.6" + resolved "https://registry.npmmirror.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +ws@^7.4.6: + version "7.5.9" + resolved "https://registry.npmmirror.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==