diff --git a/protocol/script/DeterministicDeploy.s.sol b/protocol/script/DeterministicDeploy.s.sol new file mode 100644 index 00000000..ab6275ca --- /dev/null +++ b/protocol/script/DeterministicDeploy.s.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {Script, console} from "forge-std/Script.sol"; +import {DeterministicDeployFactory} from "pod-protocol/DeterministicDeployFactory.sol"; +import {BridgeDepositWithdraw} from "pod-protocol/BridgeDepositWithdraw.sol"; + +contract DeterministicDeployScript is Script { + function run(address factory, uint256 salt, bytes calldata constructorArgs) external { + bytes memory bytecode = type(BridgeDepositWithdraw).creationCode; + bytes memory initCode = abi.encodePacked(bytecode, constructorArgs); + + console.log("Factory:", factory); + console.log("Salt:", salt); + console.log("Bytecode length:", bytecode.length); + console.log("Constructor args length:", constructorArgs.length); + + address predicted = DeterministicDeployFactory(factory).getAddress(initCode, salt); + console.log("Predicted address:", predicted); + + vm.broadcast(); + DeterministicDeployFactory(factory).deploy(initCode, salt); + + console.log("Deployed to:", predicted); + } +} diff --git a/protocol/script/deploy_bridge_deterministic.bash b/protocol/script/deploy_bridge_deterministic.bash new file mode 100755 index 00000000..2a0d87b4 --- /dev/null +++ b/protocol/script/deploy_bridge_deterministic.bash @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Usage: +# ./script/deploy_bridge_deterministic.bash +# ran from protocol folder to grab the .env file + +source .env +# Required env vars +: "${SOURCE_CHAIN_RPC:?}" # e.g. http://127.0.0.1:8546 or Sepolia RPC +: "${PK_SOURCE_CHAIN:?}" # Anvil/Sepolia deployer private key +: "${POD_REGISTRY_ADDR:?}" # PodRegistry address +: "${POD_BRIDGE_ADDR:?}" # Pod BridgeMintBurn address +: "${DETERMINISTIC_FACTORY:?}" # DeterministicDeployFactory address + +# Optional +SALT="${SALT:-0}" + +echo "SOURCE_CHAIN_RPC: $SOURCE_CHAIN_RPC" +echo "POD_REGISTRY_ADDR: $POD_REGISTRY_ADDR" +echo "POD_BRIDGE_ADDR: $POD_BRIDGE_ADDR" +echo "DETERMINISTIC_FACTORY: $DETERMINISTIC_FACTORY" +echo "SALT: $SALT" + +CONSTRUCTOR_ARGS=$(cast abi-encode "constructor(address,address)" "$POD_REGISTRY_ADDR" "$POD_BRIDGE_ADDR") + +forge script script/DeterministicDeploy.s.sol:DeterministicDeployScript \ + --sig "run(address,uint256,bytes)" \ + "$DETERMINISTIC_FACTORY" "$SALT" "$CONSTRUCTOR_ARGS" \ + --rpc-url "$SOURCE_CHAIN_RPC" \ + --private-key "$PK_SOURCE_CHAIN" \ + --broadcast + +echo "Done." diff --git a/protocol/src/DeterministicDeployFactory.sol b/protocol/src/DeterministicDeployFactory.sol new file mode 100644 index 00000000..d629f6b4 --- /dev/null +++ b/protocol/src/DeterministicDeployFactory.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; +contract DeterministicDeployFactory { + event Deploy(address addr); + + function deploy(bytes memory bytecode, uint _salt) external { + address addr; + + assembly { + addr := create2( + 0, + add(bytecode, 0x20), // Skip the first 32 bytes which contain the length of the bytecode + mload(bytecode), // Load the length of the bytecode + _salt + ) + if iszero(extcodesize(addr)) { + revert(0, 0) + } + } + emit Deploy(addr); + } + + function getAddress(bytes memory bytecode, uint _salt) public view returns (address) { + bytes32 hash = keccak256( + abi.encodePacked( + bytes1(0xff), address(this), _salt, keccak256(bytecode) + ) + ); + + return address (uint160(uint(hash))); + } +}