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

AllowanceProvider failing to return getAllowanceData values on Sepolia #76

Open
alexbabits opened this issue Aug 11, 2024 · 1 comment

Comments

@alexbabits
Copy link

I created an example Permit2App.sol that has a public function which calls permit2.permit and permit2.transferFrom. It has been deployed, the example token (LINK on Sepolia) has been approved for the Permit2, and there have been multiple successful test signature creations and transfers via Permit2 functionality. The current nonce is 7 in the Permit2 allowance mapping for the [owner, token, spender].

// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {IAllowanceTransfer} from "./IAllowanceTransfer.sol";

contract Permit2App {

    IAllowanceTransfer public immutable permit2;
    error InvalidSpender();

    constructor(address _permit2) {
        permit2 = IAllowanceTransfer(_permit2);
    }

    function permitAndTransferToMe(
        IAllowanceTransfer.PermitSingle calldata permitSingle, 
        bytes calldata signature, 
        uint160 amount
    ) public {
        _permitWithPermit2(permitSingle, signature);
        _transferToMe(permitSingle.details.token, amount);
    }

    function _permitWithPermit2(IAllowanceTransfer.PermitSingle calldata permitSingle, bytes calldata signature) internal {
        if (permitSingle.spender != address(this)) revert InvalidSpender(); // This contract must have spending permissions for the user.
        permit2.permit(msg.sender, permitSingle, signature); // owner is explicitly msg.sender 
    }

    function _transferToMe(address token, uint160 amount) internal {
        permit2.transferFrom(msg.sender, address(this), amount, token); // actually transfer the tokens
    }
}

Permit2's Sepolia Etherscan returns the correct non-zero read values for the allowance mapping result (amount, expiration, nonce) when my correct [owner, token, spender] values are input. As expected, manually calling directly on permit2.allowance also results in outputting the correct values. However, using the same input values for Permit2 SDK on Sepolia returns default zero values for getAllowanceData calls.

I suspect I'm doing something wrong with the SDK. My attempt appears identical to Uniswap's Permit2 integration guide. I am using ethers 5.7.2 because ethers v6 does not allow for AllowanceProvider instantiation. permit2-sdk is version 1.3.0. And using 0.8.23 solidity. IEIP712.sol and IAllowanceTransfer.sol are simply put in src along with Permitt2App.sol and Permit2App.js

const { ethers } = require("ethers");
const { AllowanceProvider, AllowanceTransfer, PERMIT2_ADDRESS, MaxAllowanceTransferAmount } = require('@uniswap/permit2-sdk');
require('dotenv/config');

// 1. Instantiate Provider & Signer
const provider = new ethers.providers.InfuraProvider("sepolia", process.env.SEPOLIA_KEY);
const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// 2. Instantiate our Permit2App Contract
const permit2AppABI = require("../out/Permit2App.sol/Permit2App.json").abi;
const permit2AppAddress = "0xMyExamplePermit2AppContract";
const permit2AppContract = new ethers.Contract(permit2AppAddress, permit2AppABI, signer); 

// 3. Instantiate example token to use. (You must have some of these tokens on the chain you choose).
const tokenAddress = "0x779877A7B0D9E8603169DdbD7836e478b4624789"; // LINK on Sepolia
const tokenApprovalABI = ['function approve(address spender, uint256 amount) returns (bool)']; // only need `approve()`
const tokenContract = new ethers.Contract(tokenAddress, tokenApprovalABI, signer);

// Example function that uses both methods to retrieve desired data
async function getData() {

    // 1. Using SDK (returns all 0's)
    const user = await signer.getAddress();
    const allowanceProvider = new AllowanceProvider(provider, PERMIT2_ADDRESS)
    const { amount: permitAmount, expiration, nonce } = await allowanceProvider.getAllowanceData(user, tokenAddress, permit2AppAddress);
    console.log("Allowance data:", { permitAmount, expiration, nonce }); // {0x00, 0, 0}

    // 2. Using Permit2 directly (returns correct data)
    const permit2ABI = [
        {
            "inputs": [
                {"internalType": "address", "name": "user", "type": "address"},
                {"internalType": "address", "name": "token", "type": "address"},
                {"internalType": "address", "name": "spender", "type": "address"}
            ],
            "name": "allowance",
            "outputs": [
                {"internalType": "uint160", "name": "amount", "type": "uint160"},
                {"internalType": "uint48", "name": "expiration", "type": "uint48"},
                {"internalType": "uint48", "name": "nonce", "type": "uint48"}
            ],
            "stateMutability": "view",
            "type": "function"
        }
    ];
    
    const permit2Contract = new ethers.Contract(PERMIT2_ADDRESS, permit2ABI, provider);
    const [ amount, _expiration, _nonce] = await permit2Contract.allowance(owner, tokenAddress, permit2AppAddress);
    const currentNonce = parseInt(_nonce, 10); // parse nonce's returned string value into base 10 integer.
    console.log("Allowance data:", { amount, _expiration, currentNonce });  // {0xffff..., 1725933703, 7}
}
getData();
node src/Permit2App.js

Allowance data: {
  permitAmount: BigNumber { _hex: '0x00', _isBigNumber: true },
  expiration: 0,
  nonce: 0
}
Allowance data: {
  amount: BigNumber {
    _hex: '0xffffffffffffffffffffffffffffffffffffffff',
    _isBigNumber: true
  },
  _expiration: 1725933703,
  currentNonce: 7
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants
@alexbabits and others