Hi Guys,
I have a set of the contract with a user proxy like structure wherein each user has a proxy contract like ds-proxy now I additionally have an external that I want to interact with via my proxy through delegate call function now the issue is I am able to approve the external contract to spend my tokens via the proxy but when I try to transfer the tokens from the user to the external contract which uses safe erc20 via the proxy my tx gets reverted which you might be able to see here
Now as I debug in tenderly I see the tx reverts here
(bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
the function is _functionCallWithValue which is in address.sol called by safe erc20
So I wanna Know:
am I doing something wrong here?
2.at what point is the _functionCallWithValue called from safe erc20?
Thanks
1 Like
Hi @viraj124 ,
Can you give a bit more detail on what contracts are involved?
Are you trying to do a double delegate call?
proxy -> (delegatecall) implementation -> (delegatecall) other contract
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
Which then calls:
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return _functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
@abcoathup no so it’s like this
user => proxy => approve(in token contract to approve the external contract) this passes
user => proxy => function in external contract this fails
1 Like
Hi @viraj124 ,
Ok, so if it isn’t a double delegate call, then I assume that the contract doing the transfer doesn’t have an allowance (or sufficient enough allowance). So I would manually check what the allowance the external contract has for the token.
set infinte allowance in fact @abcoathup also bdw changed the logic so changes safeTransferFrom to safeTransfer did this as a reference tx on ropsten can you take a look https://dashboard.tenderly.co/Viraz04/project/tx/ropsten/0x70ee9c6b655e71b2e79412ddfa030cab64e67139f9b7ecf0a02665a0d972c6b8/debugger what happens is while the balance of the user is changed the functionCall get’s called
1 Like
@abcoathup the latest tx https://ropsten.etherscan.io/tx/0xe6a0806f468673c9a8aa98eb7ab062e752c5cc75eb1420769e718672514667c7 you can search the hash on ropsten no I approved the external contract to spend my tokens worth > 100 tokens
and did a tx via the proxy I have transferFrom at the end but it reverts you can see the logs on tenderly if you want just search the hash
1 Like
Hi @viraj124 ,
Sorry, I haven’t had a chance to dig into this.
Were you able to resolve? Would you mind sharing what the issue was?
If you haven’t resolved, can you put together a simple example which reproduces the problem?