2

I am building an application that you can purchase USDC by paying ETH.

I am getting the USDC amount from msg.value(ETH) by directly calling a chainlink pricefeed in my function.

function ethToUsdc() payable external {
    uint256 usdcAmount = msg.value.div(uint256(priceFeedUsdcEth.latestAnswer())).mul(10 ** 6);
    IERC20(0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b).transferFrom(0x.. , msg.sender, usdcAmount);
}

The transaction was successful if the pricefeed does not change after sending transaction.

However, the transaction will fails if a chainlink pricefeed changes after sending the transaction.

In a transaction that calls another contract, if the caller's state changes, will the transaction fail unconditionally?

Also, is there any way to make the transaction succeed even if the pricefeed changes before transaction is confirmed?

9
  • 1
    I'm not sure I fully understand the question. The transaction mostly fails if you tell it to fail if certain conditions are not met Commented Jun 28, 2021 at 6:30
  • 1
    It's likely something else is going on here. The blockchain is synchronous so the price feed can't change while your contract is executing. How are you calculating usdcAmount? Commented Jun 28, 2021 at 11:52
  • 1
    @gnxvw If you calculate data off-chain (outside your contract code), then a delay in transaction confirmation might (and likely will) cause problems. However, if the data is calculated on-chain (inside solidity code), then the state is guaranteed to remain the same through the lifetime of your transaction (since each transaction is atomic within a synchronous system), and so unless you yourself modify the state within your contract code, there will never be a problem. So in your case, there should never be any price discrepancy. Commented Jun 29, 2021 at 21:38
  • 1
    Note that the oracle itself may not be consistent with whatever contract you are using to perform a trade, in which case it may not succeed. You should get the price data from the same contract you are using to trade. Commented Jun 29, 2021 at 21:39
  • 1
    The chainlink price will either be higher or lower than the real price. It will always fail in one of those cases, and will always succeed in the other. If you're code is buying USDC with ETH, then I think it will always fail if the real price is less than chainlink's price (however, I might have gotten it backwards). In half of the scenarios, the transaction will fail, and therefore I don't think you should use Chainlink's price feed for determining what price you can trade at. You should only use Chainlink for an off-chain estimation. Commented Jun 30, 2021 at 11:18

2 Answers 2

1

If you obtain data off-chain (outside your contract code), then a delay in transaction confirmation might (and likely will) cause the data to become outdated.

However, if the data is obtained on-chain (inside solidity code), then the state is guaranteed to remain the same through the lifetime of your transaction. This is because transactions are atomic and executed within a synchronous system. Unless you yourself modify the blockchain's state within your contract code, the data will be the same at the start and end of your transaction.

The on-chain code to obtain the data is only executed when the transaction is mined (confirmed), so it doesn't matter how long it takes for your transaction to be confirmed, you will always receive up-to-date data.

So in your case, your price data will match exactly that of Chainlink's at that time.

However the price data from the Chainlink oracle may not (and likely will not) match up with whatever contract you are using to perform the trade, in which case it may not succeed. You should get the price data from the same contract you are using to trade.

The oracle price will either be higher or lower than the real price. It will always fail in one of those cases, and will always succeed in the other. If your code is buying USDC with ETH, then I think it will always fail if the real price is less than the oracle's price (however, I might have gotten it backwards).

In half of the scenarios, the transaction will always fail, and therefore I don't think it is appropriate to use Chainlink's price feed for determining what price you can trade at. It is only useful as an off-chain estimation before you decide if you want to perform a trade or not.

Many dapps understand this and that is why they only show a price estimation. They will generally have an option to choose a slippage tolerance (for example 5%). This is how much the on-chain price is allowed to deviate from whatever estimation was given to the user beforehand. If the discrepancy is higher than this tolerance, the contract will choose to abort the trade. (Unfortunately, the user will still have paid gas fees).

Anyway, in your case you haven't given details about the system you are using to perform a trade. Therefore, I won't be able to tell you how or if it is possible to calculate exactly how much USDC to request in a trade. That depends on whatever system you are using. Generally, however, you should be able to specify the ETH amount instead and the system should give you the most USDC it can at the current price.

2

There's not anything in the function you posted that should cause it to fail if things change. When the transaction is included in a block, it will call priceFeedUsdcEth.latestAnswer() at that moment, and use the resulting value.

Perhaps it's failing because there isn't enough USDC available or approved at to be able to transfer with a slightly higher price reported by the oracle?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.