Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
2f10afe
feat: add verification scripts for proxy and implementation contracts
gfournierPro Jul 21, 2025
0ba9d73
feat: refactor verification targets to use reusable functions for pro…
gfournierPro Jul 21, 2025
27cf969
Merge branch 'main' into feature/re-add-verification-script
gfournierPro Jul 21, 2025
c36f051
feat: change folder from scripts/ to tools/
gfournierPro Jul 21, 2025
bec88aa
feat: simplify address extraction logic in get_config_address.sh
gfournierPro Jul 21, 2025
9cc00a4
feat: update constructor argument handling in verification scripts
gfournierPro Jul 21, 2025
2829f2d
feat: streamline implementation verification process in verification.mk
gfournierPro Jul 21, 2025
e6d06b1
feat: replace bash scripts with Solidity implementation for configura…
gfournierPro Jul 21, 2025
7158c40
feat: remove commented-out code for lzChainId in GetConfigInfo script
gfournierPro Jul 21, 2025
0410d89
feat: remove outdated comments and documentation from verification.mk
gfournierPro Jul 21, 2025
29d5af6
fix: forge fmt
gfournierPro Jul 22, 2025
c25f1c7
feat: update GetConfigInfo script to use config field names and impro…
gfournierPro Jul 22, 2025
61a0c49
fix: forge fmt
gfournierPro Jul 22, 2025
013ce86
feat: remove unused import of ConfigLib from GetConfigInfo script
gfournierPro Jul 22, 2025
e1d927e
fix: update GetConfigInfo script to retrieve rlcAddress instead of rl…
gfournierPro Jul 22, 2025
ec8391b
refactor: simplify GetConfigInfo script by removing chain parameter a…
gfournierPro Jul 22, 2025
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
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MAKEFLAGS += --no-print-directory

include report.mk
include tools/report.mk tools/verification.mk
-include .env


Expand Down
68 changes: 68 additions & 0 deletions script/GetConfigInfo.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: 2025 IEXEC BLOCKCHAIN TECH <[email protected]>
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.22;

import {Script} from "forge-std/Script.sol";
import {console} from "forge-std/console.sol";
import {stdJson} from "forge-std/StdJson.sol";
import {Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol";

/**
* @title GetConfigInfo
* @dev Script to extract configuration information and proxy implementation addresses.
* Replaces bash scripts with type-safe Solidity implementation.
*
* Usage examples:
* - Get config field: forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" "sepolia" "rlcCrosschainTokenAddress"
* - Get implementation: forge script script/GetConfigInfo.s.sol --sig "getImplementationAddress(string,string)" "sepolia" "rlcCrosschainTokenAddress"
*/
contract GetConfigInfo is Script {
using stdJson for string;
/**
* @dev Get a configuration field value for a specific chain
* @param chain The chain identifier (e.g., "sepolia", "arbitrum_sepolia")
* @param field The field name to retrieve
*/

function getConfigField(string calldata chain, string calldata field) external view {
address value = _getConfigFieldAddress(chain, field);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not:

    function getConfigField(string calldata path) external view {
        string memory config = vm.readFile("config/config.json");
        address value = config.readAddress(path);
        ...

and call it with .initialAdmin and .chains.sepolia.rlcLiquidityUnifierAddress

console.log(value);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function really necessary ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To mutualise the _getConfigFieldAddress btw getConfigField and getImplementationAddress


/**
* @dev Internal helper to get a configuration field value for a specific chain
* @param chain The chain identifier (e.g., "sepolia", "arbitrum_sepolia")
* @param field The field name to retrieve
* @return The address value for the specified field
*/
function _getConfigFieldAddress(string memory chain, string memory field) internal view returns (address) {
string memory config = vm.readFile("config/config.json");
string memory prefix = string.concat(".chains.", chain);

bytes32 fieldHash = keccak256(bytes(field));
if (
fieldHash == keccak256("initialAdmin") || fieldHash == keccak256("initialPauser")
|| fieldHash == keccak256("initialUpgrader") || fieldHash == keccak256("createxFactory")
) {
return config.readAddress(string.concat(".", field));
}
return config.readAddress(string.concat(prefix, ".", field));
}

/**
* @dev Get the implementation address of a proxy contract
* @param chain The chain identifier
* @param proxyField The config field containing the proxy address
*/
function getImplementationAddress(string calldata chain, string calldata proxyField) external view {
address proxyAddress = _getConfigFieldAddress(chain, proxyField);
if (proxyAddress == address(0)) {
console.log("Error: Proxy address is zero for field '%s'", proxyField);
revert("Zero proxy address");
}
// Get implementation address using OpenZeppelin's Upgrades library
address impl = Upgrades.getImplementationAddress(proxyAddress);
console.log(impl);
}
}
File renamed without changes.
127 changes: 127 additions & 0 deletions tools/verification.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@

# ========================================================================
# SMART CONTRACT VERIFICATION
# ========================================================================
# Chain IDs for supported networks
SEPOLIA_CHAIN_ID := 11155111
ARBITRUM_SEPOLIA_CHAIN_ID := 421614

# ========================================================================
# VERIFICATION FUNCTIONS
# ========================================================================

# Verify ERC1967 proxy contracts
# Parameters: CONTRACT_NAME, NETWORK, CONFIG_KEY, CHAIN_ID, DISPLAY_NAME
define verify-proxy
@echo "Verifying $(1) Proxy on $(5)..."
forge verify-contract \
--chain-id $(4) \
--watch \
--etherscan-api-key $(ETHERSCAN_API_KEY) \
$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" $(2) $(3) 2>/dev/null | grep "0x" | tail -n1) \
lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy
@echo "Proxy verification completed for $(1) on $(5)"
endef

# Verify implementation contracts with optional constructor arguments
# Parameters: CONTRACT_NAME, NETWORK, CONFIG_KEY, CHAIN_ID, DISPLAY_NAME, CONTRACT_PATH, RPC_URL, CONSTRUCTOR_ARGS
define verify-impl
@echo "Verifying $(1) Implementation on $(5)..."
@proxy_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" $(2) $(3) 2>/dev/null | grep "0x" | tail -n1); \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@proxy_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" $(2) $(3) 2>/dev/null | grep "0x" | tail -n1); \
@proxy_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" $(2) $(3) 2>/dev/null | grep "0x" | tail -n1);

And all others.

impl_address=$$(forge script script/GetConfigInfo.s.sol --sig "getImplementationAddress(string,string)" $(2) $(3) --rpc-url $(7) 2>/dev/null | grep "0x" | tail -n1); \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
impl_address=$$(forge script script/GetConfigInfo.s.sol --sig "getImplementationAddress(string,string)" $(2) $(3) --rpc-url $(7) 2>/dev/null | grep "0x" | tail -n1); \
@impl_address=$$(forge script script/GetConfigInfo.s.sol --sig "getImplementationAddress(string,string)" $(2) $(3) --rpc-url $(7) 2>/dev/null | grep "0x" | tail -n1);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to do so but can't make it work

echo "Proxy address: $$proxy_address"; \
echo "Implementation address: $$impl_address"; \
forge verify-contract \
--chain-id $(4) \
--watch \
$(8) \
--etherscan-api-key $(ETHERSCAN_API_KEY) \
$$impl_address \
$(6); \
echo "Implementation verification completed for $(1) on $(5)"; \
echo ""
endef

# ========================================================================
# SEPOLIA NETWORK VERIFICATION
# ========================================================================

# Proxy Verifications - Sepolia
# -----------------------------
verify-rlc-liquidity-unifier-proxy-sepolia:
$(call verify-proxy,RLCLiquidityUnifier,sepolia,rlcLiquidityUnifierAddress,$(SEPOLIA_CHAIN_ID),Sepolia Etherscan)

verify-layerzero-bridge-proxy-sepolia:
$(call verify-proxy,IexecLayerZeroBridge,sepolia,iexecLayerZeroBridgeAddress,$(SEPOLIA_CHAIN_ID),Sepolia Etherscan)

# Implementation Verifications - Sepolia
# --------------------------------------
verify-rlc-liquidity-unifier-impl-sepolia:
@rlc_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" sepolia rlcAddress 2>/dev/null | grep "0x" | tail -n1); \
constructor_args=$$(cast abi-encode "constructor(address)" $$rlc_address); \
$(MAKE) _verify-rlc-liquidity-unifier-impl-sepolia CONSTRUCTOR_ARGS="--constructor-args $$constructor_args"

_verify-rlc-liquidity-unifier-impl-sepolia:
$(call verify-impl,RLCLiquidityUnifier,sepolia,rlcLiquidityUnifierAddress,$(SEPOLIA_CHAIN_ID),Sepolia Etherscan,src/RLCLiquidityUnifier.sol:RLCLiquidityUnifier,$(SEPOLIA_RPC_URL),$(CONSTRUCTOR_ARGS))

verify-layerzero-bridge-impl-sepolia:
@echo "Building constructor arguments for IexecLayerZeroBridge..."
@rlc_liquidity_unifier_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" sepolia rlcLiquidityUnifierAddress 2>/dev/null | grep "0x" | tail -n1); \
lz_endpoint_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" sepolia lzEndpointAddress 2>/dev/null | grep "0x" | tail -n1); \
constructor_args=$$(cast abi-encode "constructor(bool,address,address)" true $$rlc_liquidity_unifier_address $$lz_endpoint_address); \
$(MAKE) _verify-layerzero-bridge-impl-sepolia CONSTRUCTOR_ARGS="--constructor-args $$constructor_args"

_verify-layerzero-bridge-impl-sepolia:
$(call verify-impl,IexecLayerZeroBridge,sepolia,iexecLayerZeroBridgeAddress,$(SEPOLIA_CHAIN_ID),Sepolia Etherscan,src/bridges/layerZero/IexecLayerZeroBridge.sol:IexecLayerZeroBridge,$(SEPOLIA_RPC_URL),$(CONSTRUCTOR_ARGS))

# ========================================================================
# ARBITRUM SEPOLIA NETWORK VERIFICATION
# ========================================================================

# Proxy Verifications - Arbitrum Sepolia
# ---------------------------------------
verify-rlc-crosschain-token-proxy-arbitrum-sepolia:
$(call verify-proxy,RLCCrosschainToken,arbitrum_sepolia,rlcCrosschainTokenAddress,$(ARBITRUM_SEPOLIA_CHAIN_ID),Arbitrum Sepolia)

verify-layerzero-bridge-proxy-arbitrum-sepolia:
$(call verify-proxy,IexecLayerZeroBridge,arbitrum_sepolia,iexecLayerZeroBridgeAddress,$(ARBITRUM_SEPOLIA_CHAIN_ID),Arbitrum Sepolia)

# Implementation Verifications - Arbitrum Sepolia
# ------------------------------------------------
verify-rlc-crosschain-token-impl-arbitrum-sepolia:
$(call verify-impl,RLCCrosschainToken,arbitrum_sepolia,rlcCrosschainTokenAddress,$(ARBITRUM_SEPOLIA_CHAIN_ID),Arbitrum Sepolia,src/RLCCrosschainToken.sol:RLCCrosschainToken,$(ARBITRUM_SEPOLIA_RPC_URL),)

verify-layerzero-bridge-impl-arbitrum-sepolia:
@echo "Building constructor arguments for IexecLayerZeroBridge..."
@rlc_crosschain_token_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" arbitrum_sepolia rlcCrosschainTokenAddress 2>/dev/null | grep "0x" | tail -n1); \
lz_endpoint_address=$$(forge script script/GetConfigInfo.s.sol --sig "getConfigField(string,string)" arbitrum_sepolia lzEndpointAddress 2>/dev/null | grep "0x" | tail -n1); \
constructor_args=$$(cast abi-encode "constructor(bool,address,address)" false $$rlc_crosschain_token_address $$lz_endpoint_address); \
$(MAKE) _verify-layerzero-bridge-impl-arbitrum-sepolia CONSTRUCTOR_ARGS="--constructor-args $$constructor_args"

_verify-layerzero-bridge-impl-arbitrum-sepolia:
$(call verify-impl,IexecLayerZeroBridge,arbitrum_sepolia,iexecLayerZeroBridgeAddress,$(ARBITRUM_SEPOLIA_CHAIN_ID),Arbitrum Sepolia,src/bridges/layerZero/IexecLayerZeroBridge.sol:IexecLayerZeroBridge,$(ARBITRUM_SEPOLIA_RPC_URL),$(CONSTRUCTOR_ARGS))

# ========================================================================
# PROXY AND IMPLEMENTATION VERIFICATION
# ========================================================================
verify-proxies-sepolia: verify-rlc-liquidity-unifier-proxy-sepolia verify-layerzero-bridge-proxy-sepolia
verify-proxies-arbitrum-sepolia: verify-rlc-crosschain-token-proxy-arbitrum-sepolia verify-layerzero-bridge-proxy-arbitrum-sepolia
verify-proxies-testnets: verify-proxies-sepolia verify-proxies-arbitrum-sepolia

verify-implementations-sepolia: verify-rlc-liquidity-unifier-impl-sepolia verify-layerzero-bridge-impl-sepolia
verify-implementations-arbitrum-sepolia: verify-rlc-crosschain-token-impl-arbitrum-sepolia verify-layerzero-bridge-impl-arbitrum-sepolia
verify-implementations-testnets: verify-implementations-sepolia verify-implementations-arbitrum-sepolia


# ========================================================================
# COMPLETION TARGETS
Copy link

Copilot AI Jul 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent tab usage in comment formatting. This line uses tabs while other comment lines use spaces for alignment.

Suggested change
# COMPLETION TARGETS
# COMPLETION TARGETS

Copilot uses AI. Check for mistakes.
# ========================================================================

verify-all-sepolia: verify-proxies-sepolia verify-implementations-sepolia
verify-all-arbitrum-sepolia: verify-proxies-arbitrum-sepolia verify-implementations-arbitrum-sepolia
verify-all-testnets: verify-all-sepolia verify-all-arbitrum-sepolia


.PHONY: verify-all-testnets verify-all-sepolia verify-all-arbitrum-sepolia \
verify-proxies-sepolia verify-proxies-arbitrum-sepolia verify-proxies-testnets \
verify-implementations-sepolia verify-implementations-arbitrum-sepolia verify-implementations-testnets