-
Notifications
You must be signed in to change notification settings - Fork 0
Description
One of the frictions with RLN is that users need to register an RLN membership, and this requires to pay some fees (transaction cost + price of the membership). Meaning that the user has to have funds in their wallet. This makes it difficult to dogfood the feature, since having funds acts as an entry barrier.
With accounts abstraction, some L2s already support features such as the zkSync Paymaster. This allows to sponsor gas for users, where the "paymaster" account pays the gas fees. In other words, a user can register a RLN membership without having to pay gas, since the paymaster pays for it. While this may not make sense for mainnet (it defeats the purpose of RLN, since if RLN memberships can be registered at no cost, we would lose the economic rate-limiting of RLN). But it may be interesting for testnet and dogfooding.
After having spent some time with this, these are the findings:
- After multiple attempts, I haven't been able to deploy our RLN contract to zkSync. Seems that the Posseidon hashing function we use (which contains some assembly code) can't be deployed. More specifically, I can't even compile it. Takes multiple hours and then errors.
- Experimented with the paymaster feature, see code below. If we had RLN deployed in zksync it could be used almost as it is to sponsor gas tx fees for RLN registration. Coolest thing about this, is that no changes are needed in RLN. Registering is a "normal" transaction and you only have to add they paymaster as a parameter.
Paymaster code in Golang
package main
import (
"context"
"io/ioutil"
"math/big"
"strings"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
log "github.com/sirupsen/logrus"
"github.com/zksync-sdk/zksync2-go/accounts"
"github.com/zksync-sdk/zksync2-go/clients"
zkTypes "github.com/zksync-sdk/zksync2-go/types"
"github.com/zksync-sdk/zksync2-go/utils"
)
func main() {
// Public endpoints for Sepolia (L1 and L2 zkSync)
ZkSyncProvider := "https://sepolia.era.zksync.dev"
EthereumProvider := "https://rpc.ankr.com/eth_sepolia"
// Connect to ZKsync network
client, err := clients.Dial(ZkSyncProvider)
if err != nil {
log.Fatal(err)
}
defer client.Close()
// Connect to Ethereum network
ethClient, err := ethclient.Dial(EthereumProvider)
if err != nil {
log.Fatal(err)
}
defer ethClient.Close()
// Load the ABI JSON file. This would be the RLN contract abi
abiFilePath := "abi.abi"
abiFile, err := ioutil.ReadFile(abiFilePath)
if err != nil {
log.Fatal("Failed to read ABI file: ", err)
}
// Parse the ABI
parsedABI, err := abi.JSON(strings.NewReader(string(abiFile)))
if err != nil {
log.Fatal("Failed to parse ABI: ", err)
}
// Method from the contract we want to call
methodName := "register"
// First field. This would be the commitment
arg1 := big.NewInt(0)
// Second field. This would be the userMessageLimit
arg2 := uint32(100)
// Pack the method call
data, err := parsedABI.Pack(methodName, arg1, arg2)
if err != nil {
log.Fatalf("Failed to pack ABI data: %v", err)
}
log.Info("Packed data:", data)
// https://sepolia.explorer.zksync.io/address/0x3cb2b87d10ac01736a65688f3e0fb1b070b3eea3#transactions
// 0xaEaD05FD4986e6128587eB2E714B6fe1751B41C3 (taken from https://www.youtube.com/watch?v=7rC9rjPtxBs)
// 0x3cb2b87d10ac01736a65688f3e0fb1b070b3eea3 (official paymaster, not working)
// Note that a custom paymaster can be also deployed and used
Paymaster := common.HexToAddress("0xaEaD05FD4986e6128587eB2E714B6fe1751B41C3")
// RLN contract address
RlnContract := common.HexToAddress("0xaEaD05FD4986e6128587eB2E714B6fe1751B41C4")
// Any account works. No need to have funds in it. Paymaster covers them
privateKey := "TODO: YOUR PRIVATE KEY"
wallet, err := accounts.NewWallet(common.Hex2Bytes(privateKey), &client, ethClient)
if err != nil {
log.Fatal("error creating new wallet ", err)
}
paymasterParams, err := utils.GetPaymasterParams(
Paymaster,
&zkTypes.GeneralPaymasterInput{})
if err != nil {
log.Fatal("error getting paymaster params: ", err)
}
hash, err := wallet.SendTransaction(context.Background(), &accounts.Transaction{
Data: data,
To: &RlnContract,
Meta: &zkTypes.Eip712Meta{
PaymasterParams: paymasterParams,
},
})
if err != nil {
log.Fatal("error sending tx: ", err)
}
log.Info("Tx hash: ", hash)
}