mirror of
https://github.com/logos-messaging/rln.waku.org.git
synced 2026-01-07 16:43:05 +00:00
feat: upgrade and use zerokit, cleanup
This commit is contained in:
parent
7622d02fe9
commit
cd599f0a97
110
package-lock.json
generated
110
package-lock.json
generated
@ -19,7 +19,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.2",
|
"@radix-ui/react-toggle": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
"@waku/rln": "0.1.7-987c6cd.0",
|
"@waku/rln": "0.1.8-e224c05.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^12.6.3",
|
"framer-motion": "^12.6.3",
|
||||||
@ -656,6 +656,12 @@
|
|||||||
"js-sha3": "0.8.0"
|
"js-sha3": "0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ethersproject/keccak256/node_modules/js-sha3": {
|
||||||
|
"version": "0.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
||||||
|
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@ethersproject/logger": {
|
"node_modules/@ethersproject/logger": {
|
||||||
"version": "5.8.0",
|
"version": "5.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz",
|
||||||
@ -1307,9 +1313,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@libp2p/crypto/node_modules/@noble/curves": {
|
"node_modules/@libp2p/crypto/node_modules/@noble/curves": {
|
||||||
"version": "1.9.2",
|
"version": "1.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz",
|
||||||
"integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==",
|
"integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "1.8.0"
|
"@noble/hashes": "1.8.0"
|
||||||
@ -2977,17 +2983,17 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@waku/core": {
|
"node_modules/@waku/core": {
|
||||||
"version": "0.0.37-987c6cd.0",
|
"version": "0.0.38-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.37-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/core/-/core-0.0.38-e224c05.0.tgz",
|
||||||
"integrity": "sha512-w3F/dzY/YA5T3l62YKKcza3fMLZNzprupoKScvtpWS8VymLIGZCMhzcKOij4lt6SWzHWyTEMa9qtcB6tZPIC+A==",
|
"integrity": "sha512-VtRfwF6WGj3HhB4cywiit3KcrHYtUtoD1wjAviO8b4AzH9LbtV7NmYvGIy5ac9sOpRQEUNagOFT6+oXu7Ay+HQ==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@libp2p/ping": "2.0.35",
|
"@libp2p/ping": "2.0.35",
|
||||||
"@noble/hashes": "^1.3.2",
|
"@noble/hashes": "^1.3.2",
|
||||||
"@waku/enr": "0.0.31-987c6cd.0",
|
"@waku/enr": "0.0.32-e224c05.0",
|
||||||
"@waku/interfaces": "0.0.32-987c6cd.0",
|
"@waku/interfaces": "0.0.33-e224c05.0",
|
||||||
"@waku/proto": "0.0.12-987c6cd.0",
|
"@waku/proto": "0.0.13-e224c05.0",
|
||||||
"@waku/utils": "0.0.25-987c6cd.0",
|
"@waku/utils": "0.0.26-e224c05.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"it-all": "^3.0.4",
|
"it-all": "^3.0.4",
|
||||||
"it-length-prefixed": "^9.0.4",
|
"it-length-prefixed": "^9.0.4",
|
||||||
@ -3025,9 +3031,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/enr": {
|
"node_modules/@waku/enr": {
|
||||||
"version": "0.0.31-987c6cd.0",
|
"version": "0.0.32-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/enr/-/enr-0.0.31-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/enr/-/enr-0.0.32-e224c05.0.tgz",
|
||||||
"integrity": "sha512-nStUXohULcatKLxCyzU7JJK2gKhMXYEAdN90uL1Ggl4tKA9uUrQ2YZC/WB61RmucnDlFNH6phFv47/WbARhhVA==",
|
"integrity": "sha512-f+DEugomxeDgCylxv2xm6eLIJBB76dctB4B/d0zUMld26zjBozRKUsaNn8DOWRT5f44WzyP+5gRqbTm4e/qsMw==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersproject/rlp": "^5.7.0",
|
"@ethersproject/rlp": "^5.7.0",
|
||||||
@ -3035,7 +3041,7 @@
|
|||||||
"@libp2p/peer-id": "5.1.7",
|
"@libp2p/peer-id": "5.1.7",
|
||||||
"@multiformats/multiaddr": "^12.0.0",
|
"@multiformats/multiaddr": "^12.0.0",
|
||||||
"@noble/secp256k1": "^1.7.1",
|
"@noble/secp256k1": "^1.7.1",
|
||||||
"@waku/utils": "0.0.25-987c6cd.0",
|
"@waku/utils": "0.0.26-e224c05.0",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"js-sha3": "^0.9.2"
|
"js-sha3": "^0.9.2"
|
||||||
},
|
},
|
||||||
@ -3079,9 +3085,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/enr/node_modules/@noble/curves": {
|
"node_modules/@waku/enr/node_modules/@noble/curves": {
|
||||||
"version": "1.9.2",
|
"version": "1.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz",
|
||||||
"integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==",
|
"integrity": "sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "1.8.0"
|
"@noble/hashes": "1.8.0"
|
||||||
@ -3105,25 +3111,19 @@
|
|||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/enr/node_modules/js-sha3": {
|
|
||||||
"version": "0.9.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz",
|
|
||||||
"integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@waku/interfaces": {
|
"node_modules/@waku/interfaces": {
|
||||||
"version": "0.0.32-987c6cd.0",
|
"version": "0.0.33-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.32-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.33-e224c05.0.tgz",
|
||||||
"integrity": "sha512-7dfGDx1bs+rs1nlMwAZYd0Di4gLyD9cWR0ApDJ+I0sU3enn1NT6hM1U3cp+LE6xqxXUoe2tfQi/4QhrECaGypQ==",
|
"integrity": "sha512-8GH7Tg0t74R32NqQHVm0ttVPb26Cvn/p+Iiht3mha8gGHQVkYYYyECXfZYAQ9pld3y0GB+yqpn5EiZiTNs3AOQ==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=22"
|
"node": ">=22"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/proto": {
|
"node_modules/@waku/proto": {
|
||||||
"version": "0.0.12-987c6cd.0",
|
"version": "0.0.13-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/proto/-/proto-0.0.12-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/proto/-/proto-0.0.13-e224c05.0.tgz",
|
||||||
"integrity": "sha512-B0u7Qkm/U6mH0ZCGYvRfg4d44JboscYBmXifeOTwY0i4QH8nvrZcPIIsUqvNmzT2CjrAwpt8H+98fGp9l4fKow==",
|
"integrity": "sha512-zvIGhAECY1v691tWnyiFcUAPvd06itXRq9BggN5Nwq+TKMl9XOL6+kHuTzovvn1PM9ajRyoP3zbqT1musxeixQ==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"protons-runtime": "^5.4.0"
|
"protons-runtime": "^5.4.0"
|
||||||
@ -3133,16 +3133,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/rln": {
|
"node_modules/@waku/rln": {
|
||||||
"version": "0.1.7-987c6cd.0",
|
"version": "0.1.8-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/rln/-/rln-0.1.7-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/rln/-/rln-0.1.8-e224c05.0.tgz",
|
||||||
"integrity": "sha512-6w/17WpD7jdw5LyM6OX0c2mMxW3cRrXG7wxi7PzhoSb2celNWZYhnPR9UK+rgsP5opoBDXD7LAyaEEqA3afbgA==",
|
"integrity": "sha512-9uSP1ARwOdpGHJ9LIpNdNo03/q60YYYuDGCX+fPfrDFooWjxvIn0+G1TzxUgJLLP6g7stxaWj+iKCCktNFpxZQ==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chainsafe/bls-keystore": "3.0.0",
|
"@chainsafe/bls-keystore": "3.0.0",
|
||||||
"@noble/hashes": "^1.2.0",
|
"@noble/hashes": "^1.2.0",
|
||||||
"@waku/core": "0.0.37-987c6cd.0",
|
"@waku/core": "0.0.38-e224c05.0",
|
||||||
"@waku/utils": "0.0.25-987c6cd.0",
|
"@waku/utils": "0.0.26-e224c05.0",
|
||||||
"@waku/zerokit-rln-wasm": "^0.0.13",
|
"@waku/zerokit-rln-wasm": "^0.2.1",
|
||||||
"chai": "^5.1.2",
|
"chai": "^5.1.2",
|
||||||
"chai-as-promised": "^8.0.1",
|
"chai-as-promised": "^8.0.1",
|
||||||
"chai-spies": "^1.1.0",
|
"chai-spies": "^1.1.0",
|
||||||
@ -3158,13 +3158,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/utils": {
|
"node_modules/@waku/utils": {
|
||||||
"version": "0.0.25-987c6cd.0",
|
"version": "0.0.26-e224c05.0",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/utils/-/utils-0.0.25-987c6cd.0.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/utils/-/utils-0.0.26-e224c05.0.tgz",
|
||||||
"integrity": "sha512-HaYkDnVtpfmsXfDBd0gB63CxidIeE9gKMRMCaaywy6W07HK32ZgMgnD/BoPbaREa4BpEZELvW3qbYUydm3AKzw==",
|
"integrity": "sha512-eleBm6L5ky5xKRoCMXfFhLmvyGix8dhOXtDIS8/lIr+CJ09cDQoAHhhpPsJnLmf8DRxYQ1PDqPsEet9sa2LT9Q==",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@noble/hashes": "^1.3.2",
|
"@noble/hashes": "^1.3.2",
|
||||||
"@waku/interfaces": "0.0.32-987c6cd.0",
|
"@waku/interfaces": "0.0.33-e224c05.0",
|
||||||
"chai": "^4.3.10",
|
"chai": "^4.3.10",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"uint8arrays": "^5.0.1"
|
"uint8arrays": "^5.0.1"
|
||||||
@ -3243,9 +3243,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@waku/zerokit-rln-wasm": {
|
"node_modules/@waku/zerokit-rln-wasm": {
|
||||||
"version": "0.0.13",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.2.1.tgz",
|
||||||
"integrity": "sha512-x7CRIIslmfCmTZc7yVp3dhLlKeLUs8ILIm9kv7+wVJ23H4pPw0Z+uH0ueLIYYfwODI6fDiwJj3S1vdFzM8D1zA==",
|
"integrity": "sha512-2Xp7e92y4qZpsiTPGBSVr4gVJ9mJTLaudlo0DQxNpxJUBtoJKpxdH5xDCQDiorbkWZC2j9EId+ohhxHO/xC1QQ==",
|
||||||
"license": "MIT or Apache2"
|
"license": "MIT or Apache2"
|
||||||
},
|
},
|
||||||
"node_modules/abort-error": {
|
"node_modules/abort-error": {
|
||||||
@ -3670,9 +3670,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/bn.js": {
|
"node_modules/bn.js": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz",
|
||||||
"integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
|
"integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/brace-expansion": {
|
"node_modules/brace-expansion": {
|
||||||
@ -4392,9 +4392,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/elliptic/node_modules/bn.js": {
|
"node_modules/elliptic/node_modules/bn.js": {
|
||||||
"version": "4.12.1",
|
"version": "4.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz",
|
||||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
"integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
@ -6506,9 +6506,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/js-sha3": {
|
"node_modules/js-sha3": {
|
||||||
"version": "0.8.0",
|
"version": "0.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.9.3.tgz",
|
||||||
"integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==",
|
"integrity": "sha512-BcJPCQeLg6WjEx3FE591wVAevlli8lxsxm9/FzV4HXkV49TmBH38Yvrpce6fjbADGMKFrBMGTqrVz3qPIZ88Gg==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/js-tokens": {
|
"node_modules/js-tokens": {
|
||||||
@ -8227,9 +8227,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/race-event": {
|
"node_modules/race-event": {
|
||||||
"version": "1.6.0",
|
"version": "1.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/race-event/-/race-event-1.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/race-event/-/race-event-1.6.1.tgz",
|
||||||
"integrity": "sha512-hXkk3CDepWELBG2MsT/zIiTbjNNucMo49vwZEdjChJlxJivc8fWIu/Gh/4vEJdWsHDmnGCC6++ftP2Afep6RUg==",
|
"integrity": "sha512-vi7WH5g5KoTFpu2mme/HqZiWH14XSOtg5rfp6raBskBHl7wnmy3F/biAIyY5MsK+BHWhoPhxtZ1Y2R7OHHaWyQ==",
|
||||||
"license": "Apache-2.0 OR MIT",
|
"license": "Apache-2.0 OR MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"abort-error": "^1.0.1"
|
"abort-error": "^1.0.1"
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
"@radix-ui/react-toggle": "^1.1.2",
|
"@radix-ui/react-toggle": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
"@waku/rln": "0.1.7-987c6cd.0",
|
"@waku/rln": "0.1.8-e224c05.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^12.6.3",
|
"framer-motion": "^12.6.3",
|
||||||
|
|||||||
@ -36,21 +36,28 @@ export function MembershipRegistration({ tabId: _tabId }: MembershipRegistration
|
|||||||
|
|
||||||
const isLineaSepolia = chainId === 59141;
|
const isLineaSepolia = chainId === 59141;
|
||||||
|
|
||||||
const [price, setPrice] = useState<string>('');
|
// Store prices for both rate limits
|
||||||
|
const [prices, setPrices] = useState<{ [key: number]: string }>({});
|
||||||
const [priceLoading, setPriceLoading] = useState(false);
|
const [priceLoading, setPriceLoading] = useState(false);
|
||||||
const [priceError, setPriceError] = useState<string | null>(null);
|
const [priceError, setPriceError] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isLoading || !isInitialized || !isStarted) return;
|
if (isLoading || !isInitialized || !isStarted) return;
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
setPrice('');
|
setPrices({});
|
||||||
setPriceError(null);
|
setPriceError(null);
|
||||||
setPriceLoading(true);
|
setPriceLoading(true);
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const result = await getPriceForRateLimit(rateLimit);
|
const [price300, price600] = await Promise.all([
|
||||||
|
getPriceForRateLimit(300),
|
||||||
|
getPriceForRateLimit(600),
|
||||||
|
]);
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
setPrice(result.price.toString());
|
setPrices({
|
||||||
|
300: price300.price.toString(),
|
||||||
|
600: price600.price.toString(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
if (!cancelled) {
|
if (!cancelled) {
|
||||||
@ -61,7 +68,7 @@ export function MembershipRegistration({ tabId: _tabId }: MembershipRegistration
|
|||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, [rateLimit, getPriceForRateLimit, isLoading, isInitialized, isStarted]);
|
}, [getPriceForRateLimit, isLoading, isInitialized, isStarted]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -234,7 +241,7 @@ export function MembershipRegistration({ tabId: _tabId }: MembershipRegistration
|
|||||||
) : priceError ? (
|
) : priceError ? (
|
||||||
<span className="text-destructive">{priceError}</span>
|
<span className="text-destructive">{priceError}</span>
|
||||||
) : (
|
) : (
|
||||||
<>{rateLimit === 300 && <>Token spend: {price} WTT</>}</>
|
<>Token spend: {prices[300] ?? "--"} WTT</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
@ -246,14 +253,12 @@ export function MembershipRegistration({ tabId: _tabId }: MembershipRegistration
|
|||||||
) : priceError ? (
|
) : priceError ? (
|
||||||
<span className="text-destructive">{priceError}</span>
|
<span className="text-destructive">{priceError}</span>
|
||||||
) : (
|
) : (
|
||||||
<>{rateLimit === 600 && <>Token spend: {price} WTT</>}</>
|
<>Token spend: {prices[600] ?? "--"} WTT</>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</ToggleGroupItem>
|
</ToggleGroupItem>
|
||||||
</ToggleGroup>
|
</ToggleGroup>
|
||||||
</div>
|
</div>
|
||||||
{/* Show calculated token spend for selected rate limit */}
|
|
||||||
{/* Removed redundant price display below, now shown in each ToggleGroupItem */}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
|
|||||||
@ -1,484 +1,77 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { createContext, useContext, useState, useEffect, ReactNode, useCallback } from 'react';
|
import { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||||
import { KeystoreEntity, MembershipInfo, RLNCredentialsManager } from '@waku/rln';
|
import { RLNInstance } from '@waku/rln';
|
||||||
import { ethers } from 'ethers';
|
|
||||||
import { useKeystore } from '../keystore';
|
import { useKeystore } from '../keystore';
|
||||||
import { ERC20_ABI, LINEA_SEPOLIA_CONFIG, ensureLineaSepoliaNetwork } from '../../utils/network';
|
import { RLNContextType } from './types';
|
||||||
|
import { useWallet } from './wallet';
|
||||||
interface RLNContextType {
|
import { useRLNInitialization } from './initialization';
|
||||||
rln: RLNCredentialsManager | null;
|
import {
|
||||||
isInitialized: boolean;
|
getCurrentRateLimit,
|
||||||
isStarted: boolean;
|
getRateLimitsBounds,
|
||||||
error: string | null;
|
getPriceForRateLimit
|
||||||
initializeRLN: () => Promise<void>;
|
} from './rateLimits';
|
||||||
registerMembership: (rateLimit: number, saveOptions?: { password: string }) => Promise<{
|
import {
|
||||||
success: boolean;
|
registerMembership,
|
||||||
error?: string;
|
extendMembership,
|
||||||
credentials?: KeystoreEntity;
|
eraseMembership,
|
||||||
keystoreHash?: string;
|
withdrawDeposit,
|
||||||
}>;
|
getMembershipInfo
|
||||||
extendMembership: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
} from './operations';
|
||||||
eraseMembership: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
|
||||||
withdrawDeposit: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
|
||||||
getMembershipInfo: (hash: string, password: string) => Promise<MembershipInfo & {
|
|
||||||
address: string;
|
|
||||||
chainId: string;
|
|
||||||
treeIndex: number;
|
|
||||||
rateLimit: number;
|
|
||||||
}>;
|
|
||||||
rateMinLimit: number;
|
|
||||||
rateMaxLimit: number;
|
|
||||||
getCurrentRateLimit: () => Promise<number | null>;
|
|
||||||
getRateLimitsBounds: () => Promise<{ success: boolean; rateMinLimit: number; rateMaxLimit: number; error?: string }>;
|
|
||||||
saveCredentialsToKeystore: (credentials: KeystoreEntity, password: string) => Promise<string>;
|
|
||||||
isLoading: boolean;
|
|
||||||
getPriceForRateLimit: (rateLimit: number) => Promise<{ price: string }>;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RLNContext = createContext<RLNContextType | undefined>(undefined);
|
const RLNContext = createContext<RLNContextType | undefined>(undefined);
|
||||||
|
|
||||||
export function RLNProvider({ children }: { children: ReactNode }) {
|
export function RLNProvider({ children }: { children: ReactNode }) {
|
||||||
const [rln, setRln] = useState<RLNCredentialsManager | null>(null);
|
// State management
|
||||||
|
const [rln, setRln] = useState<RLNInstance | null>(null);
|
||||||
const [isInitialized, setIsInitialized] = useState(false);
|
const [isInitialized, setIsInitialized] = useState(false);
|
||||||
const [isStarted, setIsStarted] = useState(false);
|
const [isStarted, setIsStarted] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
// Get the signer from window.ethereum
|
|
||||||
const [signer, setSigner] = useState<ethers.Signer | null>(null);
|
|
||||||
const [isConnected, setIsConnected] = useState(false);
|
|
||||||
const [rateMinLimit, setRateMinLimit] = useState<number>(0);
|
const [rateMinLimit, setRateMinLimit] = useState<number>(0);
|
||||||
const [rateMaxLimit, setRateMaxLimit] = useState<number>(0);
|
const [rateMaxLimit, setRateMaxLimit] = useState<number>(0);
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
const { signer, isConnected } = useWallet();
|
||||||
const { saveCredentials: saveToKeystore, getDecryptedCredential } = useKeystore();
|
const { saveCredentials: saveToKeystore, getDecryptedCredential } = useKeystore();
|
||||||
|
|
||||||
// Listen for wallet connection
|
// Initialization logic
|
||||||
useEffect(() => {
|
const state = { rln, isInitialized, isStarted, error, isLoading, rateMinLimit, rateMaxLimit };
|
||||||
const checkWallet = async () => {
|
const actions = { setRln, setIsInitialized, setIsStarted, setError, setIsLoading, setRateMinLimit, setRateMaxLimit };
|
||||||
try {
|
const { initializeRLN, initializationInProgress, hasInitialized } = useRLNInitialization(
|
||||||
if (window.ethereum) {
|
state, actions, isConnected, signer
|
||||||
const provider = new ethers.providers.Web3Provider(window.ethereum);
|
);
|
||||||
const accounts = await provider.listAccounts();
|
|
||||||
|
|
||||||
if (accounts.length > 0) {
|
// Auto-initialize effect
|
||||||
const signer = provider.getSigner();
|
|
||||||
setSigner(signer);
|
|
||||||
setIsConnected(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSigner(null);
|
|
||||||
setIsConnected(false);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error checking wallet:", err);
|
|
||||||
setSigner(null);
|
|
||||||
setIsConnected(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
checkWallet();
|
|
||||||
|
|
||||||
// Listen for account changes
|
|
||||||
if (window.ethereum) {
|
|
||||||
window.ethereum.on('accountsChanged', checkWallet);
|
|
||||||
window.ethereum.on('chainChanged', checkWallet);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (window.ethereum) {
|
|
||||||
window.ethereum.removeListener('accountsChanged', checkWallet);
|
|
||||||
window.ethereum.removeListener('chainChanged', checkWallet);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const initializeRLN = useCallback(async () => {
|
|
||||||
console.log("InitializeRLN called. Connected:", isConnected, "Signer available:", !!signer);
|
|
||||||
|
|
||||||
if (!isConnected || !signer) {
|
|
||||||
console.log("Cannot initialize RLN: Wallet not connected or signer not available.");
|
|
||||||
setError("Wallet not connected. Please connect your wallet.");
|
|
||||||
setIsLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsLoading(true);
|
|
||||||
setError(null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
let currentRln = rln;
|
|
||||||
|
|
||||||
if (!currentRln) {
|
|
||||||
console.log("Creating RLN instance...");
|
|
||||||
try {
|
|
||||||
currentRln = new RLNCredentialsManager();
|
|
||||||
setRln(currentRln);
|
|
||||||
setIsInitialized(true);
|
|
||||||
console.log("RLN instance created successfully.");
|
|
||||||
} catch (createErr) {
|
|
||||||
console.error("Error creating RLN instance:", createErr);
|
|
||||||
setError(createErr instanceof Error ? createErr.message : 'Failed to create RLN instance');
|
|
||||||
setIsLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log("RLN instance already exists, skipping creation.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentRln && !isStarted) {
|
|
||||||
console.log("Starting RLN with signer...");
|
|
||||||
try {
|
|
||||||
await currentRln.start({ signer });
|
|
||||||
setIsStarted(true);
|
|
||||||
console.log("RLN started successfully.");
|
|
||||||
|
|
||||||
if (currentRln.contract) {
|
|
||||||
try {
|
|
||||||
const minLimit = await currentRln.contract.getMinRateLimit();
|
|
||||||
const maxLimit = await currentRln.contract.getMaxRateLimit();
|
|
||||||
if (minLimit !== undefined && maxLimit !== undefined) {
|
|
||||||
setRateMinLimit(minLimit);
|
|
||||||
setRateMaxLimit(maxLimit);
|
|
||||||
console.log("Rate limits fetched:", { min: minLimit, max: maxLimit });
|
|
||||||
} else {
|
|
||||||
console.warn("Could not fetch rate limits: undefined values returned.");
|
|
||||||
}
|
|
||||||
} catch (limitErr) {
|
|
||||||
console.warn("Could not fetch rate limits after start:", limitErr);
|
|
||||||
// Don't fail initialization for this, but log it.
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.warn("RLN contract not available after start, cannot fetch rate limits.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (startErr) {
|
|
||||||
console.error("Error starting RLN:", startErr);
|
|
||||||
setError(startErr instanceof Error ? startErr.message : 'Failed to start RLN');
|
|
||||||
setIsStarted(false);
|
|
||||||
}
|
|
||||||
} else if (isStarted) {
|
|
||||||
console.log("RLN already started.");
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error in initializeRLN:', err);
|
|
||||||
setError(err instanceof Error ? err.message : 'Failed to initialize RLN');
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}, [isConnected, signer, rln, isStarted]);
|
|
||||||
|
|
||||||
// Auto-initialize effect for Light implementation
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('Auto-init check:', {
|
console.log('Auto-init check:', {
|
||||||
isConnected,
|
isConnected,
|
||||||
hasSigner: !!signer,
|
hasSigner: !!signer,
|
||||||
isInitialized,
|
isInitialized,
|
||||||
isStarted,
|
isStarted,
|
||||||
isLoading
|
isLoading,
|
||||||
|
initInProgress: initializationInProgress,
|
||||||
|
hasInitialized
|
||||||
});
|
});
|
||||||
if (isConnected && signer && !isInitialized && !isStarted && !isLoading) {
|
|
||||||
|
if (isConnected &&
|
||||||
|
signer &&
|
||||||
|
!isInitialized &&
|
||||||
|
!isStarted &&
|
||||||
|
!isLoading &&
|
||||||
|
!initializationInProgress &&
|
||||||
|
!hasInitialized) {
|
||||||
console.log('Auto-initializing Light RLN implementation...');
|
console.log('Auto-initializing Light RLN implementation...');
|
||||||
initializeRLN();
|
initializeRLN();
|
||||||
}
|
}
|
||||||
}, [isConnected, signer, isInitialized, isStarted, isLoading, initializeRLN]);
|
}, [isConnected, signer, isInitialized, isStarted, isLoading, initializationInProgress, hasInitialized, initializeRLN]);
|
||||||
|
|
||||||
const getCurrentRateLimit = async (): Promise<number | null> => {
|
// Cleanup on unmount
|
||||||
try {
|
useEffect(() => {
|
||||||
if (!rln || !rln.contract || !isStarted) {
|
return () => {
|
||||||
console.log("Cannot get rate limit: RLN not initialized or started");
|
console.log("RLN Provider unmounting");
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rateLimit = rln.contract.getRateLimit();
|
|
||||||
console.log("Current rate limit:", rateLimit);
|
|
||||||
return rateLimit;
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error getting current rate limit:", err);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getRateLimitsBounds = async () => {
|
|
||||||
try {
|
|
||||||
if (!rln || !isStarted) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
rateMinLimit: 0,
|
|
||||||
rateMaxLimit: 0,
|
|
||||||
error: 'RLN not initialized or not started'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const minLimit = await rln.contract?.getMinRateLimit();
|
|
||||||
const maxLimit = await rln.contract?.getMaxRateLimit();
|
|
||||||
if (minLimit !== undefined && maxLimit !== undefined) {
|
|
||||||
// Update state
|
|
||||||
setRateMinLimit(minLimit);
|
|
||||||
setRateMaxLimit(maxLimit);
|
|
||||||
} else {
|
|
||||||
throw new Error("Rate limits not available");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
rateMinLimit: minLimit,
|
|
||||||
rateMaxLimit: maxLimit
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
rateMinLimit: rateMinLimit,
|
|
||||||
rateMaxLimit: rateMaxLimit,
|
|
||||||
error: err instanceof Error ? err.message : 'Failed to get rate limits'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const saveCredentialsToKeystore = async (credentials: KeystoreEntity, password: string): Promise<string> => {
|
|
||||||
try {
|
|
||||||
return await saveToKeystore(credentials, password);
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error saving credentials to keystore:", err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const registerMembership = async (rateLimit: number, saveOptions?: { password: string }) => {
|
|
||||||
console.log("registerMembership called with rate limit:", rateLimit);
|
|
||||||
|
|
||||||
if (!rln || !isStarted) {
|
|
||||||
return { success: false, error: 'RLN not initialized or not started' };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!signer) {
|
|
||||||
return { success: false, error: 'No signer available' };
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Validate rate limit
|
|
||||||
if (rateLimit < rateMinLimit || rateLimit > rateMaxLimit) {
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: `Rate limit must be between ${rateMinLimit} and ${rateMaxLimit}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
await rln.contract?.setRateLimit(rateLimit);
|
|
||||||
|
|
||||||
// Ensure we're on the correct network
|
|
||||||
const isOnLineaSepolia = await ensureLineaSepoliaNetwork(signer);
|
|
||||||
if (!isOnLineaSepolia) {
|
|
||||||
console.warn("Could not switch to Linea Sepolia network. Registration may fail.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get user address and contract address
|
|
||||||
const userAddress = await signer.getAddress();
|
|
||||||
|
|
||||||
if (!rln.contract || !rln.contract.address) {
|
|
||||||
return { success: false, error: "RLN contract address not available. Cannot proceed with registration." };
|
|
||||||
}
|
|
||||||
|
|
||||||
const contractAddress = rln.contract.address;
|
|
||||||
const tokenAddress = LINEA_SEPOLIA_CONFIG.tokenAddress;
|
|
||||||
|
|
||||||
// Create token contract instance
|
|
||||||
const tokenContract = new ethers.Contract(
|
|
||||||
tokenAddress,
|
|
||||||
ERC20_ABI,
|
|
||||||
signer
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check token balance
|
|
||||||
const tokenBalance = await tokenContract.balanceOf(userAddress);
|
|
||||||
if (tokenBalance.isZero()) {
|
|
||||||
return { success: false, error: "You need tokens to register a membership. Your token balance is zero." };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and approve token allowance if needed
|
|
||||||
const currentAllowance = await tokenContract.allowance(userAddress, contractAddress);
|
|
||||||
if (currentAllowance.eq(0)) {
|
|
||||||
console.log("Requesting token approval...");
|
|
||||||
|
|
||||||
// Approve a large amount (max uint256)
|
|
||||||
const maxUint256 = ethers.constants.MaxUint256;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const approveTx = await tokenContract.approve(contractAddress, maxUint256);
|
|
||||||
console.log("Approval transaction submitted:", approveTx.hash);
|
|
||||||
|
|
||||||
// Wait for the transaction to be mined
|
|
||||||
await approveTx.wait(1);
|
|
||||||
console.log("Token approval confirmed");
|
|
||||||
} catch (approvalErr) {
|
|
||||||
console.error("Error during token approval:", approvalErr);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: `Failed to approve token: ${approvalErr instanceof Error ? approvalErr.message : String(approvalErr)}`
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
console.log("Token allowance already sufficient");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate signature for identity
|
|
||||||
const timestamp = Date.now();
|
|
||||||
const message = `Sign this message to generate your RLN credentials ${timestamp}`;
|
|
||||||
const signature = await signer.signMessage(message);
|
|
||||||
|
|
||||||
// Register membership
|
|
||||||
console.log("Registering membership...");
|
|
||||||
const credentials = await rln.registerMembership({
|
|
||||||
signature: signature
|
|
||||||
});
|
|
||||||
console.log("Credentials:", credentials);
|
|
||||||
|
|
||||||
// If we have save options, save to keystore
|
|
||||||
let keystoreHash: string | undefined;
|
|
||||||
if (saveOptions && saveOptions.password && credentials) {
|
|
||||||
try {
|
|
||||||
const credentialsEntity = credentials as KeystoreEntity;
|
|
||||||
keystoreHash = await saveCredentialsToKeystore(credentialsEntity, saveOptions.password);
|
|
||||||
console.log("Credentials saved to keystore with hash:", keystoreHash);
|
|
||||||
} catch (saveErr) {
|
|
||||||
console.error("Error saving credentials to keystore:", saveErr);
|
|
||||||
// Continue without failing the overall registration
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
credentials: credentials as KeystoreEntity,
|
|
||||||
keystoreHash
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
console.error("Error registering membership:", err);
|
|
||||||
|
|
||||||
let errorMsg = "Failed to register membership";
|
|
||||||
if (err instanceof Error) {
|
|
||||||
errorMsg = err.message;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { success: false, error: errorMsg };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const getMembershipInfo = async (hash: string, password: string) => {
|
|
||||||
if (!rln || !rln.contract) {
|
|
||||||
throw new Error('RLN not initialized or contract not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
const credential = await getDecryptedCredential(hash, password);
|
|
||||||
if (!credential) {
|
|
||||||
throw new Error('Could not decrypt credential');
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const membershipInfo = await rln.contract.getMembershipInfo(credential.identity.IDCommitmentBigInt);
|
|
||||||
if (!membershipInfo) {
|
|
||||||
throw new Error('Could not fetch membership info');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
...membershipInfo,
|
|
||||||
address: rln.contract.address,
|
|
||||||
chainId: LINEA_SEPOLIA_CONFIG.chainId.toString(),
|
|
||||||
treeIndex: Number(membershipInfo.index.toString()),
|
|
||||||
rateLimit: Number(membershipInfo.rateLimit.toString())
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log("error", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const extendMembership = async (hash: string, password: string) => {
|
|
||||||
try {
|
|
||||||
if (!rln || !rln.contract) {
|
|
||||||
throw new Error('RLN not initialized or contract not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
const credential = await getDecryptedCredential(hash, password);
|
|
||||||
if (!credential) {
|
|
||||||
throw new Error('Could not decrypt credential');
|
|
||||||
}
|
|
||||||
|
|
||||||
await rln.contract.extendMembership(credential.identity.IDCommitmentBigInt);
|
|
||||||
return { success: true };
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error extending membership:', err);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: err instanceof Error ? err.message : 'Failed to extend membership'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const eraseMembership = async (hash: string, password: string) => {
|
|
||||||
try {
|
|
||||||
if (!rln || !rln.contract) {
|
|
||||||
throw new Error('RLN not initialized or contract not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
const credential = await getDecryptedCredential(hash, password);
|
|
||||||
if (!credential) {
|
|
||||||
throw new Error('Could not decrypt credential');
|
|
||||||
}
|
|
||||||
await rln.contract.eraseMembership(credential.identity.IDCommitmentBigInt);
|
|
||||||
return { success: true };
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error erasing membership:', err);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: err instanceof Error ? err.message : 'Failed to erase membership'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const withdrawDeposit = async (hash: string, password: string) => {
|
|
||||||
try {
|
|
||||||
if (!rln || !rln.contract) {
|
|
||||||
throw new Error('RLN not initialized or contract not available');
|
|
||||||
}
|
|
||||||
|
|
||||||
const credential = await getDecryptedCredential(hash, password);
|
|
||||||
if (!credential) {
|
|
||||||
throw new Error('Could not decrypt credential');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get token address from config
|
|
||||||
const tokenAddress = LINEA_SEPOLIA_CONFIG.tokenAddress;
|
|
||||||
const userAddress = await signer?.getAddress();
|
|
||||||
|
|
||||||
if (!userAddress) {
|
|
||||||
throw new Error('No signer available');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call withdraw with token address and holder
|
|
||||||
await rln.contract.withdraw(tokenAddress, userAddress);
|
|
||||||
return { success: true };
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error withdrawing deposit:', err);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
error: err instanceof Error ? err.message : 'Failed to withdraw deposit'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPriceForRateLimit = async (rateLimit: number): Promise<{ price: string }> => {
|
|
||||||
try {
|
|
||||||
if (!rln || !rln.contract || !isStarted) {
|
|
||||||
throw new Error('RLN not initialized or contract not available');
|
|
||||||
}
|
|
||||||
const result = await rln.contract.getPriceForRateLimit(rateLimit);
|
|
||||||
const formatted = ethers.utils.formatUnits(result.price, 18);
|
|
||||||
return { price: formatted };
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Error getting price for rate limit:', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RLNContext.Provider
|
<RLNContext.Provider
|
||||||
@ -488,18 +81,30 @@ export function RLNProvider({ children }: { children: ReactNode }) {
|
|||||||
isStarted,
|
isStarted,
|
||||||
error,
|
error,
|
||||||
initializeRLN,
|
initializeRLN,
|
||||||
registerMembership,
|
registerMembership: (rateLimit, saveOptions) =>
|
||||||
extendMembership,
|
registerMembership(rln, isStarted, signer, rateLimit, rateMinLimit, rateMaxLimit, saveToKeystore, saveOptions),
|
||||||
eraseMembership,
|
extendMembership: (hash, password) =>
|
||||||
withdrawDeposit,
|
extendMembership(rln, hash, password, getDecryptedCredential),
|
||||||
getMembershipInfo,
|
eraseMembership: (hash, password) =>
|
||||||
|
eraseMembership(rln, hash, password, getDecryptedCredential),
|
||||||
|
withdrawDeposit: (hash, password) =>
|
||||||
|
withdrawDeposit(rln, signer, hash, password, getDecryptedCredential),
|
||||||
|
getMembershipInfo: (hash, password) =>
|
||||||
|
getMembershipInfo(rln, hash, password, getDecryptedCredential),
|
||||||
rateMinLimit,
|
rateMinLimit,
|
||||||
rateMaxLimit,
|
rateMaxLimit,
|
||||||
getCurrentRateLimit,
|
getCurrentRateLimit: () => getCurrentRateLimit(rln, isStarted),
|
||||||
getRateLimitsBounds,
|
getRateLimitsBounds: async () => {
|
||||||
|
const result = await getRateLimitsBounds(rln, isStarted, rateMinLimit, rateMaxLimit);
|
||||||
|
if (result.success) {
|
||||||
|
setRateMinLimit(result.rateMinLimit);
|
||||||
|
setRateMaxLimit(result.rateMaxLimit);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
saveCredentialsToKeystore: saveToKeystore,
|
saveCredentialsToKeystore: saveToKeystore,
|
||||||
isLoading,
|
isLoading,
|
||||||
getPriceForRateLimit
|
getPriceForRateLimit: (rateLimit) => getPriceForRateLimit(rln, isStarted, rateLimit)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@ -1 +1,40 @@
|
|||||||
|
// Main context exports
|
||||||
export { RLNProvider, useRLN } from './RLNContext';
|
export { RLNProvider, useRLN } from './RLNContext';
|
||||||
|
|
||||||
|
// Type exports
|
||||||
|
export type {
|
||||||
|
RLNContextType,
|
||||||
|
RateLimitBounds,
|
||||||
|
RegistrationResult,
|
||||||
|
OperationResult,
|
||||||
|
MembershipInfoExtended,
|
||||||
|
PriceResult
|
||||||
|
} from './types';
|
||||||
|
|
||||||
|
// Singleton exports
|
||||||
|
export { getOrCreateRLNInstance, resetGlobalRLNInstance } from './singleton';
|
||||||
|
|
||||||
|
// Wallet exports
|
||||||
|
export { useWallet, ensureCorrectNetwork, getUserAddress } from './wallet';
|
||||||
|
export type { WalletState, UseWalletReturn } from './wallet';
|
||||||
|
|
||||||
|
// Initialization exports
|
||||||
|
export { useRLNInitialization } from './initialization';
|
||||||
|
export type { InitializationState, InitializationActions } from './initialization';
|
||||||
|
|
||||||
|
// Rate limit exports
|
||||||
|
export {
|
||||||
|
getCurrentRateLimit,
|
||||||
|
getRateLimitsBounds,
|
||||||
|
getPriceForRateLimit,
|
||||||
|
validateRateLimit
|
||||||
|
} from './rateLimits';
|
||||||
|
|
||||||
|
// Operations exports
|
||||||
|
export {
|
||||||
|
registerMembership,
|
||||||
|
getMembershipInfo,
|
||||||
|
extendMembership,
|
||||||
|
eraseMembership,
|
||||||
|
withdrawDeposit
|
||||||
|
} from './operations';
|
||||||
212
src/contexts/rln/initialization.ts
Normal file
212
src/contexts/rln/initialization.ts
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useCallback, useRef } from 'react';
|
||||||
|
import { RLNInstance } from '@waku/rln';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import { getOrCreateRLNInstance } from './singleton';
|
||||||
|
|
||||||
|
export interface InitializationState {
|
||||||
|
rln: RLNInstance | null;
|
||||||
|
isInitialized: boolean;
|
||||||
|
isStarted: boolean;
|
||||||
|
error: string | null;
|
||||||
|
isLoading: boolean;
|
||||||
|
rateMinLimit: number;
|
||||||
|
rateMaxLimit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InitializationActions {
|
||||||
|
setRln: (rln: RLNInstance | null) => void;
|
||||||
|
setIsInitialized: (initialized: boolean) => void;
|
||||||
|
setIsStarted: (started: boolean) => void;
|
||||||
|
setError: (error: string | null) => void;
|
||||||
|
setIsLoading: (loading: boolean) => void;
|
||||||
|
setRateMinLimit: (limit: number) => void;
|
||||||
|
setRateMaxLimit: (limit: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useRLNInitialization = (
|
||||||
|
state: InitializationState,
|
||||||
|
actions: InitializationActions,
|
||||||
|
isConnected: boolean,
|
||||||
|
signer: ethers.Signer | null
|
||||||
|
) => {
|
||||||
|
// Use refs to prevent race conditions and ensure single initialization
|
||||||
|
const initializationInProgress = useRef(false);
|
||||||
|
const hasInitialized = useRef(false);
|
||||||
|
const lastInitAttempt = useRef(0);
|
||||||
|
const retryCount = useRef(0);
|
||||||
|
const maxRetries = 3;
|
||||||
|
const retryDelay = 1000; // Start with 1 second delay
|
||||||
|
|
||||||
|
const initializeRLN = useCallback(async () => {
|
||||||
|
|
||||||
|
console.log("InitializeRLN called. Connected:", isConnected, "Signer available:", !!signer);
|
||||||
|
|
||||||
|
// Prevent multiple simultaneous initialization attempts
|
||||||
|
if (initializationInProgress.current) {
|
||||||
|
console.log("Initialization already in progress, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent rapid retry attempts
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - lastInitAttempt.current < retryDelay) {
|
||||||
|
console.log("Too soon since last attempt, skipping...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastInitAttempt.current = now;
|
||||||
|
|
||||||
|
if (!isConnected || !signer) {
|
||||||
|
console.log("Cannot initialize RLN: Wallet not connected or signer not available.");
|
||||||
|
actions.setError("Wallet not connected. Please connect your wallet.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If already initialized and started, no need to reinitialize
|
||||||
|
if (state.isInitialized && state.isStarted && state.rln) {
|
||||||
|
console.log("RLN already initialized and started");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've already successfully initialized once, don't reinitialize
|
||||||
|
if (hasInitialized.current && state.rln) {
|
||||||
|
console.log("RLN already initialized once, reusing existing instance");
|
||||||
|
if (!state.isStarted) {
|
||||||
|
try {
|
||||||
|
await state.rln.start({ signer });
|
||||||
|
actions.setIsStarted(true);
|
||||||
|
console.log("RLN restarted successfully.");
|
||||||
|
} catch (startErr) {
|
||||||
|
console.error("Error restarting RLN:", startErr);
|
||||||
|
actions.setError(startErr instanceof Error ? startErr.message : 'Failed to restart RLN');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
initializationInProgress.current = true;
|
||||||
|
actions.setIsLoading(true);
|
||||||
|
actions.setError(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
let currentRln = state.rln;
|
||||||
|
|
||||||
|
// Cleanup existing instance before creating new one
|
||||||
|
if (currentRln) {
|
||||||
|
console.log("Cleaning up existing RLN instance...");
|
||||||
|
actions.setRln(null);
|
||||||
|
actions.setIsInitialized(false);
|
||||||
|
actions.setIsStarted(false);
|
||||||
|
currentRln = null;
|
||||||
|
|
||||||
|
// Small delay to ensure cleanup is complete
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentRln) {
|
||||||
|
console.log("Creating new RLN instance...");
|
||||||
|
try {
|
||||||
|
// Add a small delay before WASM initialization to prevent rapid calls
|
||||||
|
if (retryCount.current > 0) {
|
||||||
|
const delay = retryDelay * Math.pow(2, retryCount.current - 1); // Exponential backoff
|
||||||
|
console.log(`Waiting ${delay}ms before retry attempt ${retryCount.current}...`);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure we're not in a rapid initialization loop
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
|
||||||
|
// Use singleton pattern to ensure WASM is only initialized once
|
||||||
|
console.time("RLN WASM BLOB");
|
||||||
|
currentRln = await getOrCreateRLNInstance();
|
||||||
|
console.timeEnd("RLN WASM BLOB");
|
||||||
|
actions.setRln(currentRln);
|
||||||
|
actions.setIsInitialized(true);
|
||||||
|
hasInitialized.current = true; // Mark as successfully initialized
|
||||||
|
retryCount.current = 0; // Reset retry count on success
|
||||||
|
console.log("RLN instance created successfully.");
|
||||||
|
} catch (createErr) {
|
||||||
|
console.error("Error creating RLN instance:", createErr);
|
||||||
|
|
||||||
|
// Check if this is a WASM-related error and implement retry logic
|
||||||
|
const errorMessage = createErr instanceof Error ? createErr.message : String(createErr);
|
||||||
|
const isWasmError = errorMessage.includes('WebAssembly') ||
|
||||||
|
errorMessage.includes('wasm') ||
|
||||||
|
errorMessage.includes('Table.grow');
|
||||||
|
|
||||||
|
if (isWasmError && retryCount.current < maxRetries) {
|
||||||
|
retryCount.current++;
|
||||||
|
console.log(`WASM error detected, retrying... (attempt ${retryCount.current}/${maxRetries})`);
|
||||||
|
actions.setError(`Initializing RLN (attempt ${retryCount.current}/${maxRetries})...`);
|
||||||
|
|
||||||
|
// Release the lock and retry after a delay
|
||||||
|
initializationInProgress.current = false;
|
||||||
|
actions.setIsLoading(false);
|
||||||
|
|
||||||
|
// Retry with exponential backoff
|
||||||
|
setTimeout(() => {
|
||||||
|
initializeRLN();
|
||||||
|
}, retryDelay * Math.pow(2, retryCount.current - 1));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
actions.setError(errorMessage);
|
||||||
|
actions.setIsLoading(false);
|
||||||
|
initializationInProgress.current = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("RLN instance already exists, skipping creation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentRln && !state.isStarted) {
|
||||||
|
console.log("Starting RLN with signer...");
|
||||||
|
try {
|
||||||
|
await currentRln.start({ signer });
|
||||||
|
actions.setIsStarted(true);
|
||||||
|
console.log("RLN started successfully.");
|
||||||
|
|
||||||
|
if (currentRln.contract) {
|
||||||
|
try {
|
||||||
|
const minLimit = await currentRln.contract.getMinRateLimit();
|
||||||
|
const maxLimit = await currentRln.contract.getMaxRateLimit();
|
||||||
|
if (minLimit !== undefined && maxLimit !== undefined) {
|
||||||
|
actions.setRateMinLimit(minLimit);
|
||||||
|
actions.setRateMaxLimit(maxLimit);
|
||||||
|
console.log("Rate limits fetched:", { min: minLimit, max: maxLimit });
|
||||||
|
} else {
|
||||||
|
console.warn("Could not fetch rate limits: undefined values returned.");
|
||||||
|
}
|
||||||
|
} catch (limitErr) {
|
||||||
|
console.warn("Could not fetch rate limits after start:", limitErr);
|
||||||
|
// Don't fail initialization for this, but log it.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn("RLN contract not available after start, cannot fetch rate limits.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (startErr) {
|
||||||
|
console.error("Error starting RLN:", startErr);
|
||||||
|
actions.setError(startErr instanceof Error ? startErr.message : 'Failed to start RLN');
|
||||||
|
actions.setIsStarted(false);
|
||||||
|
}
|
||||||
|
} else if (state.isStarted) {
|
||||||
|
console.log("RLN already started.");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error in initializeRLN:', err);
|
||||||
|
actions.setError(err instanceof Error ? err.message : 'Failed to initialize RLN');
|
||||||
|
} finally {
|
||||||
|
actions.setIsLoading(false);
|
||||||
|
initializationInProgress.current = false;
|
||||||
|
}
|
||||||
|
}, [isConnected, signer, state.rln, state.isStarted, state.isInitialized, actions]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
initializeRLN,
|
||||||
|
initializationInProgress: initializationInProgress.current,
|
||||||
|
hasInitialized: hasInitialized.current
|
||||||
|
};
|
||||||
|
};
|
||||||
271
src/contexts/rln/operations.ts
Normal file
271
src/contexts/rln/operations.ts
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
import { ethers } from 'ethers';
|
||||||
|
import { RLNInstance, KeystoreEntity } from '@waku/rln';
|
||||||
|
import { ERC20_ABI, LINEA_SEPOLIA_CONFIG } from '../../utils/network';
|
||||||
|
import { RegistrationResult, OperationResult, MembershipInfoExtended } from './types';
|
||||||
|
import { ensureCorrectNetwork, getUserAddress } from './wallet';
|
||||||
|
import { validateRateLimit } from './rateLimits';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new RLN membership
|
||||||
|
*/
|
||||||
|
export const registerMembership = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
isStarted: boolean,
|
||||||
|
signer: ethers.Signer | null,
|
||||||
|
rateLimit: number,
|
||||||
|
rateMinLimit: number,
|
||||||
|
rateMaxLimit: number,
|
||||||
|
saveCredentialsToKeystore: (credentials: KeystoreEntity, password: string) => Promise<string>,
|
||||||
|
saveOptions?: { password: string }
|
||||||
|
): Promise<RegistrationResult> => {
|
||||||
|
console.log("registerMembership called with rate limit:", rateLimit);
|
||||||
|
|
||||||
|
if (!rln || !isStarted) {
|
||||||
|
return { success: false, error: 'RLN not initialized or not started' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signer) {
|
||||||
|
return { success: false, error: 'No signer available' };
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Validate rate limit
|
||||||
|
const validation = validateRateLimit(rateLimit, rateMinLimit, rateMaxLimit);
|
||||||
|
if (!validation.isValid) {
|
||||||
|
return { success: false, error: validation.error };
|
||||||
|
}
|
||||||
|
|
||||||
|
await rln.contract?.setRateLimit(rateLimit);
|
||||||
|
|
||||||
|
// Ensure we're on the correct network
|
||||||
|
const isOnLineaSepolia = await ensureCorrectNetwork(signer);
|
||||||
|
if (!isOnLineaSepolia) {
|
||||||
|
console.warn("Could not switch to Linea Sepolia network. Registration may fail.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get user address and contract address
|
||||||
|
const userAddress = await getUserAddress(signer);
|
||||||
|
|
||||||
|
if (!rln.contract || !rln.contract.address) {
|
||||||
|
return { success: false, error: "RLN contract address not available. Cannot proceed with registration." };
|
||||||
|
}
|
||||||
|
|
||||||
|
const contractAddress = rln.contract.address;
|
||||||
|
const tokenAddress = LINEA_SEPOLIA_CONFIG.tokenAddress;
|
||||||
|
|
||||||
|
// Create token contract instance
|
||||||
|
const tokenContract = new ethers.Contract(
|
||||||
|
tokenAddress,
|
||||||
|
ERC20_ABI,
|
||||||
|
signer
|
||||||
|
);
|
||||||
|
|
||||||
|
// Check token balance
|
||||||
|
const tokenBalance = await tokenContract.balanceOf(userAddress);
|
||||||
|
if (tokenBalance.isZero()) {
|
||||||
|
return { success: false, error: "You need tokens to register a membership. Your token balance is zero." };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and approve token allowance if needed
|
||||||
|
const currentAllowance = await tokenContract.allowance(userAddress, contractAddress);
|
||||||
|
if (currentAllowance.eq(0)) {
|
||||||
|
console.log("Requesting token approval...");
|
||||||
|
|
||||||
|
// Approve a large amount (max uint256)
|
||||||
|
const maxUint256 = ethers.constants.MaxUint256;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const approveTx = await tokenContract.approve(contractAddress, maxUint256);
|
||||||
|
console.log("Approval transaction submitted:", approveTx.hash);
|
||||||
|
|
||||||
|
// Wait for the transaction to be mined
|
||||||
|
await approveTx.wait(1);
|
||||||
|
console.log("Token approval confirmed");
|
||||||
|
} catch (approvalErr) {
|
||||||
|
console.error("Error during token approval:", approvalErr);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: `Failed to approve token: ${approvalErr instanceof Error ? approvalErr.message : String(approvalErr)}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Token allowance already sufficient");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate signature for identity
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const message = `Sign this message to generate your RLN credentials ${timestamp}`;
|
||||||
|
const signature = await signer.signMessage(message);
|
||||||
|
|
||||||
|
// Register membership
|
||||||
|
console.log("Registering membership...");
|
||||||
|
console.log({signature})
|
||||||
|
const credentials = await rln.registerMembership({
|
||||||
|
signature: signature
|
||||||
|
});
|
||||||
|
console.log("Credentials:", credentials);
|
||||||
|
|
||||||
|
// If we have save options, save to keystore
|
||||||
|
let keystoreHash: string | undefined;
|
||||||
|
if (saveOptions && saveOptions.password && credentials) {
|
||||||
|
try {
|
||||||
|
const credentialsEntity = credentials as KeystoreEntity;
|
||||||
|
keystoreHash = await saveCredentialsToKeystore(credentialsEntity, saveOptions.password);
|
||||||
|
console.log("Credentials saved to keystore with hash:", keystoreHash);
|
||||||
|
} catch (saveErr) {
|
||||||
|
console.error("Error saving credentials to keystore:", saveErr);
|
||||||
|
// Continue without failing the overall registration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
credentials: credentials as KeystoreEntity,
|
||||||
|
keystoreHash
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error registering membership:", err);
|
||||||
|
|
||||||
|
let errorMsg = "Failed to register membership";
|
||||||
|
if (err instanceof Error) {
|
||||||
|
errorMsg = err.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { success: false, error: errorMsg };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get membership information
|
||||||
|
*/
|
||||||
|
export const getMembershipInfo = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
hash: string,
|
||||||
|
password: string,
|
||||||
|
getDecryptedCredential: (hash: string, password: string) => Promise<KeystoreEntity | null>
|
||||||
|
): Promise<MembershipInfoExtended> => {
|
||||||
|
if (!rln || !rln.contract) {
|
||||||
|
throw new Error('RLN not initialized or contract not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const credential = await getDecryptedCredential(hash, password);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('Could not decrypt credential');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const membershipInfo = await rln.contract.getMembershipInfo(credential.identity.IDCommitmentBigInt);
|
||||||
|
if (!membershipInfo) {
|
||||||
|
throw new Error('Could not fetch membership info');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...membershipInfo,
|
||||||
|
address: rln.contract.address,
|
||||||
|
chainId: LINEA_SEPOLIA_CONFIG.chainId.toString(),
|
||||||
|
treeIndex: Number(membershipInfo.index.toString()),
|
||||||
|
rateLimit: Number(membershipInfo.rateLimit.toString())
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log("error", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend membership
|
||||||
|
*/
|
||||||
|
export const extendMembership = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
hash: string,
|
||||||
|
password: string,
|
||||||
|
getDecryptedCredential: (hash: string, password: string) => Promise<KeystoreEntity | null>
|
||||||
|
): Promise<OperationResult> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !rln.contract) {
|
||||||
|
throw new Error('RLN not initialized or contract not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const credential = await getDecryptedCredential(hash, password);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('Could not decrypt credential');
|
||||||
|
}
|
||||||
|
|
||||||
|
await rln.contract.extendMembership(credential.identity.IDCommitmentBigInt);
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error extending membership:', err);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: err instanceof Error ? err.message : 'Failed to extend membership'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Erase membership
|
||||||
|
*/
|
||||||
|
export const eraseMembership = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
hash: string,
|
||||||
|
password: string,
|
||||||
|
getDecryptedCredential: (hash: string, password: string) => Promise<KeystoreEntity | null>
|
||||||
|
): Promise<OperationResult> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !rln.contract) {
|
||||||
|
throw new Error('RLN not initialized or contract not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const credential = await getDecryptedCredential(hash, password);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('Could not decrypt credential');
|
||||||
|
}
|
||||||
|
await rln.contract.eraseMembership(credential.identity.IDCommitmentBigInt);
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error erasing membership:', err);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: err instanceof Error ? err.message : 'Failed to erase membership'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraw deposit
|
||||||
|
*/
|
||||||
|
export const withdrawDeposit = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
signer: ethers.Signer | null,
|
||||||
|
hash: string,
|
||||||
|
password: string,
|
||||||
|
getDecryptedCredential: (hash: string, password: string) => Promise<KeystoreEntity | null>
|
||||||
|
): Promise<OperationResult> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !rln.contract) {
|
||||||
|
throw new Error('RLN not initialized or contract not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const credential = await getDecryptedCredential(hash, password);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('Could not decrypt credential');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get token address from config
|
||||||
|
const tokenAddress = LINEA_SEPOLIA_CONFIG.tokenAddress;
|
||||||
|
const userAddress = await signer?.getAddress();
|
||||||
|
|
||||||
|
if (!userAddress) {
|
||||||
|
throw new Error('No signer available');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call withdraw with token address and holder
|
||||||
|
await rln.contract.withdraw(tokenAddress, userAddress);
|
||||||
|
return { success: true };
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error withdrawing deposit:', err);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: err instanceof Error ? err.message : 'Failed to withdraw deposit'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
108
src/contexts/rln/rateLimits.ts
Normal file
108
src/contexts/rln/rateLimits.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { RLNInstance } from '@waku/rln';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import { RateLimitBounds, PriceResult } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current rate limit from RLN contract
|
||||||
|
*/
|
||||||
|
export const getCurrentRateLimit = async (rln: RLNInstance | null, isStarted: boolean): Promise<number | null> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !rln.contract || !isStarted) {
|
||||||
|
console.log("Cannot get rate limit: RLN not initialized or started");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rateLimit = rln.contract.getRateLimit();
|
||||||
|
console.log("Current rate limit:", rateLimit);
|
||||||
|
return rateLimit;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error getting current rate limit:", err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get rate limit bounds from RLN contract
|
||||||
|
*/
|
||||||
|
export const getRateLimitsBounds = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
isStarted: boolean,
|
||||||
|
currentRateMinLimit: number,
|
||||||
|
currentRateMaxLimit: number
|
||||||
|
): Promise<RateLimitBounds> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !isStarted) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
rateMinLimit: 0,
|
||||||
|
rateMaxLimit: 0,
|
||||||
|
error: 'RLN not initialized or not started'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const minLimit = await rln.contract?.getMinRateLimit();
|
||||||
|
const maxLimit = await rln.contract?.getMaxRateLimit();
|
||||||
|
|
||||||
|
if (minLimit !== undefined && maxLimit !== undefined) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
rateMinLimit: minLimit,
|
||||||
|
rateMaxLimit: maxLimit
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("Rate limits not available");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
rateMinLimit: currentRateMinLimit,
|
||||||
|
rateMaxLimit: currentRateMaxLimit,
|
||||||
|
error: err instanceof Error ? err.message : 'Failed to get rate limits'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get price for a specific rate limit
|
||||||
|
*/
|
||||||
|
export const getPriceForRateLimit = async (
|
||||||
|
rln: RLNInstance | null,
|
||||||
|
isStarted: boolean,
|
||||||
|
rateLimit: number
|
||||||
|
): Promise<PriceResult> => {
|
||||||
|
try {
|
||||||
|
if (!rln || !rln.contract || !isStarted) {
|
||||||
|
throw new Error('RLN not initialized or contract not available');
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await rln.contract.getPriceForRateLimit(rateLimit);
|
||||||
|
|
||||||
|
// Handle null case to fix linter error
|
||||||
|
if (!result || !result.price) {
|
||||||
|
throw new Error('Price not available for this rate limit');
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatted = ethers.utils.formatUnits(result.price, 18);
|
||||||
|
return { price: formatted };
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error getting price for rate limit:', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate rate limit is within bounds
|
||||||
|
*/
|
||||||
|
export const validateRateLimit = (
|
||||||
|
rateLimit: number,
|
||||||
|
minLimit: number,
|
||||||
|
maxLimit: number
|
||||||
|
): { isValid: boolean; error?: string } => {
|
||||||
|
if (rateLimit < minLimit || rateLimit > maxLimit) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
error: `Rate limit must be between ${minLimit} and ${maxLimit}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { isValid: true };
|
||||||
|
};
|
||||||
44
src/contexts/rln/singleton.ts
Normal file
44
src/contexts/rln/singleton.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import { RLNInstance, createRLN } from '@waku/rln';
|
||||||
|
|
||||||
|
// Global singleton to ensure WASM is only initialized once
|
||||||
|
let globalRLNInstance: RLNInstance | null = null;
|
||||||
|
let globalInitPromise: Promise<RLNInstance> | null = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Singleton function to ensure WASM is only initialized once
|
||||||
|
* Handles retry logic for WASM-related errors
|
||||||
|
*/
|
||||||
|
export const getOrCreateRLNInstance = async (): Promise<RLNInstance> => {
|
||||||
|
if (globalRLNInstance) {
|
||||||
|
console.log("Reusing existing global RLN instance");
|
||||||
|
return globalRLNInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalInitPromise) {
|
||||||
|
console.log("Waiting for existing RLN initialization...");
|
||||||
|
return globalInitPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Creating new global RLN instance...");
|
||||||
|
globalInitPromise = createRLN();
|
||||||
|
|
||||||
|
try {
|
||||||
|
globalRLNInstance = await globalInitPromise;
|
||||||
|
console.log("Global RLN instance created successfully");
|
||||||
|
return globalRLNInstance;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error creating global RLN instance:", error);
|
||||||
|
globalInitPromise = null;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanup function to reset the global instance
|
||||||
|
* Useful for testing or when a fresh instance is needed
|
||||||
|
*/
|
||||||
|
export const resetGlobalRLNInstance = (): void => {
|
||||||
|
globalRLNInstance = null;
|
||||||
|
globalInitPromise = null;
|
||||||
|
console.log("Global RLN instance reset");
|
||||||
|
};
|
||||||
@ -1,12 +1,61 @@
|
|||||||
import { DecryptedCredentials, RLNCredentialsManager, RLNInstance } from "@waku/rln";
|
import { RLNInstance, KeystoreEntity, MembershipInfo } from "@waku/rln";
|
||||||
|
|
||||||
export interface RLNContextType {
|
export interface RLNContextType {
|
||||||
rln: RLNInstance | RLNCredentialsManager | null;
|
rln: RLNInstance | null;
|
||||||
isInitialized: boolean;
|
isInitialized: boolean;
|
||||||
isStarted: boolean;
|
isStarted: boolean;
|
||||||
error: string | null;
|
error: string | null;
|
||||||
initializeRLN: () => Promise<void>;
|
initializeRLN: () => Promise<void>;
|
||||||
registerMembership: (rateLimit: number) => Promise<{ success: boolean; error?: string; credentials?: DecryptedCredentials }>;
|
registerMembership: (rateLimit: number, saveOptions?: { password: string }) => Promise<{
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
credentials?: KeystoreEntity;
|
||||||
|
keystoreHash?: string;
|
||||||
|
}>;
|
||||||
|
extendMembership: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
||||||
|
eraseMembership: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
||||||
|
withdrawDeposit: (hash: string, password: string) => Promise<{ success: boolean; error?: string }>;
|
||||||
|
getMembershipInfo: (hash: string, password: string) => Promise<MembershipInfo & {
|
||||||
|
address: string;
|
||||||
|
chainId: string;
|
||||||
|
treeIndex: number;
|
||||||
|
rateLimit: number;
|
||||||
|
}>;
|
||||||
rateMinLimit: number;
|
rateMinLimit: number;
|
||||||
rateMaxLimit: number;
|
rateMaxLimit: number;
|
||||||
|
getCurrentRateLimit: () => Promise<number | null>;
|
||||||
|
getRateLimitsBounds: () => Promise<{ success: boolean; rateMinLimit: number; rateMaxLimit: number; error?: string }>;
|
||||||
|
saveCredentialsToKeystore: (credentials: KeystoreEntity, password: string) => Promise<string>;
|
||||||
|
isLoading: boolean;
|
||||||
|
getPriceForRateLimit: (rateLimit: number) => Promise<{ price: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RateLimitBounds {
|
||||||
|
success: boolean;
|
||||||
|
rateMinLimit: number;
|
||||||
|
rateMaxLimit: number;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegistrationResult {
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
credentials?: KeystoreEntity;
|
||||||
|
keystoreHash?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface OperationResult {
|
||||||
|
success: boolean;
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MembershipInfoExtended extends MembershipInfo {
|
||||||
|
address: string;
|
||||||
|
chainId: string;
|
||||||
|
treeIndex: number;
|
||||||
|
rateLimit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PriceResult {
|
||||||
|
price: string;
|
||||||
}
|
}
|
||||||
93
src/contexts/rln/wallet.ts
Normal file
93
src/contexts/rln/wallet.ts
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { ethers } from 'ethers';
|
||||||
|
import { ensureLineaSepoliaNetwork } from '../../utils/network';
|
||||||
|
|
||||||
|
export interface WalletState {
|
||||||
|
signer: ethers.Signer | null;
|
||||||
|
isConnected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UseWalletReturn extends WalletState {
|
||||||
|
checkWallet: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to manage wallet connection and signer state
|
||||||
|
*/
|
||||||
|
export const useWallet = (): UseWalletReturn => {
|
||||||
|
const [signer, setSigner] = useState<ethers.Signer | null>(null);
|
||||||
|
const [isConnected, setIsConnected] = useState(false);
|
||||||
|
|
||||||
|
const checkWallet = async () => {
|
||||||
|
try {
|
||||||
|
if (window.ethereum) {
|
||||||
|
const provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||||
|
const accounts = await provider.listAccounts();
|
||||||
|
|
||||||
|
if (accounts.length > 0) {
|
||||||
|
const signer = provider.getSigner();
|
||||||
|
setSigner(signer);
|
||||||
|
setIsConnected(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setSigner(null);
|
||||||
|
setIsConnected(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error checking wallet:", err);
|
||||||
|
setSigner(null);
|
||||||
|
setIsConnected(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listen for wallet connection
|
||||||
|
useEffect(() => {
|
||||||
|
checkWallet();
|
||||||
|
|
||||||
|
// Listen for account changes
|
||||||
|
if (window.ethereum) {
|
||||||
|
window.ethereum.on('accountsChanged', checkWallet);
|
||||||
|
window.ethereum.on('chainChanged', checkWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (window.ethereum) {
|
||||||
|
window.ethereum.removeListener('accountsChanged', checkWallet);
|
||||||
|
window.ethereum.removeListener('chainChanged', checkWallet);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return {
|
||||||
|
signer,
|
||||||
|
isConnected,
|
||||||
|
checkWallet
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to ensure wallet is on Linea Sepolia network
|
||||||
|
*/
|
||||||
|
export const ensureCorrectNetwork = async (signer: ethers.Signer): Promise<boolean> => {
|
||||||
|
try {
|
||||||
|
return await ensureLineaSepoliaNetwork(signer);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error ensuring correct network:", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility function to get user address from signer
|
||||||
|
*/
|
||||||
|
export const getUserAddress = async (signer: ethers.Signer): Promise<string> => {
|
||||||
|
try {
|
||||||
|
return await signer.getAddress();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error getting user address:", error);
|
||||||
|
throw new Error("Failed to get user address");
|
||||||
|
}
|
||||||
|
};
|
||||||
98
yarn.lock
98
yarn.lock
@ -750,9 +750,9 @@
|
|||||||
integrity sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==
|
integrity sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==
|
||||||
|
|
||||||
"@noble/curves@^1.9.1":
|
"@noble/curves@^1.9.1":
|
||||||
version "1.9.2"
|
version "1.9.4"
|
||||||
resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz"
|
resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.4.tgz"
|
||||||
integrity sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==
|
integrity sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/hashes" "1.8.0"
|
"@noble/hashes" "1.8.0"
|
||||||
|
|
||||||
@ -1440,17 +1440,17 @@
|
|||||||
resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz"
|
resolved "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz"
|
||||||
integrity sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==
|
integrity sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==
|
||||||
|
|
||||||
"@waku/core@0.0.37-987c6cd.0":
|
"@waku/core@0.0.38-e224c05.0":
|
||||||
version "0.0.37-987c6cd.0"
|
version "0.0.38-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/core/-/core-0.0.37-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/core/-/core-0.0.38-e224c05.0.tgz"
|
||||||
integrity sha512-w3F/dzY/YA5T3l62YKKcza3fMLZNzprupoKScvtpWS8VymLIGZCMhzcKOij4lt6SWzHWyTEMa9qtcB6tZPIC+A==
|
integrity sha512-VtRfwF6WGj3HhB4cywiit3KcrHYtUtoD1wjAviO8b4AzH9LbtV7NmYvGIy5ac9sOpRQEUNagOFT6+oXu7Ay+HQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@libp2p/ping" "2.0.35"
|
"@libp2p/ping" "2.0.35"
|
||||||
"@noble/hashes" "^1.3.2"
|
"@noble/hashes" "^1.3.2"
|
||||||
"@waku/enr" "0.0.31-987c6cd.0"
|
"@waku/enr" "0.0.32-e224c05.0"
|
||||||
"@waku/interfaces" "0.0.32-987c6cd.0"
|
"@waku/interfaces" "0.0.33-e224c05.0"
|
||||||
"@waku/proto" "0.0.12-987c6cd.0"
|
"@waku/proto" "0.0.13-e224c05.0"
|
||||||
"@waku/utils" "0.0.25-987c6cd.0"
|
"@waku/utils" "0.0.26-e224c05.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
it-all "^3.0.4"
|
it-all "^3.0.4"
|
||||||
it-length-prefixed "^9.0.4"
|
it-length-prefixed "^9.0.4"
|
||||||
@ -1458,42 +1458,42 @@
|
|||||||
uint8arraylist "^2.4.3"
|
uint8arraylist "^2.4.3"
|
||||||
uuid "^9.0.0"
|
uuid "^9.0.0"
|
||||||
|
|
||||||
"@waku/enr@0.0.31-987c6cd.0":
|
"@waku/enr@0.0.32-e224c05.0":
|
||||||
version "0.0.31-987c6cd.0"
|
version "0.0.32-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/enr/-/enr-0.0.31-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/enr/-/enr-0.0.32-e224c05.0.tgz"
|
||||||
integrity sha512-nStUXohULcatKLxCyzU7JJK2gKhMXYEAdN90uL1Ggl4tKA9uUrQ2YZC/WB61RmucnDlFNH6phFv47/WbARhhVA==
|
integrity sha512-f+DEugomxeDgCylxv2xm6eLIJBB76dctB4B/d0zUMld26zjBozRKUsaNn8DOWRT5f44WzyP+5gRqbTm4e/qsMw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ethersproject/rlp" "^5.7.0"
|
"@ethersproject/rlp" "^5.7.0"
|
||||||
"@libp2p/crypto" "5.1.6"
|
"@libp2p/crypto" "5.1.6"
|
||||||
"@libp2p/peer-id" "5.1.7"
|
"@libp2p/peer-id" "5.1.7"
|
||||||
"@multiformats/multiaddr" "^12.0.0"
|
"@multiformats/multiaddr" "^12.0.0"
|
||||||
"@noble/secp256k1" "^1.7.1"
|
"@noble/secp256k1" "^1.7.1"
|
||||||
"@waku/utils" "0.0.25-987c6cd.0"
|
"@waku/utils" "0.0.26-e224c05.0"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
js-sha3 "^0.9.2"
|
js-sha3 "^0.9.2"
|
||||||
|
|
||||||
"@waku/interfaces@0.0.32-987c6cd.0":
|
"@waku/interfaces@0.0.33-e224c05.0":
|
||||||
version "0.0.32-987c6cd.0"
|
version "0.0.33-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.32-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/interfaces/-/interfaces-0.0.33-e224c05.0.tgz"
|
||||||
integrity sha512-7dfGDx1bs+rs1nlMwAZYd0Di4gLyD9cWR0ApDJ+I0sU3enn1NT6hM1U3cp+LE6xqxXUoe2tfQi/4QhrECaGypQ==
|
integrity sha512-8GH7Tg0t74R32NqQHVm0ttVPb26Cvn/p+Iiht3mha8gGHQVkYYYyECXfZYAQ9pld3y0GB+yqpn5EiZiTNs3AOQ==
|
||||||
|
|
||||||
"@waku/proto@0.0.12-987c6cd.0":
|
"@waku/proto@0.0.13-e224c05.0":
|
||||||
version "0.0.12-987c6cd.0"
|
version "0.0.13-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/proto/-/proto-0.0.12-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/proto/-/proto-0.0.13-e224c05.0.tgz"
|
||||||
integrity sha512-B0u7Qkm/U6mH0ZCGYvRfg4d44JboscYBmXifeOTwY0i4QH8nvrZcPIIsUqvNmzT2CjrAwpt8H+98fGp9l4fKow==
|
integrity sha512-zvIGhAECY1v691tWnyiFcUAPvd06itXRq9BggN5Nwq+TKMl9XOL6+kHuTzovvn1PM9ajRyoP3zbqT1musxeixQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
protons-runtime "^5.4.0"
|
protons-runtime "^5.4.0"
|
||||||
|
|
||||||
"@waku/rln@0.1.7-987c6cd.0":
|
"@waku/rln@0.1.8-e224c05.0":
|
||||||
version "0.1.7-987c6cd.0"
|
version "0.1.8-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/rln/-/rln-0.1.7-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/rln/-/rln-0.1.8-e224c05.0.tgz"
|
||||||
integrity sha512-6w/17WpD7jdw5LyM6OX0c2mMxW3cRrXG7wxi7PzhoSb2celNWZYhnPR9UK+rgsP5opoBDXD7LAyaEEqA3afbgA==
|
integrity sha512-9uSP1ARwOdpGHJ9LIpNdNo03/q60YYYuDGCX+fPfrDFooWjxvIn0+G1TzxUgJLLP6g7stxaWj+iKCCktNFpxZQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@chainsafe/bls-keystore" "3.0.0"
|
"@chainsafe/bls-keystore" "3.0.0"
|
||||||
"@noble/hashes" "^1.2.0"
|
"@noble/hashes" "^1.2.0"
|
||||||
"@waku/core" "0.0.37-987c6cd.0"
|
"@waku/core" "0.0.38-e224c05.0"
|
||||||
"@waku/utils" "0.0.25-987c6cd.0"
|
"@waku/utils" "0.0.26-e224c05.0"
|
||||||
"@waku/zerokit-rln-wasm" "^0.0.13"
|
"@waku/zerokit-rln-wasm" "^0.2.1"
|
||||||
chai "^5.1.2"
|
chai "^5.1.2"
|
||||||
chai-as-promised "^8.0.1"
|
chai-as-promised "^8.0.1"
|
||||||
chai-spies "^1.1.0"
|
chai-spies "^1.1.0"
|
||||||
@ -1504,21 +1504,21 @@
|
|||||||
sinon "^19.0.2"
|
sinon "^19.0.2"
|
||||||
uuid "^11.0.5"
|
uuid "^11.0.5"
|
||||||
|
|
||||||
"@waku/utils@0.0.25-987c6cd.0":
|
"@waku/utils@0.0.26-e224c05.0":
|
||||||
version "0.0.25-987c6cd.0"
|
version "0.0.26-e224c05.0"
|
||||||
resolved "https://registry.npmjs.org/@waku/utils/-/utils-0.0.25-987c6cd.0.tgz"
|
resolved "https://registry.npmjs.org/@waku/utils/-/utils-0.0.26-e224c05.0.tgz"
|
||||||
integrity sha512-HaYkDnVtpfmsXfDBd0gB63CxidIeE9gKMRMCaaywy6W07HK32ZgMgnD/BoPbaREa4BpEZELvW3qbYUydm3AKzw==
|
integrity sha512-eleBm6L5ky5xKRoCMXfFhLmvyGix8dhOXtDIS8/lIr+CJ09cDQoAHhhpPsJnLmf8DRxYQ1PDqPsEet9sa2LT9Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@noble/hashes" "^1.3.2"
|
"@noble/hashes" "^1.3.2"
|
||||||
"@waku/interfaces" "0.0.32-987c6cd.0"
|
"@waku/interfaces" "0.0.33-e224c05.0"
|
||||||
chai "^4.3.10"
|
chai "^4.3.10"
|
||||||
debug "^4.3.4"
|
debug "^4.3.4"
|
||||||
uint8arrays "^5.0.1"
|
uint8arrays "^5.0.1"
|
||||||
|
|
||||||
"@waku/zerokit-rln-wasm@^0.0.13":
|
"@waku/zerokit-rln-wasm@^0.2.1":
|
||||||
version "0.0.13"
|
version "0.2.1"
|
||||||
resolved "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.0.13.tgz"
|
resolved "https://registry.npmjs.org/@waku/zerokit-rln-wasm/-/zerokit-rln-wasm-0.2.1.tgz"
|
||||||
integrity sha512-x7CRIIslmfCmTZc7yVp3dhLlKeLUs8ILIm9kv7+wVJ23H4pPw0Z+uH0ueLIYYfwODI6fDiwJj3S1vdFzM8D1zA==
|
integrity sha512-2Xp7e92y4qZpsiTPGBSVr4gVJ9mJTLaudlo0DQxNpxJUBtoJKpxdH5xDCQDiorbkWZC2j9EId+ohhxHO/xC1QQ==
|
||||||
|
|
||||||
abort-error@^1.0.1:
|
abort-error@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@ -1764,14 +1764,14 @@ binary-extensions@^2.0.0:
|
|||||||
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
|
||||||
|
|
||||||
bn.js@^4.11.9:
|
bn.js@^4.11.9:
|
||||||
version "4.12.1"
|
version "4.12.2"
|
||||||
resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz"
|
resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz"
|
||||||
integrity sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==
|
integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==
|
||||||
|
|
||||||
bn.js@^5.2.1:
|
bn.js@^5.2.1:
|
||||||
version "5.2.1"
|
version "5.2.2"
|
||||||
resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz"
|
resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz"
|
||||||
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
|
integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==
|
||||||
|
|
||||||
brace-expansion@^1.1.7:
|
brace-expansion@^1.1.7:
|
||||||
version "1.1.11"
|
version "1.1.11"
|
||||||
@ -4300,9 +4300,9 @@ queue-microtask@^1.2.2:
|
|||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
race-event@^1.3.0:
|
race-event@^1.3.0:
|
||||||
version "1.6.0"
|
version "1.6.1"
|
||||||
resolved "https://registry.npmjs.org/race-event/-/race-event-1.6.0.tgz"
|
resolved "https://registry.npmjs.org/race-event/-/race-event-1.6.1.tgz"
|
||||||
integrity sha512-hXkk3CDepWELBG2MsT/zIiTbjNNucMo49vwZEdjChJlxJivc8fWIu/Gh/4vEJdWsHDmnGCC6++ftP2Afep6RUg==
|
integrity sha512-vi7WH5g5KoTFpu2mme/HqZiWH14XSOtg5rfp6raBskBHl7wnmy3F/biAIyY5MsK+BHWhoPhxtZ1Y2R7OHHaWyQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
abort-error "^1.0.1"
|
abort-error "^1.0.1"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user