Application Budget Bugfixes (#60)

* Application Budget Fixes and Tests

* Adding application budget to redelivery test

* Application Budget Test with Redelivery Works

* remove console log import

* Remove console logs from tests

* Remove console logs from mockrelayerintegration

* Use uint32.max and fix outOfFund error in tests

* Removed unnecessary require
This commit is contained in:
derpy-duck 2023-01-26 14:27:57 -05:00 committed by GitHub
parent 7cd5b5871b
commit 5a3ff82c43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 516 additions and 328 deletions

View File

@ -8,8 +8,6 @@ import "../libraries/external/BytesLib.sol";
import "./CoreRelayerGovernance.sol";
import "./CoreRelayerStructs.sol";
import "forge-std/console.sol";
contract CoreRelayer is CoreRelayerGovernance {
using BytesLib for bytes;
@ -317,8 +315,8 @@ contract CoreRelayer is CoreRelayerGovernance {
(
uint256 requestFee,
uint256 applicationBudgetTarget,
uint256 maximumRefund,
uint256 applicationBudgetTarget,
bool isSufficient,
string memory reason
) = verifyFunding(
@ -359,8 +357,8 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (
uint256 requestFee,
uint256 applicationBudgetTarget,
uint256 maximumRefund,
uint256 applicationBudgetTarget,
bool isSufficient,
string memory reason
)
@ -372,7 +370,7 @@ contract CoreRelayer is CoreRelayerGovernance {
? args.provider.quoteDeliveryOverhead(args.targetChain)
: args.provider.quoteRedeliveryOverhead(args.targetChain);
uint256 overheadBudgetTarget =
quoteAssetConversion(args.sourceChain, overheadFeeSource, args.targetChain, args.provider);
assetConversionHelper(args.sourceChain, overheadFeeSource, args.targetChain, 1, 1, true, args.provider);
maximumRefund = args.isDelivery
? calculateTargetDeliveryMaximumRefund(args.targetChain, args.computeBudgetSource, args.provider)
: calculateTargetRedeliveryMaximumRefund(args.targetChain, args.computeBudgetSource, args.provider);
@ -411,7 +409,6 @@ contract CoreRelayer is CoreRelayerGovernance {
revert ReentrantCall();
}
setContractLock(true);
// store gas budget pre target invocation to calculate unused gas budget
uint256 preGas = gasleft();
@ -637,7 +634,6 @@ contract CoreRelayer is CoreRelayerGovernance {
) {
revert InsufficientRelayerFunds();
}
//Overwrite compute budget and application budget on the original request and proceed.
originalInstruction.maximumRefundTarget = redeliveryInstruction.newMaximumRefundTarget;
originalInstruction.applicationBudgetTarget = redeliveryInstruction.newApplicationBudgetTarget;
@ -740,16 +736,9 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint32 gasAmount)
{
IWormhole wormhole = wormhole();
if (computeBudget <= provider.quoteDeliveryOverhead(targetChain)) {
return 0;
} else {
uint256 remainder = computeBudget - provider.quoteDeliveryOverhead(targetChain);
uint256 gas = remainder / provider.quoteGasPrice(targetChain);
if (gas >= 2 ** 32) return uint32(2 ** 32 - 1);
return uint32(gas);
}
gasAmount = calculateTargetGasDeliveryAmountHelper(
targetChain, computeBudget, provider.quoteDeliveryOverhead(targetChain), provider
);
}
function calculateTargetDeliveryMaximumRefund(uint16 targetChain, uint256 computeBudget, IRelayProvider provider)
@ -757,13 +746,9 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 maximumRefund)
{
uint256 deliveryOverhead = provider.quoteDeliveryOverhead(targetChain);
if (computeBudget >= deliveryOverhead) {
uint256 remainder = computeBudget - deliveryOverhead;
maximumRefund = quoteAssetConversion(chainId(), remainder, targetChain, provider);
} else {
maximumRefund = 0;
}
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
targetChain, computeBudget, provider.quoteDeliveryOverhead(targetChain), provider
);
}
/**
@ -775,16 +760,9 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint32 gasAmount)
{
IWormhole wormhole = wormhole();
if (computeBudget <= wormhole.messageFee() + provider.quoteRedeliveryOverhead(targetChain)) {
return 0;
} else {
uint256 remainder = computeBudget - wormhole.messageFee() - provider.quoteRedeliveryOverhead(targetChain);
uint256 gas = remainder / provider.quoteGasPrice(targetChain);
if (gas >= 2 ** 32) return uint32(2 ** 32 - 1);
return uint32(gas);
}
gasAmount = calculateTargetGasDeliveryAmountHelper(
targetChain, computeBudget, provider.quoteRedeliveryOverhead(targetChain), provider
);
}
function calculateTargetRedeliveryMaximumRefund(uint16 targetChain, uint256 computeBudget, IRelayProvider provider)
@ -792,8 +770,41 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 maximumRefund)
{
uint256 remainder = computeBudget - provider.quoteRedeliveryOverhead(targetChain);
maximumRefund = quoteAssetConversion(chainId(), remainder, targetChain, provider);
maximumRefund = calculateTargetDeliveryMaximumRefundHelper(
targetChain, computeBudget, provider.quoteRedeliveryOverhead(targetChain), provider
);
}
function calculateTargetGasDeliveryAmountHelper(
uint16 targetChain,
uint256 computeBudget,
uint256 deliveryOverhead,
IRelayProvider provider
) internal view returns (uint32 gasAmount) {
if (computeBudget <= deliveryOverhead) {
gasAmount = 0;
} else {
uint256 gas = (computeBudget - deliveryOverhead) / provider.quoteGasPrice(targetChain);
if (gas > type(uint32).max) {
gasAmount = type(uint32).max;
} else {
gasAmount = uint32(gas);
}
}
}
function calculateTargetDeliveryMaximumRefundHelper(
uint16 targetChain,
uint256 computeBudget,
uint256 deliveryOverhead,
IRelayProvider provider
) internal view returns (uint256 maximumRefund) {
if (computeBudget >= deliveryOverhead) {
uint256 remainder = computeBudget - deliveryOverhead;
maximumRefund = assetConversionHelper(chainId(), remainder, targetChain, 1, 1, false, provider);
} else {
maximumRefund = 0;
}
}
function quoteGasDeliveryFee(uint16 targetChain, uint32 gasLimit, IRelayProvider provider)
@ -801,7 +812,7 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 deliveryQuote)
{
return provider.quoteDeliveryOverhead(targetChain) + (gasLimit * provider.quoteGasPrice(targetChain))
deliveryQuote = provider.quoteDeliveryOverhead(targetChain) + (gasLimit * provider.quoteGasPrice(targetChain))
+ wormhole().messageFee();
}
@ -810,16 +821,19 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 redeliveryQuote)
{
return provider.quoteRedeliveryOverhead(targetChain) + (gasLimit * provider.quoteGasPrice(targetChain))
+ wormhole().messageFee();
redeliveryQuote = provider.quoteRedeliveryOverhead(targetChain)
+ (gasLimit * provider.quoteGasPrice(targetChain)) + wormhole().messageFee();
}
//This is used internally to calculate the exchange rate for the provider without deducting the buffer amount
function quoteAssetConversion(uint16 sourceChain, uint256 sourceAmount, uint16 targetChain, IRelayProvider provider)
internal
view
returns (uint256 targetAmount)
{
function assetConversionHelper(
uint16 sourceChain,
uint256 sourceAmount,
uint16 targetChain,
uint256 multiplier,
uint256 multiplierDenominator,
bool roundUp,
IRelayProvider provider
) internal view returns (uint256 targetAmount) {
uint256 srcNativeCurrencyPrice = provider.quoteAssetPrice(sourceChain);
if (srcNativeCurrencyPrice == 0) {
revert SrcNativeCurrencyPriceIsZero();
@ -830,7 +844,14 @@ contract CoreRelayer is CoreRelayerGovernance {
revert DstNativeCurrencyPriceIsZero();
}
return sourceAmount * srcNativeCurrencyPrice / dstNativeCurrencyPrice;
uint256 numerator = sourceAmount * srcNativeCurrencyPrice * multiplier;
uint256 denominator = dstNativeCurrencyPrice * multiplierDenominator;
if (roundUp) {
targetAmount = (numerator + denominator - 1) / denominator;
} else {
targetAmount = numerator / denominator;
}
}
//If the integrator pays at least nativeQuote, they should receive at least targetAmount as their application budget
@ -839,9 +860,10 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 nativeQuote)
{
uint256 sourceAmount = quoteAssetConversion(targetChain, targetAmount, chainId(), provider);
(uint16 buffer, uint16 denominator) = provider.getAssetConversionBuffer(targetChain);
nativeQuote = (sourceAmount * (denominator + buffer) + denominator - 1) / denominator;
nativeQuote = assetConversionHelper(
targetChain, targetAmount, chainId(), uint256(0) + denominator + buffer, denominator, true, provider
);
}
//This should invert quoteApplicationBudgetAmount, I.E when a user pays the sourceAmount, they receive at least the value of targetAmount they requested from
@ -851,9 +873,11 @@ contract CoreRelayer is CoreRelayerGovernance {
view
returns (uint256 targetAmount)
{
uint256 amount = quoteAssetConversion(chainId(), sourceAmount, targetChain, provider);
(uint16 buffer, uint16 denominator) = provider.getAssetConversionBuffer(targetChain);
targetAmount = amount * denominator / (denominator + buffer);
targetAmount = assetConversionHelper(
chainId(), sourceAmount, targetChain, denominator, uint256(0) + denominator + buffer, false, provider
);
}
function convertToEncodedRedeliveryByTxHashInstruction(
@ -908,7 +932,7 @@ contract CoreRelayer is CoreRelayerGovernance {
newEncoded = abi.encodePacked(
newEncoded,
calculateTargetDeliveryMaximumRefund(request.targetChain, request.computeBudget, provider),
quoteAssetConversion(chainId(), request.applicationBudget, request.targetChain, provider)
convertApplicationBudgetAmount(request.applicationBudget, request.targetChain, provider)
);
newEncoded = abi.encodePacked(
newEncoded,

View File

@ -95,7 +95,6 @@ contract MockRelayerIntegration is IWormholeReceiver {
bool forward = (parsed.payload.toUint8(0) == 1);
verifiedPayloads[parsed.hash] = parsed.payload.slice(1, parsed.payload.length - 1);
message = parsed.payload.slice(1, parsed.payload.length - 1);
if (forward) {
wormhole.publishMessage{value: wormhole.messageFee()}(
parsed.nonce, abi.encodePacked(uint8(0), bytes("received!")), 200

File diff suppressed because it is too large Load Diff