From ea8fdd0798c84825fe17042d1fb4f38d384b854d Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 18 Aug 2023 17:24:04 -0400 Subject: [PATCH 1/3] feat: create `generate-rln-credentials` subcommand --- cmd/waku/main.go | 2 + cmd/waku/rlngenerate/command_no_rln.go | 19 +++ cmd/waku/rlngenerate/command_rln.go | 141 ++++++++++++++++++ cmd/waku/rlngenerate/flags.go | 75 ++++++++++ cmd/waku/rlngenerate/options.go | 21 +++ cmd/waku/rlngenerate/web3.go | 125 ++++++++++++++++ .../rln/group_manager/dynamic/dynamic.go | 19 +-- waku/v2/protocol/rln/keystore/keystore.go | 123 +++++++++------ 8 files changed, 465 insertions(+), 60 deletions(-) create mode 100644 cmd/waku/rlngenerate/command_no_rln.go create mode 100644 cmd/waku/rlngenerate/command_rln.go create mode 100644 cmd/waku/rlngenerate/flags.go create mode 100644 cmd/waku/rlngenerate/options.go create mode 100644 cmd/waku/rlngenerate/web3.go diff --git a/cmd/waku/main.go b/cmd/waku/main.go index b84c66a92..a4192839a 100644 --- a/cmd/waku/main.go +++ b/cmd/waku/main.go @@ -6,6 +6,7 @@ import ( cli "github.com/urfave/cli/v2" "github.com/urfave/cli/v2/altsrc" "github.com/waku-org/go-waku/cmd/waku/keygen" + "github.com/waku-org/go-waku/cmd/waku/rlngenerate" "github.com/waku-org/go-waku/waku/v2/node" ) @@ -114,6 +115,7 @@ func main() { }, Commands: []*cli.Command{ &keygen.Command, + &rlngenerate.Command, }, } diff --git a/cmd/waku/rlngenerate/command_no_rln.go b/cmd/waku/rlngenerate/command_no_rln.go new file mode 100644 index 000000000..edd287f67 --- /dev/null +++ b/cmd/waku/rlngenerate/command_no_rln.go @@ -0,0 +1,19 @@ +//go:build !gowaku_rln +// +build !gowaku_rln + +package rlngenerate + +import ( + "errors" + + cli "github.com/urfave/cli/v2" +) + +// Command generates a key file used to generate the node's peerID, encrypted with an optional password +var Command = cli.Command{ + Name: "generate-rln-credentials", + Usage: "Generate credentials for usage with RLN", + Action: func(cCtx *cli.Context) error { + return errors.New("not available. Execute `make RLN=true` to add RLN support to go-waku") + }, +} diff --git a/cmd/waku/rlngenerate/command_rln.go b/cmd/waku/rlngenerate/command_rln.go new file mode 100644 index 000000000..95f0ad671 --- /dev/null +++ b/cmd/waku/rlngenerate/command_rln.go @@ -0,0 +1,141 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package rlngenerate + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/ethclient" + cli "github.com/urfave/cli/v2" + "github.com/waku-org/go-waku/logging" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager/dynamic" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore" + "github.com/waku-org/go-waku/waku/v2/utils" + "github.com/waku-org/go-zerokit-rln/rln" + "go.uber.org/zap" +) + +var options Options +var logger = utils.Logger().Named("rln-credentials") + +// Command generates a key file used to generate the node's peerID, encrypted with an optional password +var Command = cli.Command{ + Name: "generate-rln-credentials", + Usage: "Generate credentials for usage with RLN", + Action: func(cCtx *cli.Context) error { + err := verifyFlags() + if err != nil { + logger.Error("validating option flags", zap.Error(err)) + return cli.Exit(err, 1) + } + + err = execute(context.Background()) + if err != nil { + logger.Error("registering RLN credentials", zap.Error(err)) + return cli.Exit(err, 1) + } + + return nil + }, + Flags: flags, +} + +func verifyFlags() error { + if options.CredentialsPath == "" { + logger.Warn("keystore: no credentials path set, using default path", zap.String("path", keystore.RLN_CREDENTIALS_FILENAME)) + options.CredentialsPath = keystore.RLN_CREDENTIALS_FILENAME + } + + if options.CredentialsPassword == "" { + logger.Warn("keystore: no credentials password set, using default password", zap.String("password", keystore.RLN_CREDENTIALS_PASSWORD)) + options.CredentialsPassword = keystore.RLN_CREDENTIALS_PASSWORD + } + + if options.ETHPrivateKey == nil { + return errors.New("a private key must be specified") + } + + return nil +} + +func execute(ctx context.Context) error { + ethClient, err := ethclient.Dial(options.ETHClientAddress) + if err != nil { + return err + } + + rlnInstance, err := rln.NewRLN() + if err != nil { + return err + } + + chainID, err := ethClient.ChainID(ctx) + if err != nil { + return err + } + + rlnContract, err := contracts.NewRLN(options.MembershipContractAddress, ethClient) + if err != nil { + return err + } + + // prepare rln membership key pair + logger.Info("generating rln credential") + identityCredential, err := rlnInstance.MembershipKeyGen() + if err != nil { + return err + } + + // register the rln-relay peer to the membership contract + membershipIndex, err := register(ctx, ethClient, rlnContract, identityCredential.IDCommitment, chainID) + if err != nil { + return err + } + + // TODO: clean private key from memory + + err = persistCredentials(identityCredential, membershipIndex, chainID) + if err != nil { + return err + } + + if logger.Level() == zap.DebugLevel { + logger.Info("registered credentials into the membership contract", + logging.HexString("IDCommitment", identityCredential.IDCommitment[:]), + logging.HexString("IDNullifier", identityCredential.IDNullifier[:]), + logging.HexString("IDSecretHash", identityCredential.IDSecretHash[:]), + logging.HexString("IDTrapDoor", identityCredential.IDTrapdoor[:]), + zap.Uint("index", membershipIndex), + ) + } else { + logger.Info("registered credentials into the membership contract", logging.HexString("idCommitment", identityCredential.IDCommitment[:]), zap.Uint("index", membershipIndex)) + } + + ethClient.Close() + + return nil +} + +func persistCredentials(identityCredential *rln.IdentityCredential, membershipIndex rln.MembershipIndex, chainID *big.Int) error { + membershipGroup := keystore.MembershipGroup{ + TreeIndex: membershipIndex, + MembershipContract: keystore.MembershipContract{ + ChainId: fmt.Sprintf("0x%X", chainID.Int64()), + Address: options.MembershipContractAddress.String(), + }, + } + + keystoreIndex, membershipGroupIndex, err := keystore.AddMembershipCredentials(options.CredentialsPath, identityCredential, membershipGroup, options.CredentialsPassword, dynamic.RLNAppInfo, keystore.DefaultSeparator) + if err != nil { + return fmt.Errorf("failed to persist credentials: %w", err) + } + + logger.Info("persisted credentials succesfully", zap.Int("keystoreIndex", keystoreIndex), zap.Int("membershipGroupIndex", membershipGroupIndex)) + + return nil +} diff --git a/cmd/waku/rlngenerate/flags.go b/cmd/waku/rlngenerate/flags.go new file mode 100644 index 000000000..460e9a724 --- /dev/null +++ b/cmd/waku/rlngenerate/flags.go @@ -0,0 +1,75 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package rlngenerate + +import ( + cli "github.com/urfave/cli/v2" + wcli "github.com/waku-org/go-waku/waku/cliutils" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore" +) + +var flags = []cli.Flag{ + &cli.PathFlag{ + Name: "cred-path", + Usage: "RLN relay membership credentials file", + Value: keystore.RLN_CREDENTIALS_FILENAME, + Destination: &options.CredentialsPath, + }, + &cli.StringFlag{ + Name: "cred-password", + Value: keystore.RLN_CREDENTIALS_PASSWORD, + Usage: "Password for encrypting RLN credentials", + Destination: &options.CredentialsPassword, + }, + &cli.GenericFlag{ + Name: "eth-account-private-key", + Usage: "Ethereum account private key used for registering in member contract", + Value: &wcli.PrivateKeyValue{ + Value: &options.ETHPrivateKey, + }, + }, + &cli.StringFlag{ + Name: "eth-client-address", + Usage: "Ethereum testnet client address", + Value: "ws://localhost:8545", + Destination: &options.ETHClientAddress, + }, + &cli.GenericFlag{ + Name: "eth-contract-address", + Usage: "Address of membership contract", + Value: &wcli.AddressValue{ + Value: &options.MembershipContractAddress, + }, + }, + &cli.StringFlag{ + Name: "eth-nonce", + Value: "", + Usage: "Set an specific ETH transaction nonce. Leave empty to calculate the nonce automatically", + Destination: &options.ETHNonce, + }, + &cli.Uint64Flag{ + Name: "eth-gas-limit", + Value: 0, + Usage: "Gas limit to set for the transaction execution (0 = estimate)", + Destination: &options.ETHGasLimit, + }, + &cli.StringFlag{ + Name: "eth-gas-price", + Value: "", + Usage: "Gas price in wei to use for the transaction execution (empty = gas price oracle)", + Destination: &options.ETHGasPrice, + }, + &cli.StringFlag{ + Name: "eth-gas-fee-cap", + Value: "", + Usage: "Gas fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)", + Destination: &options.ETHGasFeeCap, + }, + &cli.StringFlag{ + Name: "eth-gas-tip-cap", + Value: "", + Usage: "Gas priority fee cap in wei to use for the 1559 transaction execution (empty = gas price oracle)", + Destination: &options.ETHGasTipCap, + }, +} diff --git a/cmd/waku/rlngenerate/options.go b/cmd/waku/rlngenerate/options.go new file mode 100644 index 000000000..ce79d9264 --- /dev/null +++ b/cmd/waku/rlngenerate/options.go @@ -0,0 +1,21 @@ +package rlngenerate + +import ( + "crypto/ecdsa" + + "github.com/ethereum/go-ethereum/common" +) + +// Options are settings used to create RLN credentials. +type Options struct { + CredentialsPath string + CredentialsPassword string + ETHPrivateKey *ecdsa.PrivateKey + ETHClientAddress string + MembershipContractAddress common.Address + ETHGasLimit uint64 + ETHNonce string + ETHGasPrice string + ETHGasFeeCap string + ETHGasTipCap string +} diff --git a/cmd/waku/rlngenerate/web3.go b/cmd/waku/rlngenerate/web3.go new file mode 100644 index 000000000..6099e0a2b --- /dev/null +++ b/cmd/waku/rlngenerate/web3.go @@ -0,0 +1,125 @@ +//go:build gowaku_rln +// +build gowaku_rln + +package rlngenerate + +import ( + "context" + "errors" + "fmt" + "math/big" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/log" + "github.com/waku-org/go-waku/logging" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts" + "github.com/waku-org/go-zerokit-rln/rln" + "go.uber.org/zap" +) + +func getMembershipFee(ctx context.Context, rlnContract *contracts.RLN) (*big.Int, error) { + return rlnContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: ctx}) +} + +func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *contracts.RLN, idComm rln.IDCommitment, chainID *big.Int) (rln.MembershipIndex, error) { + // check if the contract exists by calling a static function + membershipFee, err := getMembershipFee(ctx, rlnContract) + if err != nil { + return 0, err + } + + auth, err := bind.NewKeyedTransactorWithChainID(options.ETHPrivateKey, chainID) + if err != nil { + return 0, err + } + auth.Value = membershipFee + auth.Context = ctx + auth.GasLimit = options.ETHGasLimit + + var ok bool + + if options.ETHNonce != "" { + nonce := &big.Int{} + auth.Nonce, ok = nonce.SetString(options.ETHNonce, 10) + if !ok { + return 0, errors.New("invalid nonce value") + } + } + + if options.ETHGasFeeCap != "" { + gasFeeCap := &big.Int{} + auth.GasFeeCap, ok = gasFeeCap.SetString(options.ETHGasFeeCap, 10) + if !ok { + return 0, errors.New("invalid gas fee cap value") + } + } + + if options.ETHGasTipCap != "" { + gasTipCap := &big.Int{} + auth.GasTipCap, ok = gasTipCap.SetString(options.ETHGasTipCap, 10) + if !ok { + return 0, errors.New("invalid gas tip cap value") + } + } + + if options.ETHGasPrice != "" { + gasPrice := &big.Int{} + auth.GasPrice, ok = gasPrice.SetString(options.ETHGasPrice, 10) + if !ok { + return 0, errors.New("invalid gas price value") + } + } + + log.Debug("registering an id commitment", zap.Binary("idComm", idComm[:])) + + // registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress + tx, err := rlnContract.Register(auth, rln.Bytes32ToBigInt(idComm)) + if err != nil { + return 0, fmt.Errorf("transaction error: %w", err) + } + + url := "" + switch chainID.Int64() { + case 1: + url = "https://etherscan.io" + case 5: + url = "https://goerli.etherscan.io" + case 11155111: + url = "https://sepolia.etherscan.io" + } + + if url != "" { + logger.Info(fmt.Sprintf("transaction broadcasted, find details of your registration transaction in %s/tx/%s", url, tx.Hash())) + } else { + logger.Info("transaction broadcasted.", zap.String("transactionHash", tx.Hash().String())) + } + + logger.Warn("waiting for transaction to be mined...") + + txReceipt, err := bind.WaitMined(ctx, ethClient, tx) + if err != nil { + return 0, fmt.Errorf("transaction error: %w", err) + } + + if txReceipt.Status != types.ReceiptStatusSuccessful { + return 0, errors.New("transaction reverted") + } + + // the receipt topic holds the hash of signature of the raised events + evt, err := rlnContract.ParseMemberRegistered(*txReceipt.Logs[0]) + if err != nil { + return 0, err + } + + var eventIDComm rln.IDCommitment = rln.BigIntToBytes32(evt.Pubkey) + + log.Debug("information extracted from tx log", zap.Uint64("blockNumber", evt.Raw.BlockNumber), logging.HexString("idCommitment", eventIDComm[:]), zap.Uint64("index", evt.Index.Uint64())) + + if eventIDComm != idComm { + return 0, errors.New("invalid id commitment key") + } + + return rln.MembershipIndex(uint(evt.Index.Int64())), nil +} diff --git a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go index 5b1da3e47..ad0bfae6c 100644 --- a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go +++ b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go @@ -215,7 +215,7 @@ func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN, if len(credentials) != 0 { if int(gm.keystoreIndex) <= len(credentials)-1 { credential := credentials[gm.keystoreIndex] - gm.identityCredential = &credential.IdentityCredential + gm.identityCredential = credential.IdentityCredential if int(gm.membershipGroupIndex) <= len(credential.MembershipGroups)-1 { gm.membershipIndex = &credential.MembershipGroups[gm.membershipGroupIndex].TreeIndex } else { @@ -275,18 +275,15 @@ func (gm *DynamicGroupManager) persistCredentials() error { return errors.New("no credentials to persist") } - keystoreCred := keystore.MembershipCredentials{ - IdentityCredential: *gm.identityCredential, - MembershipGroups: []keystore.MembershipGroup{{ - TreeIndex: *gm.membershipIndex, - MembershipContract: keystore.MembershipContract{ - ChainId: fmt.Sprintf("0x%X", gm.chainId), - Address: gm.membershipContractAddress.String(), - }, - }}, + membershipGroup := keystore.MembershipGroup{ + TreeIndex: *gm.membershipIndex, + MembershipContract: keystore.MembershipContract{ + ChainId: fmt.Sprintf("0x%X", gm.chainId), + Address: gm.membershipContractAddress.String(), + }, } - err := keystore.AddMembershipCredentials(gm.keystorePath, []keystore.MembershipCredentials{keystoreCred}, gm.keystorePassword, RLNAppInfo, keystore.DefaultSeparator) + _, _, err := keystore.AddMembershipCredentials(gm.keystorePath, gm.identityCredential, membershipGroup, gm.keystorePassword, RLNAppInfo, keystore.DefaultSeparator) if err != nil { return fmt.Errorf("failed to persist credentials: %w", err) } diff --git a/waku/v2/protocol/rln/keystore/keystore.go b/waku/v2/protocol/rln/keystore/keystore.go index 62ce3151a..f108aae27 100644 --- a/waku/v2/protocol/rln/keystore/keystore.go +++ b/waku/v2/protocol/rln/keystore/keystore.go @@ -7,6 +7,7 @@ import ( "fmt" "io/ioutil" "os" + "sort" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/waku-org/go-zerokit-rln/rln" @@ -27,8 +28,8 @@ type MembershipGroup struct { } type MembershipCredentials struct { - IdentityCredential rln.IdentityCredential `json:"identityCredential"` - MembershipGroups []MembershipGroup `json:"membershipGroups"` + IdentityCredential *rln.IdentityCredential `json:"identityCredential"` + MembershipGroups []MembershipGroup `json:"membershipGroups"` } type AppInfo struct { @@ -51,7 +52,7 @@ type AppKeystoreCredential struct { const DefaultSeparator = "\n" func (m MembershipCredentials) Equals(other MembershipCredentials) bool { - if !rln.IdentityCredentialEquals(m.IdentityCredential, other.IdentityCredential) { + if !rln.IdentityCredentialEquals(*m.IdentityCredential, *other.IdentityCredential) { return false } @@ -218,80 +219,104 @@ func GetMembershipCredentials(logger *zap.Logger, credentialsPath string, passwo return result, nil } -// Adds a sequence of membership credential to the keystore matching the application, appIdentifier and version filters. -func AddMembershipCredentials(path string, credentials []MembershipCredentials, password string, appInfo AppInfo, separator string) error { +// Adds a membership credential to the keystore matching the application, appIdentifier and version filters. +func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCredential, newMembershipGroup MembershipGroup, password string, appInfo AppInfo, separator string) (keystoreIndex int, membershipGroupIndex int, err error) { k, err := LoadAppKeystore(path, appInfo, DefaultSeparator) if err != nil { - return err + return 0, 0, err } - var credentialsToAdd []MembershipCredentials - for _, newCredential := range credentials { - // A flag to tell us if the keystore contains a credential associated to the input identity credential, i.e. membershipCredential - found := -1 - for i, existingCredentials := range k.Credentials { - credentialsBytes, err := keystore.DecryptDataV3(existingCredentials.Crypto, password) - if err != nil { - continue + // A flag to tell us if the keystore contains a credential associated to the input identity credential, i.e. membershipCredential + found := false + for i, existingCredentials := range k.Credentials { + credentialsBytes, err := keystore.DecryptDataV3(existingCredentials.Crypto, password) + if err != nil { + continue + } + + var credentials MembershipCredentials + err = json.Unmarshal(credentialsBytes, &credentials) + if err != nil { + continue + } + + if rln.IdentityCredentialEquals(*credentials.IdentityCredential, *newIdentityCredential) { + // idCredential is present in keystore. We add the input credential membership group to the one contained in the decrypted keystore credential (we deduplicate groups using sets) + allMembershipsMap := make(map[MembershipGroup]struct{}) + for _, m := range credentials.MembershipGroups { + allMembershipsMap[m] = struct{}{} + } + allMembershipsMap[newMembershipGroup] = struct{}{} + + // We sort membership groups, otherwise we will not have deterministic results in tests + var allMemberships []MembershipGroup + for k := range allMembershipsMap { + allMemberships = append(allMemberships, k) + } + sort.Slice(allMemberships, func(i, j int) bool { + return allMemberships[i].MembershipContract.Address < allMemberships[j].MembershipContract.Address + }) + + // we define the updated credential with the updated membership sets + updatedCredential := MembershipCredentials{ + IdentityCredential: newIdentityCredential, + MembershipGroups: allMemberships, } - var credentials MembershipCredentials - err = json.Unmarshal(credentialsBytes, &credentials) + // we re-encrypt creating a new keyfile + b, err := json.Marshal(updatedCredential) if err != nil { - continue + return 0, 0, err } - if rln.IdentityCredentialEquals(credentials.IdentityCredential, newCredential.IdentityCredential) { - // idCredential is present in keystore. We add the input credential membership group to the one contained in the decrypted keystore credential (we deduplicate groups using sets) - allMemberships := append(credentials.MembershipGroups, newCredential.MembershipGroups...) + encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP) + if err != nil { + return 0, 0, err + } - // we define the updated credential with the updated membership sets - updatedCredential := MembershipCredentials{ - IdentityCredential: newCredential.IdentityCredential, - MembershipGroups: allMemberships, - } + // we update the original credential field in keystoreCredentials + k.Credentials[i] = AppKeystoreCredential{Crypto: encryptedCredentials} - // we re-encrypt creating a new keyfile - b, err := json.Marshal(updatedCredential) - if err != nil { - return err - } + found = true - encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP) - if err != nil { - return err + // We setup the return values + membershipGroupIndex = len(allMemberships) + keystoreIndex = i + for mIdx, mg := range updatedCredential.MembershipGroups { + if mg.MembershipContract.Equals(newMembershipGroup.MembershipContract) { + membershipGroupIndex = mIdx + break } - - // we update the original credential field in keystoreCredentials - k.Credentials[i] = AppKeystoreCredential{Crypto: encryptedCredentials} - - found = i - - // We stop decrypting other credentials in the keystore - break } - } - if found == -1 { - credentialsToAdd = append(credentialsToAdd, newCredential) + // We stop decrypting other credentials in the keystore + break } } - for _, c := range credentialsToAdd { - b, err := json.Marshal(c) + if !found { // Not found + newCredential := MembershipCredentials{ + IdentityCredential: newIdentityCredential, + MembershipGroups: []MembershipGroup{newMembershipGroup}, + } + + b, err := json.Marshal(newCredential) if err != nil { - return err + return 0, 0, err } encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP) if err != nil { - return err + return 0, 0, err } k.Credentials = append(k.Credentials, AppKeystoreCredential{Crypto: encryptedCredentials}) + + keystoreIndex = len(k.Credentials) - 1 + membershipGroupIndex = len(newCredential.MembershipGroups) - 1 } - return save(k, path, separator) + return keystoreIndex, membershipGroupIndex, save(k, path, separator) } // Safely saves a Keystore's JsonNode to disk. From 1be7cf885240ae9c42a4d26f43b5d222d4bb2bfd Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Fri, 18 Aug 2023 17:38:30 -0400 Subject: [PATCH 2/3] refactor: remove credential registering from waku --- cmd/waku/flags_rln.go | 9 - cmd/waku/node_rln.go | 9 - cmd/waku/options.go | 1 - cmd/waku/rlngenerate/command_rln.go | 5 +- examples/chat2/exec.go | 23 --- examples/chat2/flags.go | 9 - examples/chat2/options.go | 1 - examples/rln/main.go | 45 +---- waku/v2/node/wakunode2_rln.go | 2 - waku/v2/node/wakuoptions.go | 3 - waku/v2/node/wakuoptions_rln.go | 6 +- .../rln/group_manager/dynamic/dynamic.go | 76 +------- .../rln/group_manager/dynamic/web3.go | 73 -------- waku/v2/protocol/rln/keystore/keystore.go | 22 ++- waku/v2/protocol/rln/onchain_test.go | 162 +++++++++++------- 15 files changed, 127 insertions(+), 319 deletions(-) diff --git a/cmd/waku/flags_rln.go b/cmd/waku/flags_rln.go index 4765a4cfd..e87094d3a 100644 --- a/cmd/waku/flags_rln.go +++ b/cmd/waku/flags_rln.go @@ -64,15 +64,6 @@ func rlnFlags() []cli.Flag { Usage: "the index of credentials to use", Destination: &options.RLNRelay.CredentialsIndex, }, - // TODO: this is a good candidate option for subcommands - // TODO: consider accepting a private key file and passwd - &cli.GenericFlag{ - Name: "rln-relay-eth-account-private-key", - Usage: "Ethereum account private key used for registering in member contract", - Value: &wcli.PrivateKeyValue{ - Value: &options.RLNRelay.ETHPrivateKey, - }, - }, &cli.StringFlag{ Name: "rln-relay-eth-client-address", Usage: "Ethereum testnet client address", diff --git a/cmd/waku/node_rln.go b/cmd/waku/node_rln.go index 7c0e38dfe..094ca037e 100644 --- a/cmd/waku/node_rln.go +++ b/cmd/waku/node_rln.go @@ -4,7 +4,6 @@ package main import ( - "crypto/ecdsa" "errors" "github.com/waku-org/go-waku/waku/v2/node" @@ -20,12 +19,6 @@ func checkForRLN(logger *zap.Logger, options NodeOptions, nodeOpts *[]node.WakuN if !options.RLNRelay.Dynamic { *nodeOpts = append(*nodeOpts, node.WithStaticRLNRelay(options.RLNRelay.PubsubTopic, options.RLNRelay.ContentTopic, rln.MembershipIndex(options.RLNRelay.MembershipGroupIndex), nil)) } else { - - var ethPrivKey *ecdsa.PrivateKey - if options.RLNRelay.ETHPrivateKey != nil { - ethPrivKey = options.RLNRelay.ETHPrivateKey - } - // TODO: too many parameters in this function // consider passing a config struct instead *nodeOpts = append(*nodeOpts, node.WithDynamicRLNRelay( @@ -39,8 +32,6 @@ func checkForRLN(logger *zap.Logger, options NodeOptions, nodeOpts *[]node.WakuN rln.MembershipIndex(options.RLNRelay.MembershipGroupIndex), nil, options.RLNRelay.ETHClientAddress, - ethPrivKey, - nil, )) } } diff --git a/cmd/waku/options.go b/cmd/waku/options.go index 03865004a..c6286400e 100644 --- a/cmd/waku/options.go +++ b/cmd/waku/options.go @@ -43,7 +43,6 @@ type RLNRelayOptions struct { PubsubTopic string ContentTopic string Dynamic bool - ETHPrivateKey *ecdsa.PrivateKey ETHClientAddress string MembershipContractAddress common.Address } diff --git a/cmd/waku/rlngenerate/command_rln.go b/cmd/waku/rlngenerate/command_rln.go index 95f0ad671..c689d9a43 100644 --- a/cmd/waku/rlngenerate/command_rln.go +++ b/cmd/waku/rlngenerate/command_rln.go @@ -130,12 +130,13 @@ func persistCredentials(identityCredential *rln.IdentityCredential, membershipIn }, } - keystoreIndex, membershipGroupIndex, err := keystore.AddMembershipCredentials(options.CredentialsPath, identityCredential, membershipGroup, options.CredentialsPassword, dynamic.RLNAppInfo, keystore.DefaultSeparator) + membershipGroupIndex, err := keystore.AddMembershipCredentials(options.CredentialsPath, identityCredential, membershipGroup, options.CredentialsPassword, dynamic.RLNAppInfo, keystore.DefaultSeparator) if err != nil { return fmt.Errorf("failed to persist credentials: %w", err) } - logger.Info("persisted credentials succesfully", zap.Int("keystoreIndex", keystoreIndex), zap.Int("membershipGroupIndex", membershipGroupIndex)) + // TODO: obtain keystore index? + logger.Info("persisted credentials succesfully", zap.Uint("membershipGroupIndex", membershipGroupIndex)) return nil } diff --git a/examples/chat2/exec.go b/examples/chat2/exec.go index 1f32af12c..058931827 100644 --- a/examples/chat2/exec.go +++ b/examples/chat2/exec.go @@ -6,7 +6,6 @@ import ( "net" tea "github.com/charmbracelet/bubbletea" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/libp2p/go-libp2p/core/protocol" "github.com/multiformats/go-multiaddr" @@ -48,26 +47,6 @@ func execute(options Options) { return nil } - registrationHandler := func(tx *types.Transaction) { - chainID := tx.ChainId().Int64() - url := "" - switch chainID { - case 1: - url = "https://etherscan.io" - case 5: - url = "https://goerli.etherscan.io" - case 11155111: - url = "https://sepolia.etherscan.io" - - } - - if url != "" { - fmt.Println(fmt.Sprintf("You are registered to the rln membership contract, find details of your registration transaction in %s/tx/%s", url, tx.Hash())) - } else { - fmt.Println(fmt.Sprintf("You are registered to the rln membership contract. Transaction hash: %s", url, tx.Hash())) - } - } - if options.RLNRelay.Dynamic { fmt.Println("Setting up dynamic rln...") opts = append(opts, node.WithDynamicRLNRelay( @@ -81,8 +60,6 @@ func execute(options Options) { uint(options.RLNRelay.MembershipIndex), spamHandler, options.RLNRelay.ETHClientAddress, - options.RLNRelay.ETHPrivateKey, - registrationHandler, )) } else { opts = append(opts, node.WithStaticRLNRelay( diff --git a/examples/chat2/flags.go b/examples/chat2/flags.go index e269d5567..48c3d0861 100644 --- a/examples/chat2/flags.go +++ b/examples/chat2/flags.go @@ -227,15 +227,6 @@ func getFlags() []cli.Flag { Usage: "Password for encrypting RLN credentials", Destination: &options.RLNRelay.CredentialsPassword, }, - // TODO: this is a good candidate option for subcommands - // TODO: consider accepting a private key file and passwd - &cli.GenericFlag{ - Name: "rln-relay-eth-account-private-key", - Usage: "Ethereum Goerli testnet account private key used for registering in member contract", - Value: &wcli.PrivateKeyValue{ - Value: &options.RLNRelay.ETHPrivateKey, - }, - }, &cli.StringFlag{ Name: "rln-relay-eth-client-address", Usage: "Ethereum testnet client address", diff --git a/examples/chat2/options.go b/examples/chat2/options.go index 3360e01af..b43c9f0d8 100644 --- a/examples/chat2/options.go +++ b/examples/chat2/options.go @@ -37,7 +37,6 @@ type RLNRelayOptions struct { PubsubTopic string ContentTopic string Dynamic bool - ETHPrivateKey *ecdsa.PrivateKey ETHClientAddress string MembershipContractAddress common.Address } diff --git a/examples/rln/main.go b/examples/rln/main.go index 9f317cdf2..2e9daea7f 100644 --- a/examples/rln/main.go +++ b/examples/rln/main.go @@ -12,7 +12,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/waku-org/go-waku/waku/v2/node" "github.com/waku-org/go-waku/waku/v2/payload" @@ -27,10 +26,11 @@ var log = utils.Logger().Named("rln") // Update these values // ============================================================================ const ethClientAddress = "wss://sepolia.infura.io/ws/v3/API_KEY_GOES_HERE" -const ethPrivateKey = "PRIVATE_KEY_GOES_HERE" const contractAddress = "0x9C09146844C1326c2dBC41c451766C7138F88155" -const credentialsPath = "" // Empty to store in current folder -const credentialsPassword = "" // Empty to use default +const keystorePath = "" // Empty to store in current folder +const keystorePassword = "" // Empty to use default +const keystoreIndex = 0 +const membershipGroupIndex = 0 var contentTopic = protocol.NewContentTopic("rln", 1, "test", "proto").String() var pubsubTopic = protocol.DefaultPubsubTopic() @@ -57,34 +57,6 @@ func main() { return nil } - registrationHandler := func(tx *types.Transaction) { - chainID := tx.ChainId().Int64() - url := "" - switch chainID { - case 1: - url = "https://etherscan.io" - case 5: - url = "https://goerli.etherscan.io" - case 11155111: - url = "https://sepolia.etherscan.io" - - } - - if url != "" { - fmt.Println(fmt.Sprintf("You are registered to the rln membership contract, find details of your registration transaction in %s/tx/%s", url, tx.Hash())) - } else { - fmt.Println(fmt.Sprintf("You are registered to the rln membership contract. Transaction hash: %s", url, tx.Hash())) - } - } - - // TODO: set configuration values in constants - - ethPrivKey, err := crypto.HexToECDSA(ethPrivateKey) - if err != nil { - log.Error("Could not convert hex into ecdsa key", zap.Error(err)) - return - } - wakuNode, err := node.New( node.WithPrivateKey(prvKey), node.WithHostAddress(hostAddr), @@ -93,13 +65,14 @@ func main() { node.WithDynamicRLNRelay( pubsubTopic.String(), contentTopic, - credentialsPath, - credentialsPassword, + keystorePath, + keystorePassword, + keystoreIndex, + "", // Will use default tree path common.HexToAddress(contractAddress), + membershipGroupIndex, spamHandler, ethClientAddress, - ethPrivKey, - registrationHandler, ), ) if err != nil { diff --git a/waku/v2/node/wakunode2_rln.go b/waku/v2/node/wakunode2_rln.go index 4d3c022fe..70f7aebd7 100644 --- a/waku/v2/node/wakunode2_rln.go +++ b/waku/v2/node/wakunode2_rln.go @@ -48,14 +48,12 @@ func (w *WakuNode) mountRlnRelay(ctx context.Context) error { groupManager, err = dynamic.NewDynamicGroupManager( w.opts.rlnETHClientAddress, - w.opts.rlnETHPrivateKey, w.opts.rlnMembershipContractAddress, w.opts.rlnRelayMemIndex, w.opts.keystorePath, w.opts.keystorePassword, w.opts.keystoreIndex, true, - w.opts.rlnRegistrationHandler, w.log, ) if err != nil { diff --git a/waku/v2/node/wakuoptions.go b/waku/v2/node/wakuoptions.go index f63190677..edee8b24f 100644 --- a/waku/v2/node/wakuoptions.go +++ b/waku/v2/node/wakuoptions.go @@ -9,7 +9,6 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/p2p/enode" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p" @@ -100,14 +99,12 @@ type WakuNodeParameters struct { rlnRelayContentTopic string rlnRelayDynamic bool rlnSpamHandler func(message *pb.WakuMessage) error - rlnETHPrivateKey *ecdsa.PrivateKey rlnETHClientAddress string keystorePath string keystorePassword string keystoreIndex uint rlnTreePath string rlnMembershipContractAddress common.Address - rlnRegistrationHandler func(tx *types.Transaction) keepAliveInterval time.Duration diff --git a/waku/v2/node/wakuoptions_rln.go b/waku/v2/node/wakuoptions_rln.go index a8cf212e0..f0b5715f0 100644 --- a/waku/v2/node/wakuoptions_rln.go +++ b/waku/v2/node/wakuoptions_rln.go @@ -4,8 +4,6 @@ package node import ( - "crypto/ecdsa" - "github.com/ethereum/go-ethereum/common" "github.com/waku-org/go-waku/waku/v2/protocol/rln" r "github.com/waku-org/go-zerokit-rln/rln" @@ -27,7 +25,7 @@ func WithStaticRLNRelay(pubsubTopic string, contentTopic string, memberIndex r.M // WithDynamicRLNRelay enables the Waku V2 RLN protocol in onchain mode. // Requires the `gowaku_rln` build constrain (or the env variable RLN=true if building go-waku) -func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, keystorePath string, keystorePassword string, keystoreIndex uint, treePath string, membershipContract common.Address, membershipGroupIndex uint, spamHandler rln.SpamHandler, ethClientAddress string, ethPrivateKey *ecdsa.PrivateKey, registrationHandler rln.RegistrationHandler) WakuNodeOption { +func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, keystorePath string, keystorePassword string, keystoreIndex uint, treePath string, membershipContract common.Address, membershipGroupIndex uint, spamHandler rln.SpamHandler, ethClientAddress string) WakuNodeOption { return func(params *WakuNodeParameters) error { params.enableRLN = true params.rlnRelayDynamic = true @@ -38,9 +36,7 @@ func WithDynamicRLNRelay(pubsubTopic string, contentTopic string, keystorePath s params.rlnRelayContentTopic = contentTopic params.rlnSpamHandler = spamHandler params.rlnETHClientAddress = ethClientAddress - params.rlnETHPrivateKey = ethPrivateKey params.rlnMembershipContractAddress = membershipContract - params.rlnRegistrationHandler = registrationHandler params.rlnRelayMemIndex = membershipGroupIndex params.rlnTreePath = treePath return nil diff --git a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go index ad0bfae6c..981432b8e 100644 --- a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go +++ b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go @@ -2,7 +2,6 @@ package dynamic import ( "context" - "crypto/ecdsa" "errors" "fmt" "math/big" @@ -43,17 +42,10 @@ type DynamicGroupManager struct { lastBlockProcessed uint64 - // ethAccountPrivateKey is required for signing transactions - // TODO may need to erase this ethAccountPrivateKey when is not used - // TODO may need to make ethAccountPrivateKey mandatory - ethAccountPrivateKey *ecdsa.PrivateKey - eventHandler RegistrationEventHandler - registrationHandler RegistrationHandler - chainId *big.Int - rlnContract *contracts.RLN - membershipFee *big.Int + chainId *big.Int + rlnContract *contracts.RLN saveKeystore bool keystorePath string @@ -120,14 +112,12 @@ type RegistrationHandler = func(tx *types.Transaction) func NewDynamicGroupManager( ethClientAddr string, - ethAccountPrivateKey *ecdsa.PrivateKey, memContractAddr common.Address, membershipGroupIndex uint, keystorePath string, keystorePassword string, keystoreIndex uint, saveKeystore bool, - registrationHandler RegistrationHandler, log *zap.Logger, ) (*DynamicGroupManager, error) { log = log.Named("rln-dynamic") @@ -148,8 +138,6 @@ func NewDynamicGroupManager( membershipGroupIndex: membershipGroupIndex, membershipContractAddress: memContractAddr, ethClientAddress: ethClientAddr, - ethAccountPrivateKey: ethAccountPrivateKey, - registrationHandler: registrationHandler, eventHandler: handler, saveKeystore: saveKeystore, keystorePath: path, @@ -193,7 +181,7 @@ func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN, } // check if the contract exists by calling a static function - gm.membershipFee, err = gm.getMembershipFee(ctx) + _, err = gm.getMembershipFee(ctx) if err != nil { return err } @@ -227,34 +215,6 @@ func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN, } } - if gm.identityCredential == nil && gm.ethAccountPrivateKey == nil { - return errors.New("either a credentials path or a private key must be specified") - } - - // prepare rln membership key pair - if gm.identityCredential == nil && gm.ethAccountPrivateKey != nil { - gm.log.Info("no rln-relay key is provided, generating one") - identityCredential, err := rlnInstance.MembershipKeyGen() - if err != nil { - return err - } - - gm.identityCredential = identityCredential - - // register the rln-relay peer to the membership contract - gm.membershipIndex, err = gm.Register(ctx) - if err != nil { - return err - } - - err = gm.persistCredentials() - if err != nil { - return err - } - - gm.log.Info("registered peer into the membership contract") - } - if gm.identityCredential == nil || gm.membershipIndex == nil { return errors.New("no credentials available") } @@ -266,31 +226,6 @@ func (gm *DynamicGroupManager) Start(ctx context.Context, rlnInstance *rln.RLN, return nil } -func (gm *DynamicGroupManager) persistCredentials() error { - if !gm.saveKeystore { - return nil - } - - if gm.identityCredential == nil || gm.membershipIndex == nil { - return errors.New("no credentials to persist") - } - - membershipGroup := keystore.MembershipGroup{ - TreeIndex: *gm.membershipIndex, - MembershipContract: keystore.MembershipContract{ - ChainId: fmt.Sprintf("0x%X", gm.chainId), - Address: gm.membershipContractAddress.String(), - }, - } - - _, _, err := keystore.AddMembershipCredentials(gm.keystorePath, gm.identityCredential, membershipGroup, gm.keystorePassword, RLNAppInfo, keystore.DefaultSeparator) - if err != nil { - return fmt.Errorf("failed to persist credentials: %w", err) - } - - return nil -} - func (gm *DynamicGroupManager) InsertMembers(toInsert *om.OrderedMap) error { for pair := toInsert.Oldest(); pair != nil; pair = pair.Next() { events := pair.Value.([]*contracts.RLNMemberRegistered) // TODO: should these be sortered by index? we assume all members arrive in order @@ -345,11 +280,6 @@ func (gm *DynamicGroupManager) IdentityCredentials() (rln.IdentityCredential, er return *gm.identityCredential, nil } -func (gm *DynamicGroupManager) SetCredentials(identityCredential *rln.IdentityCredential, index *rln.MembershipIndex) { - gm.identityCredential = identityCredential - gm.membershipIndex = index -} - func (gm *DynamicGroupManager) MembershipIndex() (rln.MembershipIndex, error) { if gm.membershipIndex == nil { return 0, errors.New("membership index has not been setup") diff --git a/waku/v2/protocol/rln/group_manager/dynamic/web3.go b/waku/v2/protocol/rln/group_manager/dynamic/web3.go index 92f8f2b37..e8e15f475 100644 --- a/waku/v2/protocol/rln/group_manager/dynamic/web3.go +++ b/waku/v2/protocol/rln/group_manager/dynamic/web3.go @@ -2,90 +2,17 @@ package dynamic import ( "context" - "crypto/ecdsa" "errors" - "math/big" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/rpc" "github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts" - "github.com/waku-org/go-zerokit-rln/rln" "go.uber.org/zap" ) -func register(ctx context.Context, backend *ethclient.Client, membershipFee *big.Int, idComm rln.IDCommitment, ethAccountPrivateKey *ecdsa.PrivateKey, rlnContract *contracts.RLN, chainID *big.Int, registrationHandler RegistrationHandler, log *zap.Logger) (*rln.MembershipIndex, error) { - auth, err := bind.NewKeyedTransactorWithChainID(ethAccountPrivateKey, chainID) - if err != nil { - return nil, err - } - auth.Value = membershipFee - auth.Context = ctx - - log.Debug("registering an id commitment", zap.Binary("idComm", idComm[:])) - - // registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress - tx, err := rlnContract.Register(auth, rln.Bytes32ToBigInt(idComm)) - if err != nil { - return nil, err - } - - log.Info("transaction broadcasted", zap.String("transactionHash", tx.Hash().Hex())) - - if registrationHandler != nil { - registrationHandler(tx) - } - - txReceipt, err := bind.WaitMined(ctx, backend, tx) - if err != nil { - return nil, err - } - - if txReceipt.Status != types.ReceiptStatusSuccessful { - return nil, errors.New("transaction reverted") - } - - // the receipt topic holds the hash of signature of the raised events - evt, err := rlnContract.ParseMemberRegistered(*txReceipt.Logs[0]) - if err != nil { - return nil, err - } - - var eventIDComm rln.IDCommitment = rln.BigIntToBytes32(evt.Pubkey) - - log.Debug("the identity commitment key extracted from tx log", zap.Binary("eventIDComm", eventIDComm[:])) - - if eventIDComm != idComm { - return nil, errors.New("invalid id commitment key") - } - - result := new(rln.MembershipIndex) - *result = rln.MembershipIndex(uint(evt.Index.Int64())) - - // debug "the index of registered identity commitment key", eventIndex=eventIndex - - log.Debug("the index of registered identity commitment key", zap.Uint("eventIndex", uint(*result))) - - return result, nil -} - -// Register registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey -// into the membership contract whose address is in rlnPeer.membershipContractAddress -func (gm *DynamicGroupManager) Register(ctx context.Context) (*rln.MembershipIndex, error) { - return register(ctx, - gm.ethClient, - gm.membershipFee, - gm.identityCredential.IDCommitment, - gm.ethAccountPrivateKey, - gm.rlnContract, - gm.chainId, - gm.registrationHandler, - gm.log) -} - // the types of inputs to this handler matches the MemberRegistered event/proc defined in the MembershipContract interface type RegistrationEventHandler = func(*DynamicGroupManager, []*contracts.RLNMemberRegistered) error diff --git a/waku/v2/protocol/rln/keystore/keystore.go b/waku/v2/protocol/rln/keystore/keystore.go index f108aae27..28d8996fb 100644 --- a/waku/v2/protocol/rln/keystore/keystore.go +++ b/waku/v2/protocol/rln/keystore/keystore.go @@ -220,10 +220,10 @@ func GetMembershipCredentials(logger *zap.Logger, credentialsPath string, passwo } // Adds a membership credential to the keystore matching the application, appIdentifier and version filters. -func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCredential, newMembershipGroup MembershipGroup, password string, appInfo AppInfo, separator string) (keystoreIndex int, membershipGroupIndex int, err error) { +func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCredential, newMembershipGroup MembershipGroup, password string, appInfo AppInfo, separator string) (membershipGroupIndex uint, err error) { k, err := LoadAppKeystore(path, appInfo, DefaultSeparator) if err != nil { - return 0, 0, err + return 0, err } // A flag to tell us if the keystore contains a credential associated to the input identity credential, i.e. membershipCredential @@ -266,12 +266,12 @@ func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCr // we re-encrypt creating a new keyfile b, err := json.Marshal(updatedCredential) if err != nil { - return 0, 0, err + return 0, err } encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP) if err != nil { - return 0, 0, err + return 0, err } // we update the original credential field in keystoreCredentials @@ -280,11 +280,10 @@ func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCr found = true // We setup the return values - membershipGroupIndex = len(allMemberships) - keystoreIndex = i + membershipGroupIndex = uint(len(allMemberships)) for mIdx, mg := range updatedCredential.MembershipGroups { if mg.MembershipContract.Equals(newMembershipGroup.MembershipContract) { - membershipGroupIndex = mIdx + membershipGroupIndex = uint(mIdx) break } } @@ -302,21 +301,20 @@ func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCr b, err := json.Marshal(newCredential) if err != nil { - return 0, 0, err + return 0, err } encryptedCredentials, err := keystore.EncryptDataV3(b, []byte(password), keystore.StandardScryptN, keystore.StandardScryptP) if err != nil { - return 0, 0, err + return 0, err } k.Credentials = append(k.Credentials, AppKeystoreCredential{Crypto: encryptedCredentials}) - keystoreIndex = len(k.Credentials) - 1 - membershipGroupIndex = len(newCredential.MembershipGroups) - 1 + membershipGroupIndex = uint(len(newCredential.MembershipGroups) - 1) } - return keystoreIndex, membershipGroupIndex, save(k, path, separator) + return membershipGroupIndex, save(k, path, separator) } // Safely saves a Keystore's JsonNode to disk. diff --git a/waku/v2/protocol/rln/onchain_test.go b/waku/v2/protocol/rln/onchain_test.go index fd427d113..cad5e7f54 100644 --- a/waku/v2/protocol/rln/onchain_test.go +++ b/waku/v2/protocol/rln/onchain_test.go @@ -4,11 +4,10 @@ package rln import ( - "bytes" "context" "crypto/ecdsa" "crypto/rand" - "errors" + "fmt" "math/big" "os" "testing" @@ -16,9 +15,11 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/waku-org/go-zerokit-rln/rln" + "go.uber.org/zap" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" "github.com/stretchr/testify/suite" @@ -27,11 +28,13 @@ import ( "github.com/waku-org/go-waku/waku/v2/protocol/rln/contracts" "github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager" "github.com/waku-org/go-waku/waku/v2/protocol/rln/group_manager/dynamic" + "github.com/waku-org/go-waku/waku/v2/protocol/rln/keystore" "github.com/waku-org/go-waku/waku/v2/timesource" "github.com/waku-org/go-waku/waku/v2/utils" ) -var MEMBERSHIP_FEE = big.NewInt(1000000000000000) // wei - 0.001 eth +var membershipFee = big.NewInt(1000000000000000) // wei - 0.001 eth +const keystorePassword = "test" func TestWakuRLNRelayDynamicSuite(t *testing.T) { suite.Run(t, new(WakuRLNRelayDynamicSuite)) @@ -49,11 +52,10 @@ type WakuRLNRelayDynamicSuite struct { u1PrivKey *ecdsa.PrivateKey u2PrivKey *ecdsa.PrivateKey - u3PrivKey *ecdsa.PrivateKey - u4PrivKey *ecdsa.PrivateKey - u5PrivKey *ecdsa.PrivateKey } +// TODO: on teardown, remove credentials + func (s *WakuRLNRelayDynamicSuite) SetupTest() { s.clientAddr = os.Getenv("GANACHE_NETWORK_RPC_URL") @@ -73,12 +75,6 @@ func (s *WakuRLNRelayDynamicSuite) SetupTest() { s.Require().NoError(err) s.u2PrivKey, err = crypto.ToECDSA(common.FromHex("0xa00da43843ad6b5161ddbace48f293ac3f82f8a8257af34de4c32900bb6e9a97")) s.Require().NoError(err) - s.u3PrivKey, err = crypto.ToECDSA(common.FromHex("0xa4c8d3ed78cd722521fac9d734c45187a4f5e887570be1f707a7bbce054c01ea")) - s.Require().NoError(err) - s.u4PrivKey, err = crypto.ToECDSA(common.FromHex("0x6b11ba548a7fd1958eb156877cc7bdd02d99d876b55381aa9b106c16b0b7a805")) - s.Require().NoError(err) - s.u5PrivKey, err = crypto.ToECDSA(common.FromHex("0x0410196287d0af405e5c16f610de52416bd48be74836dbca93d73e24bffb5a81")) - s.Require().NoError(err) s.backend = backend s.chainID = chainID @@ -87,35 +83,63 @@ func (s *WakuRLNRelayDynamicSuite) SetupTest() { auth, err := bind.NewKeyedTransactorWithChainID(s.u1PrivKey, chainID) s.Require().NoError(err) + // TODO: update rln contract + poseidonHasherAddr, _, _, err := contracts.DeployPoseidonHasher(auth, backend) s.Require().NoError(err) - rlnAddr, _, rlnContract, err := contracts.DeployRLN(auth, backend, MEMBERSHIP_FEE, big.NewInt(20), poseidonHasherAddr) + rlnAddr, _, rlnContract, err := contracts.DeployRLN(auth, backend, membershipFee, big.NewInt(20), poseidonHasherAddr) s.Require().NoError(err) s.rlnAddr = rlnAddr s.rlnContract = rlnContract } -func (s *WakuRLNRelayDynamicSuite) register(privKey *ecdsa.PrivateKey, commitment *big.Int, handler func(evt *contracts.RLNMemberRegistered) error) { +func (s *WakuRLNRelayDynamicSuite) removeCredentials(path string) { + err := os.Remove(path) + if err != nil { + utils.Logger().Warn("could not remove credentials", zap.String("path", path)) + } +} + +func (s *WakuRLNRelayDynamicSuite) generateCredentials(rlnInstance *rln.RLN) *rln.IdentityCredential { + identityCredential, err := rlnInstance.MembershipKeyGen() + s.Require().NoError(err) + return identityCredential +} + +func (s *WakuRLNRelayDynamicSuite) register(identityCredential *rln.IdentityCredential, privKey *ecdsa.PrivateKey, keystorePath string) (rln.MembershipIndex, uint) { + auth, err := bind.NewKeyedTransactorWithChainID(privKey, s.chainID) s.Require().NoError(err) - auth.Value = MEMBERSHIP_FEE + auth.Value = membershipFee auth.Context = context.TODO() - tx, err := s.rlnContract.Register(auth, commitment) + tx, err := s.rlnContract.Register(auth, rln.Bytes32ToBigInt(identityCredential.IDCommitment)) s.Require().NoError(err) - receipt, err := bind.WaitMined(context.TODO(), s.backend, tx) + txReceipt, err := bind.WaitMined(context.TODO(), s.backend, tx) s.Require().NoError(err) - evt, err := s.rlnContract.ParseMemberRegistered(*receipt.Logs[0]) + s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful) + + evt, err := s.rlnContract.ParseMemberRegistered(*txReceipt.Logs[0]) s.Require().NoError(err) - if handler != nil { - err = handler(evt) - s.Require().NoError(err) + membershipIndex := rln.MembershipIndex(uint(evt.Index.Int64())) + + membershipGroup := keystore.MembershipGroup{ + TreeIndex: membershipIndex, + MembershipContract: keystore.MembershipContract{ + ChainId: fmt.Sprintf("0x%X", s.chainID.Int64()), + Address: s.rlnAddr.String(), + }, } + + membershipGroupIndex, err := keystore.AddMembershipCredentials(keystorePath, identityCredential, membershipGroup, keystorePassword, dynamic.RLNAppInfo, keystore.DefaultSeparator) + s.Require().NoError(err) + + return membershipIndex, membershipGroupIndex } func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() { @@ -138,7 +162,12 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() { rt, err := group_manager.NewMerkleRootTracker(5, rlnInstance) s.Require().NoError(err) - gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.u1PrivKey, s.rlnAddr, 0, "./test_onchain.json", "", 0, false, nil, utils.Logger()) + u1Credentials := s.generateCredentials(rlnInstance) + keystorePath1 := "./test_onchain.json" + _, membershipGroupIndex := s.register(u1Credentials, s.u1PrivKey, keystorePath1) + defer s.removeCredentials(keystorePath1) + + gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath1, keystorePassword, 0, false, utils.Logger()) s.Require().NoError(err) // initialize the WakuRLNRelay @@ -151,47 +180,47 @@ func (s *WakuRLNRelayDynamicSuite) TestDynamicGroupManagement() { nullifierLog: make(map[rln.MerkleNode][]rln.ProofMetadata), } - // generate another membership key pair - keyPair2, err := rlnInstance.MembershipKeyGen() - s.Require().NoError(err) - - err = rlnRelay.Start(context.Background()) + err = rlnRelay.Start(context.TODO()) s.Require().NoError(err) - // register user - gm.Register(context.TODO()) - - handler := func(evt *contracts.RLNMemberRegistered) error { - pubkey := rln.BigIntToBytes32(evt.Pubkey) - if !bytes.Equal(pubkey[:], keyPair2.IDCommitment[:]) { - return errors.New("not found") - } - - return rlnInstance.InsertMember(pubkey) - } + u2Credentials := s.generateCredentials(rlnInstance) + keystorePath2 := "./test_onchain2.json" + membershipIndex, _ := s.register(u2Credentials, s.u2PrivKey, keystorePath2) + defer s.removeCredentials(keystorePath2) - // register member with contract - s.register(s.u2PrivKey, rln.Bytes32ToBigInt(keyPair2.IDCommitment), handler) + time.Sleep(1 * time.Second) - time.Sleep(2 * time.Second) + treeCommitment, err := rlnInstance.GetLeaf(membershipIndex) + s.Require().NoError(err) + s.Require().Equal(u2Credentials.IDCommitment, treeCommitment) } func (s *WakuRLNRelayDynamicSuite) TestInsertKeyMembershipContract() { + // Create a RLN instance + rlnInstance, err := rln.NewRLN() + s.Require().NoError(err) - s.register(s.u1PrivKey, big.NewInt(20), nil) + credentials1 := s.generateCredentials(rlnInstance) + credentials2 := s.generateCredentials(rlnInstance) + credentials3 := s.generateCredentials(rlnInstance) + + keystorePath1 := "./test_onchain.json" + s.register(credentials1, s.u1PrivKey, keystorePath1) + defer s.removeCredentials(keystorePath1) // Batch Register auth, err := bind.NewKeyedTransactorWithChainID(s.u2PrivKey, s.chainID) s.Require().NoError(err) - auth.Value = MEMBERSHIP_FEE.Mul(big.NewInt(2), MEMBERSHIP_FEE) + auth.Value = membershipFee.Mul(big.NewInt(2), membershipFee) auth.Context = context.TODO() - tx, err := s.rlnContract.RegisterBatch(auth, []*big.Int{big.NewInt(20), big.NewInt(21)}) + tx, err := s.rlnContract.RegisterBatch(auth, []*big.Int{rln.Bytes32ToBigInt(credentials2.IDCommitment), rln.Bytes32ToBigInt(credentials3.IDCommitment)}) s.Require().NoError(err) - _, err = bind.WaitMined(context.TODO(), s.backend, tx) + txReceipt, err := bind.WaitMined(context.TODO(), s.backend, tx) s.Require().NoError(err) + s.Require().Equal(txReceipt.Status, types.ReceiptStatusSuccessful) } func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() { @@ -199,16 +228,13 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() { rlnInstance, err := rln.NewRLN() s.Require().NoError(err) - keyPair1, err := rlnInstance.MembershipKeyGen() - s.Require().NoError(err) + credentials1 := s.generateCredentials(rlnInstance) + credentials2 := s.generateCredentials(rlnInstance) - keyPair2, err := rlnInstance.MembershipKeyGen() + err = rlnInstance.InsertMember(credentials1.IDCommitment) s.Require().NoError(err) - err = rlnInstance.InsertMember(keyPair1.IDCommitment) - s.Require().NoError(err) - - err = rlnInstance.InsertMember(keyPair2.IDCommitment) + err = rlnInstance.InsertMember(credentials2.IDCommitment) s.Require().NoError(err) // get the Merkle root @@ -216,8 +242,8 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() { s.Require().NoError(err) // register the members to the contract - s.register(s.u1PrivKey, rln.Bytes32ToBigInt(keyPair1.IDCommitment), nil) - s.register(s.u1PrivKey, rln.Bytes32ToBigInt(keyPair2.IDCommitment), nil) + _, membershipGroupIndex := s.register(credentials1, s.u1PrivKey, "./test_onchain.json") + _, membershipGroupIndex = s.register(credentials2, s.u1PrivKey, "./test_onchain.json") // Creating relay port, err := tests.FindFreePort(s.T(), "", 5) @@ -239,16 +265,15 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() { defer sub.Unsubscribe() // mount the rln relay protocol in the on-chain/dynamic mode - gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.u1PrivKey, s.rlnAddr, 0, "./test_onchain.json", "", 0, false, nil, utils.Logger()) + // TODO: This assumes the keystoreIndex is 0, but there are two possible credentials in this keystore due to using the same contract address + // when credentials1 and credentials2 were registered. We should remove this hardcoded value and obtain the correct value when the credentials are persisted + keystoreIndex := uint(0) + gm, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, "./test_onchain.json", keystorePassword, keystoreIndex, false, utils.Logger()) s.Require().NoError(err) rlnRelay, err := New(relay, gm, "test-merkle-tree.db", RLNRELAY_PUBSUB_TOPIC, RLNRELAY_CONTENT_TOPIC, nil, timesource.NewDefaultClock(), utils.Logger()) s.Require().NoError(err) - // PreRegistering the keypair - membershipIndex := rln.MembershipIndex(0) - gm.SetCredentials(keyPair1, &membershipIndex) - err = rlnRelay.Start(context.TODO()) s.Require().NoError(err) @@ -264,6 +289,9 @@ func (s *WakuRLNRelayDynamicSuite) TestMerkleTreeConstruction() { } func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() { + // Creating an RLN instance (just for generating membership keys) + rlnInstance, err := rln.NewRLN() + s.Require().NoError(err) // Node 1 ============================================================ port1, err := tests.FindFreePort(s.T(), "", 5) @@ -282,8 +310,14 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() { s.Require().NoError(err) defer sub1.Unsubscribe() + // Register credentials1 in contract and keystore1 + credentials1 := s.generateCredentials(rlnInstance) + keystorePath1 := "./test_onchain.json" + _, membershipGroupIndex := s.register(credentials1, s.u1PrivKey, keystorePath1) + defer s.removeCredentials(keystorePath1) + // mount the rln relay protocol in the on-chain/dynamic mode - gm1, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.u1PrivKey, s.rlnAddr, 0, "./test_onchain.json", "", 0, false, nil, utils.Logger()) + gm1, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath1, keystorePassword, 0, false, utils.Logger()) s.Require().NoError(err) rlnRelay1, err := New(relay1, gm1, "test-correct-registration-1.db", RLNRELAY_PUBSUB_TOPIC, RLNRELAY_CONTENT_TOPIC, nil, timesource.NewDefaultClock(), utils.Logger()) @@ -308,8 +342,14 @@ func (s *WakuRLNRelayDynamicSuite) TestCorrectRegistrationOfPeers() { s.Require().NoError(err) defer sub2.Unsubscribe() + // Register credentials2 in contract and keystore2 + credentials2 := s.generateCredentials(rlnInstance) + keystorePath2 := "./test_onchain2.json" + _, membershipGroupIndex = s.register(credentials2, s.u2PrivKey, keystorePath2) + defer s.removeCredentials(keystorePath2) + // mount the rln relay protocol in the on-chain/dynamic mode - gm2, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.u2PrivKey, s.rlnAddr, 0, "./test_onchain.json", "", 0, false, nil, utils.Logger()) + gm2, err := dynamic.NewDynamicGroupManager(s.clientAddr, s.rlnAddr, membershipGroupIndex, keystorePath2, keystorePassword, 0, false, utils.Logger()) s.Require().NoError(err) rlnRelay2, err := New(relay2, gm2, "test-correct-registration-2.db", RLNRELAY_PUBSUB_TOPIC, RLNRELAY_CONTENT_TOPIC, nil, timesource.NewDefaultClock(), utils.Logger()) From 93398ed4fd31bdce6cc169c8c4c98af15213adb6 Mon Sep 17 00:00:00 2001 From: Richard Ramos Date: Mon, 21 Aug 2023 15:10:32 -0400 Subject: [PATCH 3/3] chore: update smart contracts and documentation --- .gitignore | 6 + .gitmodules | 3 + cmd/waku/rlngenerate/web3.go | 48 +- .../{rln.md => onchain-rln-relay-chat2.md} | 103 +-- ...f-running-on-chain-spam-protected-chat2.md | 111 +++ .../protocol/rln/contracts/PoseidonHasher.go | 234 +++++++ waku/v2/protocol/rln/contracts/README.md | 22 + waku/v2/protocol/rln/contracts/RLN.go | 663 ++++-------------- waku/v2/protocol/rln/contracts/RLN.sol | 96 --- .../rln/contracts/crypto/PoseidonHasher.sol | 535 -------------- waku/v2/protocol/rln/contracts/generate.go | 4 +- waku/v2/protocol/rln/contracts/rln-contract | 1 + .../rln/group_manager/dynamic/dynamic.go | 2 +- .../rln/group_manager/dynamic/handler_test.go | 6 +- waku/v2/protocol/rln/keystore/keystore.go | 2 +- waku/v2/protocol/rln/onchain_test.go | 2 - 16 files changed, 597 insertions(+), 1241 deletions(-) rename docs/tutorials/{rln.md => onchain-rln-relay-chat2.md} (68%) create mode 100644 docs/tutorials/pre-requisites-of-running-on-chain-spam-protected-chat2.md create mode 100644 waku/v2/protocol/rln/contracts/PoseidonHasher.go create mode 100644 waku/v2/protocol/rln/contracts/README.md delete mode 100644 waku/v2/protocol/rln/contracts/RLN.sol delete mode 100644 waku/v2/protocol/rln/contracts/crypto/PoseidonHasher.sol create mode 160000 waku/v2/protocol/rln/contracts/rln-contract diff --git a/.gitignore b/.gitignore index d09441a67..03bb14074 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,12 @@ Icon # Nix result +# Solidity files +waku/v2/protocol/rln/contracts/*.abi +waku/v2/protocol/rln/contracts/*.sol +waku/v2/protocol/rln/contracts/*.bin + + # Thumbnails ._* diff --git a/.gitmodules b/.gitmodules index e69de29bb..6014d2622 100644 --- a/.gitmodules +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "waku/v2/protocol/rln/contracts/rln-contract"] + path = waku/v2/protocol/rln/contracts/rln-contract + url = git@github.com:vacp2p/rln-contract.git diff --git a/cmd/waku/rlngenerate/web3.go b/cmd/waku/rlngenerate/web3.go index 6099e0a2b..f817dc483 100644 --- a/cmd/waku/rlngenerate/web3.go +++ b/cmd/waku/rlngenerate/web3.go @@ -23,17 +23,12 @@ func getMembershipFee(ctx context.Context, rlnContract *contracts.RLN) (*big.Int return rlnContract.MEMBERSHIPDEPOSIT(&bind.CallOpts{Context: ctx}) } -func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *contracts.RLN, idComm rln.IDCommitment, chainID *big.Int) (rln.MembershipIndex, error) { - // check if the contract exists by calling a static function - membershipFee, err := getMembershipFee(ctx, rlnContract) - if err != nil { - return 0, err - } - +func buildTransactor(ctx context.Context, membershipFee *big.Int, chainID *big.Int) (*bind.TransactOpts, error) { auth, err := bind.NewKeyedTransactorWithChainID(options.ETHPrivateKey, chainID) if err != nil { - return 0, err + return nil, err } + auth.Value = membershipFee auth.Context = ctx auth.GasLimit = options.ETHGasLimit @@ -44,7 +39,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con nonce := &big.Int{} auth.Nonce, ok = nonce.SetString(options.ETHNonce, 10) if !ok { - return 0, errors.New("invalid nonce value") + return nil, errors.New("invalid nonce value") } } @@ -52,7 +47,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con gasFeeCap := &big.Int{} auth.GasFeeCap, ok = gasFeeCap.SetString(options.ETHGasFeeCap, 10) if !ok { - return 0, errors.New("invalid gas fee cap value") + return nil, errors.New("invalid gas fee cap value") } } @@ -60,7 +55,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con gasTipCap := &big.Int{} auth.GasTipCap, ok = gasTipCap.SetString(options.ETHGasTipCap, 10) if !ok { - return 0, errors.New("invalid gas tip cap value") + return nil, errors.New("invalid gas tip cap value") } } @@ -68,10 +63,25 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con gasPrice := &big.Int{} auth.GasPrice, ok = gasPrice.SetString(options.ETHGasPrice, 10) if !ok { - return 0, errors.New("invalid gas price value") + return nil, errors.New("invalid gas price value") } } + return auth, nil +} + +func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *contracts.RLN, idComm rln.IDCommitment, chainID *big.Int) (rln.MembershipIndex, error) { + // check if the contract exists by calling a static function + membershipFee, err := getMembershipFee(ctx, rlnContract) + if err != nil { + return 0, err + } + + auth, err := buildTransactor(ctx, membershipFee, chainID) + if err != nil { + return 0, err + } + log.Debug("registering an id commitment", zap.Binary("idComm", idComm[:])) // registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress @@ -80,18 +90,18 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con return 0, fmt.Errorf("transaction error: %w", err) } - url := "" + explorerURL := "" switch chainID.Int64() { case 1: - url = "https://etherscan.io" + explorerURL = "https://etherscan.io" case 5: - url = "https://goerli.etherscan.io" + explorerURL = "https://goerli.etherscan.io" case 11155111: - url = "https://sepolia.etherscan.io" + explorerURL = "https://sepolia.etherscan.io" } - if url != "" { - logger.Info(fmt.Sprintf("transaction broadcasted, find details of your registration transaction in %s/tx/%s", url, tx.Hash())) + if explorerURL != "" { + logger.Info(fmt.Sprintf("transaction broadcasted, find details of your registration transaction in %s/tx/%s", explorerURL, tx.Hash())) } else { logger.Info("transaction broadcasted.", zap.String("transactionHash", tx.Hash().String())) } @@ -113,7 +123,7 @@ func register(ctx context.Context, ethClient *ethclient.Client, rlnContract *con return 0, err } - var eventIDComm rln.IDCommitment = rln.BigIntToBytes32(evt.Pubkey) + var eventIDComm rln.IDCommitment = rln.BigIntToBytes32(evt.IdCommitment) log.Debug("information extracted from tx log", zap.Uint64("blockNumber", evt.Raw.BlockNumber), logging.HexString("idCommitment", eventIDComm[:]), zap.Uint64("index", evt.Index.Uint64())) diff --git a/docs/tutorials/rln.md b/docs/tutorials/onchain-rln-relay-chat2.md similarity index 68% rename from docs/tutorials/rln.md rename to docs/tutorials/onchain-rln-relay-chat2.md index a7bb2add1..e82208083 100644 --- a/docs/tutorials/rln.md +++ b/docs/tutorials/onchain-rln-relay-chat2.md @@ -1,33 +1,28 @@ # Spam-protected chat2 application with on-chain group management This document is a tutorial on how to run the chat2 application in the spam-protected mode using the Waku-RLN-Relay protocol and with dynamic/on-chain group management. -In the on-chain/dynamic group management, the state of the group members i.e., their identity commitment keys is moderated via a membership smart contract deployed on the Goerli network which is one of the Ethereum testnets. +In the on-chain/dynamic group management, the state of the group members i.e., their identity commitment keys is moderated via a membership smart contract deployed on the Sepolia network which is one of the Ethereum testnets. Members can be dynamically added to the group and the group size can grow up to 2^20 members. This differs from the prior test scenarios in which the RLN group was static and the set of members' keys was hardcoded and fixed. ## Prerequisites -To complete this tutorial, you will need 1) an account with at least `0.001` ethers on the Goerli testnet and 2) a hosted node on the Goerli testnet. -In case you are not familiar with either of these two steps, you may follow the following tutorial to fulfill the [prerequisites of running on-chain spam-protected chat2](./pre-requisites-of-running-on-chain-spam-protected-chat2.md). -Note that the required `0.001` ethers correspond to the registration fee, -however, you still need to have more funds in your account to cover the cost of the transaction gas fee. - - +To complete this tutorial, you will need +1. An rln keystore file with credentials to the rln membership smart contract you wish to use. You may obtain this by registering to the smart contract and generating a keystore. It is possible to use go-waku to register into the smart contract: +``` +make +./build/waku generate-rln-credentials --eth-account-private-key= --eth-contract-address=<0x000...> --eth-client-address= --cred-path=rlnKeystore.json +``` ## Overview Figure 1 provides an overview of the interaction of the chat2 clients with the test fleets and the membership contract. -At a high level, when a chat2 client is run with Waku-RLN-Relay mounted in on-chain mode, it creates an RLN credential (i.e., an identity key and an identity commitment key) and -sends a transaction to the membership contract to register the corresponding membership identity commitment key. -This transaction will also transfer `0.001` Ethers to the contract as a membership fee. -This amount plus the transaction fee will be deducted from the supplied Goerli account. -Once the transaction is mined and the registration is successful, the registered credential will get displayed on the console of your chat2 client. +At a high level, when a chat2 client is run with Waku-RLN-Relay mounted in on-chain mode, the passed in credential will get displayed on the console of your chat2 client. You may copy the displayed RLN credential and reuse them for the future execution of the chat2 application. Proper instructions in this regard is provided in the following [section](#how-to-persist-and-reuse-rln-credential). -If you choose not to reuse the same credential, then for each execution, a new registration will take place and more funds will get deducted from your Goerli account. Under the hood, the chat2 client constantly listens to the membership contract and keeps itself updated with the latest state of the group. In the following test setting, the chat2 clients are to be connected to the Waku test fleets as their first hop. -The test fleets will act as routers and are also set to run Waku-RLN-Relay over the same pubsub topic and content topic as chat2 clients i.e., the default pubsub topic of `/waku/2/default-waku/proto` and the content topic of `/toy-chat/2/luzhou/proto`. +The test fleets will act as routers and are also set to run Waku-RLN-Relay over the same pubsub topic and content topic as chat2 clients i.e., the default pubsub topic of `/waku/2/default-waku/proto` and the content topic of `/toy-chat/3/mingde/proto`. Spam messages published on the said combination of topics will be caught by the test fleet nodes and will not be routed. Note that spam protection does not rely on the presence of the test fleets. In fact, all the chat2 clients are also capable of catching and dropping spam messages if they receive any. @@ -48,7 +43,7 @@ git clone https://github.com/waku-org/go-waku cd go-waku ``` ## Build chat2 -``` +```bash make chat2 ``` @@ -56,34 +51,40 @@ make chat2 Run the following command to set up your chat2 client. -``` -./build/chat2 --fleet=test --content-topic=/toy-chat/2/luzhou/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x4252105670fe33d2947e8ead304969849e64f2a6 --rln-relay-eth-account-private-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx --rln-relay-eth-client-address=xxxx +```bash +./build/chat2 --fleet=test \ +--content-topic=/toy-chat/3/mingde/proto \ +--rln-relay=true \ +--rln-relay-dynamic=true \ +--rln-relay-eth-contract-address=0x9C09146844C1326c2dBC41c451766C7138F88155 \ +--rln-relay-cred-path=xxx/xx/rlnKeystore.json \ +--rln-relay-cred-password=xxxx \ +--rln-relay-eth-client-address=xxxx ``` In this command - the `--fleet=test` indicates that the chat2 app gets connected to the test fleets. -- the `toy-chat/2/luzhou/proto` passed to the `--content-topic` option indicates the content topic on which the chat2 application is going to run. +- the `toy-chat/3/mingde/proto` passed to the `--content-topic` option indicates the content topic on which the chat2 application is going to run. - the `--rln-relay` flag is set to `true` to enable the Waku-RLN-Relay protocol for spam protection. - the `--rln-relay-dynamic` flag is set to `true` to enable the on-chain mode of Waku-RLN-Relay protocol with dynamic group management. - the `--rln-relay-eth-contract-address` option gets the address of the membership contract. - The current address of the contract is `0x4252105670fe33d2947e8ead304969849e64f2a6`. - You may check the state of the contract on the [Goerli testnet](https://goerli.etherscan.io/address/0x4252105670fe33d2947e8ead304969849e64f2a6). -- the `--rln-relay-eth-account-private-key` option is for your account private key on the Goerli testnet. - It is made up of 64 hex characters (not sensitive to the `0x` prefix). -- the `--rln-relay-eth-client-address` is the WebSocket address of the hosted node on the Goerli testnet. + The current address of the contract is `0x9C09146844C1326c2dBC41c451766C7138F88155`. + You may check the state of the contract on the [Sepolia testnet](https://sepolia.etherscan.io/address/0x9C09146844C1326c2dBC41c451766C7138F88155). +- the `--rln-relay-cred-path` option denotes the path to the keystore file described above +- the `--rln-relay-cred-password` option denotes the password to the keystore +- the `rln-relay-eth-client-address` is the WebSocket address of the hosted node on the Sepolia testnet. You need to replace the `xxxx` with the actual node's address. -For the last three config options i.e., `rln-relay-eth-account-address`, `rln-relay-eth-account-private-key`, and `rln-relay-eth-client-address`, if you do not know how to obtain those, you may use the following tutorial on the [prerequisites of running on-chain spam-protected chat2](./pre-requisites-of-running-on-chain-spam-protected-chat2.md). +For `--rln-relay-eth-client-address`, if you do not know how to obtain it, you may use the following tutorial on the [prerequisites of running on-chain spam-protected chat2](./pre-requisites-of-running-on-chain-spam-protected-chat2.md). You may set up more than one chat client, -using the `--rln-relay-cred-path` flag, specifying in each client a different path to store the credentials, and using a different `--tcp-port`. +using the `--rln-relay-cred-path` flag, specifying in each client a different path to store the credentials. Once you run the command, you will see the following message: ``` Setting up dynamic rln... ``` -At this phase, your RLN credential are getting created and a transaction is being sent to the membership smart contract. -It will take some time for the transaction to be finalized. Afterwards, messages related to setting up the connections of your chat app will be shown, +At this phase, RLN is being setup by obtaining the membership information from the smart contract. Afterwards, messages related to setting up the connections of your chat app will be shown, the content may differ on your screen though: ``` INFO: Welcome, Anonymous! @@ -145,9 +146,13 @@ The reason is that under the hood a zero-knowledge proof is being generated and Try to spam the network by violating the message rate limit i.e., sending more than one message per epoch. -Your messages will be routed via test fleets that are running in spam-protected mode over the same content topic i.e., `/toy-chat/2/luzhou/proto` as your chat client. +Your messages will be routed via test fleets that are running in spam-protected mode over the same content topic i.e., `/toy-chat/3/mingde/proto` as your chat client. Your spam activity will be detected by them and your message will not reach the rest of the chat clients. You can check this by running a second chat user and verifying that spam messages are not displayed as they are filtered by the test fleets. +Furthermore, the chat client will prompt you with the following warning message indicating that the message rate is being violated: +``` +ERROR: message rate violation! +``` A sample test scenario is illustrated in the [Sample test output section](#sample-test-output). Once you are done with the test, make sure you close all the chat2 clients by typing the `/exit` command. @@ -156,28 +161,32 @@ Once you are done with the test, make sure you close all the chat2 clients by ty Bye! ``` -## How to persist and reuse RLN credential +## How to reuse RLN credential -You may pass the `--rln-relay-cred-path` config option to specify a path for 1) persisting RLN credentials and 2) retrieving persisted RLN credentials. -RLN credential is persisted in the `rlnCredentials.txt` file under the specified path. -If this file does not already exist under the supplied path, then a new credential is generated and persisted in the `rlnCredentials.txt` file. -Otherwise, the chat client does not generate a new credential and will use, instead, the persisted RLN credential. +You may pass the `--rln-relay-cred-path` config option to specify a path to a file for retrieving persisted RLN credentials. +If the keystore exists in the path provided, it is used, and will default to the 0th element in the credential array. +If the keystore does not exist in the path provided, a new keystore will be created and added to the directory it was supposed to be in. -```bash -./build/chat2 --fleet:test --content-topic:/toy-chat/2/luzhou/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x4252105670fe33d2947e8ead304969849e64f2a6 --rln-relay-eth-account-private-key=your_eth_private_key --rln-relay-eth-client-address==your_goerli_node --rln-relay-cred-path:./ -``` - -Note: If you are reusing credentials, you can omit the `--rln-relay-eth-account-private-key` flags +You may provide an index to the credential you wish to use by passing the `--rln-relay-cred-index` config option. -Therefore, the command to start chat2 would be - +You may provide an index to the membership you wish to use (within the same membership set) by passing the `--rln-relay-membership-group-index` config option. ```bash -./build/chat2 --fleet=test --content-topic=/toy-chat/2/luzhou/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x4252105670fe33d2947e8ead304969849e64f2a6 --rln-relay-eth-client-address=your_goerli_node --rln-relay-cred-path=./ +./build/chat2 --fleet=test \ +--content-topic=/toy-chat/3/mingde/proto \ +--rln-relay=true \ +--rln-relay-dynamic=true \ +--rln-relay-eth-contract-address=0x9C09146844C1326c2dBC41c451766C7138F88155 \ +--rln-relay-eth-client-address=your_sepolia_node \ +--rln-relay-cred-path=./rlnKeystore.json \ +--rln-relay-cred-password=your_password \ +--rln-relay-membership-index=0 \ +--rln-relay-membership-group-index=0 ``` # Sample test output In this section, a sample test of running two chat clients is provided. -Note that the values used for `--rln-relay-eth-account-private-key`, and `--rln-relay-eth-client-address` in the following code snippets are junk and not valid. +Note that the value used for `--rln-relay-eth-client-address` in the following code snippets is junk and not valid. The two chat clients namely `Alice` and `Bob` are connected to the test fleets. `Alice` sends 4 messages i.e., `message1`, `message2`, `message3`, and `message4`. @@ -187,9 +196,11 @@ The test fleets do not relay `message3` further, hence `Bob` never receives it. You can check this fact by looking at `Bob`'s console, where `message3` is missing. **Alice** -``` -./build/chat2 --fleet=test --content-topic=/toy-chat/2/luzhou/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x4252105670fe33d2947e8ead304969849e64f2a6 --rln-relay-eth-account-private-key=your_eth_private_key --rln-relay-eth-client-address=your_goerli_node --rln-relay-cred-path=./path/to/alice/folder --nickname=Alice +```bash +./build/chat2 --fleet=test --content-topic=/toy-chat/3/mingde/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x9C09146844C1326c2dBC41c451766C7138F88155 --rln-relay-cred-path=rlnKeystore.json --rln-relay-cred-password=password --rln-relay-eth-client-address=wss://sepolia.infura.io/ws/v3/12345678901234567890123456789012 --nickname=Alice +``` +``` Seting up dynamic rln INFO: Welcome, Alice! INFO: type /help to see available commands @@ -235,9 +246,11 @@ INFO RLN Epoch: 165886593 ``` **Bob** -``` -./build/chat2 --fleet=test --content-topic=/toy-chat/2/luzhou/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x4252105670fe33d2947e8ead304969849e64f2a6 --rln-relay-eth-account-private-key=your_eth_private_key --rln-relay-eth-client-address=your_goerli_node --rln-relay-cred-path=./path/to/bob/folder --nickname=Bob +```bash +./build/chat2 --fleet=test --content-topic=/toy-chat/3/mingde/proto --rln-relay=true --rln-relay-dynamic=true --rln-relay-eth-contract-address=0x9C09146844C1326c2dBC41c451766C7138F88155 --rln-relay-cred-path=rlnKeystore.json --rln-relay-cred-index=1 --rln-relay-cred-password=password --rln-relay-eth-client-address=wss://sepolia.infura.io/ws/v3/12345678901234567890123456789012 --nickname=Bob +``` +``` Seting up dynamic rln INFO: Welcome, Bob! INFO: type /help to see available commands diff --git a/docs/tutorials/pre-requisites-of-running-on-chain-spam-protected-chat2.md b/docs/tutorials/pre-requisites-of-running-on-chain-spam-protected-chat2.md new file mode 100644 index 000000000..fd712e7f9 --- /dev/null +++ b/docs/tutorials/pre-requisites-of-running-on-chain-spam-protected-chat2.md @@ -0,0 +1,111 @@ +In this tutotial you will learn how to: +1. Create Sepolia Ethereum Account and obtain its private key. +2. Obtain Sepolia Ethers from faucet. +3. Set up a hosted node on Sepolia Testnet using Infura. + +If you already have an Ethereum account with sufficient ethers on the Sepolia testnet then you can skip the first two sections. +## Creating Sepolia Ethereum Account and obtaining its private key + + +1. Download and install Metamask. [https://metamask.io/download/](https://metamask.io/download/) +2. Create a new wallet and save your secret recovery key. + + ![](https://i.imgur.com/HEOI0kp.jpg) + +3. Login to Metamask. + + ![](https://i.imgur.com/zFduIV8.jpg) + +4. You should already see an account created. As you can see on top right, it should be pointing to Ethereum mainnet. + + ![](https://i.imgur.com/gk3TWUd.jpg) + +5. You can use the same account for different networks. For Waku we need to connect to the Sepolia test network. +6. You can switch to a test network by clicking on the drop down menu. Select Sepolia test network for Waku: + + ![](https://i.imgur.com/kbuup6y.jpg) + +7. Click on Show/hide test networks. +8. Enable “Show Test Networks". + + ![](https://i.imgur.com/02x7iSX.jpg) + + ![](https://i.imgur.com/UFsoRHR.jpg) + +9. Close the settings and now you should see the test networks in the drop down on the top right. + + ![](https://i.imgur.com/leSYt4z.jpg) + +10. Switch to Sepolia Test Network. +11. You can see that the same account can be used with different networks. But note that the ETH balance on different networks are different and are different tokens. + + ![](https://i.imgur.com/Y7YkuEe.jpg) + +12. Now to export your private key for the account, if needed, please click on the three dots beside the account. + + ![](https://i.imgur.com/9BlBmhT.jpg) + +13. Click on Account Details. +14. Click on Export Private Key. + + ![](https://i.imgur.com/7g6SyuX.jpg) + +15. Enter your Metamask password when prompted. + + ![](https://i.imgur.com/VOojHY5.jpg) + +16. You will be shown the private key. Copy it as needed. + +Obtain Sepolia Ethers from faucet +--- + +1. Ethers on Sepolia test networks can be obtained from different faucets. +2. One of the faucets is as follows: + 1. [https://sepoliafaucet.com//](https://sepoliafaucet.com/) + (NOTE: We have not tested the security of these faucets so please feel free to do your own research or obtain Sepolia ethers from other faucets if needed.) +3. Please follow the instructions on the webpages of these faucets. +4. A lot of faucets limit the Sepolia ETH to 0.05 ETH/day. +5. To obtain more eth, you can do some POW mining. One of those POW faucet is: + [https://sepolia-faucet.pk910.de/](https://sepolia-faucet.pk910.de/) +6. Enter your Eth account address, accept Captcha and start mining. + + ![](https://i.imgur.com/IvHNsei.jpg) + +7. You can see the estimated Sepolia ETH mined per hour. Each session is restricted to a few hours. + + ![](https://i.imgur.com/qTWwyNr.jpg) + +8. When you exceed the hour limit of the session, then the mining will be stopped. +9. Alternatively, stop the mining when mined enough sepolia ether. +10. Do not forget to claim your sepolia ether. + + ![](https://i.imgur.com/cGCSexB.jpg) + + +Setting up a hosted node on Sepolia Testnet using Infura +--- + +(Note: Infura provides a simple straight-forward way of setting up endpoints for interaction with the Ethereum chain and the Waku RLN smart contract without having to run a dedicated Ethereum node. Setting up infura is not mandatory. Operators concerned with the centralized aspect introduced by infura can setup their own node.) + +1. Sign up to infura if you do not have an account already. [https://infura.io/register](https://infura.io/register) + + ![](https://i.imgur.com/SyLaG6s.jpg) + +2. After registering and verifying the account, create a new project using Ethereum and give it a name. + + ![](https://i.imgur.com/fJbNqwd.jpg) + +3. After creating the project, you will be presented with a dashboard like follows. Note that your Project Id and secret will be different. + + ![](imgs/infura-dashboard-mainnet.png) + +4. Select Sepolia network in Endpoints. + + ![](https://i.imgur.com/RgmH7C1.png) + +5. You can find the endpoints for the hosted node using https and wss. The wss endpoint is the relevant one for connecting the waku node to the RLN contract on Sepolia network. Like follows: + + ![](https://i.imgur.com/xqbOcOH.png) + +6. You can change security settings or view usage options as required in the dashboard. +7. Congratulations, you are now ready to use the Infura node. diff --git a/waku/v2/protocol/rln/contracts/PoseidonHasher.go b/waku/v2/protocol/rln/contracts/PoseidonHasher.go new file mode 100644 index 000000000..e22e0810d --- /dev/null +++ b/waku/v2/protocol/rln/contracts/PoseidonHasher.go @@ -0,0 +1,234 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package contracts + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// PoseidonHasherMetaData contains all meta data concerning the PoseidonHasher contract. +var PoseidonHasherMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"input\",\"type\":\"uint256\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"result\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50613e0b806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063b189fd4c14610030575b600080fd5b61004a60048036038101906100459190613d7e565b610060565b6040516100579190613dba565b60405180910390f35b600061006b82610072565b9050919050565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a77f0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81840182828309838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30830192507f27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e03830192507f2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d382019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d0830192507f012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e2182019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b9830192507f179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b91830192507f1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b0582019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b56830192507f28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f2043830192507f2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc9830192507f0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a9830192507f2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b8830192507f02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e830192507f1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f58282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc7830192507f1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd830192507f2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f9478882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f43830192507f175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc582019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee32830192507f1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f830192507f14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e79682019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b97052830192507f1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b830192507f057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee830192507f21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b3830192507f268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed6830192507f04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af4082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e830192507f2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e9830192507f21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b830192507e2d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c3504982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a6830192507f0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a830192507f1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba3212830192507f0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e965233872762830192507f0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d382019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d1830192507f1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f830192507f23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c06082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a7830192507f1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a782019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b376830192507f015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd1830192507f0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f429830192507f15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c6830192507f0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da016830192507f044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b830192507f1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da830192507f2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b02087595482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd830192507f2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d830192507f2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b83830192507f08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f8482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef6830192507f041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f89830192507f0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c26782019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c515211830192507f0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f830192507f24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c817182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e830192507f2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b3830192507f25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f830192507f22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b63182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a9830192507f29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b5282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f830192507f07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea830192507f01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a682019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce89830192507f2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd6890735552282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c830192507f1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe7389830192507f1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad2830192507f1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c1482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c60830192507f1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e50882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507ed7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d1791830192507f140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae56565984830192507f0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c6182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c69830192507f2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc6629830192507f0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d582019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f646830192507f1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe37830192507f07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d0830192507f269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f08201915083838409905083838583840909925083828309905083828583840909915083847f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88409857f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad586090106925082945050505050919050565b600080fd5b6000819050919050565b613d5b81613d48565b8114613d6657600080fd5b50565b600081359050613d7881613d52565b92915050565b600060208284031215613d9457613d93613d43565b5b6000613da284828501613d69565b91505092915050565b613db481613d48565b82525050565b6000602082019050613dcf6000830184613dab565b9291505056fea26469706673582212203d18c927061837bdb4f1a2ec6136959ba8b89f7bfc14d06d40fe24096592b8ec64736f6c634300080f0033", +} + +// PoseidonHasherABI is the input ABI used to generate the binding from. +// Deprecated: Use PoseidonHasherMetaData.ABI instead. +var PoseidonHasherABI = PoseidonHasherMetaData.ABI + +// PoseidonHasherBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use PoseidonHasherMetaData.Bin instead. +var PoseidonHasherBin = PoseidonHasherMetaData.Bin + +// DeployPoseidonHasher deploys a new Ethereum contract, binding an instance of PoseidonHasher to it. +func DeployPoseidonHasher(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *PoseidonHasher, error) { + parsed, err := PoseidonHasherMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(PoseidonHasherBin), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &PoseidonHasher{PoseidonHasherCaller: PoseidonHasherCaller{contract: contract}, PoseidonHasherTransactor: PoseidonHasherTransactor{contract: contract}, PoseidonHasherFilterer: PoseidonHasherFilterer{contract: contract}}, nil +} + +// PoseidonHasher is an auto generated Go binding around an Ethereum contract. +type PoseidonHasher struct { + PoseidonHasherCaller // Read-only binding to the contract + PoseidonHasherTransactor // Write-only binding to the contract + PoseidonHasherFilterer // Log filterer for contract events +} + +// PoseidonHasherCaller is an auto generated read-only Go binding around an Ethereum contract. +type PoseidonHasherCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PoseidonHasherTransactor is an auto generated write-only Go binding around an Ethereum contract. +type PoseidonHasherTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PoseidonHasherFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type PoseidonHasherFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// PoseidonHasherSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type PoseidonHasherSession struct { + Contract *PoseidonHasher // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// PoseidonHasherCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type PoseidonHasherCallerSession struct { + Contract *PoseidonHasherCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// PoseidonHasherTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type PoseidonHasherTransactorSession struct { + Contract *PoseidonHasherTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// PoseidonHasherRaw is an auto generated low-level Go binding around an Ethereum contract. +type PoseidonHasherRaw struct { + Contract *PoseidonHasher // Generic contract binding to access the raw methods on +} + +// PoseidonHasherCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type PoseidonHasherCallerRaw struct { + Contract *PoseidonHasherCaller // Generic read-only contract binding to access the raw methods on +} + +// PoseidonHasherTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type PoseidonHasherTransactorRaw struct { + Contract *PoseidonHasherTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewPoseidonHasher creates a new instance of PoseidonHasher, bound to a specific deployed contract. +func NewPoseidonHasher(address common.Address, backend bind.ContractBackend) (*PoseidonHasher, error) { + contract, err := bindPoseidonHasher(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &PoseidonHasher{PoseidonHasherCaller: PoseidonHasherCaller{contract: contract}, PoseidonHasherTransactor: PoseidonHasherTransactor{contract: contract}, PoseidonHasherFilterer: PoseidonHasherFilterer{contract: contract}}, nil +} + +// NewPoseidonHasherCaller creates a new read-only instance of PoseidonHasher, bound to a specific deployed contract. +func NewPoseidonHasherCaller(address common.Address, caller bind.ContractCaller) (*PoseidonHasherCaller, error) { + contract, err := bindPoseidonHasher(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &PoseidonHasherCaller{contract: contract}, nil +} + +// NewPoseidonHasherTransactor creates a new write-only instance of PoseidonHasher, bound to a specific deployed contract. +func NewPoseidonHasherTransactor(address common.Address, transactor bind.ContractTransactor) (*PoseidonHasherTransactor, error) { + contract, err := bindPoseidonHasher(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &PoseidonHasherTransactor{contract: contract}, nil +} + +// NewPoseidonHasherFilterer creates a new log filterer instance of PoseidonHasher, bound to a specific deployed contract. +func NewPoseidonHasherFilterer(address common.Address, filterer bind.ContractFilterer) (*PoseidonHasherFilterer, error) { + contract, err := bindPoseidonHasher(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &PoseidonHasherFilterer{contract: contract}, nil +} + +// bindPoseidonHasher binds a generic wrapper to an already deployed contract. +func bindPoseidonHasher(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := PoseidonHasherMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_PoseidonHasher *PoseidonHasherRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _PoseidonHasher.Contract.PoseidonHasherCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_PoseidonHasher *PoseidonHasherRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _PoseidonHasher.Contract.PoseidonHasherTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_PoseidonHasher *PoseidonHasherRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _PoseidonHasher.Contract.PoseidonHasherTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_PoseidonHasher *PoseidonHasherCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _PoseidonHasher.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_PoseidonHasher *PoseidonHasherTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _PoseidonHasher.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_PoseidonHasher *PoseidonHasherTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _PoseidonHasher.Contract.contract.Transact(opts, method, params...) +} + +// Hash is a free data retrieval call binding the contract method 0xb189fd4c. +// +// Solidity: function hash(uint256 input) pure returns(uint256 result) +func (_PoseidonHasher *PoseidonHasherCaller) Hash(opts *bind.CallOpts, input *big.Int) (*big.Int, error) { + var out []interface{} + err := _PoseidonHasher.contract.Call(opts, &out, "hash", input) + + if err != nil { + return *new(*big.Int), err + } + + out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) + + return out0, err + +} + +// Hash is a free data retrieval call binding the contract method 0xb189fd4c. +// +// Solidity: function hash(uint256 input) pure returns(uint256 result) +func (_PoseidonHasher *PoseidonHasherSession) Hash(input *big.Int) (*big.Int, error) { + return _PoseidonHasher.Contract.Hash(&_PoseidonHasher.CallOpts, input) +} + +// Hash is a free data retrieval call binding the contract method 0xb189fd4c. +// +// Solidity: function hash(uint256 input) pure returns(uint256 result) +func (_PoseidonHasher *PoseidonHasherCallerSession) Hash(input *big.Int) (*big.Int, error) { + return _PoseidonHasher.Contract.Hash(&_PoseidonHasher.CallOpts, input) +} diff --git a/waku/v2/protocol/rln/contracts/README.md b/waku/v2/protocol/rln/contracts/README.md new file mode 100644 index 000000000..6717c75b0 --- /dev/null +++ b/waku/v2/protocol/rln/contracts/README.md @@ -0,0 +1,22 @@ +# RLN Contracts + +### Requirements: +- Node.js +- Go +- [solcjs 0.8.15](https://github.com/ethereum/solc-js) +- [abigen](https://github.com/ethereum/go-ethereum/tree/master/cmd/abigen) + +### Build +1. Install solcjs with `npm install -g solc@0.8.15` +2. Clone [go-ethereum](https://github.com/ethereum/go-ethereum) and install `abigen` +``` +cd $GOPATH/src/github.com/ethereum/go-ethereum +$ go install ./cmd/abigen +``` +3. Execute `go generate` to create go bindings for the RLN smart contracts +``` +go generate +``` + +### Notes +Follow https://github.com/vacp2p/rln-contract for updates on solc versions \ No newline at end of file diff --git a/waku/v2/protocol/rln/contracts/RLN.go b/waku/v2/protocol/rln/contracts/RLN.go index a79b5f3e0..a8bc83873 100644 --- a/waku/v2/protocol/rln/contracts/RLN.go +++ b/waku/v2/protocol/rln/contracts/RLN.go @@ -4,6 +4,7 @@ package contracts import ( + "errors" "math/big" "strings" @@ -17,6 +18,7 @@ import ( // Reference imports to suppress errors if they are not otherwise used. var ( + _ = errors.New _ = big.NewInt _ = strings.NewReader _ = ethereum.NotFound @@ -24,479 +26,34 @@ var ( _ = common.Big1 _ = types.BloomLookup _ = event.NewSubscription + _ = abi.ConvertType ) -// IPoseidonHasherABI is the input ABI used to generate the binding from. -const IPoseidonHasherABI = "[{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"input\",\"type\":\"uint256[2]\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"result\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"identity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]" - -// IPoseidonHasherFuncSigs maps the 4-byte function signature to its string representation. -var IPoseidonHasherFuncSigs = map[string]string{ - "561558fe": "hash(uint256[2])", - "2c159a1a": "identity()", -} - -// IPoseidonHasher is an auto generated Go binding around an Ethereum contract. -type IPoseidonHasher struct { - IPoseidonHasherCaller // Read-only binding to the contract - IPoseidonHasherTransactor // Write-only binding to the contract - IPoseidonHasherFilterer // Log filterer for contract events -} - -// IPoseidonHasherCaller is an auto generated read-only Go binding around an Ethereum contract. -type IPoseidonHasherCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IPoseidonHasherTransactor is an auto generated write-only Go binding around an Ethereum contract. -type IPoseidonHasherTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IPoseidonHasherFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type IPoseidonHasherFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// IPoseidonHasherSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type IPoseidonHasherSession struct { - Contract *IPoseidonHasher // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IPoseidonHasherCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type IPoseidonHasherCallerSession struct { - Contract *IPoseidonHasherCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// IPoseidonHasherTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type IPoseidonHasherTransactorSession struct { - Contract *IPoseidonHasherTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// IPoseidonHasherRaw is an auto generated low-level Go binding around an Ethereum contract. -type IPoseidonHasherRaw struct { - Contract *IPoseidonHasher // Generic contract binding to access the raw methods on -} - -// IPoseidonHasherCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type IPoseidonHasherCallerRaw struct { - Contract *IPoseidonHasherCaller // Generic read-only contract binding to access the raw methods on -} - -// IPoseidonHasherTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type IPoseidonHasherTransactorRaw struct { - Contract *IPoseidonHasherTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewIPoseidonHasher creates a new instance of IPoseidonHasher, bound to a specific deployed contract. -func NewIPoseidonHasher(address common.Address, backend bind.ContractBackend) (*IPoseidonHasher, error) { - contract, err := bindIPoseidonHasher(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &IPoseidonHasher{IPoseidonHasherCaller: IPoseidonHasherCaller{contract: contract}, IPoseidonHasherTransactor: IPoseidonHasherTransactor{contract: contract}, IPoseidonHasherFilterer: IPoseidonHasherFilterer{contract: contract}}, nil -} - -// NewIPoseidonHasherCaller creates a new read-only instance of IPoseidonHasher, bound to a specific deployed contract. -func NewIPoseidonHasherCaller(address common.Address, caller bind.ContractCaller) (*IPoseidonHasherCaller, error) { - contract, err := bindIPoseidonHasher(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &IPoseidonHasherCaller{contract: contract}, nil -} - -// NewIPoseidonHasherTransactor creates a new write-only instance of IPoseidonHasher, bound to a specific deployed contract. -func NewIPoseidonHasherTransactor(address common.Address, transactor bind.ContractTransactor) (*IPoseidonHasherTransactor, error) { - contract, err := bindIPoseidonHasher(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &IPoseidonHasherTransactor{contract: contract}, nil -} - -// NewIPoseidonHasherFilterer creates a new log filterer instance of IPoseidonHasher, bound to a specific deployed contract. -func NewIPoseidonHasherFilterer(address common.Address, filterer bind.ContractFilterer) (*IPoseidonHasherFilterer, error) { - contract, err := bindIPoseidonHasher(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &IPoseidonHasherFilterer{contract: contract}, nil -} - -// bindIPoseidonHasher binds a generic wrapper to an already deployed contract. -func bindIPoseidonHasher(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(IPoseidonHasherABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IPoseidonHasher *IPoseidonHasherRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IPoseidonHasher.Contract.IPoseidonHasherCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IPoseidonHasher *IPoseidonHasherRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IPoseidonHasher.Contract.IPoseidonHasherTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IPoseidonHasher *IPoseidonHasherRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IPoseidonHasher.Contract.IPoseidonHasherTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_IPoseidonHasher *IPoseidonHasherCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _IPoseidonHasher.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_IPoseidonHasher *IPoseidonHasherTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _IPoseidonHasher.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_IPoseidonHasher *IPoseidonHasherTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _IPoseidonHasher.Contract.contract.Transact(opts, method, params...) -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_IPoseidonHasher *IPoseidonHasherCaller) Hash(opts *bind.CallOpts, input [2]*big.Int) (*big.Int, error) { - var out []interface{} - err := _IPoseidonHasher.contract.Call(opts, &out, "hash", input) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_IPoseidonHasher *IPoseidonHasherSession) Hash(input [2]*big.Int) (*big.Int, error) { - return _IPoseidonHasher.Contract.Hash(&_IPoseidonHasher.CallOpts, input) -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_IPoseidonHasher *IPoseidonHasherCallerSession) Hash(input [2]*big.Int) (*big.Int, error) { - return _IPoseidonHasher.Contract.Hash(&_IPoseidonHasher.CallOpts, input) -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_IPoseidonHasher *IPoseidonHasherCaller) Identity(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _IPoseidonHasher.contract.Call(opts, &out, "identity") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_IPoseidonHasher *IPoseidonHasherSession) Identity() (*big.Int, error) { - return _IPoseidonHasher.Contract.Identity(&_IPoseidonHasher.CallOpts) -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_IPoseidonHasher *IPoseidonHasherCallerSession) Identity() (*big.Int, error) { - return _IPoseidonHasher.Contract.Identity(&_IPoseidonHasher.CallOpts) -} - -// PoseidonHasherABI is the input ABI used to generate the binding from. -const PoseidonHasherABI = "[{\"inputs\":[{\"internalType\":\"uint256[2]\",\"name\":\"input\",\"type\":\"uint256[2]\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"result\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"identity\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]" - -// PoseidonHasherFuncSigs maps the 4-byte function signature to its string representation. -var PoseidonHasherFuncSigs = map[string]string{ - "561558fe": "hash(uint256[2])", - "2c159a1a": "identity()", -} - -// PoseidonHasherBin is the compiled bytecode used for deploying new contracts. -var PoseidonHasherBin = "0x608060405234801561001057600080fd5b50612142806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80632c159a1a1461003b578063561558fe14610055575b600080fd5b6100436100a0565b60408051918252519081900360200190f35b6100436004803603604081101561006b57600080fd5b604080518082018252918301929181830191839060029083908390808284376000920191909152509194506100af9350505050565b60006100aa6100c0565b905090565b60006100ba826100e4565b92915050565b7f2ff267fd23782a5625e6d804f0a7fa700b8dc6084e2e7a5aff7cd4b1c506d30b90565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000016040517f165d45ae851912f9a33800b04cc6617b184bf67db11ce904dc82601244551ae281527f10fc284d0af588165f4fc650fe7c53b1d80fbaac16d30518bf142117f42f820460208201527f06b687bd3c688aa9a03545d0835bca75ae82c434bf7d5fb065a2818b5c74814f60408201527f01057eb8e4bba26f12f4ea819251708d72e0605e6de827e990c3ba4ae13f5ecd60608201527e23779a38eb9ef4a9beaf4dc0a2ab5233a28ce6d10ad2512230a275b83017c360808201527f012e5dfdd4f34081753b70c897773f5d2987c8bbae32ad202a27cd61d7fba2fb7f0d1807f022a8d80d9304a1522087b8692dc0acf7b43fea28782d2ae672c0b11f7f17d468d0e6541de501481931453ed1e4a250e5e301f27dc91fe3b4bd522aa53c7f1ea09a4bd33f14eafd75e775d85e568fa668938fdd2f16fad1d4d2d2b9862b007f061f2e832c23bee84c2f09d63d371cc5eda2f749cdbe9a6a6d20469e9fa36e8b8851017f061f2e832c23bee84c2f09d63d371cc5eda2f749cdbe9a6a6d20469e9fa36e8b60208a0151017f061f2e832c23bee84c2f09d63d371cc5eda2f749cdbe9a6a6d20469e9fa36e8b8883840989848b83840909935089838409905089838b83840909925089828309905089828b8384090991507f0e4d154ca9b7f5111958289f43ed5bbc4d4f6118d45d9aefeb778179d921a59b9050808a60408b015184098b60208c015186098c8c518809010101818b8a85098c60808d015187098d60608e01518909010101828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991508b81820992508b818d8586090990508b84850992508b848d8586090993507f298d683000ab71c72fe4371cf6cd37bb584b6d816a653ee4bfea62518a337e079250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995508b85860992508b858d8586090994508b84850992508b848d8586090993507f2f860295bc93d694e74905913ddcae47290b9b5abb43a537fe40d9305bd1e1679250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991508b81820992508b818d8586090990508b84850992508b848d8586090993507f1dd8b95942d95c7896be7f3f455e595cbfee5e1023c5d45e6573c8513f1f3dfa9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f189aa3023aeaa7267dd3c74e2c8b9cba363546619bb9c54bcb02b22fe64c51619250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0da6b697fd05fe54a523131d91e2a7f6ac18184e237c1b20ab1936616f08e5239250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f019df963bfafa7f0e34cf092f33ce93b38b9d130fb44f276196e59f16e63ac5a9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f295332d5ab168bc3c5eb671528c9896b7bd5034fb02472ff2af4fa1087ae658f9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f0f423b84792458876c314228be9361a604c75010411b87add91b791df2f980fa9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f1171744890a155b5ad9cde4f1f5c4eab878f3730a9fc71f546eb737c84abec5f9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2a557a13928c7eacff5dc049bc603cff1d7959c3975c5c9fc035b0c67173abac9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507ec9c858d5d1ab1622d7ea2174cd9a35b07c2655dd08dcda3f5a9f7222c021af9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f0b358e01fc7cf925b6d3ba6e80c345881b54ff289479cc532f9fec01b500b9789250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f26c26f6e5a92ff96ec05a61d5f36df4f8134f8d61ff0eaa28cf7a480ee2b7f849250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f020930074e8c6c15295104a58533a601f202d3b3f959650d7b8cfa754ae41e7f9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f10f5f06286fdde345a5cd8ba4ad94828271ea16309f5fa906841e72eb4c330279250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f116ce0fb46b45c99fec7d369ab5c0d11d374a16b2107c5d6f21e3792d33fc9699250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f2a59da7487bf7a05c3dbdfca6084e2ec589b1baf87ddd790d9bbc9c23557255b9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f1559c4b2c04c419e948f42a7f8fecfb1525dbdf2b6830632723ff4fa77030ea89250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f030b1745767217e6d8df6885a85651f9aebefcf468003d2dd25906897c3ca92a9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2668ff336585f1e64cd6ddf2cbcaa8a695585f0db79cbd1727becfeabe76d0449250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f158c1ceb605d6cb3e0c3a7e6650b1f297c4fccb1aeed560a09dfd474c4e47f999250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f27506f4872c8b8bb7f42921afbefd206cef54f5001f1c32efbc2a22094d172d49250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0e915e793df4e8ee01fd861b22ee463c985c691fb2a54c8657575ed93ab92c739250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f264bd2bc0486212803e5ef729bcaf466eb14f5b6ac18b898ed94844dda28d8a99250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f2f23c5d822cd0d5b27fee9ff2c51f30a40654cdd08677543244f6aad8f2ebc8a9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2776a03893ed5c5ce680ca5acda3c7d4b60b81269cabca38bfe060ce6eb6c4129250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f07aba324bd6d746b9f23313249f6a1809f3cfea3b1f3eb70c37951eb77120d3a9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f09c0a6b8cf7f1c457987d7bb476b8ed8ddf88dbb146f2d887821d93d453d0fa39250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f292e4542f0e5b148bc7c9188b9db100f0f2aa2a62edb236041c4e4ebf44eb1469250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f01b08e9289e3a73080f49265283832fc48dfb2da2d540503b8274d7c0e52c9b69250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0d897c5adfe393f4c0247e718eb0b227f87226cc416b703eb2a96d61581af2e39250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f057582e2ebdd031c39c69ed08086d969d22de5d1bf79ee1be837234977e3477c9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0be6726fc2d3d2b9681fdc9ce4e274395f9e6dc5c6e647a3a5343e3f3fe77edf9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f0e919ea6e332df81ae88f1155eac9e3c4b7dd7d8637feb112bcb2176f45fd9429250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f2dadfa8057c413974c1c03aa2d38aac0d8c09748d08edc0e97450320c889c40d9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2954c27dbde3ba4f887becde3fc6c47db5266d436914d50d4e93faa79e40f7789250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f1e8f4f1b4fa7cc676e0d02084ce2bbf095adf6bcee924520e57c2f2a4b43f98a9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f01892c0a3e4c3ffce3763f5d67ea86157c3b2461e08ff82ee28342ad41e636259250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f297b80afd662c439ff4837049ea3d95f565007b2defd87d981bfa45ce9ce80bf9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f28def6e44cc1e6b1826dd02d19d3383ddfd0dcdf96d5e9ce0b2834c6ad5c17b89250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0e7efce2651888246927ee306c83f4b24982ae2a126ff3be0217ea155e850d3e9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f1b61bcbf0030070f3ca673d814ad8ea269bf0b4ddf75c4b4dd8383835be6b3809250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f2bfc5e31157cdf08d36dcba28d869c209688dcb9da74df689427efbfe7ef20409250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2535e86274b29f682edc2f95d8fc9aa4b660b1992da99d3e3ccfd551b25280ae9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f2e26f31955ddb83a0866535943960e6bf1d75532494e07382a1886df2eba4f2c9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f1367f3092e878d4204f8597f09a6e75e596f8f859f7c4f0e4ee3bdefb14185759250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f0786e0a89d59f9f1ec5a24b4e77471afb551993358839a2ad7f0cd30ee34a5939250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f05a623c15705f67c426798eb1aeb61d16bd599b73c618801e79ce87e4acf44439250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f216a2cd9a5dec0ce0f298c37a605d63a7a241fd04f74ee76d955ec729f75c7749250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f1ac59c277950c8cf903e1e0b04c13b6be622d88a899267ccd30957e8b24feb899250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f21181ae96428a48600806eb2d2b94b4972bc69f4b69d99fb1edcbce69d1a73029250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f2a24403e8cf5fb93ed9408b11d96e377bf1f1a2e183b0e14a18d6b794fc482909250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f13324a9a9db19a8f877c22de405a88bd39bec4696dc84721e7ccfef724a8e4f59250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f17f556db73809befc58822ad53ad5785aee4ff6891f211ae7183284b57a3910a9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f22e4f8f9c9ae56f5254ca73dc68572e805b9406a45fb4e10a831a7619b129fe59250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f066e36c90fda2dd52aa0c05909831d1dd345f75fcb17934ecb754d74e7ce8df99250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991507f190c65fb8440d50383891cbe244a8b063f0f9afbf14adce401416de7d6c755e19250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995507f0b4fec4e028a67f9a9b932ae35a1269eeec8b98b96793d29811a766ad089ab1b9250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991508b81820992508b818d8586090990508b84850992508b848d8586090993507f1def7475769de3cd372283c7d36bd153637723ff14615542bfe8b27108ad4de79250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c860901010193508b86870992508b868d8586090995508b85860992508b858d8586090994508b84850992508b848d8586090993507f119217aded5f1ebf525a69e23a08f6a976178e5939646f6c87033299d2d3c8749250828c60408d015186098d60208e015188098e8e518a090101019150828c8b86098d60808e015188098e60608f01518a090101019050828c8886098d8a88098e8c8a0901010193508b82830992508b828d8586090991508b81820992508b818d8586090990508b84850992508b848d8586090993507f036bd8311510a8d03c5b354f03c664f9f2d23f57b1e4286d1938f8dbe4a7c28c9250828c60408d015186098d60208e015184098e8e5186090101019550828c8b86098d60808e015184098e60608f015186090101019450828c8886098d8a84098e8c86090101019350505089848509905089848b83840909935089838409905089838b83840909925089828309905089828b838409505050929b9a505050505050505050505056fea264697066735822122022fc21868d907bed4fa3abb78ab3ed4f2a0fb08b5292320b05ffb1408625623f64736f6c63430007040033" - -// DeployPoseidonHasher deploys a new Ethereum contract, binding an instance of PoseidonHasher to it. -func DeployPoseidonHasher(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *PoseidonHasher, error) { - parsed, err := abi.JSON(strings.NewReader(PoseidonHasherABI)) - if err != nil { - return common.Address{}, nil, nil, err - } - - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(PoseidonHasherBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &PoseidonHasher{PoseidonHasherCaller: PoseidonHasherCaller{contract: contract}, PoseidonHasherTransactor: PoseidonHasherTransactor{contract: contract}, PoseidonHasherFilterer: PoseidonHasherFilterer{contract: contract}}, nil -} - -// PoseidonHasher is an auto generated Go binding around an Ethereum contract. -type PoseidonHasher struct { - PoseidonHasherCaller // Read-only binding to the contract - PoseidonHasherTransactor // Write-only binding to the contract - PoseidonHasherFilterer // Log filterer for contract events -} - -// PoseidonHasherCaller is an auto generated read-only Go binding around an Ethereum contract. -type PoseidonHasherCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PoseidonHasherTransactor is an auto generated write-only Go binding around an Ethereum contract. -type PoseidonHasherTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PoseidonHasherFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type PoseidonHasherFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// PoseidonHasherSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type PoseidonHasherSession struct { - Contract *PoseidonHasher // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PoseidonHasherCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type PoseidonHasherCallerSession struct { - Contract *PoseidonHasherCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// PoseidonHasherTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type PoseidonHasherTransactorSession struct { - Contract *PoseidonHasherTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// PoseidonHasherRaw is an auto generated low-level Go binding around an Ethereum contract. -type PoseidonHasherRaw struct { - Contract *PoseidonHasher // Generic contract binding to access the raw methods on -} - -// PoseidonHasherCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type PoseidonHasherCallerRaw struct { - Contract *PoseidonHasherCaller // Generic read-only contract binding to access the raw methods on -} - -// PoseidonHasherTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type PoseidonHasherTransactorRaw struct { - Contract *PoseidonHasherTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewPoseidonHasher creates a new instance of PoseidonHasher, bound to a specific deployed contract. -func NewPoseidonHasher(address common.Address, backend bind.ContractBackend) (*PoseidonHasher, error) { - contract, err := bindPoseidonHasher(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &PoseidonHasher{PoseidonHasherCaller: PoseidonHasherCaller{contract: contract}, PoseidonHasherTransactor: PoseidonHasherTransactor{contract: contract}, PoseidonHasherFilterer: PoseidonHasherFilterer{contract: contract}}, nil -} - -// NewPoseidonHasherCaller creates a new read-only instance of PoseidonHasher, bound to a specific deployed contract. -func NewPoseidonHasherCaller(address common.Address, caller bind.ContractCaller) (*PoseidonHasherCaller, error) { - contract, err := bindPoseidonHasher(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &PoseidonHasherCaller{contract: contract}, nil -} - -// NewPoseidonHasherTransactor creates a new write-only instance of PoseidonHasher, bound to a specific deployed contract. -func NewPoseidonHasherTransactor(address common.Address, transactor bind.ContractTransactor) (*PoseidonHasherTransactor, error) { - contract, err := bindPoseidonHasher(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &PoseidonHasherTransactor{contract: contract}, nil -} - -// NewPoseidonHasherFilterer creates a new log filterer instance of PoseidonHasher, bound to a specific deployed contract. -func NewPoseidonHasherFilterer(address common.Address, filterer bind.ContractFilterer) (*PoseidonHasherFilterer, error) { - contract, err := bindPoseidonHasher(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &PoseidonHasherFilterer{contract: contract}, nil -} - -// bindPoseidonHasher binds a generic wrapper to an already deployed contract. -func bindPoseidonHasher(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(PoseidonHasherABI)) - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PoseidonHasher *PoseidonHasherRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _PoseidonHasher.Contract.PoseidonHasherCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PoseidonHasher *PoseidonHasherRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PoseidonHasher.Contract.PoseidonHasherTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PoseidonHasher *PoseidonHasherRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PoseidonHasher.Contract.PoseidonHasherTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_PoseidonHasher *PoseidonHasherCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _PoseidonHasher.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_PoseidonHasher *PoseidonHasherTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _PoseidonHasher.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_PoseidonHasher *PoseidonHasherTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _PoseidonHasher.Contract.contract.Transact(opts, method, params...) -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_PoseidonHasher *PoseidonHasherCaller) Hash(opts *bind.CallOpts, input [2]*big.Int) (*big.Int, error) { - var out []interface{} - err := _PoseidonHasher.contract.Call(opts, &out, "hash", input) - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_PoseidonHasher *PoseidonHasherSession) Hash(input [2]*big.Int) (*big.Int, error) { - return _PoseidonHasher.Contract.Hash(&_PoseidonHasher.CallOpts, input) -} - -// Hash is a free data retrieval call binding the contract method 0x561558fe. -// -// Solidity: function hash(uint256[2] input) pure returns(uint256 result) -func (_PoseidonHasher *PoseidonHasherCallerSession) Hash(input [2]*big.Int) (*big.Int, error) { - return _PoseidonHasher.Contract.Hash(&_PoseidonHasher.CallOpts, input) -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_PoseidonHasher *PoseidonHasherCaller) Identity(opts *bind.CallOpts) (*big.Int, error) { - var out []interface{} - err := _PoseidonHasher.contract.Call(opts, &out, "identity") - - if err != nil { - return *new(*big.Int), err - } - - out0 := *abi.ConvertType(out[0], new(*big.Int)).(**big.Int) - - return out0, err - -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_PoseidonHasher *PoseidonHasherSession) Identity() (*big.Int, error) { - return _PoseidonHasher.Contract.Identity(&_PoseidonHasher.CallOpts) -} - -// Identity is a free data retrieval call binding the contract method 0x2c159a1a. -// -// Solidity: function identity() pure returns(uint256) -func (_PoseidonHasher *PoseidonHasherCallerSession) Identity() (*big.Int, error) { - return _PoseidonHasher.Contract.Identity(&_PoseidonHasher.CallOpts) +// RLNMetaData contains all meta data concerning the RLN contract. +var RLNMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"membershipDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_poseidonHasher\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"DuplicateIdCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"EmptyBatch\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"FullBatch\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"required\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"provided\",\"type\":\"uint256\"}],\"name\":\"InsufficientDeposit\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"}],\"name\":\"InvalidWithdrawalAddress\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"idCommitment\",\"type\":\"uint256\"}],\"name\":\"MemberHasNoStake\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"idCommitment\",\"type\":\"uint256\"}],\"name\":\"MemberNotRegistered\",\"type\":\"error\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"givenSecretsLen\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"givenReceiversLen\",\"type\":\"uint256\"}],\"name\":\"MismatchedBatchSize\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"idCommitment\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"MemberRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"idCommitment\",\"type\":\"uint256\"}],\"name\":\"MemberWithdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEPTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MEMBERSHIP_DEPOSIT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SET_SIZE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"idCommitmentIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"members\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"poseidonHasher\",\"outputs\":[{\"internalType\":\"contractIPoseidonHasher\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"idCommitment\",\"type\":\"uint256\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"idCommitments\",\"type\":\"uint256[]\"}],\"name\":\"registerBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"stakedAmounts\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"secret\",\"type\":\"uint256\"},{\"internalType\":\"addresspayable\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"secrets\",\"type\":\"uint256[]\"},{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"}],\"name\":\"withdrawBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x60e06040523480156200001157600080fd5b50604051620012c0380380620012c0833981810160405281019062000037919062000142565b82608081815250508160a08181525050816001901b60c0818152505080600360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050506200019e565b600080fd5b6000819050919050565b620000b781620000a2565b8114620000c357600080fd5b50565b600081519050620000d781620000ac565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200010a82620000dd565b9050919050565b6200011c81620000fd565b81146200012857600080fd5b50565b6000815190506200013c8162000111565b92915050565b6000806000606084860312156200015e576200015d6200009d565b5b60006200016e86828701620000c6565b93505060206200018186828701620000c6565b925050604062000194868287016200012b565b9150509250925092565b60805160a05160c0516110cf620001f1600039600081816104140152818161058501526109070152600061054301526000818161047d015281816105a9015281816105d0015261063c01526110cf6000f3fe60806040526004361061009b5760003560e01c806398366e351161006457806398366e3514610176578063ae74552a146101a1578063bc499128146101cc578063d0383d6814610209578063f207564e14610234578063f220b9ec146102505761009b565b8062f714ce146100a0578063331b6ab3146100c957806340070712146100f45780635daf08ca1461011d57806369e4863f1461015a575b600080fd5b3480156100ac57600080fd5b506100c760048036038101906100c29190610b3f565b61027b565b005b3480156100d557600080fd5b506100de610289565b6040516100eb9190610bde565b60405180910390f35b34801561010057600080fd5b5061011b60048036038101906101169190610cb4565b6102af565b005b34801561012957600080fd5b50610144600480360381019061013f9190610d35565b6103b0565b6040516101519190610d7d565b60405180910390f35b610174600480360381019061016f9190610d98565b6103d0565b005b34801561018257600080fd5b5061018b610541565b6040516101989190610df4565b60405180910390f35b3480156101ad57600080fd5b506101b6610565565b6040516101c39190610df4565b60405180910390f35b3480156101d857600080fd5b506101f360048036038101906101ee9190610d35565b61056b565b6040516102009190610df4565b60405180910390f35b34801561021557600080fd5b5061021e610583565b60405161022b9190610df4565b60405180910390f35b61024e60048036038101906102499190610d35565b6105a7565b005b34801561025c57600080fd5b5061026561063a565b6040516102729190610df4565b60405180910390f35b610285828261065e565b5050565b600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000848490509050600081036102f1576040517fc2e5347d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8282905081146103405784849050838390506040517f727c6a75000000000000000000000000000000000000000000000000000000008152600401610337929190610e0f565b60405180910390fd5b60005b818110156103a85761039586868381811061036157610360610e38565b5b9050602002013585858481811061037b5761037a610e38565b5b90506020020160208101906103909190610e67565b61065e565b80806103a090610ec3565b915050610343565b505050505050565b60026020528060005260406000206000915054906101000a900460ff1681565b600082829050905060008103610412576040517fc2e5347d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000000000000000000000000000000000000000000000816000546104419190610f0b565b10610478576040517f75eb4dbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000817f00000000000000000000000000000000000000000000000000000000000000006104a69190610f61565b90508034146104ee5780346040517f25c3f46e0000000000000000000000000000000000000000000000000000000081526004016104e5929190610e0f565b60405180910390fd5b60005b8281101561053a5761052785858381811061050f5761050e610e38565b5b9050602002013584346105229190610fea565b6108ae565b808061053290610ec3565b9150506104f1565b5050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60005481565b60016020528060005260406000206000915090505481565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f0000000000000000000000000000000000000000000000000000000000000000341461062d577f0000000000000000000000000000000000000000000000000000000000000000346040517f25c3f46e000000000000000000000000000000000000000000000000000000008152600401610624929190610e0f565b60405180910390fd5b61063781346108ae565b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b3073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614806106c45750600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b1561070657806040517f21680a040000000000000000000000000000000000000000000000000000000081526004016106fd919061103c565b60405180910390fd5b6000610711836109fc565b90506002600082815260200190815260200160002060009054906101000a900460ff1661077557806040517f5a971ebb00000000000000000000000000000000000000000000000000000000815260040161076c9190610df4565b60405180910390fd5b60006001600083815260200190815260200160002054036107cd57806040517faabeeba50000000000000000000000000000000000000000000000000000000081526004016107c49190610df4565b60405180910390fd5b60006001600083815260200190815260200160002054905060006002600084815260200190815260200160002060006101000a81548160ff021916908315150217905550600060016000848152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015610870573d6000803e3d6000fd5b507fad2d771c5ad1c1e6f50cc769e53ec1e194002c29f28c3dd2af5639b60d8072a6826040516108a09190610df4565b60405180910390a150505050565b6002600083815260200190815260200160002060009054906101000a900460ff1615610905576040517e0a60f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000060005410610960576040517f75eb4dbe00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60016002600084815260200190815260200160002060006101000a81548160ff0219169083151502179055508060016000848152602001908152602001600020819055507f5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2826000546040516109d7929190610e0f565b60405180910390a160016000808282546109f19190610f0b565b925050819055505050565b6000600360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b189fd4c836040518263ffffffff1660e01b8152600401610a599190610df4565b602060405180830381865afa158015610a76573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a9a919061106c565b9050919050565b600080fd5b600080fd5b6000819050919050565b610abe81610aab565b8114610ac957600080fd5b50565b600081359050610adb81610ab5565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610b0c82610ae1565b9050919050565b610b1c81610b01565b8114610b2757600080fd5b50565b600081359050610b3981610b13565b92915050565b60008060408385031215610b5657610b55610aa1565b5b6000610b6485828601610acc565b9250506020610b7585828601610b2a565b9150509250929050565b6000819050919050565b6000610ba4610b9f610b9a84610ae1565b610b7f565b610ae1565b9050919050565b6000610bb682610b89565b9050919050565b6000610bc882610bab565b9050919050565b610bd881610bbd565b82525050565b6000602082019050610bf36000830184610bcf565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610c1e57610c1d610bf9565b5b8235905067ffffffffffffffff811115610c3b57610c3a610bfe565b5b602083019150836020820283011115610c5757610c56610c03565b5b9250929050565b60008083601f840112610c7457610c73610bf9565b5b8235905067ffffffffffffffff811115610c9157610c90610bfe565b5b602083019150836020820283011115610cad57610cac610c03565b5b9250929050565b60008060008060408587031215610cce57610ccd610aa1565b5b600085013567ffffffffffffffff811115610cec57610ceb610aa6565b5b610cf887828801610c08565b9450945050602085013567ffffffffffffffff811115610d1b57610d1a610aa6565b5b610d2787828801610c5e565b925092505092959194509250565b600060208284031215610d4b57610d4a610aa1565b5b6000610d5984828501610acc565b91505092915050565b60008115159050919050565b610d7781610d62565b82525050565b6000602082019050610d926000830184610d6e565b92915050565b60008060208385031215610daf57610dae610aa1565b5b600083013567ffffffffffffffff811115610dcd57610dcc610aa6565b5b610dd985828601610c08565b92509250509250929050565b610dee81610aab565b82525050565b6000602082019050610e096000830184610de5565b92915050565b6000604082019050610e246000830185610de5565b610e316020830184610de5565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600060208284031215610e7d57610e7c610aa1565b5b6000610e8b84828501610b2a565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610ece82610aab565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203610f0057610eff610e94565b5b600182019050919050565b6000610f1682610aab565b9150610f2183610aab565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115610f5657610f55610e94565b5b828201905092915050565b6000610f6c82610aab565b9150610f7783610aab565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615610fb057610faf610e94565b5b828202905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000610ff582610aab565b915061100083610aab565b9250826110105761100f610fbb565b5b828204905092915050565b600061102682610bab565b9050919050565b6110368161101b565b82525050565b6000602082019050611051600083018461102d565b92915050565b60008151905061106681610ab5565b92915050565b60006020828403121561108257611081610aa1565b5b600061109084828501611057565b9150509291505056fea26469706673582212201eba48f9e121352ff146b50c2c2a98d3cbb52bcd90bf3d5e555aa60d7c6778f064736f6c634300080f0033", } // RLNABI is the input ABI used to generate the binding from. -const RLNABI = "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"membershipDeposit\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"depth\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"_poseidonHasher\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"pubkey\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"MemberRegistered\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"pubkey\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"}],\"name\":\"MemberWithdrawn\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"DEPTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MEMBERSHIP_DEPOSIT\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"SET_SIZE\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"members\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"poseidonHasher\",\"outputs\":[{\"internalType\":\"contractIPoseidonHasher\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"pubkeyIndex\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"pubkey\",\"type\":\"uint256\"}],\"name\":\"register\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"pubkeys\",\"type\":\"uint256[]\"}],\"name\":\"registerBatch\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"secret\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_pubkeyIndex\",\"type\":\"uint256\"},{\"internalType\":\"addresspayable\",\"name\":\"receiver\",\"type\":\"address\"}],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"secrets\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256[]\",\"name\":\"pubkeyIndexes\",\"type\":\"uint256[]\"},{\"internalType\":\"addresspayable[]\",\"name\":\"receivers\",\"type\":\"address[]\"}],\"name\":\"withdrawBatch\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]" - -// RLNFuncSigs maps the 4-byte function signature to its string representation. -var RLNFuncSigs = map[string]string{ - "98366e35": "DEPTH()", - "f220b9ec": "MEMBERSHIP_DEPOSIT()", - "d0383d68": "SET_SIZE()", - "5daf08ca": "members(uint256)", - "331b6ab3": "poseidonHasher()", - "61579a93": "pubkeyIndex()", - "f207564e": "register(uint256)", - "69e4863f": "registerBatch(uint256[])", - "0ad58d2f": "withdraw(uint256,uint256,address)", - "a9d85eba": "withdrawBatch(uint256[],uint256[],address[])", -} +// Deprecated: Use RLNMetaData.ABI instead. +var RLNABI = RLNMetaData.ABI // RLNBin is the compiled bytecode used for deploying new contracts. -var RLNBin = "0x60e06040526000805534801561001457600080fd5b50604051610c4f380380610c4f8339818101604052606081101561003757600080fd5b5080516020820151604090920151608082905260a08390526001831b60c0819052600280546001600160a01b0319166001600160a01b0390931692909217909155909190610b936100bc6000398061037a52806105c352806105e752806106eb52508061047f5250806103f2528061065d52806106c7528061087b5250610b936000f3fe6080604052600436106100915760003560e01c806398366e351161005957806398366e35146101c7578063a9d85eba146101dc578063d0383d68146102f7578063f207564e1461030c578063f220b9ec1461032957610091565b80630ad58d2f14610096578063331b6ab3146100d75780635daf08ca1461010857806361579a931461014457806369e4863f14610159575b600080fd5b3480156100a257600080fd5b506100d5600480360360608110156100b957600080fd5b50803590602081013590604001356001600160a01b031661033e565b005b3480156100e357600080fd5b506100ec61034e565b604080516001600160a01b039092168252519081900360200190f35b34801561011457600080fd5b506101326004803603602081101561012b57600080fd5b503561035d565b60408051918252519081900360200190f35b34801561015057600080fd5b5061013261036f565b6100d56004803603602081101561016f57600080fd5b810190602081018135600160201b81111561018957600080fd5b82018360208201111561019b57600080fd5b803590602001918460208302840111600160201b831117156101bc57600080fd5b509092509050610375565b3480156101d357600080fd5b5061013261047d565b3480156101e857600080fd5b506100d5600480360360608110156101ff57600080fd5b810190602081018135600160201b81111561021957600080fd5b82018360208201111561022b57600080fd5b803590602001918460208302840111600160201b8311171561024c57600080fd5b919390929091602081019035600160201b81111561026957600080fd5b82018360208201111561027b57600080fd5b803590602001918460208302840111600160201b8311171561029c57600080fd5b919390929091602081019035600160201b8111156102b957600080fd5b8201836020820111156102cb57600080fd5b803590602001918460208302840111600160201b831117156102ec57600080fd5b5090925090506104a1565b34801561030357600080fd5b506101326105c1565b6100d56004803603602081101561032257600080fd5b50356105e5565b34801561033557600080fd5b506101326106c5565b6103498383836106e9565b505050565b6002546001600160a01b031681565b60016020526000908152604090205481565b60005481565b6000547f000000000000000000000000000000000000000000000000000000000000000090820111156103ef576040805162461bcd60e51b815260206004820152601f60248201527f524c4e2c20726567697374657242617463683a207365742069732066756c6c00604482015290519081900360640190fd5b347f000000000000000000000000000000000000000000000000000000000000000082021461044f5760405162461bcd60e51b8152600401808060200182810382526037815260200180610a566037913960400191505060405180910390fd5b60005b818110156103495761047583838381811061046957fe5b90506020020135610902565b600101610452565b7f000000000000000000000000000000000000000000000000000000000000000081565b84806104de5760405162461bcd60e51b8152600401808060200182810382526023815260200180610a336023913960400191505060405180910390fd5b80841461051c5760405162461bcd60e51b81526004018080602001828103825260368152602001806109fd6036913960400191505060405180910390fd5b80821461055a5760405162461bcd60e51b8152600401808060200182810382526031815260200180610a8d6031913960400191505060405180910390fd5b60005b818110156105b7576105af88888381811061057457fe5b9050602002013587878481811061058757fe5b9050602002013586868581811061059a57fe5b905060200201356001600160a01b03166106e9565b60010161055d565b5050505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f00000000000000000000000000000000000000000000000000000000000000006000541061065b576040805162461bcd60e51b815260206004820152601a60248201527f524c4e2c2072656769737465723a207365742069732066756c6c000000000000604482015290519081900360640190fd5b7f000000000000000000000000000000000000000000000000000000000000000034146106b95760405162461bcd60e51b8152600401808060200182810382526032815260200180610abe6032913960400191505060405180910390fd5b6106c281610902565b50565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000082106107475760405162461bcd60e51b8152600401808060200182810382526024815260200180610af06024913960400191505060405180910390fd5b6000828152600160205260409020546107915760405162461bcd60e51b8152600401808060200182810382526024815260200180610b146024913960400191505060405180910390fd5b6001600160a01b0381166107d65760405162461bcd60e51b8152600401808060200182810382526026815260200180610b386026913960400191505060405180910390fd5b60006107f66040518060400160405280868152602001600081525061095b565b600084815260016020526040902054909150811461085b576040805162461bcd60e51b815260206004820152601c60248201527f524c4e2c205f77697468647261773a206e6f7420766572696669656400000000604482015290519081900360640190fd5b600083815260016020526040808220829055516001600160a01b038416917f000000000000000000000000000000000000000000000000000000000000000080156108fc02929091818181858888f193505050501580156108c0573d6000803e3d6000fd5b50604080518281526020810185905281517f62ec3a516d22a993ce5cb4e7593e878c74f4d799dde522a88dc27a994fd5a943929181900390910190a150505050565b600080548152600160209081526040808320849055915482518481529182015281517f5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2929181900390910190a150600080546001019055565b60025460408051632b0aac7f60e11b81526000926001600160a01b03169163561558fe918591600490910190819083908083838a5b838110156109a8578181015183820152602001610990565b5050505090500191505060206040518083038186803b1580156109ca57600080fd5b505afa1580156109de573d6000803e3d6000fd5b505050506040513d60208110156109f457600080fd5b50519291505056fe524c4e2c20776974686472617742617463683a2062617463682073697a65206d69736d61746368207075626b657920696e6465786573524c4e2c20776974686472617742617463683a2062617463682073697a65207a65726f524c4e2c20726567697374657242617463683a206d656d62657273686970206465706f736974206973206e6f7420736174697366696564524c4e2c20776974686472617742617463683a2062617463682073697a65206d69736d6174636820726563656976657273524c4e2c2072656769737465723a206d656d62657273686970206465706f736974206973206e6f7420736174697366696564524c4e2c205f77697468647261773a20696e76616c6964207075626b657920696e646578524c4e2c205f77697468647261773a206d656d62657220646f65736e2774206578697374524c4e2c205f77697468647261773a20656d7074792072656365697665722061646472657373a264697066735822122089b1a09f209b826ff6506cf1ad2811656094f532866b769f0bb8e9a160a21dc464736f6c63430007040033" +// Deprecated: Use RLNMetaData.Bin instead. +var RLNBin = RLNMetaData.Bin // DeployRLN deploys a new Ethereum contract, binding an instance of RLN to it. func DeployRLN(auth *bind.TransactOpts, backend bind.ContractBackend, membershipDeposit *big.Int, depth *big.Int, _poseidonHasher common.Address) (common.Address, *types.Transaction, *RLN, error) { - parsed, err := abi.JSON(strings.NewReader(RLNABI)) + parsed, err := RLNMetaData.GetAbi() if err != nil { return common.Address{}, nil, nil, err } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } - address, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(RLNBin), backend, membershipDeposit, depth, _poseidonHasher) + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(RLNBin), backend, membershipDeposit, depth, _poseidonHasher) if err != nil { return common.Address{}, nil, nil, err } @@ -600,11 +157,11 @@ func NewRLNFilterer(address common.Address, filterer bind.ContractFilterer) (*RL // bindRLN binds a generic wrapper to an already deployed contract. func bindRLN(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := abi.JSON(strings.NewReader(RLNABI)) + parsed, err := RLNMetaData.GetAbi() if err != nil { return nil, err } - return bind.NewBoundContract(address, parsed, caller, transactor, filterer), nil + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil } // Call invokes the (constant) contract method with params as input values and @@ -738,12 +295,12 @@ func (_RLN *RLNCallerSession) SETSIZE() (*big.Int, error) { return _RLN.Contract.SETSIZE(&_RLN.CallOpts) } -// Members is a free data retrieval call binding the contract method 0x5daf08ca. +// IdCommitmentIndex is a free data retrieval call binding the contract method 0xae74552a. // -// Solidity: function members(uint256 ) view returns(uint256) -func (_RLN *RLNCaller) Members(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { +// Solidity: function idCommitmentIndex() view returns(uint256) +func (_RLN *RLNCaller) IdCommitmentIndex(opts *bind.CallOpts) (*big.Int, error) { var out []interface{} - err := _RLN.contract.Call(opts, &out, "members", arg0) + err := _RLN.contract.Call(opts, &out, "idCommitmentIndex") if err != nil { return *new(*big.Int), err @@ -755,17 +312,48 @@ func (_RLN *RLNCaller) Members(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, er } +// IdCommitmentIndex is a free data retrieval call binding the contract method 0xae74552a. +// +// Solidity: function idCommitmentIndex() view returns(uint256) +func (_RLN *RLNSession) IdCommitmentIndex() (*big.Int, error) { + return _RLN.Contract.IdCommitmentIndex(&_RLN.CallOpts) +} + +// IdCommitmentIndex is a free data retrieval call binding the contract method 0xae74552a. +// +// Solidity: function idCommitmentIndex() view returns(uint256) +func (_RLN *RLNCallerSession) IdCommitmentIndex() (*big.Int, error) { + return _RLN.Contract.IdCommitmentIndex(&_RLN.CallOpts) +} + +// Members is a free data retrieval call binding the contract method 0x5daf08ca. +// +// Solidity: function members(uint256 ) view returns(bool) +func (_RLN *RLNCaller) Members(opts *bind.CallOpts, arg0 *big.Int) (bool, error) { + var out []interface{} + err := _RLN.contract.Call(opts, &out, "members", arg0) + + if err != nil { + return *new(bool), err + } + + out0 := *abi.ConvertType(out[0], new(bool)).(*bool) + + return out0, err + +} + // Members is a free data retrieval call binding the contract method 0x5daf08ca. // -// Solidity: function members(uint256 ) view returns(uint256) -func (_RLN *RLNSession) Members(arg0 *big.Int) (*big.Int, error) { +// Solidity: function members(uint256 ) view returns(bool) +func (_RLN *RLNSession) Members(arg0 *big.Int) (bool, error) { return _RLN.Contract.Members(&_RLN.CallOpts, arg0) } // Members is a free data retrieval call binding the contract method 0x5daf08ca. // -// Solidity: function members(uint256 ) view returns(uint256) -func (_RLN *RLNCallerSession) Members(arg0 *big.Int) (*big.Int, error) { +// Solidity: function members(uint256 ) view returns(bool) +func (_RLN *RLNCallerSession) Members(arg0 *big.Int) (bool, error) { return _RLN.Contract.Members(&_RLN.CallOpts, arg0) } @@ -800,12 +388,12 @@ func (_RLN *RLNCallerSession) PoseidonHasher() (common.Address, error) { return _RLN.Contract.PoseidonHasher(&_RLN.CallOpts) } -// PubkeyIndex is a free data retrieval call binding the contract method 0x61579a93. +// StakedAmounts is a free data retrieval call binding the contract method 0xbc499128. // -// Solidity: function pubkeyIndex() view returns(uint256) -func (_RLN *RLNCaller) PubkeyIndex(opts *bind.CallOpts) (*big.Int, error) { +// Solidity: function stakedAmounts(uint256 ) view returns(uint256) +func (_RLN *RLNCaller) StakedAmounts(opts *bind.CallOpts, arg0 *big.Int) (*big.Int, error) { var out []interface{} - err := _RLN.contract.Call(opts, &out, "pubkeyIndex") + err := _RLN.contract.Call(opts, &out, "stakedAmounts", arg0) if err != nil { return *new(*big.Int), err @@ -817,102 +405,102 @@ func (_RLN *RLNCaller) PubkeyIndex(opts *bind.CallOpts) (*big.Int, error) { } -// PubkeyIndex is a free data retrieval call binding the contract method 0x61579a93. +// StakedAmounts is a free data retrieval call binding the contract method 0xbc499128. // -// Solidity: function pubkeyIndex() view returns(uint256) -func (_RLN *RLNSession) PubkeyIndex() (*big.Int, error) { - return _RLN.Contract.PubkeyIndex(&_RLN.CallOpts) +// Solidity: function stakedAmounts(uint256 ) view returns(uint256) +func (_RLN *RLNSession) StakedAmounts(arg0 *big.Int) (*big.Int, error) { + return _RLN.Contract.StakedAmounts(&_RLN.CallOpts, arg0) } -// PubkeyIndex is a free data retrieval call binding the contract method 0x61579a93. +// StakedAmounts is a free data retrieval call binding the contract method 0xbc499128. // -// Solidity: function pubkeyIndex() view returns(uint256) -func (_RLN *RLNCallerSession) PubkeyIndex() (*big.Int, error) { - return _RLN.Contract.PubkeyIndex(&_RLN.CallOpts) +// Solidity: function stakedAmounts(uint256 ) view returns(uint256) +func (_RLN *RLNCallerSession) StakedAmounts(arg0 *big.Int) (*big.Int, error) { + return _RLN.Contract.StakedAmounts(&_RLN.CallOpts, arg0) } // Register is a paid mutator transaction binding the contract method 0xf207564e. // -// Solidity: function register(uint256 pubkey) payable returns() -func (_RLN *RLNTransactor) Register(opts *bind.TransactOpts, pubkey *big.Int) (*types.Transaction, error) { - return _RLN.contract.Transact(opts, "register", pubkey) +// Solidity: function register(uint256 idCommitment) payable returns() +func (_RLN *RLNTransactor) Register(opts *bind.TransactOpts, idCommitment *big.Int) (*types.Transaction, error) { + return _RLN.contract.Transact(opts, "register", idCommitment) } // Register is a paid mutator transaction binding the contract method 0xf207564e. // -// Solidity: function register(uint256 pubkey) payable returns() -func (_RLN *RLNSession) Register(pubkey *big.Int) (*types.Transaction, error) { - return _RLN.Contract.Register(&_RLN.TransactOpts, pubkey) +// Solidity: function register(uint256 idCommitment) payable returns() +func (_RLN *RLNSession) Register(idCommitment *big.Int) (*types.Transaction, error) { + return _RLN.Contract.Register(&_RLN.TransactOpts, idCommitment) } // Register is a paid mutator transaction binding the contract method 0xf207564e. // -// Solidity: function register(uint256 pubkey) payable returns() -func (_RLN *RLNTransactorSession) Register(pubkey *big.Int) (*types.Transaction, error) { - return _RLN.Contract.Register(&_RLN.TransactOpts, pubkey) +// Solidity: function register(uint256 idCommitment) payable returns() +func (_RLN *RLNTransactorSession) Register(idCommitment *big.Int) (*types.Transaction, error) { + return _RLN.Contract.Register(&_RLN.TransactOpts, idCommitment) } // RegisterBatch is a paid mutator transaction binding the contract method 0x69e4863f. // -// Solidity: function registerBatch(uint256[] pubkeys) payable returns() -func (_RLN *RLNTransactor) RegisterBatch(opts *bind.TransactOpts, pubkeys []*big.Int) (*types.Transaction, error) { - return _RLN.contract.Transact(opts, "registerBatch", pubkeys) +// Solidity: function registerBatch(uint256[] idCommitments) payable returns() +func (_RLN *RLNTransactor) RegisterBatch(opts *bind.TransactOpts, idCommitments []*big.Int) (*types.Transaction, error) { + return _RLN.contract.Transact(opts, "registerBatch", idCommitments) } // RegisterBatch is a paid mutator transaction binding the contract method 0x69e4863f. // -// Solidity: function registerBatch(uint256[] pubkeys) payable returns() -func (_RLN *RLNSession) RegisterBatch(pubkeys []*big.Int) (*types.Transaction, error) { - return _RLN.Contract.RegisterBatch(&_RLN.TransactOpts, pubkeys) +// Solidity: function registerBatch(uint256[] idCommitments) payable returns() +func (_RLN *RLNSession) RegisterBatch(idCommitments []*big.Int) (*types.Transaction, error) { + return _RLN.Contract.RegisterBatch(&_RLN.TransactOpts, idCommitments) } // RegisterBatch is a paid mutator transaction binding the contract method 0x69e4863f. // -// Solidity: function registerBatch(uint256[] pubkeys) payable returns() -func (_RLN *RLNTransactorSession) RegisterBatch(pubkeys []*big.Int) (*types.Transaction, error) { - return _RLN.Contract.RegisterBatch(&_RLN.TransactOpts, pubkeys) +// Solidity: function registerBatch(uint256[] idCommitments) payable returns() +func (_RLN *RLNTransactorSession) RegisterBatch(idCommitments []*big.Int) (*types.Transaction, error) { + return _RLN.Contract.RegisterBatch(&_RLN.TransactOpts, idCommitments) } -// Withdraw is a paid mutator transaction binding the contract method 0x0ad58d2f. +// Withdraw is a paid mutator transaction binding the contract method 0x00f714ce. // -// Solidity: function withdraw(uint256 secret, uint256 _pubkeyIndex, address receiver) returns() -func (_RLN *RLNTransactor) Withdraw(opts *bind.TransactOpts, secret *big.Int, _pubkeyIndex *big.Int, receiver common.Address) (*types.Transaction, error) { - return _RLN.contract.Transact(opts, "withdraw", secret, _pubkeyIndex, receiver) +// Solidity: function withdraw(uint256 secret, address receiver) returns() +func (_RLN *RLNTransactor) Withdraw(opts *bind.TransactOpts, secret *big.Int, receiver common.Address) (*types.Transaction, error) { + return _RLN.contract.Transact(opts, "withdraw", secret, receiver) } -// Withdraw is a paid mutator transaction binding the contract method 0x0ad58d2f. +// Withdraw is a paid mutator transaction binding the contract method 0x00f714ce. // -// Solidity: function withdraw(uint256 secret, uint256 _pubkeyIndex, address receiver) returns() -func (_RLN *RLNSession) Withdraw(secret *big.Int, _pubkeyIndex *big.Int, receiver common.Address) (*types.Transaction, error) { - return _RLN.Contract.Withdraw(&_RLN.TransactOpts, secret, _pubkeyIndex, receiver) +// Solidity: function withdraw(uint256 secret, address receiver) returns() +func (_RLN *RLNSession) Withdraw(secret *big.Int, receiver common.Address) (*types.Transaction, error) { + return _RLN.Contract.Withdraw(&_RLN.TransactOpts, secret, receiver) } -// Withdraw is a paid mutator transaction binding the contract method 0x0ad58d2f. +// Withdraw is a paid mutator transaction binding the contract method 0x00f714ce. // -// Solidity: function withdraw(uint256 secret, uint256 _pubkeyIndex, address receiver) returns() -func (_RLN *RLNTransactorSession) Withdraw(secret *big.Int, _pubkeyIndex *big.Int, receiver common.Address) (*types.Transaction, error) { - return _RLN.Contract.Withdraw(&_RLN.TransactOpts, secret, _pubkeyIndex, receiver) +// Solidity: function withdraw(uint256 secret, address receiver) returns() +func (_RLN *RLNTransactorSession) Withdraw(secret *big.Int, receiver common.Address) (*types.Transaction, error) { + return _RLN.Contract.Withdraw(&_RLN.TransactOpts, secret, receiver) } -// WithdrawBatch is a paid mutator transaction binding the contract method 0xa9d85eba. +// WithdrawBatch is a paid mutator transaction binding the contract method 0x40070712. // -// Solidity: function withdrawBatch(uint256[] secrets, uint256[] pubkeyIndexes, address[] receivers) returns() -func (_RLN *RLNTransactor) WithdrawBatch(opts *bind.TransactOpts, secrets []*big.Int, pubkeyIndexes []*big.Int, receivers []common.Address) (*types.Transaction, error) { - return _RLN.contract.Transact(opts, "withdrawBatch", secrets, pubkeyIndexes, receivers) +// Solidity: function withdrawBatch(uint256[] secrets, address[] receivers) returns() +func (_RLN *RLNTransactor) WithdrawBatch(opts *bind.TransactOpts, secrets []*big.Int, receivers []common.Address) (*types.Transaction, error) { + return _RLN.contract.Transact(opts, "withdrawBatch", secrets, receivers) } -// WithdrawBatch is a paid mutator transaction binding the contract method 0xa9d85eba. +// WithdrawBatch is a paid mutator transaction binding the contract method 0x40070712. // -// Solidity: function withdrawBatch(uint256[] secrets, uint256[] pubkeyIndexes, address[] receivers) returns() -func (_RLN *RLNSession) WithdrawBatch(secrets []*big.Int, pubkeyIndexes []*big.Int, receivers []common.Address) (*types.Transaction, error) { - return _RLN.Contract.WithdrawBatch(&_RLN.TransactOpts, secrets, pubkeyIndexes, receivers) +// Solidity: function withdrawBatch(uint256[] secrets, address[] receivers) returns() +func (_RLN *RLNSession) WithdrawBatch(secrets []*big.Int, receivers []common.Address) (*types.Transaction, error) { + return _RLN.Contract.WithdrawBatch(&_RLN.TransactOpts, secrets, receivers) } -// WithdrawBatch is a paid mutator transaction binding the contract method 0xa9d85eba. +// WithdrawBatch is a paid mutator transaction binding the contract method 0x40070712. // -// Solidity: function withdrawBatch(uint256[] secrets, uint256[] pubkeyIndexes, address[] receivers) returns() -func (_RLN *RLNTransactorSession) WithdrawBatch(secrets []*big.Int, pubkeyIndexes []*big.Int, receivers []common.Address) (*types.Transaction, error) { - return _RLN.Contract.WithdrawBatch(&_RLN.TransactOpts, secrets, pubkeyIndexes, receivers) +// Solidity: function withdrawBatch(uint256[] secrets, address[] receivers) returns() +func (_RLN *RLNTransactorSession) WithdrawBatch(secrets []*big.Int, receivers []common.Address) (*types.Transaction, error) { + return _RLN.Contract.WithdrawBatch(&_RLN.TransactOpts, secrets, receivers) } // RLNMemberRegisteredIterator is returned from FilterMemberRegistered and is used to iterate over the raw logs and unpacked data for MemberRegistered events raised by the RLN contract. @@ -984,14 +572,14 @@ func (it *RLNMemberRegisteredIterator) Close() error { // RLNMemberRegistered represents a MemberRegistered event raised by the RLN contract. type RLNMemberRegistered struct { - Pubkey *big.Int - Index *big.Int - Raw types.Log // Blockchain specific contextual infos + IdCommitment *big.Int + Index *big.Int + Raw types.Log // Blockchain specific contextual infos } // FilterMemberRegistered is a free log retrieval operation binding the contract event 0x5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2. // -// Solidity: event MemberRegistered(uint256 pubkey, uint256 index) +// Solidity: event MemberRegistered(uint256 idCommitment, uint256 index) func (_RLN *RLNFilterer) FilterMemberRegistered(opts *bind.FilterOpts) (*RLNMemberRegisteredIterator, error) { logs, sub, err := _RLN.contract.FilterLogs(opts, "MemberRegistered") @@ -1003,7 +591,7 @@ func (_RLN *RLNFilterer) FilterMemberRegistered(opts *bind.FilterOpts) (*RLNMemb // WatchMemberRegistered is a free log subscription operation binding the contract event 0x5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2. // -// Solidity: event MemberRegistered(uint256 pubkey, uint256 index) +// Solidity: event MemberRegistered(uint256 idCommitment, uint256 index) func (_RLN *RLNFilterer) WatchMemberRegistered(opts *bind.WatchOpts, sink chan<- *RLNMemberRegistered) (event.Subscription, error) { logs, sub, err := _RLN.contract.WatchLogs(opts, "MemberRegistered") @@ -1040,7 +628,7 @@ func (_RLN *RLNFilterer) WatchMemberRegistered(opts *bind.WatchOpts, sink chan<- // ParseMemberRegistered is a log parse operation binding the contract event 0x5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2. // -// Solidity: event MemberRegistered(uint256 pubkey, uint256 index) +// Solidity: event MemberRegistered(uint256 idCommitment, uint256 index) func (_RLN *RLNFilterer) ParseMemberRegistered(log types.Log) (*RLNMemberRegistered, error) { event := new(RLNMemberRegistered) if err := _RLN.contract.UnpackLog(event, "MemberRegistered", log); err != nil { @@ -1119,14 +707,13 @@ func (it *RLNMemberWithdrawnIterator) Close() error { // RLNMemberWithdrawn represents a MemberWithdrawn event raised by the RLN contract. type RLNMemberWithdrawn struct { - Pubkey *big.Int - Index *big.Int - Raw types.Log // Blockchain specific contextual infos + IdCommitment *big.Int + Raw types.Log // Blockchain specific contextual infos } -// FilterMemberWithdrawn is a free log retrieval operation binding the contract event 0x62ec3a516d22a993ce5cb4e7593e878c74f4d799dde522a88dc27a994fd5a943. +// FilterMemberWithdrawn is a free log retrieval operation binding the contract event 0xad2d771c5ad1c1e6f50cc769e53ec1e194002c29f28c3dd2af5639b60d8072a6. // -// Solidity: event MemberWithdrawn(uint256 pubkey, uint256 index) +// Solidity: event MemberWithdrawn(uint256 idCommitment) func (_RLN *RLNFilterer) FilterMemberWithdrawn(opts *bind.FilterOpts) (*RLNMemberWithdrawnIterator, error) { logs, sub, err := _RLN.contract.FilterLogs(opts, "MemberWithdrawn") @@ -1136,9 +723,9 @@ func (_RLN *RLNFilterer) FilterMemberWithdrawn(opts *bind.FilterOpts) (*RLNMembe return &RLNMemberWithdrawnIterator{contract: _RLN.contract, event: "MemberWithdrawn", logs: logs, sub: sub}, nil } -// WatchMemberWithdrawn is a free log subscription operation binding the contract event 0x62ec3a516d22a993ce5cb4e7593e878c74f4d799dde522a88dc27a994fd5a943. +// WatchMemberWithdrawn is a free log subscription operation binding the contract event 0xad2d771c5ad1c1e6f50cc769e53ec1e194002c29f28c3dd2af5639b60d8072a6. // -// Solidity: event MemberWithdrawn(uint256 pubkey, uint256 index) +// Solidity: event MemberWithdrawn(uint256 idCommitment) func (_RLN *RLNFilterer) WatchMemberWithdrawn(opts *bind.WatchOpts, sink chan<- *RLNMemberWithdrawn) (event.Subscription, error) { logs, sub, err := _RLN.contract.WatchLogs(opts, "MemberWithdrawn") @@ -1173,9 +760,9 @@ func (_RLN *RLNFilterer) WatchMemberWithdrawn(opts *bind.WatchOpts, sink chan<- }), nil } -// ParseMemberWithdrawn is a log parse operation binding the contract event 0x62ec3a516d22a993ce5cb4e7593e878c74f4d799dde522a88dc27a994fd5a943. +// ParseMemberWithdrawn is a log parse operation binding the contract event 0xad2d771c5ad1c1e6f50cc769e53ec1e194002c29f28c3dd2af5639b60d8072a6. // -// Solidity: event MemberWithdrawn(uint256 pubkey, uint256 index) +// Solidity: event MemberWithdrawn(uint256 idCommitment) func (_RLN *RLNFilterer) ParseMemberWithdrawn(log types.Log) (*RLNMemberWithdrawn, error) { event := new(RLNMemberWithdrawn) if err := _RLN.contract.UnpackLog(event, "MemberWithdrawn", log); err != nil { diff --git a/waku/v2/protocol/rln/contracts/RLN.sol b/waku/v2/protocol/rln/contracts/RLN.sol deleted file mode 100644 index 1a647ac0b..000000000 --- a/waku/v2/protocol/rln/contracts/RLN.sol +++ /dev/null @@ -1,96 +0,0 @@ -pragma solidity ^0.7.4; - -import { IPoseidonHasher } from "./crypto/PoseidonHasher.sol"; - -contract RLN { - uint256 public immutable MEMBERSHIP_DEPOSIT; - uint256 public immutable DEPTH; - uint256 public immutable SET_SIZE; - - uint256 public pubkeyIndex = 0; - mapping(uint256 => uint256) public members; - - IPoseidonHasher public poseidonHasher; - - event MemberRegistered(uint256 pubkey, uint256 index); - event MemberWithdrawn(uint256 pubkey, uint256 index); - - constructor( - uint256 membershipDeposit, - uint256 depth, - address _poseidonHasher - ) public { - MEMBERSHIP_DEPOSIT = membershipDeposit; - DEPTH = depth; - SET_SIZE = 1 << depth; - poseidonHasher = IPoseidonHasher(_poseidonHasher); - } - - function register(uint256 pubkey) external payable { - require(pubkeyIndex < SET_SIZE, "RLN, register: set is full"); - require(msg.value == MEMBERSHIP_DEPOSIT, "RLN, register: membership deposit is not satisfied"); - _register(pubkey); - } - - function registerBatch(uint256[] calldata pubkeys) external payable { - require(pubkeyIndex + pubkeys.length <= SET_SIZE, "RLN, registerBatch: set is full"); - require(msg.value == MEMBERSHIP_DEPOSIT * pubkeys.length, "RLN, registerBatch: membership deposit is not satisfied"); - for (uint256 i = 0; i < pubkeys.length; i++) { - _register(pubkeys[i]); - } - } - - function _register(uint256 pubkey) internal { - members[pubkeyIndex] = pubkey; - emit MemberRegistered(pubkey, pubkeyIndex); - pubkeyIndex += 1; - } - - function withdrawBatch( - uint256[] calldata secrets, - uint256[] calldata pubkeyIndexes, - address payable[] calldata receivers - ) external { - uint256 batchSize = secrets.length; - require(batchSize != 0, "RLN, withdrawBatch: batch size zero"); - require(batchSize == pubkeyIndexes.length, "RLN, withdrawBatch: batch size mismatch pubkey indexes"); - require(batchSize == receivers.length, "RLN, withdrawBatch: batch size mismatch receivers"); - for (uint256 i = 0; i < batchSize; i++) { - _withdraw(secrets[i], pubkeyIndexes[i], receivers[i]); - } - } - - function withdraw( - uint256 secret, - uint256 _pubkeyIndex, - address payable receiver - ) external { - _withdraw(secret, _pubkeyIndex, receiver); - } - - function _withdraw( - uint256 secret, - uint256 _pubkeyIndex, - address payable receiver - ) internal { - require(_pubkeyIndex < SET_SIZE, "RLN, _withdraw: invalid pubkey index"); - require(members[_pubkeyIndex] != 0, "RLN, _withdraw: member doesn't exist"); - require(receiver != address(0), "RLN, _withdraw: empty receiver address"); - - // derive public key - uint256 pubkey = hash([secret, 0]); - require(members[_pubkeyIndex] == pubkey, "RLN, _withdraw: not verified"); - - // delete member - members[_pubkeyIndex] = 0; - - // refund deposit - receiver.transfer(MEMBERSHIP_DEPOSIT); - - emit MemberWithdrawn(pubkey, _pubkeyIndex); - } - - function hash(uint256[2] memory input) internal view returns (uint256) { - return poseidonHasher.hash(input); - } -} \ No newline at end of file diff --git a/waku/v2/protocol/rln/contracts/crypto/PoseidonHasher.sol b/waku/v2/protocol/rln/contracts/crypto/PoseidonHasher.sol deleted file mode 100644 index c00bb8b30..000000000 --- a/waku/v2/protocol/rln/contracts/crypto/PoseidonHasher.sol +++ /dev/null @@ -1,535 +0,0 @@ -// https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/crypto/PoseidonHasher.sol - -pragma solidity 0.7.4; - -interface IPoseidonHasher { - function hash(uint256[2] memory input) external pure returns (uint256 result); - - function identity() external pure returns (uint256); -} - -contract PoseidonHasher is IPoseidonHasher { - uint256 constant Q = 21888242871839275222246405745257275088548364400416034343698204186575808495617; - uint256 constant C0 = 2768970367241139781802170833007148522174069744848643939234067191877771423371; - uint256 constant C1 = 6468574107656347268529237497718336587709069456280471580424455063721832719771; - uint256 constant C2 = 18794671303815708509784162368644133457448839260573151733485130900959816547847; - uint256 constant C3 = 21495479230478098685877232964279351350768322664786520160088149860043275231591; - uint256 constant C4 = 13499990804456294376331975175669076043666672782766959528979369127842395667962; - uint256 constant C5 = 11128727858753328237562379127901473551876426168355298792273038389175814738273; - uint256 constant C6 = 6174623859769212836350518599861056828848352474434521101649917228563284157731; - uint256 constant C7 = 731429061815452030222739129549549044853294286077603862495031070831228988506; - uint256 constant C8 = 18691825946094184197601861261718857711439992232978967087150603050561229972879; - uint256 constant C9 = 6901715409529528992021081413007214967207374659260807285380744444309443019002; - uint256 constant C10 = 7889774703159213060685393199720756541539275646424166159037924832893670779999; - uint256 constant C11 = 19148164181730036907570646123652401621475121269795476659255226436085540432812; - uint256 constant C12 = 356519004282890736138910009474234839367086357569508205089190200287135015343; - uint256 constant C13 = 5070064330380484074844995745007722918545766490350556589468108281662282971512; - uint256 constant C14 = 17531425645708334340342421865584088711059286683026910061769879104052748058500; - uint256 constant C15 = 920858801565935944623869688790191117976818337296182581403952541435643043455; - uint256 constant C16 = 7671542183617251806500810220803333911317855932989746628699368932279406768167; - uint256 constant C17 = 7881690674485945577862776772342991782415236259307258648854817257894786877801; - uint256 constant C18 = 19155896751615806549889067080381563929649717724892491357642801041215501837659; - uint256 constant C19 = 9657176770419678097838646349393281787292209556252142440714968703151552794280; - uint256 constant C20 = 1376534476338443314506167934949939673567644510933411653555577922098640496938; - uint256 constant C21 = 17373401671868429549652772677366856294616993437583002599910365256220696563780; - uint256 constant C22 = 9746128003951157537728271629364357225604237114762257721895149249266834505625; - uint256 constant C23 = 17782316906978487011972931426261039391542241330560756508577882755911543517908; - uint256 constant C24 = 6589224737393540076643416156354549730831080306137040791236143083907274321011; - uint256 constant C25 = 17321856211701727875100310423669922181823762220382619531116210312384063527081; - uint256 constant C26 = 21321909001724533038371153813693276559530291455431564073497502239396933319818; - uint256 constant C27 = 17849794853142289789836828064662594833303692772683927435966421769162340090898; - uint256 constant C28 = 3469446763321625523201767743510820386262850368964003752018684310306935672122; - uint256 constant C29 = 4411200946062535851397814394775457104021582693964231752948256822578636459939; - uint256 constant C30 = 18626579782117576204277882219675177684589838126472487652629778677837675278662; - uint256 constant C31 = 764261930639154699767774045099363658161006905585481283735008957581415860662; - uint256 constant C32 = 6122983345977564957406231576949193286198709429730716375547595362175192593123; - uint256 constant C33 = 2469188694307740124657403582315280809174737971010077914159812443136587941756; - uint256 constant C34 = 5382605971470296415808536561267917764719132018437742878552512928718168489695; - uint256 constant C35 = 6589667679759352998039311059993721585330589021804485020627575514256149305666; - uint256 constant C36 = 20661471625156349582050865201555079410137144327315643708284763422133754381325; - uint256 constant C37 = 18694584274137621868895160209707042629719656780873050479100267791928497600376; - uint256 constant C38 = 13822590562029956399621741895244911145933359734099212387467069390727913142666; - uint256 constant C39 = 694674849457359992382704784272941309716157308424480468618786287819256378917; - uint256 constant C40 = 18763037144982179742008371677750585549220053470184500098542470704194556690623; - uint256 constant C41 = 18486457976264107916834430437402981813449917200007719339429151501964183082936; - uint256 constant C42 = 6556747954001777118869362753998468478855885460502383141235961204400638463294; - uint256 constant C43 = 12385133754714463216711399717325449316164682530612784512290690756146937377664; - uint256 constant C44 = 19895348036861519723386861870711743699604138662509897355377030959682349375552; - uint256 constant C45 = 16830822151531046474312344756361243376821272897299262546129244900502111682734; - uint256 constant C46 = 20875209030695524214960780268667166557156788659940284813793529164900666593068; - uint256 constant C47 = 8777606742656153264634386709062440729894098167014885703560793183003141571957; - uint256 constant C48 = 3404497983786933300887052921900023151252717521554164668384012034556256626067; - uint256 constant C49 = 2555107629226010512992356367848094165962022522393505508367085820070687884355; - uint256 constant C50 = 15113919336730148565553505760820732613676431799289611544548947520407297443700; - uint256 constant C51 = 12109280671570307231007703707720632582709786369013364642897329602318304275337; - uint256 constant C52 = 14968914070423010632399365015358049892440762915276845426568596163422798377730; - uint256 constant C53 = 19061189532957010364709072574663003871548558794774753349573267371990486123152; - uint256 constant C54 = 8682801373989521576522508447484143687434748406228624907362693631377691698421; - uint256 constant C55 = 10836672514863795455996193088790111107823297731722043988991810099345596059914; - uint256 constant C56 = 15783196349960742821266383686606772431598902255698169764526487081837237805029; - uint256 constant C57 = 2908608383546665417899486637528022511748691900266764564499649456344035921401; - uint256 constant C58 = 11329727236614532496067886659074662970462346457991275919233250048151273297377; - uint256 constant C59 = 5116653167814666817290578004214535117470888177090558374943095066718387153691; - uint256 constant C60 = 13540152826778549413479417002435847356268346234631393477044136590757331815911; - uint256 constant C61 = 7947441526608065582264952807420254797193034288774248212171921641395121801332; - uint256 constant C62 = 1547483282147791156522335107475157206253201614573941966672490820147450725004; - uint256 constant M0 = 10115680371401748607263639966297231210785101245789087039760048681884121897698; - uint256 constant M1 = 7682529184580308813007726368887641784100790067958820768670102409394963579396; - uint256 constant M2 = 3036380094837744536618704667164758501777151816139077990926623931426168668495; - uint256 constant M3 = 462021688665431536448264191536285854244979957674130050775621906384644169421; - uint256 constant M4 = 62665112908715427992420108025470785827183241813778563254523765114425841603; - uint256 constant M5 = 534236519266104271325123542701236478972353175554309786393016883839422407419; - uint256 constant M6 = 5922526147398848214826466482573128257954044394758836008121691281747299315999; - uint256 constant M7 = 10778490508693548114587990025762035374898560218037495485187480124708600063292; - uint256 constant M8 = 13853145901042782779715203529626320031162484246107565810821674712070680357632; - - function hash(uint256[2] memory input) external pure override returns (uint256 result) { - return _hash(input); - } - - function _hash(uint256[2] memory input) internal pure returns (uint256 result) { - assembly { - let q := Q - let pos := mload(0x40) - mstore(pos, M0) - mstore(add(pos, 32), M1) - mstore(add(pos, 64), M2) - mstore(add(pos, 96), M3) - mstore(add(pos, 128), M4) - - // mstore(add(pos, 160), M5) - // mstore(add(pos, 192), M6) - // mstore(add(pos, 224), M7) - // mstore(add(pos, 256), M8) - - // use stack intensively - let m5 := M5 - let m6 := M6 - let m7 := M7 - let m8 := M8 - - let s0 := add(mload(input), C0) - let s1 := add(mload(add(input, 32)), C0) - let s2 := C0 - - let t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := mulmod(s1, s1, q) - s1 := mulmod(mulmod(t, t, q), s1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C1 - let z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - let z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := mulmod(z1, z1, q) - z1 := mulmod(mulmod(t, t, q), z1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C2 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := mulmod(s1, s1, q) - s1 := mulmod(mulmod(t, t, q), s1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C3 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := mulmod(z1, z1, q) - z1 := mulmod(mulmod(t, t, q), z1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C4 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C5 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C6 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C7 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C8 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C9 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C10 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C11 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C12 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C13 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C14 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C15 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C16 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C17 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C18 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C19 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C20 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C21 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C22 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C23 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C24 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C25 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C26 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C27 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C28 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C29 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C30 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C31 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C32 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C33 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C34 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C35 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C36 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C37 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C38 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C39 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C40 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C41 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C42 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C43 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C44 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C45 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C46 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C47 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C48 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C49 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C50 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C51 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C52 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C53 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C54 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C55 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C56 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C57 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := C58 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := C59 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := mulmod(z1, z1, q) - z1 := mulmod(mulmod(t, t, q), z1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C60 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := mulmod(s1, s1, q) - s1 := mulmod(mulmod(t, t, q), s1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C61 - z0 := add(add(add(mulmod(s0, mload(pos), q), mulmod(s1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - z1 := add(add(add(mulmod(s0, mload(add(pos, 96)), q), mulmod(s1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(s0, m6, q), mulmod(s1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(z0, z0, q) - z0 := mulmod(mulmod(t, t, q), z0, q) - t := mulmod(z1, z1, q) - z1 := mulmod(mulmod(t, t, q), z1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - t := C62 - s0 := add(add(add(mulmod(z0, mload(pos), q), mulmod(z1, mload(add(pos, 32)), q)), mulmod(s2, mload(add(pos, 64)), q)), t) - s1 := add(add(add(mulmod(z0, mload(add(pos, 96)), q), mulmod(z1, mload(add(pos, 128)), q)), mulmod(s2, m5, q)), t) - s2 := add(add(add(mulmod(z0, m6, q), mulmod(z1, m7, q)), mulmod(s2, m8, q)), t) - t := mulmod(s0, s0, q) - s0 := mulmod(mulmod(t, t, q), s0, q) - t := mulmod(s1, s1, q) - s1 := mulmod(mulmod(t, t, q), s1, q) - t := mulmod(s2, s2, q) - s2 := mulmod(mulmod(t, t, q), s2, q) - - result := s0 - } - } - - function identity() external pure override returns (uint256) { - return _identity(); - } - - function _identity() internal pure returns (uint256) { - return 0x2ff267fd23782a5625e6d804f0a7fa700b8dc6084e2e7a5aff7cd4b1c506d30b; - } -} \ No newline at end of file diff --git a/waku/v2/protocol/rln/contracts/generate.go b/waku/v2/protocol/rln/contracts/generate.go index 0ae8bd4cb..254bad181 100644 --- a/waku/v2/protocol/rln/contracts/generate.go +++ b/waku/v2/protocol/rln/contracts/generate.go @@ -1,3 +1,5 @@ package contracts -//go:generate abigen -sol ./RLN.sol -pkg contracts -out ./RLN.go +//go:generate solcjs --abi --bin ./rln-contract/contracts/Rln.sol -o ./ +//go:generate abigen --abi ./rln-contract_contracts_Rln_sol_RLN.abi --pkg contracts --type RLN --out ./RLN.go --bin ./rln-contract_contracts_Rln_sol_RLN.bin +//go:generate abigen --abi ./rln-contract_contracts_PoseidonHasher_sol_PoseidonHasher.abi --pkg contracts --type PoseidonHasher --out ./PoseidonHasher.go --bin ./rln-contract_contracts_PoseidonHasher_sol_PoseidonHasher.bin diff --git a/waku/v2/protocol/rln/contracts/rln-contract b/waku/v2/protocol/rln/contracts/rln-contract new file mode 160000 index 000000000..f99eb2aa0 --- /dev/null +++ b/waku/v2/protocol/rln/contracts/rln-contract @@ -0,0 +1 @@ +Subproject commit f99eb2aa0d62bb27631f6ffb4c6161ceb334d2a3 diff --git a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go index 981432b8e..cc7cb8deb 100644 --- a/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go +++ b/waku/v2/protocol/rln/group_manager/dynamic/dynamic.go @@ -235,7 +235,7 @@ func (gm *DynamicGroupManager) InsertMembers(toInsert *om.OrderedMap) error { if oldestIndexInBlock == nil { oldestIndexInBlock = evt.Index } - idCommitments = append(idCommitments, rln.BigIntToBytes32(evt.Pubkey)) + idCommitments = append(idCommitments, rln.BigIntToBytes32(evt.IdCommitment)) } if len(idCommitments) == 0 { diff --git a/waku/v2/protocol/rln/group_manager/dynamic/handler_test.go b/waku/v2/protocol/rln/group_manager/dynamic/handler_test.go index b20e542ed..4e221dd12 100644 --- a/waku/v2/protocol/rln/group_manager/dynamic/handler_test.go +++ b/waku/v2/protocol/rln/group_manager/dynamic/handler_test.go @@ -14,14 +14,14 @@ import ( "github.com/waku-org/go-zerokit-rln/rln" ) -func eventBuilder(blockNumber uint64, removed bool, pubkey int64, index int64) *contracts.RLNMemberRegistered { +func eventBuilder(blockNumber uint64, removed bool, idCommitment int64, index int64) *contracts.RLNMemberRegistered { return &contracts.RLNMemberRegistered{ Raw: types.Log{ BlockNumber: blockNumber, Removed: removed, }, - Index: big.NewInt(index), - Pubkey: big.NewInt(pubkey), + Index: big.NewInt(index), + IdCommitment: big.NewInt(idCommitment), } } diff --git a/waku/v2/protocol/rln/keystore/keystore.go b/waku/v2/protocol/rln/keystore/keystore.go index 28d8996fb..184bac120 100644 --- a/waku/v2/protocol/rln/keystore/keystore.go +++ b/waku/v2/protocol/rln/keystore/keystore.go @@ -219,7 +219,7 @@ func GetMembershipCredentials(logger *zap.Logger, credentialsPath string, passwo return result, nil } -// Adds a membership credential to the keystore matching the application, appIdentifier and version filters. +// AddMembershipCredentials inserts a membership credential to the keystore matching the application, appIdentifier and version filters. func AddMembershipCredentials(path string, newIdentityCredential *rln.IdentityCredential, newMembershipGroup MembershipGroup, password string, appInfo AppInfo, separator string) (membershipGroupIndex uint, err error) { k, err := LoadAppKeystore(path, appInfo, DefaultSeparator) if err != nil { diff --git a/waku/v2/protocol/rln/onchain_test.go b/waku/v2/protocol/rln/onchain_test.go index cad5e7f54..3d1296745 100644 --- a/waku/v2/protocol/rln/onchain_test.go +++ b/waku/v2/protocol/rln/onchain_test.go @@ -83,8 +83,6 @@ func (s *WakuRLNRelayDynamicSuite) SetupTest() { auth, err := bind.NewKeyedTransactorWithChainID(s.u1PrivKey, chainID) s.Require().NoError(err) - // TODO: update rln contract - poseidonHasherAddr, _, _, err := contracts.DeployPoseidonHasher(auth, backend) s.Require().NoError(err)