Skip to content

Implement DVN zero fees, dynamic gas estimation, and multi-arch Dockerfiles#10

Open
devin-ai-integration[bot] wants to merge 24 commits into
devfrom
devin/1747591106-deploy-layerzero-contracts
Open

Implement DVN zero fees, dynamic gas estimation, and multi-arch Dockerfiles#10
devin-ai-integration[bot] wants to merge 24 commits into
devfrom
devin/1747591106-deploy-layerzero-contracts

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented May 18, 2025

Copy link
Copy Markdown
Contributor

User description

Implement DVN zero fees, dynamic gas estimation, and multi-arch Dockerfiles

Changes

  • Removed DVN fee parameters since they're always set to zero
  • Removed exec_fee parameters from input requirements, making them optional with a default of zero
  • Implemented dynamic gas estimation for executor fees based on destination chain execution costs
  • Added official LayerZero contract implementations for endpoint and messagelib
  • Created multi-architecture Dockerfiles (arm64/amd64) for building these contract images
  • Added contract deployment scripts for empty networks
  • Modified input parser to handle networks without predefined contract addresses

Implementation Details

  • DVN and exec fees are now optional in the input, defaulting to zero
  • Executor initializes with zero fees and dynamically updates them using gas estimation
  • Added Dockerfiles that pull official LayerZero contracts from GitHub repository
  • Created multi-stage builds to support both arm64 and amd64 architectures
  • Added contract deployment scripts for endpoint and messagelib contracts

Link to Devin run: https://app.devin.ai/sessions/4ec4ef975e7443c19dbf8a7bd808acc3
Requested by: Til Jordan (til@bloctopus.io)


PR Type

Enhancement, Bug fix, Documentation


Description

  • Add automatic deployment for LayerZero Endpoint and MessageLib contracts:

    • Deploys endpoint, send, and receive libraries if not present on a network.
    • Supports networks without predefined contract addresses.
  • Remove DVN fee logic and make exec_fee optional:

    • DVN fees always zero; exec_fee defaults to zero if omitted.
    • Input parser and contract deployers updated accordingly.
  • Implement dynamic executor fee estimation:

    • Executor estimates gas for execution and updates fee on-chain.
    • Adds new contract method and TypeScript logic for fee updates.
  • Add multi-arch Dockerfiles and deployment scripts:

    • Dockerfiles for endpoint and messagelib support arm64/amd64.
    • Entrypoint scripts and build improvements for contract images.
  • Documentation and schema updates:

    • Update README and add schema.yaml for input validation.
    • Add example config for empty networks.

Changes walkthrough 📝

Relevant files
Enhancement
17 files
main.star
Add LayerZero endpoint and library auto-deployment logic 
+34/-5   
input_parser.star
Make exec_fee optional, support empty networks, improve RPC validation
+41/-13 
contract_deployer.star
Remove DVN fee logic, simplify deployment                               
+1/-5     
contract_deployer.star
Make exec_fee optional, update image version                         
+4/-3     
LayerZeroExecutor.ts
Add dynamic gas estimation and executor fee update             
+64/-9   
index.ts
Inject public client for gas estimation                                   
+7/-1     
config.ts
Add executor address to chain config                                         
+2/-0     
SimpleExecutor.sol
Add updateFeeWithGasEstimate method for dynamic fees         
+11/-1   
contract_deployer.star
Add endpoint auto-deployment logic for empty networks       
+27/-0   
send_lib_deployer.star
Add send library auto-deployment logic                                     
+28/-0   
receive_lib_deployer.star
Add receive library auto-deployment logic                               
+27/-0   
Deploy.sol
Add endpoint deployment script for LayerZero                         
+24/-0   
DeploySendLib.sol
Add send library deployment script for LayerZero                 
+34/-0   
Dockerfile
Add multi-arch Dockerfile for endpoint contracts                 
+56/-0   
Dockerfile
Add multi-arch Dockerfile for messagelib contracts             
+70/-0   
entrypoint.sh
Add entrypoint script for endpoint Docker image                   
+4/-0     
entrypoint.sh
Add entrypoint script for messagelib Docker image               
+4/-0     
Bug fix
1 files
DeployReceiveLib.sol
Fix import and contract name for receive lib deployer       
+2/-2     
Documentation
3 files
schema.yaml
Add schema for input validation and documentation               
+66/-0   
network_test_empty.yaml
Add example config for empty local networks                           
+15/-0   
README.md
Update documentation for new features and usage                   
+6/-4     
Additional files
101 files
network_custom.yaml +0/-2     
network_remote.yaml +0/-2     
Dockerfile +0/-21   
package.json +0/-23   
server_launcher.star +0/-18   
index.ts +0/-27   
tsconfig.json +0/-10   
executor_launcher.star +1/-1     
contract_deployer.star +0/-24   
Dockerfile +0/-27   
MessageLibBase.sol +0/-21   
ReceiveLibBaseE2.sol +0/-28   
SendLibBase.sol +0/-258 
SendLibBaseE2.sol +0/-140 
Worker.sol +0/-167 
solidity-files-cache.json +0/-1     
foundry.toml +0/-25   
IExecutor.sol +0/-46   
IExecutorFeeLib.sol +0/-35   
ILayerZeroExecutor.sol +0/-29   
ILayerZeroPriceFeed.sol +0/-61   
ILayerZeroTreasury.sol +0/-19   
IWorker.sol +0/-29   
.gitattributes +0/-1     
ci.yml +0/-128 
sync.yml +0/-31   
CONTRIBUTING.md +0/-193 
LICENSE-APACHE +0/-203 
LICENSE-MIT +0/-25   
README.md +0/-266 
foundry.toml +0/-23   
package.json +0/-16   
vm.py +0/-646 
Base.sol +0/-35   
Script.sol +0/-27   
StdAssertions.sol +0/-669 
StdChains.sol +0/-287 
StdCheats.sol +0/-829 
StdError.sol +0/-15   
StdInvariant.sol +0/-122 
StdJson.sol +0/-283 
StdMath.sol +0/-43   
StdStorage.sol +0/-473 
StdStyle.sol +0/-333 
StdToml.sol +0/-283 
StdUtils.sol +0/-209 
Test.sol +0/-33   
Vm.sol +0/-2263
console.sol +0/-1560
console2.sol +0/-4     
IERC1155.sol +0/-105 
IERC165.sol +0/-12   
IERC20.sol +0/-43   
IERC4626.sol +0/-190 
IERC721.sol +0/-164 
IMulticall3.sol +0/-73   
safeconsole.sol +0/-13937
StdAssertions.t.sol +0/-141 
StdChains.t.sol +0/-227 
StdCheats.t.sol +0/-618 
StdError.t.sol +0/-120 
StdJson.t.sol +0/-49   
StdMath.t.sol +0/-202 
StdStorage.t.sol +0/-488 
StdStyle.t.sol +0/-110 
StdToml.t.sol +0/-49   
StdUtils.t.sol +0/-342 
Vm.t.sol +0/-18   
CompilationScript.sol +0/-10   
CompilationScriptBase.sol +0/-10   
CompilationTest.sol +0/-10   
CompilationTestBase.sol +0/-10   
broadcast.log.json +0/-187 
test.json +0/-8     
test.toml +0/-6     
SafeCall.sol +0/-123 
package.json +0/-51   
LzExecutor.sol +0/-129 
ReceiveUlnBase.sol +0/-125 
SendUlnBase.sol +0/-129 
UlnBase.sol +0/-195 
DVN.sol +0/-349 
DVNFeeLib.sol +0/-145 
MultiSig.sol +0/-104 
CCIPDVNAdapter.sol +0/-150 
CCIPDVNAdapterFeeLib.sol +0/-71   
DVNAdapterBase.sol +0/-112 
AxelarDVNAdapter.sol +0/-141 
AxelarDVNAdapterFeeLib.sol +0/-128 
DVNAdapterMessageCodec.sol +0/-36   
IDVN.sol +0/-25   
IDVNFeeLib.sol +0/-31   
ILayerZeroDVN.sol +0/-34   
IReceiveUlnE2.sol +0/-13   
IAxelarDVNAdapter.sol +0/-45   
IAxelarDVNAdapterFeeLib.sol +0/-49   
ICCIPDVNAdapter.sol +0/-30   
ICCIPDVNAdapterFeeLib.sol +0/-46   
DVNOptions.sol +0/-181 
UlnOptions.sol +0/-176 
Additional files not shown

Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • devin-ai-integration Bot and others added 13 commits May 18, 2025 18:00
    …ibraries for empty networks
    
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    … empty networks, set DVN fees to zero, and implement gas estimation for executor fees
    
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    Co-Authored-By: Til Jordan <til@bloctopus.io>
    @devin-ai-integration

    Copy link
    Copy Markdown
    Contributor Author

    🤖 Devin AI Engineer

    I'll be helping with this pull request! Here's what you should know:

    ✅ I will automatically:

    • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
    • Look at CI failures and help fix them

    Note: I can only respond to comments from users who have write access to this repository.

    ⚙️ Control Options:

    • Disable automatic comment and CI monitoring

    @tiljrd

    tiljrd commented May 18, 2025

    Copy link
    Copy Markdown
    Collaborator

    Could we call it receive_lib_deployer.star instead of just messagelib/contract_deployer.star maybe? Cause it seems like that's what it's doing and would be more consistent with the send lib. Also, it seems like the whole messagelib contract stuff is in this repo but maybe would be better to also pull it from the repo, the same way we're doing it for the endpoint contract stuff.

    @devin-ai-integration

    Copy link
    Copy Markdown
    Contributor Author

    Closing due to inactivity for more than 7 days.

    @tiljrd tiljrd reopened this Jun 1, 2025
    @qodo-code-review

    Copy link
    Copy Markdown

    Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here.

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    The error handling in the execute method catches and logs errors but then rethrows them without specific recovery logic. This could lead to failed transactions without proper fallback mechanisms.

    try {
        const gasEstimate = await this.publicClient.estimateContractGas({
            address: chainConfig.endpoint,
            abi: endpointABI,
            functionName: "lzReceive",
            args: [origin, receiver, guid, message, extraData],
        });
    
        console.log(`Estimated gas for execution: ${gasEstimate}`);
    
        const safetyMultiplier = 1.2;
        const adjustedGasEstimate = BigInt(Math.floor(Number(gasEstimate) * safetyMultiplier));
    
        await this.updateExecutorFee(Number(packet.srcEid), adjustedGasEstimate);
    
        const txResult = await this.walletClient.writeContract({
            address: chainConfig.endpoint,
            abi: endpointABI,
            functionName: "lzReceive",
            args: [origin, receiver, guid, message, extraData],
        });
    
        console.log("Execution submitted:", txResult);
    } catch (error) {
        console.error("Error processing execution:", error);
        throw error;
    }
    Validation Logic

    The input parser now skips chain ID verification for local networks but doesn't validate other critical parameters like private keys or endpoint addresses for these networks.

    # For local networks, skip verification entirely
    is_local_network = network["name"].startswith("local") or "127.0.0.1" in network["rpc"] or "localhost" in network["rpc"]
    
    # Debug output
    plan.print("Network: %s, Is Local: %s, Output: '%s'" % (network["name"], str(is_local_network), result.output))
    
    if is_local_network:
        plan.print("Skipping chain ID verification for local network %s" % network["name"])
    else:
        # Only verify non-local networks
        plan.verify(
            value = result.output,
            assertion = "==",
            target_value = expected_chain_id,
            description = "Verifying chain id for network %s" % network["name"]
        )
    
    Gas Estimation

    The gas estimation uses a hardcoded safety multiplier of 1.2 which may not be sufficient for all chains, especially those with volatile gas prices or complex execution requirements.

    const safetyMultiplier = 1.2;
    const adjustedGasEstimate = BigInt(Math.floor(Number(gasEstimate) * safetyMultiplier));

    @qodo-code-review

    Copy link
    Copy Markdown

    Qodo Merge was enabled for this repository. To continue using it, please link your Git account with your Qodo account here.

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix precision loss risk

    Converting a bigint to Number and back to BigInt can cause precision loss for
    large values, potentially leading to incorrect gas estimates. This is
    particularly risky for high-gas operations on congested networks. Use BigInt
    arithmetic directly to calculate the adjusted gas estimate.

    src/executor/executor/src/LayerZeroExecutor.ts [46-59]

     try {
         const gasEstimate = await this.publicClient.estimateContractGas({
             address: chainConfig.endpoint,
             abi: endpointABI,
             functionName: "lzReceive",
             args: [origin, receiver, guid, message, extraData],
         });
         
         console.log(`Estimated gas for execution: ${gasEstimate}`);
         
    -    const safetyMultiplier = 1.2;
    -    const adjustedGasEstimate = BigInt(Math.floor(Number(gasEstimate) * safetyMultiplier));
    +    // Use BigInt arithmetic directly to avoid precision loss
    +    const safetyMultiplier = 120n;
    +    const adjustedGasEstimate = (gasEstimate * safetyMultiplier) / 100n;
         
         await this.updateExecutorFee(Number(packet.srcEid), adjustedGasEstimate);
    • Apply / Chat
    Suggestion importance[1-10]: 7

    __

    Why: Important fix for potential precision loss when converting BigInt to Number and back. Using BigInt arithmetic directly prevents loss of precision for large gas values.

    Medium
    Propagate fee update errors

    The error in the fee update is silently caught and logged, but execution
    continues without handling the failure. This could lead to inconsistent fee
    states where the executor attempts to process messages with incorrect fee
    settings. Add proper error propagation to ensure the system knows when fee
    updates fail.

    src/executor/executor/src/LayerZeroExecutor.ts [75-108]

     private async updateExecutorFee(srcEid: number, gasEstimate: bigint): Promise<void> {
         try {
             const executorAddress = chainConfig.executor;
             
             const txResult = await this.walletClient.writeContract({
                 address: executorAddress,
                 abi: [
                     {
                         "inputs": [
                             {
                                 "internalType": "uint32",
                                 "name": "dstEid",
                                 "type": "uint32"
                             },
                             {
                                 "internalType": "uint256",
                                 "name": "estimatedGas",
                                 "type": "uint256"
                             }
                         ],
                         "name": "updateFeeWithGasEstimate",
                         "outputs": [],
                         "stateMutability": "nonpayable",
                         "type": "function"
                     }
                 ],
                 functionName: "updateFeeWithGasEstimate",
                 args: [srcEid, gasEstimate],
             });
             console.log(`Updated executor fee for EID ${srcEid} to ${gasEstimate}. Transaction: ${txResult}`);
         } catch (error) {
             console.error("Error updating executor fee:", error);
    +        throw new Error(`Failed to update executor fee: ${error.message}`);
         }
     }
    • Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: Valid improvement to error handling by propagating fee update failures instead of silently catching them. This ensures the calling code is aware when fee updates fail.

    Low
    Security
    Add gas estimate validation

    The function lacks input validation for the estimatedGas parameter. Without
    validation, extremely high gas values could be set accidentally or maliciously
    by the owner, potentially causing transactions to fail or funds to be locked.
    Add a reasonable upper bound check.

    src/executor/executor-contract/src/SimpleExecutor.sol [80-88]

     // Update fee based on estimated gas
     function updateFeeWithGasEstimate(
         uint32 dstEid,
         uint256 estimatedGas
     ) external onlyOwner {
    +    // Validate the gas estimate is within reasonable bounds
    +    require(estimatedGas > 0 && estimatedGas <= 10_000_000, "Invalid gas estimate");
    +    
         // Update the fee with a new estimated gas cost
         messageFees[dstEid] = estimatedGas;
         emit MessageFeeSet(dstEid, estimatedGas);
     }
    • Apply / Chat
    Suggestion importance[1-10]: 6

    __

    Why: Reasonable security improvement by adding bounds checking for gas estimates, though the function is already protected by onlyOwner modifier.

    Low
    • More

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

    Projects

    None yet

    Development

    Successfully merging this pull request may close these issues.

    1 participant