'I am prepared permit EIP712, but tx "Reverted", function selector 'Reverted 0x08c379a

I'm trying to send a permit for a transaction, but I get a function call mismatch return if I call through the smartcontract token function. If I call via encodeABI and add the same arguments, I don't see the message in the transaction. I use the following code

def build_permit(owner, spender, value, deadline, web3):
    data = {
        "types": {
            "EIP712Domain": [
                {"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"},
            ],
        },
        "domain": {
            "name": "TestToken", 
            "version": "1",
            "chainId": 4,
            "verifyingContract": address_token,
        },
        "primaryType": "Permit",
        "message": {
            "owner": owner,
            "spender": spender,
            "value": value,
            "nonce": web3.eth.getTransactionCount(my_account.address),
            "deadline": deadline,
        },
    }

    return encode_structured_data(data)

def test_permit():
    signer = my_account
    owner = my_account.address
    holder = signer.address
    address_token = SC.USDT("RINKEBY")
    spender = SC.ROUTER('RINKEBY')
    deadline = int(time.time()) + 3600
    #print(deadline)
    amount = web3.toWei(1, 'ether')
    usdt = token_contract(address_token,web3n(RINKEBY))
    permit = build_permit(owner, spender, amount, deadline,web3n(RINKEBY))
    signed = signer.sign_message(permit)
    tx = usdt.functions.permit(holder, spender, 1000000000000000000, int(time.time()) + 3600,  signed.v, Web3.toBytes(signed.r), Web3.toBytes(signed.s)).call()

Why does the beginning of the data start with a different function and how do I get the correct signature?

    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/contract.py:957: in call
    return call_contract_function(
    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/contract.py:1501: in call_contract_function
        return_data = web3.eth.call(
    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/module.py:57: in caller
        result = w3.manager.request_blocking(method_str,
    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/manager.py:198: in request_blocking
        return self.formatted_response(response,
    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/manager.py:170: in formatted_response
        apply_error_formatters(error_formatters, response)
    ../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/manager.py:70: in apply_error_formatters
    formatted_resp = pipe(response, error_formatters)
cytoolz/functoolz.pyx:667: in cytoolz.functoolz.pipe
    ???
cytoolz/functoolz.pyx:642: in cytoolz.functoolz.c_pipe
    ???
response = {'error': {'code': 3, 'data': '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000...207369676e61747572650000', 'message': 'execution reverted: ERC20Permit: invalid signature'}, 'id': 1, 'jsonrpc': '2.0'}

    def raise_solidity_error_on_revert(response: RPCResponse) -> RPCResponse:
        """
        Reverts contain a `data` attribute with the following layout:
            "Reverted "
            Function selector for Error(string): 08c379a (4 bytes)
            Data offset: 32 (32 bytes)
            String length (32 bytes)
            Reason string (padded, use string length from above to get meaningful part)
    
        See also https://solidity.readthedocs.io/en/v0.6.3/control-structures.html#revert
        """
        if not isinstance(response['error'], dict):
            raise ValueError('Error expected to be a dict')
    
        data = response['error'].get('data', '')
    
        # Ganache case:
        if isinstance(data, dict) and response['error'].get('message'):
            raise ContractLogicError(f'execution reverted: {response["error"]["message"]}')
    
        # Parity/OpenEthereum case:
        if data.startswith('Reverted '):
            # "Reverted", function selector and offset are always the same for revert errors
            prefix = 'Reverted 0x08c379a00000000000000000000000000000000000000000000000000000000000000020'  # noqa: 501
            if not data.startswith(prefix):
                raise ContractLogicError('execution reverted')
    
            reason_length = int(data[len(prefix):len(prefix) + 64], 16)
            reason = data[len(prefix) + 64:len(prefix) + 64 + reason_length * 2]
            raise ContractLogicError(f'execution reverted: {bytes.fromhex(reason).decode("utf8")}')
    
        # Geth case:
        if 'message' in response['error'] and response['error'].get('code', '') == 3:
>           raise ContractLogicError(response['error']['message'])
E           web3.exceptions.ContractLogicError: execution reverted: ERC20Permit: invalid signature

../PycharmProjects/1/venv/lib/python3.9/site-packages/web3/_utils/method_formatters.py:576: ContractLogicError


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source