Compare commits
3 Commits
794c06c56a
...
07558de31c
Author | SHA1 | Date |
---|---|---|
derpy-duck | 07558de31c | |
derpy-duck | e5b5fbfc71 | |
derpy-duck | 014dc79f49 |
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue