Usage
Wrapped Native is backwards compatible with WETH9 - it includes all interfaces available in the original WETH. However, it includes additional features for better quality of life and better protocol integrations. This page covers typical usage scenarios.
Deployment
Wrapped Native can be deployed to any EVM blockchain at address 0x6000030000842044000077551D00cfc6b4005900 using Limit Break's infrastructure deployment tool at https://developers.apptokens.com/infrastructure.
Depositing/Wrapping Native Tokens
Native value transfer to contract
A native token transfer to the contract without calldata will trigger a deposit via the receive() function. A native token transfer to the contract with calldata will trigger a deposit via the fallback() function. The msg.sender account will be credited with WNATIVE.
deposit Function
Calling the deposit function and including native value will credit the msg.sender account with WNATIVE.
/**
* @notice Deposits `msg.value` funds into the `msg.sender` account, increasing their wrapped native token balance.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has increased by `msg.value`.
* @dev 2. The `msg.sender`'s native token balance has decreased by `msg.value`.
* @dev 3. The `msg.sender`'s wrapped native token balance has increased by `msg.value`.
* @dev 4. A `Deposit` event has been emitted. The `msg.sender` address is logged in the event.
*/
function deposit() public payable;
depositTo Function
Calling the depositTo function and including native value will credit the specified to account with WNATIVE, while depositing the msg.sender account's native funds. For protocols that issue native refunds by wrapping them and transferring the ERC-20 to the refundee, depositTo offers the most direct, gas-efficient mechanism. Some protocols may issue refunds this way to limit re-entrancy risk.
/**
* @notice Deposits `msg.value` funds into specified user's account, increasing their wrapped native token balance.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has increased by `msg.value`.
* @dev 2. The `msg.sender`'s native token balance has decreased by `msg.value`.
* @dev 3. The `to` account's wrapped native token balance has increased by `msg.value`.
* @dev 4. A `Deposit` event has been emitted. Caveat: The `to` address is logged in the event, not `msg.sender`.
*
* @param to The address that receives wrapped native tokens.
*/
function depositTo(address to) public payable;
Withdrawing/Unwrapping Native Tokens
withdraw Function
Calling the withdraw function will debit the msg.sender account's WNATIVE balance and credit them with the equivalent amount of native token.
/**
* @notice Withdraws `amount` funds from the `msg.sender` account, decreasing their wrapped native token balance.
*
* @dev Throws when the `msg.sender`'s wrapped native token balance is less than `amount` to withdraw.
* @dev Throws when the unwrapped native funds cannot be transferred to the `msg.sender` account.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has decreased by `amount`.
* @dev 2. The `msg.sender`'s wrapped native token balance has decreased by `amount`.
* @dev 3. The `msg.sender`'s native token balance has increased by `amount`.
* @dev 4. A `Withdrawal` event has been emitted. The `msg.sender` address is logged in the event.
*
* @param amount The amount of wrapped native tokens to withdraw.
*/
function withdraw(uint256 amount) public;
withdrawToAccount Function
Calling the withdrawToAccount function will debit the msg.sender account's WNATIVE balance, but credit the to account with the equivalent amount of native token.
/**
* @notice Withdraws `amount` funds from the `msg.sender` account, decreasing their wrapped native token balance.
*
* @dev Throws when the `msg.sender`'s wrapped native token balance is less than `amount` to withdraw.
* @dev Throws when the unwrapped native funds cannot be transferred to the `to` account.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has decreased by `amount`.
* @dev 2. The `msg.sender`'s wrapped native token balance has decreased by `amount`.
* @dev 3. The `to` account's native token balance has increased by `amount`.
* @dev 4. A `Withdrawal` event has been emitted. Caveat: The `msg.sender` address is logged in the event, not `to`.
*
* @param to The address that receives the unwrapped native tokens.
* @param amount The amount of wrapped native tokens to withdraw.
*/
function withdrawToAccount(address to, uint256 amount) public;
withdrawSplit Function
Calling the withdrawSplit function will debit the msg.sender account's WNATIVE balance, but credit the specified amounts the multiple to accounts.
/**
* @notice Withdraws funds from the `msg.sender` and splits the funds between multiple receiver addresses.
*
* @dev Throws when the `msg.sender`'s wrapped native token balance is less than the sum of `amounts` to withdraw.
* @dev Throws when the unwrapped native funds cannot be transferred to one or more of the receiver addresses.
* @dev Throws when the `toAddresses` and `amounts` arrays are not the same length.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has decreased by the sum of `amounts`.
* @dev 2. The `msg.sender`'s wrapped native token balance has decreased by the sum of `amounts`.
* @dev 3. The receiver addresses' native token balances have increased by the corresponding amounts in `amounts`.
* @dev 4. A `Withdrawal` event has been emitted for each receiver address. Caveat: The `msg.sender` address is
* logged in the events, not the receiver address.
*
* @param toAddresses The addresses that receive the unwrapped native tokens.
* @param amounts The amounts of wrapped native tokens to withdraw for each receiver address.
*/
function withdrawSplit(address[] calldata toAddresses, uint256[] calldata amounts) external;
Approvals and Transfers
approve Function
ERC-20 WNATIVE approval for spenders, but with optional deposit feature. This is a powerful UX improvement, as protocols such as Seaport and Payment Processor no longer need separate deposit and approval calls when making offers.
/**
* @notice Approves `spender` to spend/transfer `amount` of the `msg.sender`'s wrapped native tokens.
* When `amount` is set to `type(uint256).max`, the approval is unlimited.
*
* @notice Unlike a typical ERC-20 token, this function is payable, allowing for a `deposit` and approval to be
* executed simultaneously. If `msg.value` is greater than zero, the function will deposit the funds
* into the `msg.sender` account before approving the `spender` to spend/transfer the funds.
* If `msg.value` is zero, the function will only approve the `spender` to spend/transfer the funds.
* This feature is intended to improve the UX of users using wrapped native tokens so that users don't have
* to perform two transactions to first deposit, then approve the spending of their tokens, saving gas in
* the process.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. The `spender` is approved to spend/transfer `amount` of the `msg.sender`'s wrapped native tokens.
* @dev 2. A `Approval` event has been emitted. The `msg.sender` address, `spender` address, and `amount` of the
* updated approval are logged in the event.
* @dev 3. If `msg.value` is greater than zero, the `msg.sender`'s wrapped native token balance has increased by
* `msg.value`.
* @dev 4. If `msg.value` is greater than zero, a `Deposit` event has been emitted. The `msg.sender` address is
* logged in the event.
*
* @param spender The address that is approved to spend/transfer the `msg.sender`'s wrapped native tokens.
* @param amount The amount of wrapped native tokens that the `spender` is approved to spend/transfer. Approved
* spending is unlimited when this values is set to `type(uint256).max`.
*
* @return Always returns `true`.
*/
function approve(address spender, uint256 amount) public payable returns (bool);
transfer Function
ERC-20 WNATIVE transfer, but with optional deposit feature.
/**
* @notice Transfers an `amount` of wrapped native tokens from the `msg.sender` to the `to` address.
*
* @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `msg.sender` account
* before transferring the wrapped funds. Otherwise, the function will only transfer the funds.
*
* @dev Throws when the `msg.sender` has an insufficient balance to transfer `amount` of wrapped native tokens.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
* @dev 2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
* @dev 3. When `msg.value` is greater than zero, the `msg.sender`'s wrapped native token balance has increased by `msg.value`.
* @dev 4. When `msg.value` is greater than zero, a `Deposit` event has been emitted. The `msg.sender` address is logged in the event.
* @dev 5. The `amount` of wrapped native tokens has been transferred from the `msg.sender` account to the `to` account.
* @dev 6. A `Transfer` event has been emitted. The `msg.sender` address, `to` address, and `amount` are logged in the event.
*
* @param to The address that receives the wrapped native tokens.
* @param amount The amount of wrapped native tokens to transfer.
*
* @return Always returns `true`.
*/
function transfer(address to, uint256 amount) public payable returns (bool);
transferFrom Function
ERC-20 WNATIVE transferFrom, but with optional deposit feature.
/**
* @notice Transfers an `amount` of wrapped native tokens from the `from` to the `to` address.
*
* @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `from` account
* before transferring the wrapped funds. Otherwise, the function will only transfer the funds.
* @notice **As a reminder, the `msg.sender`'s native tokens will be deposited and the `from` (not the `msg.sender`)
* address will be credited before the transfer. Integrating spender/operator protocols MUST be aware that
* deposits made during transfers will not credit their own account.**
*
* @dev Throws when the `from` account has an insufficient balance to transfer `amount` of wrapped native tokens.
* @dev Throws when the `msg.sender` is not the `from` address, and the `msg.sender` has not been approved
* by `from` for an allowance greater than or equal to `amount`.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
* @dev 2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
* @dev 3. When `msg.value` is greater than zero, the `from` account's wrapped native token balance has increased by `msg.value`.
* @dev 4. When `msg.value` is greater than zero, a `Deposit` event has been emitted. The `from` address is logged in the event.
* @dev 5. The `amount` of wrapped native tokens has been transferred from the `from` account to the `to` account.
* @dev 6. A `Transfer` event has been emitted. The `from` address, `to` address, and `amount` are logged in the event.
*
* @param from The address that transfers the wrapped native tokens.
* @param to The address that receives the wrapped native tokens.
* @param amount The amount of wrapped native tokens to transfer.
*
* @return Always returns `true`.
*/
function transferFrom(address from, address to, uint256 amount) public payable returns (bool);
Permits
Note: Permit signatures may be signed by EOAs or smart contracts supporting EIP-1271.
permitTransfer Function
Allows a spender / protocol to transfer a user's WNATIVE tokens without a prior on-chain approval. Transfer permits are single-use, and can be used to pre-approve a spender to transfer a specific amount of WNATIVE token with a gasless signature.
/**
* @notice Allows a spender/operator to transfer wrapped native tokens from the `from` account to the `to` account
* using a gasless signature from the `from` account so that the `from` account does not need to pay gas
* to set an on-chain allowance.
*
* @notice If the `msg.value` is greater than zero, the function will deposit the funds into the `from` account
* before transferring the wrapped funds. Otherwise, the function will only transfer the funds.
* @notice **As a reminder, the `msg.sender`'s native tokens will be deposited and the `from` (not the `msg.sender`)
* address will be credited before the transfer. Integrating spender/operator protocols MUST be aware that
* deposits made during transfers will not credit their own account.**
*
* @dev Throws when the `from` account is the zero address.
* @dev Throws when the `msg.sender` does not match the operator/spender from the signed transfer permit.
* @dev Throws when the permitAmount does not match the signed transfer permit.
* @dev Throws when the nonce does not match the signed transfer permit.
* @dev Throws when the expiration does not match the signed transfer permit.
* @dev Throws when the permit has expired.
* @dev Throws when the requested transfer amount exceeds the maximum permitted transfer amount.
* @dev Throws when the permit nonce has already been used or revoked/cancelled.
* @dev Throws when the master nonce has been revoked/cancelled since the permit was signed.
* @dev Throws when the permit signature is invalid, or was not signed by the `from` account.
* @dev Throws when the `from` account has an insufficient balance to transfer `transferAmount` of wrapped native tokens.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. When `msg.value` is greater than zero, this contract's native token balance has increased by `msg.value`.
* @dev 2. When `msg.value` is greater than zero, the `msg.sender`'s native token balance has decreased by `msg.value`.
* @dev 3. When `msg.value` is greater than zero, the `from` account's wrapped native token balance has increased by `msg.value`.
* @dev 4. When `msg.value` is greater than zero, a `Deposit` event has been emitted. The `from` address is logged in the event.
* @dev 5. `nonce` for `from` account is invalidated.
* @dev 6. A `PermitNonceInvalidated` event has been emitted.
* @dev 7. The `transferAmount` of wrapped native tokens has been transferred from the `from` account to the `to` account.
* @dev 8. A `Transfer` event has been emitted. The `from` address, `to` address, and `transferAmount` are logged in the event.
*
* @param from The address that transfers the wrapped native tokens.
* @param to The address that receives the wrapped native tokens.
* @param transferAmount The amount of wrapped native tokens to transfer.
* @param permitAmount The maximum amount of wrapped native tokens that can be transferred, signed in permit.
* @param nonce The nonce, signed in permit.
* @param expiration The expiration timestamp, signed in permit.
* @param signedPermit The signature of the permit.
*/
function permitTransfer(
address from,
address to,
uint256 transferAmount,
uint256 permitAmount,
uint256 nonce,
uint256 expiration,
bytes calldata signedPermit
) external payable
The permit is a signed EIP-712 message that matches the following format/typehash and domain separator. Domain separator values are:
- name: "Wrapped Native"
- version: "1"
- chainId: Specify the chainId of the chain where the permit is valid.
- verifyingContract:
0x6000030000842044000077551D00cfc6b4005900
bytes32 private constant DOMAIN_SEPARATOR =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 constant PERMIT_TRANSFER_TYPEHASH =
keccak256("PermitTransfer(address operator,uint256 amount,uint256 nonce,uint256 expiration,uint256 masterNonce)");
doPermittedWithdraw Function
Allows a user to withdraw or unwrap WNATIVE tokens on a user's behalf. This is useful when a user has WNATIVE tokens, but has insufficient native funds to withdraw or unwrap themselves. In this case, the permitted operator could be an app that charges a small convenience fee for the withdrawal service. Note that convenience fees are taxed by the protocol at a rate of 10%. So if the convience fee is 0.25%, the protocol fee will be 0.025% and the convenience fee receiver gets to keep 0.225% of the withdrawn amount. Convenience fees for the app are acknowledged in the user's signed permit.
/**
* @notice Allows a spender/operator to withdraw wrapped native tokens from the `from` account to the `to` account
* using a gasless signature signed by the `from` account to prove authorization of the withdrawal.
*
* @dev Throws when the `from` account is the zero address.
* @dev Throws when the `msg.sender` does not match the operator/spender from the signed withdrawal permit.
* @dev Throws when the permit has expired.
* @dev Throws when the amount does not match the signed withdrawal permit.
* @dev Throws when the nonce does not match the signed withdrawal permit.
* @dev Throws when the expiration does not match the signed withdrawal permit.
* @dev Throws when the convenience fee reciever and fee does not match the signed withdrawal permit.
* @dev Throws when the `to` address does not match the signed withdrawal permit.
* @dev Throws when the permit nonce has already been used or revoked/cancelled.
* @dev Throws when the master nonce has been revoked/cancelled since the permit was signed.
* @dev Throws when the permit signature is invalid, or was not signed by the `from` account.
* @dev Throws when the `from` account has an insufficient balance to transfer `transferAmount` of wrapped native tokens.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. This contract's native token balance has decreased by `amount`, less convenience and infrastructure
* fees that remain wrapped.
* @dev 2. The `from` account's wrapped native token balance has decreased by `amount`.
* @dev 3. The `to` account's native token balance has increased by `amount`, less convenience and/or infrastructure fees.
* @dev 4. The `convenienceFeeReceiver` account's wrapped native token balance has increased by the convenience fee.
* @dev 5. The infrastructure tax account's wrapped native token balance has increased by the infrastructure fee.
* @dev 6. `nonce` for `from` account is invalidated.
* @dev 7. A `PermitNonceInvalidated` event has been emitted.
* @dev 8. A `Withdrawal` event has been emitted. Caveat: The `from` address is logged in the event, not `to` or `msg.sender`.
*
* @param from The address that from which funds are withdrawn.
* @param to The address that receives the withdrawn funds.
* @param amount The amount of wrapped native tokens to withdraw.
* @param nonce The nonce, signed in permit.
* @param expiration The expiration timestamp, signed in permit.
* @param convenienceFeeReceiver The address that receives the convenience fee.
* @param convenienceFeeBps The basis points of the convenience fee.
* @param signedPermit The signature of the permit.
*/
function doPermittedWithdraw(
address from,
address to,
uint256 amount,
uint256 nonce,
uint256 expiration,
address convenienceFeeReceiver,
uint256 convenienceFeeBps,
bytes calldata signedPermit
) external;
The withdrawal permit is a signed EIP-712 message that matches the following format/typehash and domain separator. Domain separator values are:
- name: "Wrapped Native"
- version: "1"
- chainId: Specify the chainId of the chain where the permit is valid.
- verifyingContract:
0x6000030000842044000077551D00cfc6b4005900
bytes32 private constant DOMAIN_SEPARATOR =
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
bytes32 constant PERMIT_WITHDRAWAL_TYPEHASH =
keccak256("PermitWithdrawal(address operator,uint256 amount,uint256 nonce,uint256 expiration,uint256 masterNonce,address to,address convenienceFeeReceiver,uint256 convenienceFeeBps)");
Cancelling Permits
revokeMyOutstandingPermits Function
To cancel ALL outstanding permits (both transfer and withdrawal), use the revokeMyOutstandingPermits function, which will increment the user's master nonce. The user must call this function themselves.
/**
* @notice Allows the `msg.sender` to revoke/cancel all prior permitted transfer and withdrawal signatures.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. The `msg.sender`'s master nonce has been incremented by `1` in contract storage, rendering all signed
* permits using the prior master nonce unusable.
* @dev 2. A `MasterNonceInvalidated` event has been emitted.
*/
function revokeMyOutstandingPermits() external;
revokeMyNonce Function
To cancel a single transfer or withdrawal permit, use the revokeMyNonce function, which will permanently invalidate the supplied permit nonce.
/**
* @notice Allows the `msg.sender` to revoke/cancel a single, previously signed permitted transfer or withdrawal
* signature by specifying the nonce of the individual permit.
*
* @dev Throws when the `msg.sender` has already revoked the permit nonce.
* @dev Throws when the permit nonce was already used successfully.
*
* @dev <h4>Postconditions:</h4>
* @dev 1. The specified `nonce` for the `msg.sender` has been revoked and can
* no longer be used to execute a permitted transfer or withdrawal.
* @dev 2. A `PermitNonceInvalidated` event has been emitted.
*
* @param nonce The nonce that was signed in the permitted transfer or withdrawal.
*/
function revokeMyNonce(uint256 nonce) external;
