Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ackGasCostDefault SUP-5371 #451

Merged
merged 6 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ env:
AVALANCHE_RPC_URL: ${{ secrets.AVALANCHE_RPC_URL }}
FANTOM_RPC_URL: ${{ secrets.FANTOM_RPC_URL }}
TENDERLY_ACCESS_KEY: ${{ secrets.TENDERLY_ACCESS_KEY }}
TENDERLY_PROJECT_SLUG: 'superform-v1-d5' # your project slug
TENDERLY_ACCOUNT_ID: 'superform' # your username or organization name
FOUNDRY_EXPORTS_OVERWRITE_LATEST: 'true'
TENDERLY_PROJECT_SLUG: "v1" # your project slug
TENDERLY_ACCOUNT_ID: "superform" # your username or organization name
FOUNDRY_EXPORTS_OVERWRITE_LATEST: "true"

jobs:
build:
Expand Down Expand Up @@ -85,13 +85,13 @@ jobs:
echo "FOUNDRY_FUZZ_SEED=$(echo $(($EPOCHSECONDS / 604800)))" >> $GITHUB_ENV

- name: "Run all tests except invariant against the optimized build and produce gas reports"
run: "forge test --gas-report --no-match-path \"test/invariant/**/*.sol\""
run: 'forge test --gas-report --no-match-path "test/invariant/**/*.sol"'

- name: "Add test summary"
run: |
echo "## Tests result" >> $GITHUB_STEP_SUMMARY
echo "✅ Passed" >> $GITHUB_STEP_SUMMARY

coverage:
runs-on: SuperformCore2
steps:
Expand Down Expand Up @@ -127,9 +127,9 @@ jobs:
submodules: "recursive"
- name: "Install Foundry"
uses: "foundry-rs/foundry-toolchain@v1"
- name: 'Install Tenderly CLI'
- name: "Install Tenderly CLI"
run: curl https://raw.githubusercontent.com/Tenderly/tenderly-cli/master/scripts/install-linux.sh | sudo sh
- name: 'Deploy to Tenderly Devnets'
- name: "Deploy to Tenderly Devnets"
run: ./script/utils/run_script_tenderly.sh
shell: bash
- name: "Add devnet deployment summary"
Expand Down
12 changes: 3 additions & 9 deletions script/utils/run_script_tenderly.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@
# Read the RPC URL
source .env

#BSC_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template bscdevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
#POLYGON_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template polygondevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
#AVAX_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template avaxdevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
ETHEREUM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template ethereumdevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
OPTIMISM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template optimismdevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
ARBITRUM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template arbitrumdevnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
ETHEREUM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template ethereum-devnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
OPTIMISM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template optimism-devnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)
ARBITRUM_DEVNET=$(tenderly devnet spawn-rpc --project $TENDERLY_PROJECT_SLUG --template arbitrum-devnet --account $TENDERLY_ACCOUNT_ID --access_key $TENDERLY_ACCESS_KEY --return-url)

# Run the script
echo Running Stage 1: ...


FOUNDRY_PROFILE=default forge script script/Tenderly.Deploy.s.sol:TenderlyDeploy --sig "deployStage1(uint256,uint256)" 0 1337 --rpc-url $ETHEREUM_DEVNET --broadcast --unlocked --sender 0x0000000000000000000000000000000000000000

wait
Expand All @@ -28,7 +24,6 @@ wait

echo Running Stage 2: ...


FOUNDRY_PROFILE=default forge script script/Tenderly.Deploy.s.sol:TenderlyDeploy --sig "deployStage2(uint256)" 0 --rpc-url $ETHEREUM_DEVNET --broadcast --unlocked --sender 0x0000000000000000000000000000000000000000

wait
Expand All @@ -52,4 +47,3 @@ FOUNDRY_PROFILE=default forge script script/Tenderly.Deploy.s.sol:TenderlyDeploy
wait

FOUNDRY_PROFILE=default forge script script/Tenderly.Deploy.s.sol:TenderlyDeploy --sig "deployStage3(uint256)" 2 --rpc-url $ARBITRUM_DEVNET --broadcast --unlocked --sender 0x0000000000000000000000000000000000000000

65 changes: 49 additions & 16 deletions src/interfaces/IPaymentHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,6 @@ interface IPaymentHelper {
/// @return extraData the amb specific override information
function getRegisterTransmuterAMBData() external view returns (bytes memory extraData);

/// @dev returns the gas fees estimation in native tokens if we send message through a combination of AMBs
/// @param ambIds_ is the identifier of different AMBs
/// @param dstChainId_ is the identifier of the destination chain
/// @param message_ is the cross-chain message
/// @param extraData_ is any amb-specific information
/// @return ambFees is the native_tokens to be sent along the transaction for all the ambIds_ included
function estimateAMBFees(
uint8[] memory ambIds_,
uint64 dstChainId_,
bytes memory message_,
bytes[] memory extraData_
)
external
view
returns (uint256 ambFees, uint256[] memory);

/// @dev estimates the gas fees for multiple destination and multi vault operation
/// @param req_ is the request object containing all necessary data for the actual operation on SuperRouter
/// @param isDeposit_ indicated if the datatype will be used for a deposit
Expand Down Expand Up @@ -177,6 +161,55 @@ interface IPaymentHelper {
view
returns (uint256 liqAmount, uint256 srcAmount, uint256 totalAmount);

/// @dev returns the gas fees estimation in native tokens if we send message through a combination of AMBs
/// @param ambIds_ is the identifier of different AMBs
/// @param dstChainId_ is the identifier of the destination chain
/// @param message_ is the cross-chain message
/// @param extraData_ is any amb-specific information
/// @return ambFees is the native_tokens to be sent along the transaction for all the ambIds_ included
function estimateAMBFees(
uint8[] memory ambIds_,
uint64 dstChainId_,
bytes memory message_,
bytes[] memory extraData_
)
external
view
returns (uint256 ambFees, uint256[] memory);

/// @dev helps estimate the acknowledgement costs for amb processing
/// @param payloadId_ is the payload identifier
/// @return totalFees is the total fees to be paid in native tokens
function estimateAckCost(uint256 payloadId_) external view returns (uint256 totalFees);

/// @dev helps estimate the acknowledgement costs for amb processing without relying on payloadId (using max values)
/// @param multi is the flag indicating if the payload is multi or single
/// @param ackAmbIds is the list of ambIds to be used for acknowledgement
/// @param srcChainId is the source chain identifier
/// @return totalFees is the total fees to be paid in native tokens
function estimateAckCostDefault(
bool multi,
uint8[] memory ackAmbIds,
uint64 srcChainId
)
external
view
returns (uint256 totalFees);

/// @dev helps estimate the acknowledgement costs for amb processing without relying on payloadId (using max values)
/// with source native amounts
/// @param multi is the flag indicating if the payload is multi or single
/// @param ackAmbIds is the list of ambIds to be used for acknowledgement
/// @param srcChainId is the source chain identifier
/// @return totalFees is the total fees to be paid in native tokens
function estimateAckCostDefaultNativeSource(
bool multi,
uint8[] memory ackAmbIds,
uint64 srcChainId
)
external
view
returns (uint256 totalFees);
//////////////////////////////////////////////////////////////
// EXTERNAL WRITE FUNCTIONS //
//////////////////////////////////////////////////////////////
Expand Down
111 changes: 63 additions & 48 deletions src/payments/PaymentHelper.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ contract PaymentHelper is IPaymentHelper {
//////////////////////////////////////////////////////////////

modifier onlyProtocolAdmin() {
if (!ISuperRBAC(superRegistry.getAddress(keccak256("SUPER_RBAC"))).hasProtocolAdminRole(msg.sender)) {
if (!ISuperRBAC(_getAddress(keccak256("SUPER_RBAC"))).hasProtocolAdminRole(msg.sender)) {
revert Error.NOT_PROTOCOL_ADMIN();
}
_;
}

modifier onlyEmergencyAdmin() {
if (!ISuperRBAC(superRegistry.getAddress(keccak256("SUPER_RBAC"))).hasEmergencyAdminRole(msg.sender)) {
if (!ISuperRBAC(_getAddress(keccak256("SUPER_RBAC"))).hasEmergencyAdminRole(msg.sender)) {
revert Error.NOT_EMERGENCY_ADMIN();
}
_;
Expand Down Expand Up @@ -176,7 +176,7 @@ contract PaymentHelper is IPaymentHelper {
LocalEstimateVars memory v;
v.len = req_.dstChainIds.length;

ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));
for (uint256 i; i < v.len; ++i) {
bool xChain = req_.dstChainIds[i] != CHAIN_ID;

Expand Down Expand Up @@ -225,19 +225,7 @@ contract PaymentHelper is IPaymentHelper {

/// @dev step 7: estimate execution costs in destination including sending acknowledgement to source
/// @dev ensure that acknowledgement costs from dst to src are not double counted
bool noRetain4626;
for (uint256 j; j < v.superformIdsLen; ++j) {
if (!req_.superformsData[i].retain4626s[j]) {
noRetain4626 = true;
break;
}
}
if (noRetain4626 && xChain) {
v.totalDstGas += _estimateDstExecutionCost(isDeposit_, false, req_.dstChainIds[i], v.superformIdsLen);
} else {
v.totalDstGas +=
xChain ? _estimateDstExecutionCost(isDeposit_, true, req_.dstChainIds[i], v.superformIdsLen) : 0;
}
v.totalDstGas += xChain ? _estimateDstExecutionCost(isDeposit_, req_.dstChainIds[i], v.superformIdsLen) : 0;

/// @dev step 8: convert all dst gas estimates to src chain estimate (withdraw / deposit)
dstAmount += _convertToNativeFee(req_.dstChainIds[i], v.totalDstGas);
Expand All @@ -257,7 +245,7 @@ contract PaymentHelper is IPaymentHelper {
returns (uint256 liqAmount, uint256 srcAmount, uint256 dstAmount, uint256 totalAmount)
{
uint256 len = req_.dstChainIds.length;
ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));

for (uint256 i; i < len; ++i) {
bool xChain = req_.dstChainIds[i] != CHAIN_ID;
Expand Down Expand Up @@ -301,9 +289,7 @@ contract PaymentHelper is IPaymentHelper {
}

/// @dev step 7: estimate execution costs in destination including sending acknowledgement to source
totalDstGas += xChain
? _estimateDstExecutionCost(isDeposit_, req_.superformsData[i].retain4626, req_.dstChainIds[i], 1)
: 0;
totalDstGas += xChain ? _estimateDstExecutionCost(isDeposit_, req_.dstChainIds[i], 1) : 0;

/// @dev step 8: convert all dst gas estimates to src chain estimate
dstAmount += _convertToNativeFee(req_.dstChainIds[i], totalDstGas);
Expand All @@ -325,7 +311,7 @@ contract PaymentHelper is IPaymentHelper {
uint256 totalDstGas;
uint256 superformIdsLen = req_.superformsData.superformIds.length;

ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));

/// @dev step 1: estimate AMB costs
uint256 ambFees =
Expand Down Expand Up @@ -366,18 +352,7 @@ contract PaymentHelper is IPaymentHelper {

/// @dev step 7: estimate execution costs in destination including sending acknowledgement to source
/// @dev ensure that acknowledgement costs from dst to src are not double counted
bool noRetain4626;
for (uint256 i; i < superformIdsLen; ++i) {
if (!req_.superformsData.retain4626s[i]) {
noRetain4626 = true;
break;
}
}
if (noRetain4626) {
totalDstGas += _estimateDstExecutionCost(isDeposit_, false, req_.dstChainId, superformIdsLen);
} else {
totalDstGas += _estimateDstExecutionCost(isDeposit_, true, req_.dstChainId, superformIdsLen);
}
totalDstGas += _estimateDstExecutionCost(isDeposit_, req_.dstChainId, superformIdsLen);

/// @dev step 8: convert all destination gas estimates to source chain estimate
dstAmount += _convertToNativeFee(req_.dstChainId, totalDstGas);
Expand All @@ -396,7 +371,7 @@ contract PaymentHelper is IPaymentHelper {
returns (uint256 liqAmount, uint256 srcAmount, uint256 dstAmount, uint256 totalAmount)
{
uint256 totalDstGas;
ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));

/// @dev step 1: estimate AMB costs
uint256 ambFees =
Expand Down Expand Up @@ -431,7 +406,7 @@ contract PaymentHelper is IPaymentHelper {
}

/// @dev step 7: estimate execution costs in destination including sending acknowledgement to source
totalDstGas += _estimateDstExecutionCost(isDeposit_, req_.superformData.retain4626, req_.dstChainId, 1);
totalDstGas += _estimateDstExecutionCost(isDeposit_, req_.dstChainId, 1);

/// @dev step 8: convert all destination gas estimates to source chain estimate
dstAmount += _convertToNativeFee(req_.dstChainId, totalDstGas);
Expand All @@ -449,7 +424,7 @@ contract PaymentHelper is IPaymentHelper {
override
returns (uint256 liqAmount, uint256 srcAmount, uint256 totalAmount)
{
ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));

if (!isDeposit_) {
/// @dev only if timelock form withdrawal is involved
Expand Down Expand Up @@ -480,7 +455,7 @@ contract PaymentHelper is IPaymentHelper {
override
returns (uint256 liqAmount, uint256 srcAmount, uint256 totalAmount)
{
ISuperformFactory factory = ISuperformFactory(superRegistry.getAddress(keccak256("SUPERFORM_FACTORY")));
ISuperformFactory factory = ISuperformFactory(_getAddress(keccak256("SUPERFORM_FACTORY")));

if (!isDeposit_) {
uint256 len = req_.superformData.superformIds.length;
Expand Down Expand Up @@ -513,6 +488,7 @@ contract PaymentHelper is IPaymentHelper {
)
public
view
override
returns (uint256 totalFees, uint256[] memory)
{
uint256 len = ambIds_.length;
Expand All @@ -532,11 +508,10 @@ contract PaymentHelper is IPaymentHelper {
return (totalFees, fees);
}

/// @dev helps estimate the acknowledgement costs for amb processing
function estimateAckCost(uint256 payloadId_) external view returns (uint256 totalFees) {
/// @inheritdoc IPaymentHelper
function estimateAckCost(uint256 payloadId_) external view override returns (uint256 totalFees) {
EstimateAckCostVars memory v;
IBaseStateRegistry coreStateRegistry =
IBaseStateRegistry(superRegistry.getAddress(keccak256("CORE_STATE_REGISTRY")));
IBaseStateRegistry coreStateRegistry = IBaseStateRegistry(_getAddress(keccak256("CORE_STATE_REGISTRY")));
v.currPayloadId = coreStateRegistry.payloadsCount();

if (payloadId_ > v.currPayloadId) revert Error.INVALID_PAYLOAD_ID();
Expand Down Expand Up @@ -564,6 +539,47 @@ contract PaymentHelper is IPaymentHelper {
return _estimateAMBFees(v.ackAmbIds, v.srcChainId, v.message);
}

/// @inheritdoc IPaymentHelper
function estimateAckCostDefault(
bool multi,
uint8[] memory ackAmbIds,
uint64 srcChainId
)
public
view
override
returns (uint256 totalFees)
{
bytes memory payloadBody;
if (multi) {
uint256 vaultLimitPerDst = superRegistry.getVaultLimitPerDestination(srcChainId);
uint256[] memory maxUints = new uint256[](vaultLimitPerDst);

for (uint256 i; i < vaultLimitPerDst; ++i) {
maxUints[i] = type(uint256).max;
}
payloadBody = abi.encode(ReturnMultiData(type(uint256).max, maxUints, maxUints));
} else {
payloadBody = abi.encode(ReturnSingleData(type(uint256).max, type(uint256).max, type(uint256).max));
}

return _estimateAMBFees(ackAmbIds, srcChainId, abi.encode(AMBMessage(type(uint256).max, payloadBody)));
}

/// @inheritdoc IPaymentHelper
function estimateAckCostDefaultNativeSource(
bool multi,
uint8[] memory ackAmbIds,
uint64 srcChainId
)
external
view
override
returns (uint256)
{
return _convertToNativeFee(srcChainId, estimateAckCostDefault(multi, ackAmbIds, srcChainId));
}

//////////////////////////////////////////////////////////////
// EXTERNAL WRITE FUNCTIONS //
//////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -852,7 +868,6 @@ contract PaymentHelper is IPaymentHelper {
/// @dev assumes that withdrawals optimisically succeed
function _estimateDstExecutionCost(
bool isDeposit_,
bool retain4626_,
uint64 dstChainId_,
uint256 vaultsCount_
)
Expand All @@ -862,11 +877,6 @@ contract PaymentHelper is IPaymentHelper {
{
uint256 executionGasPerVault = isDeposit_ ? depositGasUsed[dstChainId_] : withdrawGasUsed[dstChainId_];
gasUsed = executionGasPerVault * vaultsCount_;

/// @dev add ackGasCost only if it's a deposit and retain4626 is false
if (isDeposit_ && !retain4626_) {
gasUsed += ackGasCost[dstChainId_];
}
}

/// @dev helps estimate the src chain processing fee
Expand Down Expand Up @@ -953,7 +963,7 @@ contract PaymentHelper is IPaymentHelper {
/// @dev helps generate the new payload id
/// @dev next payload id = current payload id + 1
function _getNextPayloadId() internal view returns (uint256 nextPayloadId) {
nextPayloadId = ReadOnlyBaseRegistry(superRegistry.getAddress(keccak256("CORE_STATE_REGISTRY"))).payloadsCount();
nextPayloadId = ReadOnlyBaseRegistry(_getAddress(keccak256("CORE_STATE_REGISTRY"))).payloadsCount();
++nextPayloadId;
}

Expand Down Expand Up @@ -994,4 +1004,9 @@ contract PaymentHelper is IPaymentHelper {

return nativePrice[chainId_];
}

/// @dev returns the address from super registry
function _getAddress(bytes32 id_) internal view returns (address) {
return superRegistry.getAddress(id_);
}
}
Loading
Loading