feat: rln-v2 (#35)
* feat: init rln-v2 changes * chore: remove poseidont3, dont calculate rate commitments * fix: deploy script * feat: add g16 verifier * chore: deploy to sepolia and polygon-zkevm-testnet * chore: snapshot * fix(rln): reuse getDepositAmount func
This commit is contained in:
parent
9ee3217886
commit
5d9108a138
|
@ -1,15 +1,17 @@
|
|||
RlnTest:test__Constants() (gas: 7921)
|
||||
RlnTest:test__InvalidRegistration__DuplicateCommitment(uint256) (runs: 1000, μ: 120248, ~: 120248)
|
||||
RlnTest:test__InvalidRegistration__FullSet() (gas: 1242442)
|
||||
RlnTest:test__InvalidRegistration__InsufficientDeposit(uint256) (runs: 1000, μ: 17189, ~: 17189)
|
||||
RlnTest:test__InvalidRegistration__InvalidIdCommitment(uint256) (runs: 1000, μ: 16963, ~: 16968)
|
||||
RlnTest:test__InvalidSlash__InvalidProof() (gas: 958986)
|
||||
RlnTest:test__InvalidSlash__MemberNotRegistered(uint256) (runs: 1000, μ: 30287, ~: 30287)
|
||||
RlnTest:test__InvalidSlash__NoStake(uint256,address) (runs: 1000, μ: 301136, ~: 301143)
|
||||
RlnTest:test__InvalidSlash__ToRlnAddress() (gas: 128396)
|
||||
RlnTest:test__InvalidSlash__ToZeroAddress() (gas: 128301)
|
||||
RlnTest:test__InvalidWithdraw__InsufficientContractBalance() (gas: 126872)
|
||||
RlnTest:test__InvalidWithdraw__InsufficientWithdrawalBalance() (gas: 10494)
|
||||
RlnTest:test__ValidRegistration(uint256) (runs: 1000, μ: 112053, ~: 112053)
|
||||
RlnTest:test__ValidSlash(uint256,address) (runs: 1000, μ: 184955, ~: 184966)
|
||||
RlnTest:test__ValidWithdraw(address) (runs: 1000, μ: 183699, ~: 183687)
|
||||
RlnTest:test__Constants() (gas: 8619)
|
||||
RlnTest:test__InvalidRegistration__DuplicateCommitment(uint256) (runs: 1000, μ: 144113, ~: 144113)
|
||||
RlnTest:test__InvalidRegistration__FullSet() (gas: 1433224)
|
||||
RlnTest:test__InvalidRegistration__InsufficientDeposit(uint256) (runs: 1000, μ: 17440, ~: 17440)
|
||||
RlnTest:test__InvalidRegistration__InvalidIdCommitment(uint256) (runs: 1000, μ: 17053, ~: 17058)
|
||||
RlnTest:test__InvalidRegistration__InvalidUserMessageLimit() (gas: 17055)
|
||||
RlnTest:test__InvalidRegistration__MaxUserMessageLimit() (gas: 17203)
|
||||
RlnTest:test__InvalidSlash__InvalidProof() (gas: 1081919)
|
||||
RlnTest:test__InvalidSlash__MemberNotRegistered(uint256) (runs: 1000, μ: 32521, ~: 32521)
|
||||
RlnTest:test__InvalidSlash__NoStake(uint256,address) (runs: 1000, μ: 319630, ~: 319682)
|
||||
RlnTest:test__InvalidSlash__ToRlnAddress() (gas: 151034)
|
||||
RlnTest:test__InvalidSlash__ToZeroAddress() (gas: 150939)
|
||||
RlnTest:test__InvalidWithdraw__InsufficientContractBalance() (gas: 145224)
|
||||
RlnTest:test__InvalidWithdraw__InsufficientWithdrawalBalance() (gas: 10538)
|
||||
RlnTest:test__ValidRegistration(uint256) (runs: 1000, μ: 135760, ~: 135760)
|
||||
RlnTest:test__ValidSlash(uint256,address) (runs: 1000, μ: 203402, ~: 203412)
|
||||
RlnTest:test__ValidWithdraw(address) (runs: 1000, μ: 202120, ~: 202108)
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -14,7 +14,7 @@ contract Deploy is BaseScript {
|
|||
// step 1: deploy the verifier
|
||||
Verifier verifier = new Verifier();
|
||||
// step 2: deploy the rln contract
|
||||
rln = new Rln(0, 20, address(verifier));
|
||||
rln = new Rln(0, 20, 20, address(verifier));
|
||||
vm.stopBroadcast();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@ pragma solidity >=0.8.19;
|
|||
|
||||
interface IVerifier {
|
||||
function verifyProof(
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c,
|
||||
uint256[2] memory input
|
||||
uint256[2] calldata a,
|
||||
uint256[2][2] calldata b,
|
||||
uint256[2] calldata c,
|
||||
uint256[2] calldata input
|
||||
)
|
||||
external
|
||||
view
|
||||
|
|
|
@ -7,9 +7,10 @@ contract Rln is RlnBase {
|
|||
constructor(
|
||||
uint256 membershipDeposit,
|
||||
uint256 depth,
|
||||
uint256 maxMessageLimit,
|
||||
address _verifier
|
||||
)
|
||||
RlnBase(membershipDeposit, depth, _verifier)
|
||||
RlnBase(membershipDeposit, depth, maxMessageLimit, _verifier)
|
||||
{ }
|
||||
|
||||
function _validateRegistration(uint256 idCommitment) internal pure override { }
|
||||
|
|
|
@ -21,6 +21,9 @@ error FailedValidation();
|
|||
/// Invalid idCommitment
|
||||
error InvalidIdCommitment(uint256 idCommitment);
|
||||
|
||||
/// Invalid userMessageLimit
|
||||
error InvalidUserMessageLimit(uint256 messageLimit);
|
||||
|
||||
/// Invalid receiver address, when the receiver is the contract itself or 0x0
|
||||
error InvalidReceiverAddress(address to);
|
||||
|
||||
|
@ -47,6 +50,9 @@ abstract contract RlnBase {
|
|||
uint256 public constant Q =
|
||||
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
|
||||
|
||||
/// @notice The max message limit per epoch
|
||||
uint256 public immutable MAX_MESSAGE_LIMIT;
|
||||
|
||||
/// @notice The deposit amount required to register as a member
|
||||
uint256 public immutable MEMBERSHIP_DEPOSIT;
|
||||
|
||||
|
@ -67,6 +73,10 @@ abstract contract RlnBase {
|
|||
/// maps from idCommitment to their index in the set
|
||||
mapping(uint256 => uint256) public members;
|
||||
|
||||
/// @notice the user message limit of each member
|
||||
/// maps from idCommitment to their user message limit
|
||||
mapping(uint256 => uint256) public userMessageLimits;
|
||||
|
||||
/// @notice the index to commitment mapping
|
||||
mapping(uint256 => uint256) public indexToCommitment;
|
||||
|
||||
|
@ -84,8 +94,9 @@ abstract contract RlnBase {
|
|||
|
||||
/// Emitted when a new member is added to the set
|
||||
/// @param idCommitment The idCommitment of the member
|
||||
/// @param userMessageLimit the user message limit of the member
|
||||
/// @param index The index of the member in the set
|
||||
event MemberRegistered(uint256 idCommitment, uint256 index);
|
||||
event MemberRegistered(uint256 idCommitment, uint256 userMessageLimit, uint256 index);
|
||||
|
||||
/// Emitted when a member is removed from the set
|
||||
/// @param idCommitment The idCommitment of the member
|
||||
|
@ -97,28 +108,54 @@ abstract contract RlnBase {
|
|||
_;
|
||||
}
|
||||
|
||||
constructor(uint256 membershipDeposit, uint256 depth, address _verifier) {
|
||||
modifier onlyValidUserMessageLimit(uint256 messageLimit) {
|
||||
if (messageLimit > MAX_MESSAGE_LIMIT) revert InvalidUserMessageLimit(messageLimit);
|
||||
if (messageLimit == 0) revert InvalidUserMessageLimit(messageLimit);
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(uint256 membershipDeposit, uint256 depth, uint256 maxMessageLimit, address _verifier) {
|
||||
MEMBERSHIP_DEPOSIT = membershipDeposit;
|
||||
MAX_MESSAGE_LIMIT = maxMessageLimit;
|
||||
DEPTH = depth;
|
||||
SET_SIZE = 1 << depth;
|
||||
verifier = IVerifier(_verifier);
|
||||
deployedBlockNumber = uint32(block.number);
|
||||
}
|
||||
|
||||
/// Returns the deposit amount required to register as a member
|
||||
/// @param userMessageLimit The message limit of the member
|
||||
/// TODO: update this function as per tokenomics design
|
||||
function getDepositAmount(uint256 userMessageLimit) public view returns (uint256) {
|
||||
return userMessageLimit * MEMBERSHIP_DEPOSIT;
|
||||
}
|
||||
|
||||
/// Allows a user to register as a member
|
||||
/// @param idCommitment The idCommitment of the member
|
||||
function register(uint256 idCommitment) external payable virtual onlyValidIdCommitment(idCommitment) {
|
||||
if (msg.value != MEMBERSHIP_DEPOSIT) {
|
||||
/// @param userMessageLimit The message limit of the member
|
||||
function register(
|
||||
uint256 idCommitment,
|
||||
uint256 userMessageLimit
|
||||
)
|
||||
external
|
||||
payable
|
||||
virtual
|
||||
onlyValidIdCommitment(idCommitment)
|
||||
onlyValidUserMessageLimit(userMessageLimit)
|
||||
{
|
||||
uint256 requiredDeposit = getDepositAmount(userMessageLimit);
|
||||
if (msg.value != requiredDeposit) {
|
||||
revert InsufficientDeposit(MEMBERSHIP_DEPOSIT, msg.value);
|
||||
}
|
||||
_validateRegistration(idCommitment);
|
||||
_register(idCommitment, msg.value);
|
||||
_register(idCommitment, userMessageLimit, msg.value);
|
||||
}
|
||||
|
||||
/// Registers a member
|
||||
/// @param idCommitment The idCommitment of the member
|
||||
/// @param userMessageLimit The message limit of the member
|
||||
/// @param stake The amount of eth staked by the member
|
||||
function _register(uint256 idCommitment, uint256 stake) internal virtual {
|
||||
function _register(uint256 idCommitment, uint256 userMessageLimit, uint256 stake) internal virtual {
|
||||
if (memberExists[idCommitment]) revert DuplicateIdCommitment();
|
||||
if (idCommitmentIndex >= SET_SIZE) revert FullTree();
|
||||
|
||||
|
@ -126,8 +163,9 @@ abstract contract RlnBase {
|
|||
indexToCommitment[idCommitmentIndex] = idCommitment;
|
||||
memberExists[idCommitment] = true;
|
||||
stakedAmounts[idCommitment] = stake;
|
||||
userMessageLimits[idCommitment] = userMessageLimit;
|
||||
|
||||
emit MemberRegistered(idCommitment, idCommitmentIndex);
|
||||
emit MemberRegistered(idCommitment, userMessageLimit, idCommitmentIndex);
|
||||
idCommitmentIndex += 1;
|
||||
}
|
||||
|
||||
|
@ -158,6 +196,7 @@ abstract contract RlnBase {
|
|||
revert InvalidReceiverAddress(receiver);
|
||||
}
|
||||
|
||||
uint256 userMessageLimit = userMessageLimits[idCommitment];
|
||||
if (memberExists[idCommitment] == false) revert MemberNotRegistered(idCommitment);
|
||||
// check if member is registered
|
||||
if (stakedAmounts[idCommitment] == 0) {
|
||||
|
@ -176,7 +215,7 @@ abstract contract RlnBase {
|
|||
indexToCommitment[index] = 0;
|
||||
memberExists[idCommitment] = false;
|
||||
stakedAmounts[idCommitment] = 0;
|
||||
// TODO: remove from IMT
|
||||
userMessageLimits[idCommitment] = 0;
|
||||
|
||||
// refund deposit
|
||||
withdrawalBalance[receiver] += amountToTransfer;
|
||||
|
|
|
@ -1,330 +1,203 @@
|
|||
// File: https://github.com/Rate-Limiting-Nullifier/rln-contract-v1/blob/main/src/RLNVerifier.sol
|
||||
// Copyright 2017 Christian Reitwiessner
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
||||
// Software.
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// 2019 OKIMS
|
||||
// ported to solidity 0.6
|
||||
// fixed linter warnings
|
||||
// added requiere error messages
|
||||
//
|
||||
//
|
||||
// File: https://github.com/Rate-Limiting-Nullifier/rln-contract/blob/main/src/Verifier.sol
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.8.19;
|
||||
/*
|
||||
Copyright 2021 0KIMS association.
|
||||
|
||||
library Pairing {
|
||||
struct G1Point {
|
||||
uint256 X;
|
||||
uint256 Y;
|
||||
}
|
||||
// Encoding of field elements is: X[0] * z + X[1]
|
||||
This file is generated with [snarkJS](https://github.com/iden3/snarkjs).
|
||||
|
||||
struct G2Point {
|
||||
uint256[2] X;
|
||||
uint256[2] Y;
|
||||
}
|
||||
/// @return the generator of G1
|
||||
snarkJS is a free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
function P1() internal pure returns (G1Point memory) {
|
||||
return G1Point(1, 2);
|
||||
}
|
||||
/// @return the generator of G2
|
||||
snarkJS is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
function P2() internal pure returns (G2Point memory) {
|
||||
// Original code point
|
||||
return G2Point(
|
||||
[
|
||||
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634,
|
||||
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781
|
||||
],
|
||||
[
|
||||
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531,
|
||||
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930
|
||||
]
|
||||
);
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
// Changed by Jordi point
|
||||
return G2Point(
|
||||
[10857046999023057135944570762232829481370756359578518086990519993285655852781,
|
||||
11559732032986387107991004021392285783925812861821192530917403151452391805634],
|
||||
[8495653923123431417604973247489272438418190587263600148770280649306958101930,
|
||||
4082367875863433681332203403145435568316851327593401208105741076214120093531]
|
||||
);*/
|
||||
}
|
||||
/// @return r the negation of p, i.e. p.addition(p.negate()) should be zero.
|
||||
|
||||
function negate(G1Point memory p) internal pure returns (G1Point memory r) {
|
||||
// The prime q in the base field F_q for G1
|
||||
uint256 q =
|
||||
21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583;
|
||||
if (p.X == 0 && p.Y == 0) {
|
||||
return G1Point(0, 0);
|
||||
}
|
||||
return G1Point(p.X, q - (p.Y % q));
|
||||
}
|
||||
/// @return r the sum of two points of G1
|
||||
|
||||
function addition(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
|
||||
uint256[4] memory input;
|
||||
input[0] = p1.X;
|
||||
input[1] = p1.Y;
|
||||
input[2] = p2.X;
|
||||
input[3] = p2.Y;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 6, input, 0xc0, r, 0x60)
|
||||
// Use "invalid" to make gas estimation work
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
require(success, "pairing-add-failed");
|
||||
}
|
||||
/// @return r the product of a point on G1 and a scalar, i.e.
|
||||
/// p == p.scalar_mul(1) and p.addition(p) == p.scalar_mul(2) for all points p.
|
||||
|
||||
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
|
||||
uint256[3] memory input;
|
||||
input[0] = p.X;
|
||||
input[1] = p.Y;
|
||||
input[2] = s;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
|
||||
// Use "invalid" to make gas estimation work
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
require(success, "pairing-mul-failed");
|
||||
}
|
||||
/// @return the result of computing the pairing check
|
||||
/// e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
|
||||
/// For example pairing([P1(), P1().negate()], [P2(), P2()]) should
|
||||
/// return true.
|
||||
|
||||
function pairing(G1Point[] memory p1, G2Point[] memory p2) internal view returns (bool) {
|
||||
require(p1.length == p2.length, "pairing-lengths-failed");
|
||||
uint256 elements = p1.length;
|
||||
uint256 inputSize = elements * 6;
|
||||
uint256[] memory input = new uint256[](inputSize);
|
||||
for (uint256 i = 0; i < elements; i++) {
|
||||
input[i * 6 + 0] = p1[i].X;
|
||||
input[i * 6 + 1] = p1[i].Y;
|
||||
input[i * 6 + 2] = p2[i].X[0];
|
||||
input[i * 6 + 3] = p2[i].X[1];
|
||||
input[i * 6 + 4] = p2[i].Y[0];
|
||||
input[i * 6 + 5] = p2[i].Y[1];
|
||||
}
|
||||
uint256[1] memory out;
|
||||
bool success;
|
||||
// solium-disable-next-line security/no-inline-assembly
|
||||
assembly {
|
||||
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
|
||||
// Use "invalid" to make gas estimation work
|
||||
switch success
|
||||
case 0 { invalid() }
|
||||
}
|
||||
require(success, "pairing-opcode-failed");
|
||||
return out[0] != 0;
|
||||
}
|
||||
/// Convenience method for a pairing check for two pairs.
|
||||
|
||||
function pairingProd2(
|
||||
G1Point memory a1,
|
||||
G2Point memory a2,
|
||||
G1Point memory b1,
|
||||
G2Point memory b2
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
G1Point[] memory p1 = new G1Point[](2);
|
||||
G2Point[] memory p2 = new G2Point[](2);
|
||||
p1[0] = a1;
|
||||
p1[1] = b1;
|
||||
p2[0] = a2;
|
||||
p2[1] = b2;
|
||||
return pairing(p1, p2);
|
||||
}
|
||||
/// Convenience method for a pairing check for three pairs.
|
||||
|
||||
function pairingProd3(
|
||||
G1Point memory a1,
|
||||
G2Point memory a2,
|
||||
G1Point memory b1,
|
||||
G2Point memory b2,
|
||||
G1Point memory c1,
|
||||
G2Point memory c2
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
G1Point[] memory p1 = new G1Point[](3);
|
||||
G2Point[] memory p2 = new G2Point[](3);
|
||||
p1[0] = a1;
|
||||
p1[1] = b1;
|
||||
p1[2] = c1;
|
||||
p2[0] = a2;
|
||||
p2[1] = b2;
|
||||
p2[2] = c2;
|
||||
return pairing(p1, p2);
|
||||
}
|
||||
/// Convenience method for a pairing check for four pairs.
|
||||
|
||||
function pairingProd4(
|
||||
G1Point memory a1,
|
||||
G2Point memory a2,
|
||||
G1Point memory b1,
|
||||
G2Point memory b2,
|
||||
G1Point memory c1,
|
||||
G2Point memory c2,
|
||||
G1Point memory d1,
|
||||
G2Point memory d2
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
G1Point[] memory p1 = new G1Point[](4);
|
||||
G2Point[] memory p2 = new G2Point[](4);
|
||||
p1[0] = a1;
|
||||
p1[1] = b1;
|
||||
p1[2] = c1;
|
||||
p1[3] = d1;
|
||||
p2[0] = a2;
|
||||
p2[1] = b2;
|
||||
p2[2] = c2;
|
||||
p2[3] = d2;
|
||||
return pairing(p1, p2);
|
||||
}
|
||||
}
|
||||
pragma solidity >=0.7.0 <0.9.0;
|
||||
|
||||
contract Verifier {
|
||||
using Pairing for *;
|
||||
// Scalar field size
|
||||
uint256 constant r =
|
||||
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
|
||||
// Base field size
|
||||
uint256 constant q =
|
||||
21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583;
|
||||
|
||||
struct VerifyingKey {
|
||||
Pairing.G1Point alfa1;
|
||||
Pairing.G2Point beta2;
|
||||
Pairing.G2Point gamma2;
|
||||
Pairing.G2Point delta2;
|
||||
Pairing.G1Point[] IC;
|
||||
}
|
||||
// Verification Key data
|
||||
uint256 constant alphax =
|
||||
20_491_192_805_390_485_299_153_009_773_594_534_940_189_261_866_228_447_918_068_658_471_970_481_763_042;
|
||||
uint256 constant alphay =
|
||||
9_383_485_363_053_290_200_918_347_156_157_836_566_562_967_994_039_712_273_449_902_621_266_178_545_958;
|
||||
uint256 constant betax1 =
|
||||
4_252_822_878_758_300_859_123_897_981_450_591_353_533_073_413_197_771_768_651_442_665_752_259_397_132;
|
||||
uint256 constant betax2 =
|
||||
6_375_614_351_688_725_206_403_948_262_868_962_793_625_744_043_794_305_715_222_011_528_459_656_738_731;
|
||||
uint256 constant betay1 =
|
||||
21_847_035_105_528_745_403_288_232_691_147_584_728_191_162_732_299_865_338_377_159_692_350_059_136_679;
|
||||
uint256 constant betay2 =
|
||||
10_505_242_626_370_262_277_552_901_082_094_356_697_409_835_680_220_590_971_873_171_140_371_331_206_856;
|
||||
uint256 constant gammax1 =
|
||||
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634;
|
||||
uint256 constant gammax2 =
|
||||
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781;
|
||||
uint256 constant gammay1 =
|
||||
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531;
|
||||
uint256 constant gammay2 =
|
||||
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930;
|
||||
uint256 constant deltax1 =
|
||||
11_551_021_181_461_167_826_461_759_140_322_976_337_427_023_987_127_500_996_455_457_136_635_486_400_849;
|
||||
uint256 constant deltax2 =
|
||||
16_440_331_697_014_556_916_876_897_072_677_669_680_121_386_347_171_004_539_353_252_116_876_383_229_648;
|
||||
uint256 constant deltay1 =
|
||||
16_935_666_883_311_644_237_478_257_793_713_075_046_951_222_500_094_443_222_621_864_730_929_684_383_196;
|
||||
uint256 constant deltay2 =
|
||||
15_542_122_065_551_809_636_611_024_015_159_689_732_218_122_471_819_623_718_488_423_844_152_861_811_271;
|
||||
|
||||
struct Proof {
|
||||
Pairing.G1Point A;
|
||||
Pairing.G2Point B;
|
||||
Pairing.G1Point C;
|
||||
}
|
||||
uint256 constant IC0x =
|
||||
19_490_069_286_251_317_200_471_893_224_761_952_280_235_157_078_692_599_655_063_040_494_106_083_015_102;
|
||||
uint256 constant IC0y =
|
||||
15_613_730_057_977_833_735_664_106_983_317_680_013_118_142_165_231_654_768_046_521_650_638_333_652_991;
|
||||
|
||||
function verifyingKey() internal pure returns (VerifyingKey memory vk) {
|
||||
vk.alfa1 = Pairing.G1Point(
|
||||
20_491_192_805_390_485_299_153_009_773_594_534_940_189_261_866_228_447_918_068_658_471_970_481_763_042,
|
||||
9_383_485_363_053_290_200_918_347_156_157_836_566_562_967_994_039_712_273_449_902_621_266_178_545_958
|
||||
);
|
||||
uint256 constant IC1x =
|
||||
1_563_543_155_852_853_229_359_605_494_188_815_884_199_915_022_658_219_002_707_722_789_976_065_966_419;
|
||||
uint256 constant IC1y =
|
||||
858_819_375_930_654_753_672_617_171_465_307_097_688_802_650_498_051_619_587_167_586_479_724_200_799;
|
||||
|
||||
vk.beta2 = Pairing.G2Point(
|
||||
[
|
||||
4_252_822_878_758_300_859_123_897_981_450_591_353_533_073_413_197_771_768_651_442_665_752_259_397_132,
|
||||
6_375_614_351_688_725_206_403_948_262_868_962_793_625_744_043_794_305_715_222_011_528_459_656_738_731
|
||||
],
|
||||
[
|
||||
21_847_035_105_528_745_403_288_232_691_147_584_728_191_162_732_299_865_338_377_159_692_350_059_136_679,
|
||||
10_505_242_626_370_262_277_552_901_082_094_356_697_409_835_680_220_590_971_873_171_140_371_331_206_856
|
||||
]
|
||||
);
|
||||
vk.gamma2 = Pairing.G2Point(
|
||||
[
|
||||
11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634,
|
||||
10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781
|
||||
],
|
||||
[
|
||||
4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531,
|
||||
8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930
|
||||
]
|
||||
);
|
||||
vk.delta2 = Pairing.G2Point(
|
||||
[
|
||||
12_423_666_958_566_268_737_444_308_034_237_892_912_702_648_013_927_558_883_280_319_245_968_679_130_649,
|
||||
15_986_964_528_637_281_931_410_749_976_607_406_939_789_163_617_014_270_799_373_312_764_775_965_360_012
|
||||
],
|
||||
[
|
||||
8_394_023_076_056_524_902_583_796_202_128_496_802_110_914_536_948_580_183_128_578_071_394_816_660_799,
|
||||
4_964_607_673_011_101_982_600_772_762_445_991_192_038_811_950_832_626_693_345_350_322_823_626_470_007
|
||||
]
|
||||
);
|
||||
vk.IC = new Pairing.G1Point[](3);
|
||||
uint256 constant IC2x =
|
||||
3_808_889_614_445_935_800_597_561_392_085_733_302_718_838_702_771_107_544_944_545_050_886_958_022_904;
|
||||
uint256 constant IC2y =
|
||||
13_293_649_293_049_947_010_793_838_294_353_767_499_934_999_769_633_605_908_974_566_715_226_392_122_400;
|
||||
|
||||
vk.IC[0] = Pairing.G1Point(
|
||||
1_655_549_413_518_972_190_198_478_012_616_802_994_254_462_093_161_203_201_613_599_472_264_958_303_841,
|
||||
21_742_734_017_792_296_281_216_385_119_397_138_748_114_275_727_065_024_271_646_515_586_404_591_497_876
|
||||
);
|
||||
// Memory data
|
||||
uint16 constant pVk = 0;
|
||||
uint16 constant pPairing = 128;
|
||||
|
||||
vk.IC[1] = Pairing.G1Point(
|
||||
16_497_930_821_522_159_474_595_176_304_955_625_435_616_718_625_609_462_506_360_632_944_366_974_274_906,
|
||||
10_404_924_572_941_018_678_793_755_094_259_635_830_045_501_866_471_999_610_240_845_041_996_101_882_275
|
||||
);
|
||||
|
||||
vk.IC[2] = Pairing.G1Point(
|
||||
9_567_910_551_099_174_794_221_497_568_036_631_681_620_409_346_997_815_381_833_929_247_558_241_020_796,
|
||||
17_282_591_858_786_007_768_931_802_126_325_866_705_896_012_606_427_630_592_145_070_155_065_868_649_172
|
||||
);
|
||||
}
|
||||
|
||||
function verify(uint256[] memory input, Proof memory proof) internal view returns (uint256) {
|
||||
uint256 snark_scalar_field =
|
||||
21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617;
|
||||
VerifyingKey memory vk = verifyingKey();
|
||||
require(input.length + 1 == vk.IC.length, "verifier-bad-input");
|
||||
// Compute the linear combination vk_x
|
||||
Pairing.G1Point memory vk_x = Pairing.G1Point(0, 0);
|
||||
for (uint256 i = 0; i < input.length; i++) {
|
||||
require(input[i] < snark_scalar_field, "verifier-gte-snark-scalar-field");
|
||||
vk_x = Pairing.addition(vk_x, Pairing.scalar_mul(vk.IC[i + 1], input[i]));
|
||||
}
|
||||
vk_x = Pairing.addition(vk_x, vk.IC[0]);
|
||||
if (
|
||||
!Pairing.pairingProd4(
|
||||
Pairing.negate(proof.A), proof.B, vk.alfa1, vk.beta2, vk_x, vk.gamma2, proof.C, vk.delta2
|
||||
)
|
||||
) return 1;
|
||||
return 0;
|
||||
}
|
||||
/// @return r bool true if proof is valid
|
||||
uint16 constant pLastMem = 896;
|
||||
|
||||
function verifyProof(
|
||||
uint256[2] memory a,
|
||||
uint256[2][2] memory b,
|
||||
uint256[2] memory c,
|
||||
uint256[2] memory input
|
||||
uint256[2] calldata _pA,
|
||||
uint256[2][2] calldata _pB,
|
||||
uint256[2] calldata _pC,
|
||||
uint256[2] calldata _pubSignals
|
||||
)
|
||||
public
|
||||
view
|
||||
returns (bool r)
|
||||
returns (bool)
|
||||
{
|
||||
Proof memory proof;
|
||||
proof.A = Pairing.G1Point(a[0], a[1]);
|
||||
proof.B = Pairing.G2Point([b[0][0], b[0][1]], [b[1][0], b[1][1]]);
|
||||
proof.C = Pairing.G1Point(c[0], c[1]);
|
||||
uint256[] memory inputValues = new uint256[](input.length);
|
||||
for (uint256 i = 0; i < input.length; i++) {
|
||||
inputValues[i] = input[i];
|
||||
}
|
||||
if (verify(inputValues, proof) == 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
assembly {
|
||||
function checkField(v) {
|
||||
if iszero(lt(v, q)) {
|
||||
mstore(0, 0)
|
||||
return(0, 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
// G1 function to multiply a G1 value(x,y) to value in an address
|
||||
function g1_mulAccC(pR, x, y, s) {
|
||||
let success
|
||||
let mIn := mload(0x40)
|
||||
mstore(mIn, x)
|
||||
mstore(add(mIn, 32), y)
|
||||
mstore(add(mIn, 64), s)
|
||||
|
||||
success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)
|
||||
|
||||
if iszero(success) {
|
||||
mstore(0, 0)
|
||||
return(0, 0x20)
|
||||
}
|
||||
|
||||
mstore(add(mIn, 64), mload(pR))
|
||||
mstore(add(mIn, 96), mload(add(pR, 32)))
|
||||
|
||||
success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)
|
||||
|
||||
if iszero(success) {
|
||||
mstore(0, 0)
|
||||
return(0, 0x20)
|
||||
}
|
||||
}
|
||||
|
||||
function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
|
||||
let _pPairing := add(pMem, pPairing)
|
||||
let _pVk := add(pMem, pVk)
|
||||
|
||||
mstore(_pVk, IC0x)
|
||||
mstore(add(_pVk, 32), IC0y)
|
||||
|
||||
// Compute the linear combination vk_x
|
||||
|
||||
g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))
|
||||
|
||||
g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))
|
||||
|
||||
// -A
|
||||
mstore(_pPairing, calldataload(pA))
|
||||
mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))
|
||||
|
||||
// B
|
||||
mstore(add(_pPairing, 64), calldataload(pB))
|
||||
mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
|
||||
mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
|
||||
mstore(add(_pPairing, 160), calldataload(add(pB, 96)))
|
||||
|
||||
// alpha1
|
||||
mstore(add(_pPairing, 192), alphax)
|
||||
mstore(add(_pPairing, 224), alphay)
|
||||
|
||||
// beta2
|
||||
mstore(add(_pPairing, 256), betax1)
|
||||
mstore(add(_pPairing, 288), betax2)
|
||||
mstore(add(_pPairing, 320), betay1)
|
||||
mstore(add(_pPairing, 352), betay2)
|
||||
|
||||
// vk_x
|
||||
mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
|
||||
mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))
|
||||
|
||||
// gamma2
|
||||
mstore(add(_pPairing, 448), gammax1)
|
||||
mstore(add(_pPairing, 480), gammax2)
|
||||
mstore(add(_pPairing, 512), gammay1)
|
||||
mstore(add(_pPairing, 544), gammay2)
|
||||
|
||||
// C
|
||||
mstore(add(_pPairing, 576), calldataload(pC))
|
||||
mstore(add(_pPairing, 608), calldataload(add(pC, 32)))
|
||||
|
||||
// delta2
|
||||
mstore(add(_pPairing, 640), deltax1)
|
||||
mstore(add(_pPairing, 672), deltax2)
|
||||
mstore(add(_pPairing, 704), deltay1)
|
||||
mstore(add(_pPairing, 736), deltay2)
|
||||
|
||||
let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)
|
||||
|
||||
isOk := and(success, mload(_pPairing))
|
||||
}
|
||||
|
||||
let pMem := mload(0x40)
|
||||
mstore(0x40, add(pMem, pLastMem))
|
||||
|
||||
// Validate that all evaluations ∈ F
|
||||
|
||||
checkField(calldataload(add(_pubSignals, 0)))
|
||||
|
||||
checkField(calldataload(add(_pubSignals, 32)))
|
||||
|
||||
checkField(calldataload(add(_pubSignals, 64)))
|
||||
|
||||
// Validate all evaluations
|
||||
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)
|
||||
|
||||
mstore(0, isValid)
|
||||
return(0, 0x20)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,10 +21,11 @@ contract RlnTest is Test {
|
|||
trueVerifier = new TrueVerifier();
|
||||
falseVerifier = new FalseVerifier();
|
||||
|
||||
rln = new Rln(MEMBERSHIP_DEPOSIT, DEPTH, address(trueVerifier));
|
||||
rln = new Rln(MEMBERSHIP_DEPOSIT, DEPTH, MAX_MESSAGE_LIMIT, address(trueVerifier));
|
||||
}
|
||||
|
||||
uint256 public constant MEMBERSHIP_DEPOSIT = 1_000_000_000_000_000;
|
||||
uint256 public constant MAX_MESSAGE_LIMIT = 20;
|
||||
uint256 public constant DEPTH = 20;
|
||||
uint256 public constant SET_SIZE = 1_048_576;
|
||||
uint256[8] public zeroedProof = [0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
@ -34,49 +35,68 @@ contract RlnTest is Test {
|
|||
assertEq(rln.MEMBERSHIP_DEPOSIT(), MEMBERSHIP_DEPOSIT);
|
||||
assertEq(rln.DEPTH(), DEPTH);
|
||||
assertEq(rln.SET_SIZE(), SET_SIZE);
|
||||
assertEq(rln.MAX_MESSAGE_LIMIT(), MAX_MESSAGE_LIMIT);
|
||||
assertEq(rln.deployedBlockNumber(), 1);
|
||||
}
|
||||
|
||||
function test__ValidRegistration(uint256 idCommitment) public {
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
assertEq(rln.memberExists(idCommitment), true);
|
||||
assertEq(rln.members(idCommitment), 0);
|
||||
assertEq(rln.userMessageLimits(idCommitment), 1);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__DuplicateCommitment(uint256 idCommitment) public {
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
assertEq(rln.memberExists(idCommitment), true);
|
||||
assertEq(rln.members(idCommitment), 0);
|
||||
assertEq(rln.userMessageLimits(idCommitment), 1);
|
||||
vm.expectRevert(DuplicateIdCommitment.selector);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__InvalidIdCommitment(uint256 idCommitment) public {
|
||||
vm.assume(!rln.isValidCommitment(idCommitment));
|
||||
vm.expectRevert(abi.encodeWithSelector(InvalidIdCommitment.selector, idCommitment));
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__InvalidUserMessageLimit() public {
|
||||
uint256 idCommitment =
|
||||
9_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
vm.expectRevert(abi.encodeWithSelector(InvalidUserMessageLimit.selector, 0));
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 0);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__MaxUserMessageLimit() public {
|
||||
uint256 idCommitment =
|
||||
9_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
vm.expectRevert(abi.encodeWithSelector(InvalidUserMessageLimit.selector, MAX_MESSAGE_LIMIT + 1));
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, MAX_MESSAGE_LIMIT + 1);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__InsufficientDeposit(uint256 idCommitment) public {
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
uint256 badDepositAmount = MEMBERSHIP_DEPOSIT - 1;
|
||||
vm.expectRevert(abi.encodeWithSelector(InsufficientDeposit.selector, MEMBERSHIP_DEPOSIT, badDepositAmount));
|
||||
rln.register{ value: badDepositAmount }(idCommitment);
|
||||
rln.register{ value: badDepositAmount }(idCommitment, 1);
|
||||
}
|
||||
|
||||
function test__InvalidRegistration__FullSet() public {
|
||||
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, address(rln.verifier()));
|
||||
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, MAX_MESSAGE_LIMIT, address(rln.verifier()));
|
||||
uint256 setSize = tempRln.SET_SIZE();
|
||||
for (uint256 i = 1; i <= setSize; i++) {
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(i);
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(i, 1);
|
||||
}
|
||||
assertEq(tempRln.idCommitmentIndex(), 4);
|
||||
vm.expectRevert(FullTree.selector);
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(setSize + 1);
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(setSize + 1, 1);
|
||||
}
|
||||
|
||||
function test__ValidSlash(uint256 idCommitment, address payable to) public {
|
||||
|
@ -87,7 +107,7 @@ contract RlnTest is Test {
|
|||
vm.assume(to != address(0));
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
|
||||
uint256 balanceBefore = to.balance;
|
||||
|
@ -105,7 +125,7 @@ contract RlnTest is Test {
|
|||
uint256 idCommitment =
|
||||
9_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
vm.expectRevert(abi.encodeWithSelector(InvalidReceiverAddress.selector, address(0)));
|
||||
rln.slash(idCommitment, payable(address(0)), zeroedProof);
|
||||
|
@ -114,7 +134,7 @@ contract RlnTest is Test {
|
|||
function test__InvalidSlash__ToRlnAddress() public {
|
||||
uint256 idCommitment =
|
||||
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
vm.expectRevert(abi.encodeWithSelector(InvalidReceiverAddress.selector, address(rln)));
|
||||
rln.slash(idCommitment, payable(address(rln)), zeroedProof);
|
||||
|
@ -134,7 +154,7 @@ contract RlnTest is Test {
|
|||
vm.assume(to != address(0));
|
||||
vm.assume(rln.isValidCommitment(idCommitment));
|
||||
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
|
||||
rln.slash(idCommitment, to, zeroedProof);
|
||||
|
@ -152,9 +172,9 @@ contract RlnTest is Test {
|
|||
uint256 idCommitment =
|
||||
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
|
||||
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, address(falseVerifier));
|
||||
Rln tempRln = new Rln(MEMBERSHIP_DEPOSIT, 2, MAX_MESSAGE_LIMIT, address(falseVerifier));
|
||||
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
tempRln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
|
||||
vm.expectRevert(InvalidProof.selector);
|
||||
tempRln.slash(idCommitment, payable(address(this)), zeroedProof);
|
||||
|
@ -168,7 +188,7 @@ contract RlnTest is Test {
|
|||
function test__InvalidWithdraw__InsufficientContractBalance() public {
|
||||
uint256 idCommitment =
|
||||
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
rln.slash(idCommitment, payable(address(this)), zeroedProof);
|
||||
assertEq(rln.stakedAmounts(idCommitment), 0);
|
||||
|
@ -187,7 +207,7 @@ contract RlnTest is Test {
|
|||
uint256 idCommitment =
|
||||
19_014_214_495_641_488_759_237_505_126_948_346_942_972_912_379_615_652_741_039_992_445_865_937_985_820;
|
||||
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment);
|
||||
rln.register{ value: MEMBERSHIP_DEPOSIT }(idCommitment, 1);
|
||||
assertEq(rln.stakedAmounts(idCommitment), MEMBERSHIP_DEPOSIT);
|
||||
rln.slash(idCommitment, to, zeroedProof);
|
||||
assertEq(rln.stakedAmounts(idCommitment), 0);
|
||||
|
|
Loading…
Reference in New Issue