Permit Extension
A standardized smart contract interface for approvals via signatures (CIP-712), enabling energyless approvals for CBC-20 tokens and similar standards.
Abstract
This standard defines a method for approvals via off-chain signatures (CIP-712), allowing users to approve token allowances for CBC-20 tokens without sending an on-chain transaction. CBC-2612 enables energyless approvals, improving UX and composability for wallets, dApps, and DeFi protocols.
Motivation
Traditional CBC-20 approvals require users to send an on-chain transaction, incurring energy costs and requiring two transactions for many workflows (approve + transferFrom). CBC-2612 introduces a permit
function, allowing approvals to be made via signed messages, enabling energyless approvals and meta-transactions.
Specification
Compliant contracts MUST implement the following functions in addition to CBC-20:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICBC2612 /* is ICBC20 */ {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
The semantics are as follows:
For all addresses owner
, spender
, uint256s value
, deadline
and nonce
, uint8 v
, bytes32 r
and s
, a call to permit(owner, spender, value, deadline, v, r, s)
MUST set allowance[owner][spender]
to value
, increment nonces[owner]
by 1, and emit a corresponding Approval
event, IF and ONLY IF all the following conditions are met:
- The current blocktime is less than or equal to
deadline
. owner
is not the zero address.nonces[owner]
(before the state update) is equal tononce
.r
,s
andv
is a valid secp256k1 signature fromowner
of the message:
sha256(abi.encodePacked(
hex"1901",
DOMAIN_SEPARATOR,
sha256(abi.encode(
sha256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"),
owner,
spender,
value,
nonce,
deadline))
))
where DOMAIN_SEPARATOR
is defined according to CIP-712. The DOMAIN_SEPARATOR
should be unique to the contract and chain to prevent replay attacks from other domains, and satisfy the requirements of CIP-712, but is otherwise unconstrained. A common choice for DOMAIN_SEPARATOR
is:
DOMAIN_SEPARATOR = sha256(
abi.encode(
sha256('CIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
sha256(bytes(name)),
sha256(bytes(version)),
chainid,
address(this)
));
The message is the CIP-712 typed structure:
{
"types": {
"CIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"Permit": [
{ "name": "owner", "type": "address" },
{ "name": "spender", "type": "address" },
{ "name": "value", "type": "uint256" },
{ "name": "nonce", "type": "uint256" },
{ "name": "deadline", "type": "uint256" }
]
},
"primaryType": "Permit",
"domain": {
"name": cbc20name,
"version": version,
"chainId": chainid,
"verifyingContract": tokenAddress
},
"message": {
"owner": owner,
"spender": spender,
"value": value,
"nonce": nonce,
"deadline": deadline
}
}
The caller of the permit
function can be any address. If any of the above conditions are not met, the call MUST revert.
Method Behaviors
- The
permit
function MUST setspender
's allowance overowner
's tokens tovalue
if a valid signature is provided, and MUST increment the owner's nonce. - The
permit
function MUST revert if the signature is invalid or expired. - The
DOMAIN_SEPARATOR
MUST be implemented according to CIP-712. - The
nonces
function MUST return the current nonce for an address. - The
Approval
event MUST be emitted on a successful permit.
Backward Compatibility
There are existing permit
functions in some token contracts (e.g., DAI, Stake) with different semantics:
- DAI uses a
bool allowed
instead of avalue
argument, andexpiry
instead ofdeadline
. - Stake allows expiring approvals, only permitting
transferFrom
whileexpiry >= block.timestamp
.
CBC-2612 aligns with the Uniswap V2 implementation and the CBC-20 standard, using value
and deadline
as specified above. The requirement to revert if the permit is invalid is consistent with all major implementations.
Reference Implementation
A reference implementation can be provided upon request, following the CBC-2612 interface and best practices for signature verification and nonce management.
Rationale
CBC-2612 improves UX and composability by enabling energyless approvals, reducing friction for users and enabling new workflows for wallets and dApps.
Security Considerations
- Implementers must ensure signatures are unique and cannot be replayed (use nonces).
- The
permit
function must be resistant to signature malleability. - The
DOMAIN_SEPARATOR
must be unique per contract and chain. - Upgradability and access control best practices should be followed.
Copyright
Copyright and related rights waived via CC0.