Compare commits

...

3 Commits

Author SHA1 Message Date
derpy-duck 07558de31c remove console logs 2023-06-09 21:46:06 +00:00
derpy-duck e5b5fbfc71 Fix Delivery Provider Pricing and add a test 2023-06-09 21:12:52 +00:00
derpy-duck 014dc79f49 remove unnecessary comments 2023-06-09 18:44:03 +00:00
3 changed files with 154 additions and 42 deletions

View File

@ -171,15 +171,9 @@ library WeiLib {
uint32 multiplierDenom,
bool roundUp
) internal pure returns (Wei) {
// console.log("heyo");
Dollar numerator = w.toDollars(fromPrice).mul(multiplierNum);
// console.log("numerator", numerator.unwrap());
// console.log("multiplierDenom", multiplierDenom);
// console.log("toPrice", toPrice.unwrap());
WeiPrice denom = toPrice.mul(multiplierDenom);
// console.log("denom", denom.unwrap());
Wei res = numerator.toWei(denom, roundUp);
// console.log("res", res.unwrap());
return res;
}
}

View File

@ -29,17 +29,18 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerUnitGasUnused)
{
(uint16 buffer, uint16 denominator) = assetConversionBuffer(targetChain);
targetChainRefundPerUnitGasUnused = GasPrice.wrap(gasPrice(targetChain).unwrap() * (denominator - buffer) / denominator);
targetChainRefundPerUnitGasUnused = GasPrice.wrap(gasPrice(targetChain).unwrap() * (denominator) / (uint256(denominator) + buffer));
TargetNative targetCostIfNoGasLimitUsed = gasLimit.toWei(targetChainRefundPerUnitGasUnused).asTargetNative();
TargetNative targetCostIfFullGasLimitUsed = gasLimit.toWei(gasPrice(targetChain)).asTargetNative();
LocalNative costIfNoGasLimitUsed = quoteAssetCost(targetChain, targetCostIfNoGasLimitUsed);
LocalNative costIfFullGasLimitUsed = gasLimit.toWei(quoteGasPrice(targetChain)).asLocalNative();
LocalNative costIfFullGasLimitUsed = quoteGasCost(targetChain, gasLimit);
LocalNative receiverValueCost = quoteAssetCost(targetChain, receiverValue);
nativePriceQuote = quoteDeliveryOverhead(targetChain) +
costIfFullGasLimitUsed.asNative().max(costIfNoGasLimitUsed.asNative()).asLocalNative() + receiverValueCost;
nativePriceQuote = quoteDeliveryOverhead(targetChain) + costIfFullGasLimitUsed + receiverValueCost;
require(costIfNoGasLimitUsed.unwrap() <= costIfFullGasLimitUsed.unwrap(), "target chain refund per gas unused is too high");
require(targetCostIfNoGasLimitUsed.unwrap() <= targetCostIfFullGasLimitUsed.unwrap(), "target chain refund per gas unused is too high");
require(
receiverValue.asNative() + targetCostIfNoGasLimitUsed.asNative().max(targetCostIfFullGasLimitUsed.asNative()) <= maximumBudget(targetChain).asNative(),
receiverValue.asNative() + targetCostIfFullGasLimitUsed.asNative() <= maximumBudget(targetChain).asNative(),
"Exceeds maximum budget"
);
}
@ -82,12 +83,10 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
return sourceChainAmount.asNative().convertAsset(
nativeCurrencyPrice(sourceChain),
nativeCurrencyPrice(targetChain),
(buffer),
(bufferDenominator),
(uint32(buffer) + bufferDenominator),
false
)
// round down
.asTargetNative();
false // round down
).asTargetNative();
}
//Returns the address on this chain that rewards should be sent to
@ -116,27 +115,36 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
//Returns the delivery overhead fee required to deliver a message to the target chain, denominated in this chain's wei.
function quoteDeliveryOverhead(uint16 targetChain) public view returns (LocalNative nativePriceQuote) {
Gas overhead = deliverGasOverhead(targetChain);
Wei targetFees = overhead.toWei(gasPrice(targetChain));
Wei result = assetConversion(targetChain, targetFees, chainId());
require(result.unwrap() <= type(uint128).max, "Overflow");
return result.asLocalNative();
nativePriceQuote = quoteGasCost(targetChain, deliverGasOverhead(targetChain));
require(nativePriceQuote.unwrap() <= type(uint128).max, "Overflow");
}
//Returns the price of purchasing 1 unit of gas on the target chain, denominated in this chain's wei.
function quoteGasPrice(uint16 targetChain) public view returns (GasPrice) {
Wei gasPriceInSourceChainCurrency =
assetConversion(targetChain, gasPrice(targetChain).priceAsWei(), chainId());
require(gasPriceInSourceChainCurrency.unwrap() <= type(uint88).max, "Overflow");
return GasPrice.wrap(uint88(gasPriceInSourceChainCurrency.unwrap()));
//Returns the price of purchasing gasAmount units of gas on the target chain, denominated in this chain's wei.
function quoteGasCost(uint16 targetChain, Gas gasAmount) public view returns (LocalNative totalCost) {
Wei gasCostInSourceChainCurrency =
assetConversion(targetChain, gasAmount.toWei(gasPrice(targetChain)), chainId());
totalCost = LocalNative.wrap(gasCostInSourceChainCurrency.unwrap());
}
function quoteGasPrice(uint16 targetChain) public view returns (GasPrice price) {
price = GasPrice.wrap(quoteGasCost(targetChain, Gas.wrap(1)).unwrap());
require(price.unwrap() <= type(uint88).max, "Overflow");
}
error PriceIsZero(uint16 chain);
// relevant for chains that have dynamic execution pricing (e.g. Ethereum)
function assetConversion(
uint16 sourceChain,
Wei sourceAmount,
uint16 targetChain
) internal view returns (Wei targetAmount) {
if(nativeCurrencyPrice(sourceChain).unwrap() == 0) {
revert PriceIsZero(sourceChain);
}
if(nativeCurrencyPrice(targetChain).unwrap() == 0) {
revert PriceIsZero(targetChain);
}
return sourceAmount.convertAsset(
nativeCurrencyPrice(sourceChain),
nativeCurrencyPrice(targetChain),
@ -152,11 +160,17 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
TargetNative targetChainAmount
) internal view returns (LocalNative currentChainAmount) {
(uint16 buffer, uint16 bufferDenominator) = assetConversionBuffer(targetChain);
if(nativeCurrencyPrice(chainId()).unwrap() == 0) {
revert PriceIsZero(chainId());
}
if(nativeCurrencyPrice(targetChain).unwrap() == 0) {
revert PriceIsZero(targetChain);
}
return targetChainAmount.asNative().convertAsset(
nativeCurrencyPrice(chainId()),
nativeCurrencyPrice(targetChain),
nativeCurrencyPrice(chainId()),
(uint32(buffer) + bufferDenominator),
(buffer),
(bufferDenominator),
// round up
true
).asLocalNative();

View File

@ -120,53 +120,52 @@ contract TestDeliveryProvider is Test {
deliveryProvider.updatePrice(updateChainId, updateGasPrice, updateNativeCurrencyPrice);
}
/*
TODO: Uncomment these tests once revert messages are back in
function testCannotGetPriceBeforeUpdateSrcPrice(
uint16 dstChainId,
uint128 dstGasPrice,
uint128 dstNativeCurrencyPrice
uint64 dstGasPrice,
WeiPrice dstNativeCurrencyPrice
)
public
{
vm.assume(dstChainId > 0);
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
vm.assume(dstGasPrice > 0);
vm.assume(dstNativeCurrencyPrice > 0);
vm.assume(dstNativeCurrencyPrice.unwrap() > 0);
initializeDeliveryProvider();
// update the price with reasonable values
deliveryProvider.updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice);
deliveryProvider.updatePrice(dstChainId, GasPrice.wrap(dstGasPrice), dstNativeCurrencyPrice);
// you shall not pass
vm.expectRevert("srcNativeCurrencyPrice == 0");
vm.expectRevert(abi.encodeWithSignature("PriceIsZero(uint16)", TEST_ORACLE_CHAIN_ID));
deliveryProvider.quoteDeliveryOverhead(dstChainId);
}
function testCannotGetPriceBeforeUpdateDstPrice(
uint16 dstChainId,
uint128 srcGasPrice,
uint128 srcNativeCurrencyPrice
uint64 srcGasPrice,
WeiPrice srcNativeCurrencyPrice
)
public
{
vm.assume(dstChainId > 0);
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
vm.assume(srcGasPrice > 0);
vm.assume(srcNativeCurrencyPrice > 0);
vm.assume(srcNativeCurrencyPrice.unwrap() > 0);
initializeDeliveryProvider();
// update the price with reasonable values
//vm.prank(deliveryProvider.owner());
deliveryProvider.updatePrice(TEST_ORACLE_CHAIN_ID, srcGasPrice, srcNativeCurrencyPrice);
deliveryProvider.updatePrice(TEST_ORACLE_CHAIN_ID, GasPrice.wrap(srcGasPrice), srcNativeCurrencyPrice);
// you shall not pass
vm.expectRevert("dstNativeCurrencyPrice == 0");
vm.expectRevert(abi.encodeWithSignature("PriceIsZero(uint16)", dstChainId));
deliveryProvider.quoteDeliveryOverhead(dstChainId);
}
*/
function testUpdatePrice(
uint16 dstChainId,
@ -268,4 +267,109 @@ contract TestDeliveryProvider is Test {
assertTrue(newAddress == updated);
}
function testQuoteDeliveryOverhead(
uint16 dstChainId,
uint64 dstGasPrice,
uint64 dstNativeCurrencyPrice,
uint64 srcGasPrice,
uint64 srcNativeCurrencyPrice,
uint32 gasOverhead
) public {
initializeDeliveryProvider();
vm.assume(dstChainId > 0);
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID); // wormhole.chainId()
vm.assume(dstGasPrice > 0);
vm.assume(dstNativeCurrencyPrice > 0);
vm.assume(srcGasPrice > 0);
vm.assume(srcNativeCurrencyPrice > 0);
vm.assume(dstGasPrice >= dstNativeCurrencyPrice / srcNativeCurrencyPrice);
vm.assume(dstGasPrice * uint256(dstNativeCurrencyPrice) / srcNativeCurrencyPrice < 2 ** 72);
vm.assume(gasOverhead < uint256(2)**31);
// update the prices with reasonable values
deliveryProvider.updatePrice(
dstChainId, GasPrice.wrap(dstGasPrice), WeiPrice.wrap(dstNativeCurrencyPrice)
);
deliveryProvider.updatePrice(
TEST_ORACLE_CHAIN_ID, GasPrice.wrap(srcGasPrice), WeiPrice.wrap(srcNativeCurrencyPrice)
);
deliveryProvider.updateAssetConversionBuffer(dstChainId, 5, 100);
deliveryProvider.updateDeliverGasOverhead(dstChainId, Gas.wrap(gasOverhead));
deliveryProvider.updateMaximumBudget(dstChainId, Wei.wrap(uint256(2)**191));
// verify price
uint256 expectedOverhead = (
uint256(dstNativeCurrencyPrice) * (uint256(dstGasPrice) * gasOverhead) + (srcNativeCurrencyPrice - 1)
) / srcNativeCurrencyPrice;
LocalNative deliveryOverhead = deliveryProvider.quoteDeliveryOverhead(dstChainId);
require(expectedOverhead == LocalNative.unwrap(deliveryOverhead), "deliveryProvider overhead quote is not what is expected");
}
function testQuoteDeliveryPrice(
uint16 dstChainId,
uint64 dstGasPrice,
uint64 dstNativeCurrencyPrice,
uint64 srcGasPrice,
uint64 srcNativeCurrencyPrice,
uint32 gasLimit,
uint32 gasOverhead,
uint64 receiverValue
) public {
initializeDeliveryProvider();
vm.assume(dstChainId > 0);
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID); // wormhole.chainId()
vm.assume(dstGasPrice > 0);
vm.assume(dstNativeCurrencyPrice > 0);
vm.assume(srcGasPrice > 0);
vm.assume(srcNativeCurrencyPrice > 0);
vm.assume(dstGasPrice >= dstNativeCurrencyPrice / srcNativeCurrencyPrice);
vm.assume(dstGasPrice * uint256(dstNativeCurrencyPrice) / srcNativeCurrencyPrice < 2 ** 72);
vm.assume(gasLimit < uint256(2)**31);
vm.assume(gasOverhead < uint256(2)**31);
// update the prices with reasonable values
deliveryProvider.updatePrice(
dstChainId, GasPrice.wrap(dstGasPrice), WeiPrice.wrap(dstNativeCurrencyPrice)
);
deliveryProvider.updatePrice(
TEST_ORACLE_CHAIN_ID, GasPrice.wrap(srcGasPrice), WeiPrice.wrap(srcNativeCurrencyPrice)
);
deliveryProvider.updateAssetConversionBuffer(dstChainId, 5, 100);
deliveryProvider.updateDeliverGasOverhead(dstChainId, Gas.wrap(gasOverhead));
deliveryProvider.updateMaximumBudget(dstChainId, Wei.wrap(uint256(2)**191));
// verify price
uint256 expectedGasCost = (
uint256(dstNativeCurrencyPrice) * (uint256(dstGasPrice) * (gasLimit)) + (srcNativeCurrencyPrice - 1)
) / srcNativeCurrencyPrice;
uint256 expectedOverheadCost = (
uint256(dstNativeCurrencyPrice) * (uint256(dstGasPrice) * ( gasOverhead)) + (srcNativeCurrencyPrice - 1)
) / srcNativeCurrencyPrice;
uint256 expectedReceiverValueCost = (
uint256(dstNativeCurrencyPrice) * (receiverValue) * 105 + (srcNativeCurrencyPrice * uint256(100) - 1)
) / srcNativeCurrencyPrice / 100;
(LocalNative nativePriceQuote,) = deliveryProvider.quoteEvmDeliveryPrice(dstChainId, Gas.wrap(gasLimit), TargetNative.wrap(receiverValue));
require(expectedGasCost == LocalNative.unwrap(deliveryProvider.quoteGasCost(dstChainId, Gas.wrap(gasLimit))), "Gas cost is not what is expected");
require(expectedOverheadCost == LocalNative.unwrap(deliveryProvider.quoteGasCost(dstChainId, Gas.wrap(gasOverhead))), "Overhead cost is not what is expected");
require(expectedGasCost + expectedOverheadCost + expectedReceiverValueCost == LocalNative.unwrap(nativePriceQuote), "deliveryProvider price quote is not what is expected");
}
}