@waku/rln 0.1.4 → 0.1.5-053bb95.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +5 -0
  2. package/bundle/_virtual/index2.js +1 -1
  3. package/bundle/_virtual/utils.js +2 -2
  4. package/bundle/_virtual/utils2.js +2 -2
  5. package/bundle/index.js +3 -1
  6. package/bundle/node_modules/@ethersproject/abi/lib.esm/_version.js +1 -1
  7. package/bundle/node_modules/@ethersproject/abstract-provider/lib.esm/_version.js +1 -1
  8. package/bundle/node_modules/@ethersproject/abstract-signer/lib.esm/_version.js +1 -1
  9. package/bundle/node_modules/@ethersproject/address/lib.esm/_version.js +1 -1
  10. package/bundle/node_modules/@ethersproject/bignumber/lib.esm/_version.js +1 -1
  11. package/bundle/node_modules/@ethersproject/contracts/lib.esm/_version.js +1 -1
  12. package/bundle/node_modules/@ethersproject/contracts/lib.esm/index.js +1 -1
  13. package/bundle/node_modules/@ethersproject/hash/lib.esm/_version.js +1 -1
  14. package/bundle/node_modules/@ethersproject/keccak256/lib.esm/index.js +1 -1
  15. package/bundle/node_modules/{js-sha3 → @ethersproject/keccak256/node_modules/js-sha3}/src/sha3.js +2 -2
  16. package/bundle/node_modules/@ethersproject/networks/lib.esm/_version.js +1 -1
  17. package/bundle/node_modules/@ethersproject/networks/lib.esm/index.js +1 -19
  18. package/bundle/node_modules/@ethersproject/properties/lib.esm/_version.js +1 -1
  19. package/bundle/node_modules/@ethersproject/providers/lib.esm/_version.js +1 -1
  20. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/_version.js +1 -1
  21. package/bundle/node_modules/@ethersproject/signing-key/lib.esm/elliptic.js +10 -58
  22. package/bundle/node_modules/@ethersproject/strings/lib.esm/_version.js +1 -1
  23. package/bundle/node_modules/@ethersproject/transactions/lib.esm/_version.js +1 -1
  24. package/bundle/node_modules/@ethersproject/web/lib.esm/_version.js +1 -1
  25. package/bundle/packages/rln/dist/contract/abi.js +502 -248
  26. package/bundle/packages/rln/dist/contract/constants.js +5 -8
  27. package/bundle/packages/rln/dist/contract/errors.js +62 -0
  28. package/bundle/packages/rln/dist/contract/rln_base_contract.js +347 -0
  29. package/bundle/packages/rln/dist/contract/rln_contract.js +81 -392
  30. package/bundle/packages/rln/dist/contract/types.js +9 -0
  31. package/bundle/packages/rln/dist/create.js +1 -1
  32. package/bundle/packages/rln/dist/credentials_manager.js +215 -0
  33. package/bundle/packages/rln/dist/identity.js +8 -0
  34. package/bundle/packages/rln/dist/keystore/cipher.js +3 -3
  35. package/bundle/packages/rln/dist/keystore/keystore.js +21 -29
  36. package/bundle/packages/rln/dist/rln.js +56 -166
  37. package/bundle/packages/rln/dist/zerokit.js +5 -5
  38. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/checksum.js +3 -3
  39. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/cipher.js +4 -4
  40. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/class.js +7 -7
  41. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/functional.js +7 -7
  42. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/index.js +6 -6
  43. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/kdf.js +5 -5
  44. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/password.js +1 -1
  45. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/schema-validation-generated.js +1 -1
  46. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/schema-validation.js +2 -2
  47. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/lib/types.js +1 -1
  48. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/aes.js +3 -3
  49. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/pbkdf2.js +7 -7
  50. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/random.js +3 -3
  51. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/scrypt.js +3 -3
  52. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/sha256.js +3 -3
  53. package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/ethereum-cryptography/utils.js +7 -7
  54. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/_assert.js +1 -1
  55. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/_sha2.js +3 -3
  56. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/_u64.js +1 -1
  57. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/cryptoBrowser.js +1 -1
  58. package/bundle/packages/rln/node_modules/@noble/hashes/esm/_assert.js +43 -0
  59. package/bundle/packages/rln/node_modules/@noble/hashes/esm/_sha2.js +116 -0
  60. package/bundle/packages/rln/node_modules/@noble/hashes/esm/hmac.js +79 -0
  61. package/bundle/packages/rln/node_modules/@noble/hashes/esm/sha256.js +126 -0
  62. package/bundle/packages/rln/node_modules/@noble/hashes/esm/utils.js +43 -0
  63. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/hmac.js +3 -3
  64. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/pbkdf2.js +4 -4
  65. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/scrypt.js +5 -5
  66. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/sha256.js +3 -3
  67. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/sha512.js +4 -4
  68. package/bundle/{node_modules/@chainsafe/bls-keystore → packages/rln}/node_modules/@noble/hashes/utils.js +2 -2
  69. package/dist/.tsbuildinfo +1 -1
  70. package/dist/codec.test-utils.d.ts +36 -0
  71. package/dist/codec.test-utils.js +56 -0
  72. package/dist/codec.test-utils.js.map +1 -0
  73. package/dist/contract/abi.d.ts +21 -17
  74. package/dist/contract/abi.js +502 -248
  75. package/dist/contract/abi.js.map +1 -1
  76. package/dist/contract/constants.d.ts +23 -19
  77. package/dist/contract/constants.js +3 -3
  78. package/dist/contract/constants.js.map +1 -1
  79. package/dist/contract/errors.d.ts +30 -0
  80. package/dist/contract/errors.js +61 -0
  81. package/dist/contract/errors.js.map +1 -0
  82. package/dist/contract/rln_base_contract.d.ts +88 -0
  83. package/dist/contract/rln_base_contract.js +330 -0
  84. package/dist/contract/rln_base_contract.js.map +1 -0
  85. package/dist/contract/rln_contract.d.ts +19 -109
  86. package/dist/contract/rln_contract.js +80 -390
  87. package/dist/contract/rln_contract.js.map +1 -1
  88. package/dist/contract/test-setup.d.ts +26 -0
  89. package/dist/contract/test-setup.js +56 -0
  90. package/dist/contract/test-setup.js.map +1 -0
  91. package/dist/contract/test-utils.d.ts +39 -0
  92. package/dist/contract/test-utils.js +118 -0
  93. package/dist/contract/test-utils.js.map +1 -0
  94. package/dist/contract/types.d.ts +40 -0
  95. package/dist/contract/types.js +8 -0
  96. package/dist/contract/types.js.map +1 -0
  97. package/dist/create.js +1 -1
  98. package/dist/create.js.map +1 -1
  99. package/dist/credentials_manager.d.ts +44 -0
  100. package/dist/credentials_manager.js +197 -0
  101. package/dist/credentials_manager.js.map +1 -0
  102. package/dist/identity.d.ts +1 -0
  103. package/dist/identity.js +8 -0
  104. package/dist/identity.js.map +1 -1
  105. package/dist/index.d.ts +5 -2
  106. package/dist/index.js +4 -2
  107. package/dist/index.js.map +1 -1
  108. package/dist/keystore/keystore.d.ts +0 -1
  109. package/dist/keystore/keystore.js +20 -28
  110. package/dist/keystore/keystore.js.map +1 -1
  111. package/dist/keystore/types.d.ts +2 -1
  112. package/dist/rln.d.ts +9 -52
  113. package/dist/rln.js +54 -163
  114. package/dist/rln.js.map +1 -1
  115. package/dist/types.d.ts +27 -0
  116. package/dist/types.js +2 -0
  117. package/dist/types.js.map +1 -0
  118. package/dist/zerokit.d.ts +3 -3
  119. package/dist/zerokit.js +5 -5
  120. package/dist/zerokit.js.map +1 -1
  121. package/package.json +1 -91
  122. package/src/codec.test-utils.ts +80 -0
  123. package/src/contract/abi.ts +502 -248
  124. package/src/contract/constants.ts +3 -3
  125. package/src/contract/errors.ts +75 -0
  126. package/src/contract/rln_base_contract.ts +500 -0
  127. package/src/contract/rln_contract.ts +102 -619
  128. package/src/contract/test-setup.ts +86 -0
  129. package/src/contract/test-utils.ts +179 -0
  130. package/src/contract/types.ts +48 -0
  131. package/src/create.ts +1 -1
  132. package/src/credentials_manager.ts +282 -0
  133. package/src/identity.ts +9 -0
  134. package/src/index.ts +17 -2
  135. package/src/keystore/keystore.ts +32 -46
  136. package/src/keystore/types.ts +2 -1
  137. package/src/rln.ts +67 -258
  138. package/src/types.ts +31 -0
  139. package/src/zerokit.ts +3 -3
  140. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/index.js +0 -0
  141. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/md5.js +0 -0
  142. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/nil.js +0 -0
  143. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/parse.js +0 -0
  144. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/regex.js +0 -0
  145. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/rng.js +0 -0
  146. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/sha1.js +0 -0
  147. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/stringify.js +0 -0
  148. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v1.js +0 -0
  149. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v3.js +0 -0
  150. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v35.js +0 -0
  151. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v4.js +0 -0
  152. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/v5.js +0 -0
  153. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/validate.js +0 -0
  154. /package/bundle/{node_modules → packages/rln/node_modules}/@chainsafe/bls-keystore/node_modules/uuid/dist/esm-browser/version.js +0 -0
@@ -1,8 +1,8 @@
1
1
  import { RLN_ABI } from './abi.js';
2
2
 
3
- const SEPOLIA_CONTRACT = {
4
- chainId: 11155111,
5
- address: "0xCB33Aa5B38d79E3D9Fa8B10afF38AA201399a7e3",
3
+ const LINEA_CONTRACT = {
4
+ chainId: "59141",
5
+ address: "0xb9cd878c90e49f797b4431fbf4fb333108cb90e6",
6
6
  abi: RLN_ABI
7
7
  };
8
8
  /**
@@ -17,10 +17,7 @@ const RATE_LIMIT_TIERS = {
17
17
  // Global rate limit parameters
18
18
  const RATE_LIMIT_PARAMS = {
19
19
  MIN_RATE: RATE_LIMIT_TIERS.LOW,
20
- MAX_RATE: RATE_LIMIT_TIERS.HIGH,
21
- MAX_TOTAL_RATE: 160_000, // Maximum total rate limit across all memberships
22
- EPOCH_LENGTH: 600 // Epoch length in seconds (10 minutes)
23
- };
20
+ MAX_RATE: RATE_LIMIT_TIERS.HIGH};
24
21
  const DEFAULT_RATE_LIMIT = RATE_LIMIT_PARAMS.MAX_RATE;
25
22
 
26
- export { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS, SEPOLIA_CONTRACT };
23
+ export { DEFAULT_RATE_LIMIT, LINEA_CONTRACT, RATE_LIMIT_PARAMS, RATE_LIMIT_TIERS };
@@ -0,0 +1,62 @@
1
+ class RLNContractError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "RLNContractError";
5
+ }
6
+ }
7
+ class MembershipError extends RLNContractError {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = "MembershipError";
11
+ }
12
+ }
13
+ class RateLimitError extends RLNContractError {
14
+ constructor(message) {
15
+ super(message);
16
+ this.name = "RateLimitError";
17
+ }
18
+ }
19
+ class InvalidMembershipError extends MembershipError {
20
+ constructor(idCommitment) {
21
+ super(`Invalid membership ID commitment: ${idCommitment}`);
22
+ this.name = "InvalidMembershipError";
23
+ }
24
+ }
25
+ class MembershipNotFoundError extends MembershipError {
26
+ constructor(idCommitment) {
27
+ super(`Membership not found for ID commitment: ${idCommitment}`);
28
+ this.name = "MembershipNotFoundError";
29
+ }
30
+ }
31
+ class MembershipExistsError extends MembershipError {
32
+ constructor(idCommitment, index) {
33
+ super(`Membership already exists for ID commitment: ${idCommitment} at index ${index}`);
34
+ this.name = "MembershipExistsError";
35
+ }
36
+ }
37
+ class RateLimitExceededError extends RateLimitError {
38
+ constructor(requested, available) {
39
+ super(`Rate limit exceeded. Requested: ${requested}, Available: ${available}`);
40
+ this.name = "RateLimitExceededError";
41
+ }
42
+ }
43
+ class InvalidRateLimitError extends RateLimitError {
44
+ constructor(rateLimit, minRate, maxRate) {
45
+ super(`Invalid rate limit: ${rateLimit}. Must be between ${minRate} and ${maxRate}`);
46
+ this.name = "InvalidRateLimitError";
47
+ }
48
+ }
49
+ class ContractStateError extends RLNContractError {
50
+ constructor(message) {
51
+ super(`Contract state error: ${message}`);
52
+ this.name = "ContractStateError";
53
+ }
54
+ }
55
+ class TransactionError extends RLNContractError {
56
+ constructor(message) {
57
+ super(`Transaction failed: ${message}`);
58
+ this.name = "TransactionError";
59
+ }
60
+ }
61
+
62
+ export { ContractStateError, InvalidMembershipError, InvalidRateLimitError, MembershipError, MembershipExistsError, MembershipNotFoundError, RLNContractError, RateLimitError, RateLimitExceededError, TransactionError };
@@ -0,0 +1,347 @@
1
+ import '../../../interfaces/dist/protocols.js';
2
+ import '../../../interfaces/dist/connection_manager.js';
3
+ import '../../../interfaces/dist/health_indicator.js';
4
+ import '../../../../node_modules/multiformats/dist/src/bases/base10.js';
5
+ import '../../../../node_modules/multiformats/dist/src/bases/base16.js';
6
+ import '../../../../node_modules/multiformats/dist/src/bases/base2.js';
7
+ import '../../../../node_modules/multiformats/dist/src/bases/base256emoji.js';
8
+ import '../../../../node_modules/multiformats/dist/src/bases/base32.js';
9
+ import '../../../../node_modules/multiformats/dist/src/bases/base36.js';
10
+ import '../../../../node_modules/multiformats/dist/src/bases/base58.js';
11
+ import '../../../../node_modules/multiformats/dist/src/bases/base64.js';
12
+ import '../../../../node_modules/multiformats/dist/src/bases/base8.js';
13
+ import '../../../../node_modules/multiformats/dist/src/bases/identity.js';
14
+ import '../../../../node_modules/multiformats/dist/src/codecs/json.js';
15
+ import { Logger } from '../../../utils/dist/logger/index.js';
16
+ import { RLN_ABI } from './abi.js';
17
+ import { DEFAULT_RATE_LIMIT, RATE_LIMIT_PARAMS } from './constants.js';
18
+ import { RLNContractError, InvalidMembershipError, MembershipNotFoundError, MembershipExistsError, RateLimitExceededError, InvalidRateLimitError, TransactionError } from './errors.js';
19
+ import { MembershipState } from './types.js';
20
+ import { Contract } from '../../../../node_modules/@ethersproject/contracts/lib.esm/index.js';
21
+ import { BigNumber } from '../../../../node_modules/@ethersproject/bignumber/lib.esm/bignumber.js';
22
+
23
+ const log = new Logger("waku:rln:contract:base");
24
+ class RLNBaseContract {
25
+ contract;
26
+ rateLimit;
27
+ constructor(options) {
28
+ const { address, signer, rateLimit = DEFAULT_RATE_LIMIT, contract } = options;
29
+ this.validateRateLimit(rateLimit);
30
+ this.contract = contract || new Contract(address, RLN_ABI, signer);
31
+ this.rateLimit = rateLimit;
32
+ }
33
+ /**
34
+ * Gets the current rate limit for this contract instance
35
+ */
36
+ getRateLimit() {
37
+ return this.rateLimit;
38
+ }
39
+ /**
40
+ * Gets the contract address
41
+ */
42
+ get address() {
43
+ return this.contract.address;
44
+ }
45
+ /**
46
+ * Gets the contract provider
47
+ */
48
+ get provider() {
49
+ return this.contract.provider;
50
+ }
51
+ /**
52
+ * Gets the minimum allowed rate limit from the contract
53
+ * @returns Promise<number> The minimum rate limit in messages per epoch
54
+ */
55
+ async getMinRateLimit() {
56
+ const minRate = await this.contract.minMembershipRateLimit();
57
+ return BigNumber.from(minRate).toNumber();
58
+ }
59
+ /**
60
+ * Gets the maximum allowed rate limit from the contract
61
+ * @returns Promise<number> The maximum rate limit in messages per epoch
62
+ */
63
+ async getMaxRateLimit() {
64
+ const maxRate = await this.contract.maxMembershipRateLimit();
65
+ return BigNumber.from(maxRate).toNumber();
66
+ }
67
+ /**
68
+ * Gets the maximum total rate limit across all memberships
69
+ * @returns Promise<number> The maximum total rate limit in messages per epoch
70
+ */
71
+ async getMaxTotalRateLimit() {
72
+ const maxTotalRate = await this.contract.maxTotalRateLimit();
73
+ return maxTotalRate.toNumber();
74
+ }
75
+ /**
76
+ * Gets the current total rate limit usage across all memberships
77
+ * @returns Promise<number> The current total rate limit usage in messages per epoch
78
+ */
79
+ async getCurrentTotalRateLimit() {
80
+ const currentTotal = await this.contract.currentTotalRateLimit();
81
+ return currentTotal.toNumber();
82
+ }
83
+ /**
84
+ * Gets the remaining available total rate limit that can be allocated
85
+ * @returns Promise<number> The remaining rate limit that can be allocated
86
+ */
87
+ async getRemainingTotalRateLimit() {
88
+ const [maxTotal, currentTotal] = await Promise.all([
89
+ this.contract.maxTotalRateLimit(),
90
+ this.contract.currentTotalRateLimit()
91
+ ]);
92
+ return Number(maxTotal) - Number(currentTotal);
93
+ }
94
+ /**
95
+ * Updates the rate limit for future registrations
96
+ * @param newRateLimit The new rate limit to use
97
+ */
98
+ async setRateLimit(newRateLimit) {
99
+ this.validateRateLimit(newRateLimit);
100
+ this.rateLimit = newRateLimit;
101
+ }
102
+ /**
103
+ * Gets all members in the given range
104
+ * @param startIndex Start index (inclusive)
105
+ * @param endIndex End index (exclusive)
106
+ */
107
+ async getMembersInRange(startIndex, endIndex) {
108
+ try {
109
+ // Get all commitments in one call
110
+ const idCommitments = await this.contract.getRateCommitmentsInRangeBoundsInclusive(startIndex, endIndex - 1 // -1 because getRateCommitmentsInRangeBoundsInclusive is inclusive
111
+ );
112
+ // Get membership info for each commitment in a single batch
113
+ const membershipPromises = idCommitments.map((idCommitment) => this.contract
114
+ .memberships(idCommitment)
115
+ .then((info) => ({
116
+ idCommitment: idCommitment.toString(),
117
+ index: BigNumber.from(info.index)
118
+ }))
119
+ .catch(() => null) // Skip invalid members
120
+ );
121
+ // Wait for all promises to resolve
122
+ const members = (await Promise.all(membershipPromises)).filter((m) => m !== null);
123
+ return members;
124
+ }
125
+ catch (error) {
126
+ if (error instanceof Error &&
127
+ error.message.includes("InvalidPaginationQuery")) {
128
+ throw new RLNContractError(`Invalid pagination range: start=${startIndex}, end=${endIndex}`);
129
+ }
130
+ throw error;
131
+ }
132
+ }
133
+ /**
134
+ * Gets all current members
135
+ */
136
+ async getAllMembers() {
137
+ const nextIndex = (await this.contract.nextFreeIndex()).toNumber();
138
+ return this.getMembersInRange(0, nextIndex);
139
+ }
140
+ /**
141
+ * Gets the member index if it exists, or null if it doesn't
142
+ * Throws only on actual errors (invalid input, network issues, etc)
143
+ */
144
+ async getMemberIndex(idCommitment) {
145
+ try {
146
+ const isValid = await this.contract.isInMembershipSet(idCommitment);
147
+ if (!isValid) {
148
+ return null;
149
+ }
150
+ const membershipInfo = await this.contract.memberships(idCommitment);
151
+ return BigNumber.from(membershipInfo.index);
152
+ }
153
+ catch (error) {
154
+ log.error(`Error getting member index: ${error.message}`);
155
+ throw new InvalidMembershipError(idCommitment);
156
+ }
157
+ }
158
+ async getMembershipInfo(idCommitment) {
159
+ try {
160
+ const [startBlock, endBlock, rateLimit] = await this.contract.getMembershipInfo(idCommitment);
161
+ const currentBlock = await this.contract.provider.getBlockNumber();
162
+ let state;
163
+ if (currentBlock < startBlock) {
164
+ state = MembershipState.Active;
165
+ }
166
+ else if (currentBlock < endBlock) {
167
+ state = MembershipState.GracePeriod;
168
+ }
169
+ else {
170
+ state = MembershipState.Expired;
171
+ }
172
+ const index = await this.getMemberIndex(idCommitment);
173
+ if (index === null) {
174
+ throw new MembershipNotFoundError(idCommitment);
175
+ }
176
+ return {
177
+ index,
178
+ idCommitment,
179
+ rateLimit: rateLimit.toNumber(),
180
+ startBlock: startBlock.toNumber(),
181
+ endBlock: endBlock.toNumber(),
182
+ state
183
+ };
184
+ }
185
+ catch (error) {
186
+ if (error instanceof RLNContractError) {
187
+ throw error;
188
+ }
189
+ log.error(`Error getting membership info: ${error.message}`);
190
+ throw new InvalidMembershipError(idCommitment);
191
+ }
192
+ }
193
+ async extendMembership(idCommitment) {
194
+ const tx = await this.contract.extendMemberships([idCommitment]);
195
+ await this.confirmTransaction(tx, "MembershipExtended", (event) => ({
196
+ idCommitment: event.args.idCommitment,
197
+ endBlock: event.args.endBlock
198
+ }));
199
+ }
200
+ async eraseMembership(idCommitment, eraseFromMembershipSet = true) {
201
+ const tx = await this.contract.eraseMemberships([idCommitment], eraseFromMembershipSet);
202
+ await this.confirmTransaction(tx, "MembershipErased", (event) => ({
203
+ idCommitment: event.args.idCommitment,
204
+ index: event.args.index
205
+ }));
206
+ }
207
+ async registerMembership(idCommitment, rateLimit = DEFAULT_RATE_LIMIT) {
208
+ if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
209
+ rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
210
+ throw new Error(`Rate limit must be between ${RATE_LIMIT_PARAMS.MIN_RATE} and ${RATE_LIMIT_PARAMS.MAX_RATE}`);
211
+ }
212
+ const tx = await this.contract.register(idCommitment, rateLimit, []);
213
+ await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
214
+ idCommitment: event.args.idCommitment,
215
+ membershipRateLimit: event.args.membershipRateLimit,
216
+ index: event.args.index
217
+ }));
218
+ }
219
+ async withdraw(token, holder) {
220
+ try {
221
+ const tx = await this.contract.withdraw(token, { from: holder });
222
+ await this.confirmTransaction(tx, "TokenWithdrawn", (event) => ({
223
+ token: event.args.token,
224
+ holder: event.args.holder,
225
+ amount: event.args.amount
226
+ }));
227
+ }
228
+ catch (error) {
229
+ log.error(`Error in withdraw: ${error.message}`);
230
+ throw error;
231
+ }
232
+ }
233
+ async registerWithIdentity(identity) {
234
+ try {
235
+ log.info(`Registering identity with rate limit: ${this.rateLimit} messages/epoch`);
236
+ // Check if the ID commitment is already registered
237
+ const existingIndex = await this.getMemberIndex(identity.IDCommitmentBigInt.toString());
238
+ if (existingIndex !== null) {
239
+ throw new MembershipExistsError(identity.IDCommitmentBigInt.toString(), existingIndex.toString());
240
+ }
241
+ // Check if there's enough remaining rate limit
242
+ const remainingRateLimit = await this.getRemainingTotalRateLimit();
243
+ if (remainingRateLimit < this.rateLimit) {
244
+ throw new RateLimitExceededError(this.rateLimit, remainingRateLimit);
245
+ }
246
+ const estimatedGas = await this.contract.estimateGas.register(identity.IDCommitmentBigInt, this.rateLimit, []);
247
+ const gasLimit = estimatedGas.add(10000);
248
+ const tx = await this.contract.register(identity.IDCommitmentBigInt, this.rateLimit, [], { gasLimit });
249
+ const decodedData = await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
250
+ idCommitment: event.args.idCommitment,
251
+ membershipRateLimit: event.args.membershipRateLimit,
252
+ index: event.args.index
253
+ }));
254
+ log.info(`Successfully registered membership with index ${decodedData.index} ` +
255
+ `and rate limit ${decodedData.membershipRateLimit}`);
256
+ const network = await this.contract.provider.getNetwork();
257
+ const address = this.contract.address;
258
+ const membershipId = decodedData.index.toString();
259
+ return {
260
+ identity,
261
+ membership: {
262
+ address,
263
+ treeIndex: parseInt(membershipId),
264
+ chainId: network.chainId.toString(),
265
+ rateLimit: decodedData.membershipRateLimit.toNumber()
266
+ }
267
+ };
268
+ }
269
+ catch (error) {
270
+ if (error instanceof RLNContractError) {
271
+ throw error;
272
+ }
273
+ if (error instanceof Error) {
274
+ const errorMessage = error.message;
275
+ log.error("registerWithIdentity - error message:", errorMessage);
276
+ log.error("registerWithIdentity - error stack:", error.stack);
277
+ // Map contract errors to our custom errors
278
+ if (errorMessage.includes("CannotExceedMaxTotalRateLimit")) {
279
+ throw new RateLimitExceededError(this.rateLimit, await this.getRemainingTotalRateLimit());
280
+ }
281
+ else if (errorMessage.includes("InvalidIdCommitment")) {
282
+ throw new InvalidMembershipError(identity.IDCommitmentBigInt.toString());
283
+ }
284
+ else if (errorMessage.includes("InvalidMembershipRateLimit")) {
285
+ throw new InvalidRateLimitError(this.rateLimit, RATE_LIMIT_PARAMS.MIN_RATE, RATE_LIMIT_PARAMS.MAX_RATE);
286
+ }
287
+ else if (errorMessage.includes("execution reverted")) {
288
+ throw new TransactionError("Contract execution reverted. Check contract requirements.");
289
+ }
290
+ throw new RLNContractError(`Error in registerWithIdentity: ${errorMessage}`);
291
+ }
292
+ throw new RLNContractError("Unknown error in registerWithIdentity");
293
+ }
294
+ }
295
+ async registerWithPermitAndErase(identity, permit, idCommitmentsToErase) {
296
+ try {
297
+ log.info(`Registering identity with permit and rate limit: ${this.rateLimit} messages/epoch`);
298
+ const tx = await this.contract.registerWithPermit(permit.owner, permit.deadline, permit.v, permit.r, permit.s, identity.IDCommitmentBigInt, this.rateLimit, idCommitmentsToErase.map((id) => BigNumber.from(id)));
299
+ const decodedData = await this.confirmTransaction(tx, "MembershipRegistered", (event) => ({
300
+ idCommitment: event.args.idCommitment,
301
+ membershipRateLimit: event.args.membershipRateLimit,
302
+ index: event.args.index
303
+ }));
304
+ log.info(`Successfully registered membership with permit. Index: ${decodedData.index}, ` +
305
+ `Rate limit: ${decodedData.membershipRateLimit}, Erased ${idCommitmentsToErase.length} commitments`);
306
+ const network = await this.contract.provider.getNetwork();
307
+ const address = this.contract.address;
308
+ const membershipId = decodedData.index.toString();
309
+ return {
310
+ identity,
311
+ membership: {
312
+ address,
313
+ treeIndex: parseInt(membershipId),
314
+ chainId: network.chainId.toString(),
315
+ rateLimit: decodedData.membershipRateLimit.toNumber()
316
+ }
317
+ };
318
+ }
319
+ catch (error) {
320
+ log.error(`Error in registerWithPermitAndErase: ${error.message}`);
321
+ throw error;
322
+ }
323
+ }
324
+ /**
325
+ * Validates that the rate limit is within the allowed range
326
+ * @throws Error if the rate limit is outside the allowed range
327
+ */
328
+ validateRateLimit(rateLimit) {
329
+ if (rateLimit < RATE_LIMIT_PARAMS.MIN_RATE ||
330
+ rateLimit > RATE_LIMIT_PARAMS.MAX_RATE) {
331
+ throw new InvalidRateLimitError(rateLimit, RATE_LIMIT_PARAMS.MIN_RATE, RATE_LIMIT_PARAMS.MAX_RATE);
332
+ }
333
+ }
334
+ /**
335
+ * Helper to confirm a transaction and extract event data
336
+ */
337
+ async confirmTransaction(tx, expectedEvent, transform) {
338
+ const receipt = await tx.wait();
339
+ const event = receipt.events?.find((e) => e.event === expectedEvent);
340
+ if (!event || !event.args) {
341
+ throw new TransactionError(`Expected event ${expectedEvent} not found`);
342
+ }
343
+ return transform(event);
344
+ }
345
+ }
346
+
347
+ export { RLNBaseContract };