Call Permit
Detailed guide by Tanssi
Last updated
Detailed guide by Tanssi
Last updated
The Call Permit Precompile on parodychain allows a user to sign a permit, an signed message, for any EVM call and it can be dispatched by anyone or any smart contract. It is similar to the Permit Signing of ERC-20 approvals introduced in , except it applies to any EVM call instead of only approvals.
When the call permit is dispatched, it is done so on behalf of the user who signed the permit and the user or contract that dispatches the permit is responsible for paying transaction fees. As such, the precompile can be used to perform gas-less transactions.
For example, Alice signs a call permit and Bob dispatches it and performs the call on behalf of Alice. Bob pays for the transaction fees and as such, Alice doesn't need to have any of the native currency to pay for the transaction, unless the call includes a transfer.
The Call Permit Precompile is located at the following address:
Note
There can be some unintended consequences when using precompiles. Parodychain's Call Permit Precompile is derived from Moonbeam's, and as such, please familiarize yourself with .
is a Solidity interface that allows developers to interact with the precompile's three methods.
The interface includes the following functions:
The parameters of the hash can be broken down as follows:
PERMIT_DOMAIN - is the keccak256
of EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)
name - is the name of the signing domain and must be 'Call Permit Precompile'
exactly
version - is the version of the signing domain. For this case version is set to 1
chainId - is the chain ID of your appchain
verifyingContract - is the address of the contract that will verify the signature. In this case, the Call Permit Precompile address
Once you've set up the example contract, then you can set up the Call Permit Precompile contract.
The SetMessage.sol
contract is a perfect example to demonstrate use of the Call Permit Precompile.
Click on the File explorer tab
Paste the CallPermit.sol
contract into a Remix file named CallPermit.sol
Paste the SetMessage.sol
contract into a Remix file named SetMessage.sol
First, you'll need to compile the example contract:
Click on the Compile tab
Then to compile the interface, click on Compile SetMessage.sol
Then you can deploy it:
Click on the Deploy and Run tab, directly below the Compile tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed
Make sure Injected Provider - Metamask is selected in the ENVIRONMENT drop down
Ensure SetMessage.sol is selected in the CONTRACT dropdown
Click Deploy
MetaMask will pop up and you'll need to Confirm the transaction
The contract will appear under the list of Deployed Contracts on the left side panel. Copy the contract address as you will need to use it to generate the call permit signature in the next section.
First you'll need to compile the Call Permit Precompile contract:
Click on the Compile tab
Then to compile the interface, click on Compile CallPermit.sol
Then, instead of deploying the contract, you'll just need to access it given the address of the precompile:
Click on the Deploy and Run tab, directly below the Compile tab in Remix. Note: you are not deploying a contract here, instead you are accessing a precompiled contract that is already deployed
Make sure Injected Provider - Metamask is selected in the ENVIRONMENT drop down
Ensure CallPermit.sol is selected in the CONTRACT dropdown. Since this is a precompiled contract, there is no deployment step. Rather you'll provide the address of the precompile in the At Address field
Provide the address of the Call Permit Precompile for Tanssi EVM appchains: 0x0000000000000000000000000000000000000802
and click At Address
The Call Permit Precompile will appear in the list of Deployed Contracts
Here's an overview of the steps that you'll need to take to obtain the signature:
The message
will be created and includes some of the data that is needed to create the call permit. It includes the arguments that will be passed into the dispatch
function and the nonce of the signer
A JSON structure of the data the user needs to sign will be assembled for the call permit and include all of the types for the dispatch
arguments and the nonce. This will result in the CallPermit
type and will be saved as the primaryType
The domain separator will be created using "Call Permit Precompile"
exactly for the name, the version of your dApp or platform, the chain ID of the network the signature is to be used on, and the address of the contract that will verify the signature. Note that you'll need to specify the chain ID of your appchain in the script to generate the correct signature
All of the assembled data will be signed using Ethers.js
In order to get the signature arguments (v
, r
, and s
), you'll need to sign a message containing the arguments for the remainder of the aforementioned parameters, plus the nonce of the signer.
from
- the address of the account you want to sign the call permit with
to
- the contract address for the SetMessage.sol
contract
value
- can be 0
for this example as you'll just be setting a message instead of transferring any funds
data
- you can send any message you would like. You'll just need the hex representation of the message you want to set using the SetMessage.sol
contract. This will contain the function selector of the set
function and the string of the message. For this example, you can send hello world
. To do so, you can use this hex representation:
gasLimit
- 100000
will be enough to send the dispatched call
deadline
- you can get the current time in UNIX seconds by running console.log(Date.now())
in a JavaScript script or a browser console. Once you have the current time, you should generously add additional seconds to represent when the call permit will expire
The nonce of the signer will also be needed. If this is your first time signing a call permit the nonce will be 0
. You can also check the nonce in Remix:
Expand the call permit contract
Next to the nonces function, enter the address of the signer and click on nonces
The result will be returned directly under the function
To generate the call permit signature using JavaScript and Ethers, you'll first need to create a project locally. You can do so with the following commands:
You should now have a file where you can create the script to get the signature along with a package.json
file. Open the package.json
file, and below the "dependencies"
section, add:
Remember
Never reveal your private keys, as they give direct access to your funds. The following steps are for demonstration purposes only.
To run the script, use the following command:
In the console, you should see the concatenated signature along with the values for the signature including the v
, r
, and s
values. Copy these values as you'll need them when interacting with the Call Permit Precompile in the following sections.
Note
Take care when copying the v
, r
, and s
values to the dispatch
method of the precompile. The ordering of v
, r
, and s
values in the precompile may not be the same as output by the script.
Now that you have generated the call permit signature, you will be able to test out calling the dispatch
function of the Call Permit Precompile.
When you send the dispatch
function, you'll need the same arguments as you used to sign the call permit. To get started, go back to the Deploy and Run tab in Remix, and under the Deployed Contracts section, expand the call permit contract. Make sure that you're connected to the account that you want to consume the call permit and pay the transaction fees. Then take the following steps:
For the from field, enter the account address you used to sign the call permit with
Copy and paste the contract address of SetMessage.sol
Enter 0
for the value field
Enter the hex representation of the function selector for the set
function and the string you want to set as the message for the SetMessage.sol
contract. For this example, hello world
can be used:
Enter 100000
for the gasLimit field
Enter the deadline
you used when signing the call permit
Copy the v
value you should have retrieved while generating the call permit signature and paste it into the v field
Copy the r
value you should have retrieved while generating the call permit signature and paste it into the r field
Copy the s
value you should have retrieved while generating the call permit signature and paste it into the s field
Click transact to send the transaction
MetaMask should pop up and you can confirm the transaction
Once the transaction goes through, you can verify that the message was updated to hello world
. To do so, you can:
Expand the SetMessage.sol
contract
Click on get
The result will appear below the function, and it should show hello world
Congratulations! You've successfully generated a call permit signature and used it to dispatch a call on behalf of the call permit signer.
The domain separator is defined in the and is calculated as:
When dispatch
is called, the permit needs to be verified before the call is dispatched. The first step is to . The calculation can be seen in or you can check out a practical example in .
From there, a is generated which guarantees that the signature can only be used for the call permit. It uses a given nonce to ensure the signature is not subject to a replay attack. It is similar to , except the PERMIT_TYPEHASH
is for a call permit, and the arguments match that of the plus the nonce.
The domain separator and the hash struct can be used to build the of the fully encoded message. A practical example is shown in .
With the final hash and the v, r, and s values, the signature can be . If successfully verified, the nonce will increase by one and the call will be dispatched.
For this example, you'll learn how to sign a call permit that updates a message in a simple example contract, . Before you can generate the call permit signature, you'll need to deploy the contract and define the dispatch
function arguments for the call permit.
To follow along with this tutorial, you will need to have your wallet configured to work with your EVM appchain and an account funded with native tokens. You can add your EVM appchain to MetaMask with one click on the . Or, you can .
You can use to compile the example contract and deploy it. You'll need a copy of and . To add the contracts to Remix, you can take the following steps:
In order to interact with the Call Permit Precompile, you have to have or generate a signature to dispatch the call permit. There are several ways you can generate the signature. This guide will show how to generate the signature using .
The signature will be returned and you can use to return the v
, r
, and s
values of the signature
As seen in the section, the dispatch
function takes the following parameters: from
, to
, value
, data
, gasLimit
, deadline
, v
, r
, and s
.
Next, you can install :
In the getSignature.js
file, you can copy and edit the following code snippet. In addition to the fields discussed above in the , you'll need to insert the Chain ID of your appchain in the Domain Separator component to properly generate the signature. If you use an incorrect Chain ID, the generated signature will be invalid and no transaction can be dispatched.