Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: refactor permit types and add ERC20 permit support #91

Merged
merged 2 commits into from
Oct 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,20 @@ sol! {

function burn(uint256 tokenId) external payable;

function safeTransferFrom(address from, address to, uint256 tokenId) external;

function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

interface IERC721Permit {
#[derive(Debug, PartialEq, Eq)]
struct Permit {
address spender;
uint256 tokenId;
uint256 nonce;
uint256 deadline;
}

function permit(
address spender,
uint256 tokenId,
Expand All @@ -87,17 +101,35 @@ sol! {
bytes32 r,
bytes32 s
) external payable;

function safeTransferFrom(address from, address to, uint256 tokenId) external;

function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}

interface ISelfPermit {
function selfPermit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external payable;
function selfPermitAllowed(address token, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external payable;
}

interface IERC20Permit {
#[derive(Debug, PartialEq, Eq)]
struct Permit {
address owner;
address spender;
uint256 value;
uint256 nonce;
uint256 deadline;
}
}
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

interface IDaiPermit {
#[derive(Debug, PartialEq, Eq)]
struct Permit {
address holder;
address spender;
uint256 nonce;
uint256 expiry;
bool allowed;
}
}
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

interface IPeripheryPaymentsWithFee {
function unwrapWETH9(uint256 amountMinimum, address recipient) external payable;

Expand Down
20 changes: 5 additions & 15 deletions src/nonfungible_position_manager.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::prelude::{Error, *};
use alloy_primitives::{Bytes, Signature, U256};
use alloy_sol_types::{eip712_domain, sol, Eip712Domain, SolCall};
use alloy_sol_types::{eip712_domain, Eip712Domain, SolCall};
use uniswap_sdk_core::prelude::*;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -66,20 +66,10 @@ pub struct CollectOptions<Currency0: BaseCurrency, Currency1: BaseCurrency> {
pub recipient: Address,
}

sol! {
#[derive(Debug, PartialEq, Eq)]
struct Permit {
address spender;
uint256 tokenId;
uint256 nonce;
uint256 deadline;
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NFTPermitData {
pub domain: Eip712Domain,
pub values: Permit,
pub values: IERC721Permit::Permit,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
Expand Down Expand Up @@ -341,7 +331,7 @@ where

if let Some(permit) = options.permit {
calldatas.push(
INonfungiblePositionManager::permitCall {
IERC721Permit::permitCall {
spender: permit.spender,
tokenId: token_id,
deadline: permit.deadline,
Expand Down Expand Up @@ -451,7 +441,7 @@ pub fn safe_transfer_from_parameters(options: SafeTransferOptions) -> MethodPara
/// use alloy_sol_types::SolStruct;
/// use uniswap_v3_sdk::prelude::*;
///
/// let permit = Permit {
/// let permit = IERC721Permit::Permit {
/// spender: address!("0000000000000000000000000000000000000002"),
/// tokenId: uint!(1_U256),
/// nonce: uint!(1_U256),
Expand All @@ -477,7 +467,7 @@ pub fn safe_transfer_from_parameters(options: SafeTransferOptions) -> MethodPara
#[inline]
#[must_use]
pub const fn get_permit_data(
permit: Permit,
permit: IERC721Permit::Permit,
position_manager: Address,
chain_id: u64,
) -> NFTPermitData {
Expand Down
93 changes: 92 additions & 1 deletion src/self_permit.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,99 @@
use super::abi::ISelfPermit;
use alloy_primitives::{Bytes, Signature, U256};
use alloy_sol_types::SolCall;
use alloy_sol_types::{eip712_domain, Eip712Domain, SolCall};
use uniswap_sdk_core::prelude::*;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ERC20PermitData<P> {
pub domain: Eip712Domain,
pub values: P,
}
shuhuiluo marked this conversation as resolved.
Show resolved Hide resolved

/// Get the EIP-2612 domain and values to sign for an ERC20 permit.
///
/// ## Arguments
///
/// * `permit`: The ERC20 permit
/// * `name`: The name of the contract
/// * `version`: The version of the contract
/// * `token`: The address of the token
/// * `chain_id`: The chain ID
///
/// ## Returns
///
/// The EIP-2612 domain and values to sign
///
/// ## Examples
///
/// ```
/// use alloy_primitives::{address, b256, uint, Signature, B256};
/// use alloy_signer::SignerSync;
/// use alloy_signer_local::PrivateKeySigner;
/// use alloy_sol_types::SolStruct;
/// use uniswap_v3_sdk::prelude::*;
///
/// let signer = PrivateKeySigner::random();
/// let permit = IERC20Permit::Permit {
/// owner: signer.address(),
/// spender: address!("0000000000000000000000000000000000000002"),
/// value: uint!(1_U256),
/// nonce: uint!(1_U256),
/// deadline: uint!(123_U256),
/// };
/// assert_eq!(
/// permit.eip712_type_hash(),
/// b256!("6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9")
/// );
/// assert_eq!(
/// IDaiPermit::Permit {
/// holder: signer.address(),
/// spender: address!("0000000000000000000000000000000000000002"),
/// nonce: uint!(1_U256),
/// expiry: uint!(123_U256),
/// allowed: true,
/// }
/// .eip712_type_hash(),
/// b256!("ea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb")
/// );
///
/// let data = get_erc20_permit_data(
/// permit,
/// "ONE",
/// "1",
/// address!("0000000000000000000000000000000000000001"),
/// 1,
/// );
///
/// // Derive the EIP-712 signing hash.
/// let hash: B256 = data.values.eip712_signing_hash(&data.domain);
///
/// let signature: Signature = signer.sign_hash_sync(&hash).unwrap();
/// assert_eq!(
/// signature.recover_address_from_prehash(&hash).unwrap(),
/// signer.address()
/// );
/// ```
#[inline]
#[must_use]
pub fn get_erc20_permit_data<P>(
permit: P,
name: &'static str,
version: &'static str,
token: Address,
chain_id: u64,
) -> ERC20PermitData<P> {
let domain = eip712_domain! {
name: name,
version: version,
chain_id: chain_id,
verifying_contract: token,
};
ERC20PermitData {
domain,
values: permit,
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct StandardPermitArguments {
pub signature: Signature,
Expand Down