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,
|
uint32 multiplierDenom,
|
||||||
bool roundUp
|
bool roundUp
|
||||||
) internal pure returns (Wei) {
|
) internal pure returns (Wei) {
|
||||||
// console.log("heyo");
|
|
||||||
Dollar numerator = w.toDollars(fromPrice).mul(multiplierNum);
|
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);
|
WeiPrice denom = toPrice.mul(multiplierDenom);
|
||||||
// console.log("denom", denom.unwrap());
|
|
||||||
Wei res = numerator.toWei(denom, roundUp);
|
Wei res = numerator.toWei(denom, roundUp);
|
||||||
// console.log("res", res.unwrap());
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,17 +29,18 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
|
||||||
returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerUnitGasUnused)
|
returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerUnitGasUnused)
|
||||||
{
|
{
|
||||||
(uint16 buffer, uint16 denominator) = assetConversionBuffer(targetChain);
|
(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 targetCostIfNoGasLimitUsed = gasLimit.toWei(targetChainRefundPerUnitGasUnused).asTargetNative();
|
||||||
TargetNative targetCostIfFullGasLimitUsed = gasLimit.toWei(gasPrice(targetChain)).asTargetNative();
|
TargetNative targetCostIfFullGasLimitUsed = gasLimit.toWei(gasPrice(targetChain)).asTargetNative();
|
||||||
LocalNative costIfNoGasLimitUsed = quoteAssetCost(targetChain, targetCostIfNoGasLimitUsed);
|
LocalNative costIfNoGasLimitUsed = quoteAssetCost(targetChain, targetCostIfNoGasLimitUsed);
|
||||||
LocalNative costIfFullGasLimitUsed = gasLimit.toWei(quoteGasPrice(targetChain)).asLocalNative();
|
LocalNative costIfFullGasLimitUsed = quoteGasCost(targetChain, gasLimit);
|
||||||
LocalNative receiverValueCost = quoteAssetCost(targetChain, receiverValue);
|
LocalNative receiverValueCost = quoteAssetCost(targetChain, receiverValue);
|
||||||
nativePriceQuote = quoteDeliveryOverhead(targetChain) +
|
nativePriceQuote = quoteDeliveryOverhead(targetChain) + costIfFullGasLimitUsed + receiverValueCost;
|
||||||
costIfFullGasLimitUsed.asNative().max(costIfNoGasLimitUsed.asNative()).asLocalNative() + 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(
|
require(
|
||||||
receiverValue.asNative() + targetCostIfNoGasLimitUsed.asNative().max(targetCostIfFullGasLimitUsed.asNative()) <= maximumBudget(targetChain).asNative(),
|
receiverValue.asNative() + targetCostIfFullGasLimitUsed.asNative() <= maximumBudget(targetChain).asNative(),
|
||||||
"Exceeds maximum budget"
|
"Exceeds maximum budget"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -82,12 +83,10 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
|
||||||
return sourceChainAmount.asNative().convertAsset(
|
return sourceChainAmount.asNative().convertAsset(
|
||||||
nativeCurrencyPrice(sourceChain),
|
nativeCurrencyPrice(sourceChain),
|
||||||
nativeCurrencyPrice(targetChain),
|
nativeCurrencyPrice(targetChain),
|
||||||
(buffer),
|
(bufferDenominator),
|
||||||
(uint32(buffer) + bufferDenominator),
|
(uint32(buffer) + bufferDenominator),
|
||||||
false
|
false // round down
|
||||||
)
|
).asTargetNative();
|
||||||
// round down
|
|
||||||
.asTargetNative();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns the address on this chain that rewards should be sent to
|
//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.
|
//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) {
|
function quoteDeliveryOverhead(uint16 targetChain) public view returns (LocalNative nativePriceQuote) {
|
||||||
Gas overhead = deliverGasOverhead(targetChain);
|
nativePriceQuote = quoteGasCost(targetChain, deliverGasOverhead(targetChain));
|
||||||
Wei targetFees = overhead.toWei(gasPrice(targetChain));
|
require(nativePriceQuote.unwrap() <= type(uint128).max, "Overflow");
|
||||||
Wei result = assetConversion(targetChain, targetFees, chainId());
|
|
||||||
require(result.unwrap() <= type(uint128).max, "Overflow");
|
|
||||||
return result.asLocalNative();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Returns the price of purchasing 1 unit of gas on the target chain, denominated in this chain's wei.
|
//Returns the price of purchasing gasAmount units of gas on the target chain, denominated in this chain's wei.
|
||||||
function quoteGasPrice(uint16 targetChain) public view returns (GasPrice) {
|
function quoteGasCost(uint16 targetChain, Gas gasAmount) public view returns (LocalNative totalCost) {
|
||||||
Wei gasPriceInSourceChainCurrency =
|
Wei gasCostInSourceChainCurrency =
|
||||||
assetConversion(targetChain, gasPrice(targetChain).priceAsWei(), chainId());
|
assetConversion(targetChain, gasAmount.toWei(gasPrice(targetChain)), chainId());
|
||||||
require(gasPriceInSourceChainCurrency.unwrap() <= type(uint88).max, "Overflow");
|
totalCost = LocalNative.wrap(gasCostInSourceChainCurrency.unwrap());
|
||||||
return GasPrice.wrap(uint88(gasPriceInSourceChainCurrency.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)
|
// relevant for chains that have dynamic execution pricing (e.g. Ethereum)
|
||||||
function assetConversion(
|
function assetConversion(
|
||||||
uint16 sourceChain,
|
uint16 sourceChain,
|
||||||
Wei sourceAmount,
|
Wei sourceAmount,
|
||||||
uint16 targetChain
|
uint16 targetChain
|
||||||
) internal view returns (Wei targetAmount) {
|
) internal view returns (Wei targetAmount) {
|
||||||
|
if(nativeCurrencyPrice(sourceChain).unwrap() == 0) {
|
||||||
|
revert PriceIsZero(sourceChain);
|
||||||
|
}
|
||||||
|
if(nativeCurrencyPrice(targetChain).unwrap() == 0) {
|
||||||
|
revert PriceIsZero(targetChain);
|
||||||
|
}
|
||||||
return sourceAmount.convertAsset(
|
return sourceAmount.convertAsset(
|
||||||
nativeCurrencyPrice(sourceChain),
|
nativeCurrencyPrice(sourceChain),
|
||||||
nativeCurrencyPrice(targetChain),
|
nativeCurrencyPrice(targetChain),
|
||||||
|
@ -152,11 +160,17 @@ contract DeliveryProvider is DeliveryProviderGovernance, IDeliveryProvider {
|
||||||
TargetNative targetChainAmount
|
TargetNative targetChainAmount
|
||||||
) internal view returns (LocalNative currentChainAmount) {
|
) internal view returns (LocalNative currentChainAmount) {
|
||||||
(uint16 buffer, uint16 bufferDenominator) = assetConversionBuffer(targetChain);
|
(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(
|
return targetChainAmount.asNative().convertAsset(
|
||||||
nativeCurrencyPrice(chainId()),
|
|
||||||
nativeCurrencyPrice(targetChain),
|
nativeCurrencyPrice(targetChain),
|
||||||
|
nativeCurrencyPrice(chainId()),
|
||||||
(uint32(buffer) + bufferDenominator),
|
(uint32(buffer) + bufferDenominator),
|
||||||
(buffer),
|
(bufferDenominator),
|
||||||
// round up
|
// round up
|
||||||
true
|
true
|
||||||
).asLocalNative();
|
).asLocalNative();
|
||||||
|
|
|
@ -120,53 +120,52 @@ contract TestDeliveryProvider is Test {
|
||||||
deliveryProvider.updatePrice(updateChainId, updateGasPrice, updateNativeCurrencyPrice);
|
deliveryProvider.updatePrice(updateChainId, updateGasPrice, updateNativeCurrencyPrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
TODO: Uncomment these tests once revert messages are back in
|
|
||||||
function testCannotGetPriceBeforeUpdateSrcPrice(
|
function testCannotGetPriceBeforeUpdateSrcPrice(
|
||||||
uint16 dstChainId,
|
uint16 dstChainId,
|
||||||
uint128 dstGasPrice,
|
uint64 dstGasPrice,
|
||||||
uint128 dstNativeCurrencyPrice
|
WeiPrice dstNativeCurrencyPrice
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
{
|
{
|
||||||
vm.assume(dstChainId > 0);
|
vm.assume(dstChainId > 0);
|
||||||
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
|
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
|
||||||
vm.assume(dstGasPrice > 0);
|
vm.assume(dstGasPrice > 0);
|
||||||
vm.assume(dstNativeCurrencyPrice > 0);
|
vm.assume(dstNativeCurrencyPrice.unwrap() > 0);
|
||||||
|
|
||||||
initializeDeliveryProvider();
|
initializeDeliveryProvider();
|
||||||
|
|
||||||
// update the price with reasonable values
|
// update the price with reasonable values
|
||||||
deliveryProvider.updatePrice(dstChainId, dstGasPrice, dstNativeCurrencyPrice);
|
deliveryProvider.updatePrice(dstChainId, GasPrice.wrap(dstGasPrice), dstNativeCurrencyPrice);
|
||||||
|
|
||||||
// you shall not pass
|
// you shall not pass
|
||||||
vm.expectRevert("srcNativeCurrencyPrice == 0");
|
vm.expectRevert(abi.encodeWithSignature("PriceIsZero(uint16)", TEST_ORACLE_CHAIN_ID));
|
||||||
deliveryProvider.quoteDeliveryOverhead(dstChainId);
|
deliveryProvider.quoteDeliveryOverhead(dstChainId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCannotGetPriceBeforeUpdateDstPrice(
|
function testCannotGetPriceBeforeUpdateDstPrice(
|
||||||
uint16 dstChainId,
|
uint16 dstChainId,
|
||||||
uint128 srcGasPrice,
|
uint64 srcGasPrice,
|
||||||
uint128 srcNativeCurrencyPrice
|
WeiPrice srcNativeCurrencyPrice
|
||||||
)
|
)
|
||||||
public
|
public
|
||||||
{
|
{
|
||||||
vm.assume(dstChainId > 0);
|
vm.assume(dstChainId > 0);
|
||||||
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
|
vm.assume(dstChainId != TEST_ORACLE_CHAIN_ID);
|
||||||
vm.assume(srcGasPrice > 0);
|
vm.assume(srcGasPrice > 0);
|
||||||
vm.assume(srcNativeCurrencyPrice > 0);
|
vm.assume(srcNativeCurrencyPrice.unwrap() > 0);
|
||||||
|
|
||||||
initializeDeliveryProvider();
|
initializeDeliveryProvider();
|
||||||
|
|
||||||
// update the price with reasonable values
|
// update the price with reasonable values
|
||||||
//vm.prank(deliveryProvider.owner());
|
//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
|
// you shall not pass
|
||||||
vm.expectRevert("dstNativeCurrencyPrice == 0");
|
vm.expectRevert(abi.encodeWithSignature("PriceIsZero(uint16)", dstChainId));
|
||||||
deliveryProvider.quoteDeliveryOverhead(dstChainId);
|
deliveryProvider.quoteDeliveryOverhead(dstChainId);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
function testUpdatePrice(
|
function testUpdatePrice(
|
||||||
uint16 dstChainId,
|
uint16 dstChainId,
|
||||||
|
@ -268,4 +267,109 @@ contract TestDeliveryProvider is Test {
|
||||||
|
|
||||||
assertTrue(newAddress == updated);
|
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