diff --git a/.vscode/settings.json b/.vscode/settings.json index 00c61618..68705c52 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,8 @@ { - "solidity.compileUsingRemoteVersion": "v0.8.13+commit.abaa5c0e" + "workbench.colorCustomizations": { + "statusBar.background": "#7C21D7", + "statusBar.debuggingBackground": "#7C21D7", + "statusBar.noFolderBackground": "#7C21D7", + "statussBar.prominentBackground": "#7C21D7" + } } \ No newline at end of file diff --git a/deploy/11_layer_zero.ts b/deploy/11_layer_zero.ts index 87e849f0..eeec020c 100755 --- a/deploy/11_layer_zero.ts +++ b/deploy/11_layer_zero.ts @@ -21,7 +21,7 @@ const func: DeployFunction = async function (hre1: HardhatRuntimeEnvironment) { const currentNetworkType: NetworkType = networks[hre.networkName].type; let lzEndpoint = networks[hre.networkName].lzEndpoint.toLowerCase(); - if (lzEndpoint && lzEndpoint !== zeroAddress) { + if (lzEndpoint) { if (currentNetworkType === NetworkType.local && lzEndpoint === zeroAddress) { lzEndpoint = (await hre.getNamedAccounts()).lzEndpoint; const mockLZEndpoint = await hre.deployments.deploy('MockLZEndpoint', { @@ -32,13 +32,14 @@ const func: DeployFunction = async function (hre1: HardhatRuntimeEnvironment) { gasLimit: await hre.ethers.provider.estimateGas( (await hre.ethers.getContractFactory('MockLZEndpoint')).getDeployTransaction() ), - nonce: await hre.ethers.provider.getTransactionCount(lzEndpoint), + // nonce: await hre.ethers.provider.getTransactionCount(lzEndpoint), })), args: [], log: true, waitConfirmations: 1, } as any); lzEndpoint = mockLZEndpoint.address.toLowerCase(); + console.log(`Deployed MockLZEndpoint to: ${mockLZEndpoint.address}`); } const layerZeroModuleProxy = await hre.ethers.getContract('LayerZeroModuleProxy', deployerAddress); diff --git a/src/HolographBridge.sol b/src/HolographBridge.sol index 47896671..97a02952 100644 --- a/src/HolographBridge.sol +++ b/src/HolographBridge.sol @@ -112,7 +112,7 @@ import "./interface/HolographFactoryInterface.sol"; import "./interface/HolographOperatorInterface.sol"; import "./interface/HolographRegistryInterface.sol"; import "./interface/InitializableInterface.sol"; - +import {console} from "forge-std/Test.sol"; /** * @title Holograph Bridge * @author https://github.com/holographxyz @@ -354,6 +354,7 @@ contract HolographBridge is Admin, Initializable, HolographBridgeInterface { "HOLOGRAPH: not holographed" ); bytes memory payload; + console.log("############## HolographBridge 1 "); /** * @dev the revertedBridgeOutRequest function is wrapped into a try/catch function */ @@ -363,11 +364,14 @@ contract HolographBridge is Admin, Initializable, HolographBridgeInterface { /** * @dev a non reverted result is actually a revert */ + console.log("############## HolographBridge 2 "); + console.log(revertReason); revert(revertReason); } catch (bytes memory realResponse) { /** * @dev a revert is actually success, so the return data is stored as payload */ + console.log("############## HolographBridge 3 "); payload = realResponse; } uint256 jobNonce; @@ -378,6 +382,7 @@ contract HolographBridge is Admin, Initializable, HolographBridgeInterface { * @dev extract hlgFee from operator */ uint256 fee = 0; + console.log("############## HolographBridge 4 "); if (gasPrice < type(uint256).max && gasLimit < type(uint256).max) { (uint256 hlgFee, , uint256 dstGasPrice) = _operator().getMessageFee( toChain, @@ -393,6 +398,7 @@ contract HolographBridge is Admin, Initializable, HolographBridgeInterface { /** * @dev the data is abi encoded into actual bridgeOutRequest payload bytes */ + console.log("############## HolographBridge 5 "); bytes memory encodedData = abi.encodeWithSelector( HolographBridgeInterface.bridgeInRequest.selector, /** @@ -407,6 +413,7 @@ contract HolographBridge is Admin, Initializable, HolographBridgeInterface { true, payload ); + console.log("############## HolographBridge 6 "); /** * @dev this abi encodes the data just like in Holograph Operator */ diff --git a/src/HolographFactory.sol b/src/HolographFactory.sol index 42902499..f94217cd 100644 --- a/src/HolographFactory.sol +++ b/src/HolographFactory.sol @@ -119,6 +119,7 @@ import "./struct/Verification.sol"; import "./library/Strings.sol"; +import {console} from "forge-std/Test.sol"; /** * @title Holograph Factory * @author https://github.com/holographxyz @@ -233,6 +234,14 @@ contract HolographFactory is Admin, Initializable, Holographable, HolographFacto /** * @dev the configuration is encoded and hashed along with signer address */ + console.log("------- Factory - config.contractType: "); + console.logBytes32(config.contractType); + console.log("------- Factory - config.chainType: "); + console.logUint(config.chainType); + console.log("------- Factory - config.salt: "); + console.logBytes32(config.salt); + console.log("------- Factory - config.signer: "); + console.logAddress(signer); bytes32 hash = keccak256( abi.encodePacked( config.contractType, @@ -243,10 +252,29 @@ contract HolographFactory is Admin, Initializable, Holographable, HolographFacto signer ) ); + console.log("------- Factory - hash: "); + console.logBytes32(hash); + if (hash == 0xa3a2316b8119471cb8f7f5d293ef00c9a2544864c2cc4ac7efaadfb71736b99e) { + console.log("sample found"); + console.log("------- Factory - config.byteCode: "); + console.logBytes32(keccak256(config.byteCode)); + console.log("------- Factory - config.initCode: "); + console.logBytes32(keccak256(config.initCode)); + } /** * @dev the hash is validated against signature * this is to guarantee that the original creator's configuration has not been altered */ + console.log("------- Factory - signatyre.r: "); + console.logBytes32(signature.r); + console.log("------- Factory - signatyre.s: "); + console.logBytes32(signature.s); + console.log("------- Factory - signatyre.v: "); + console.logUint(signature.v); + console.log("------- Factory - hash: "); + console.logBytes32(hash); + console.log("------- Factory - signer: "); + console.logAddress(signer); require(_verifySigner(signature.r, signature.s, signature.v, hash, signer), "HOLOGRAPH: invalid signature"); /** * @dev check that this contract has not already been deployed on this chain @@ -255,6 +283,8 @@ contract HolographFactory is Admin, Initializable, Holographable, HolographFacto address holographerAddress = address( uint160(uint256(keccak256(abi.encodePacked(bytes1(0xff), address(this), hash, keccak256(holographerBytecode))))) ); + console.log("------- Factory - holographerAddress 1 : "); + console.logAddress(holographerAddress); require(!_isContract(holographerAddress), "HOLOGRAPH: already deployed"); /** * @dev convert hash into uint256 which will be used as the salt for create2 @@ -262,6 +292,8 @@ contract HolographFactory is Admin, Initializable, Holographable, HolographFacto uint256 saltInt = uint256(hash); address sourceContractAddress; bytes memory sourceByteCode = config.byteCode; + console.log("------- Factory - saltInt: "); + console.logUint(saltInt); assembly { /** * @dev deploy the user created smart contract first @@ -277,16 +309,28 @@ contract HolographFactory is Admin, Initializable, Holographable, HolographFacto /** * @dev initialize the Holographer contract */ + console.log("------- Factory - InitializableInterface.init.selector: "); + console.logBytes4(InitializableInterface.init.selector); + console.log("------- Factory - initializableinterface"); + // console.logBytes4(InitializableInterface(holographerAddress).init( + // abi.encode(abi.encode(config.chainType, holograph, config.contractType, sourceContractAddress), config.initCode) + // )); require( InitializableInterface(holographerAddress).init( abi.encode(abi.encode(config.chainType, holograph, config.contractType, sourceContractAddress), config.initCode) ) == InitializableInterface.init.selector, "initialization failed" ); + console.log("------- Factory - si paso"); /** + * * @dev update the Holograph Registry with deployed contract address */ HolographRegistryInterface(registry).setHolographedHashAddress(hash, holographerAddress); + console.log("------- Factory - holographerAddress 2 : "); + console.logAddress(holographerAddress); + console.log("------- Factory - hash: "); + console.logBytes32(hash); /** * @dev emit an event that on-chain indexers can easily read */ diff --git a/src/HolographOperator.sol b/src/HolographOperator.sol index a5742043..5a39048c 100644 --- a/src/HolographOperator.sol +++ b/src/HolographOperator.sol @@ -115,6 +115,7 @@ import "./interface/HolographInterfacesInterface.sol"; import "./interface/Ownable.sol"; import "./struct/OperatorJob.sol"; +import {console} from "forge-std/Test.sol"; /** * @title Holograph Operator @@ -497,6 +498,9 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { * @dev This function is restricted for use by Holograph Messaging Module only */ function crossChainMessage(bytes calldata bridgeInRequestPayload) external payable { + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 1"); + console.logAddress(msg.sender); + console.logAddress(address(_messagingModule())); require(msg.sender == address(_messagingModule()), "HOLOGRAPH: messaging only call"); uint256 gasPrice = 0; assembly { @@ -506,8 +510,10 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { gasPrice := calldataload(sub(add(bridgeInRequestPayload.offset, bridgeInRequestPayload.length), 0x20)) } bool underpriced = gasPrice < _minGasPrice(); + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 2"); unchecked { bytes32 jobHash = keccak256(bridgeInRequestPayload); + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 3"); /** * @dev load and increment operator temp storage in one call */ @@ -516,12 +522,14 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { * @dev use job hash, job nonce, block number, and block timestamp for generating a random number */ uint256 random = uint256(keccak256(abi.encodePacked(jobHash, _jobNonce(), block.number, block.timestamp))); + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 4"); // use the left 128 bits of random number uint256 random1 = uint256(random >> 128); // use the right 128 bits of random number uint256 random2 = uint256(uint128(random)); // combine the two new random numbers for use in additional pod operator selection logic random = uint256(keccak256(abi.encodePacked(random1 + random2))); + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 5"); /** * @dev divide by total number of pods, use modulus/remainder */ @@ -530,6 +538,7 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { * @dev identify the total number of available operators in pod */ uint256 podSize = _operatorPods[pod].length; + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 6"); /** * @dev select a primary operator */ @@ -541,6 +550,7 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { */ _operatorTempStorage[_operatorTempStorageCounter] = _operatorPods[pod][operatorIndex]; _popOperator(pod, operatorIndex); + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 7"); if (podSize > 1) { podSize--; } @@ -559,6 +569,8 @@ contract HolographOperator is Admin, Initializable, HolographOperatorInterface { /** * @dev emit event to signal to operators that a job has become available */ + console.log("$$$$$$$$$$$$$ Operator crossChainMessage 7"); + console.logBytes32(jobHash); emit AvailableOperatorJob(jobHash, bridgeInRequestPayload); } } diff --git a/test/foundry/deploy/06_CrossChainMinting.t.sol b/test/foundry/deploy/06_CrossChainMinting.t.sol new file mode 100644 index 00000000..f4a01090 --- /dev/null +++ b/test/foundry/deploy/06_CrossChainMinting.t.sol @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.13; + +import {Test, Vm, console} from "forge-std/Test.sol"; +import {Constants} from "../utils/Constants.sol"; + +import {Holograph} from "../../../src/Holograph.sol"; +import {HolographBridge} from "../../../src/HolographBridge.sol"; +import {HolographRegistry} from "../../../src/HolographRegistry.sol"; +import {HolographFactory} from "../../../src/HolographFactory.sol"; +import {HolographOperator, OperatorJob} from "../../../src/HolographOperator.sol"; + +import {LayerZeroModule, GasParameters} from "../../../src/module/LayerZeroModule.sol"; +import {HolographERC20} from "../../../src/enforcer/HolographERC20.sol"; +import {Holographer} from "../../../src/enforcer/Holographer.sol"; +import {HolographERC721} from "../../../src/enforcer/HolographERC721.sol"; +import {SampleERC721} from "../../../src/token/SampleERC721.sol"; +import {MockLZEndpoint} from "../../../src/mock/MockLZEndpoint.sol"; +import {Verification} from "../../../src/struct/Verification.sol"; +import {DeploymentConfig} from "../../../src/struct/DeploymentConfig.sol"; +import {SampleERC20} from "../../../src/token/SampleERC20.sol"; + +import {HolographRegistry} from "../../../src/HolographRegistry.sol"; + +import {HolographEvents} from "../utils/HolographEvents.sol"; + +contract CrossChainMinting is Test, HolographEvents { + event BridgeableContractDeployed(address indexed contractAddress, bytes32 indexed hash); + + uint256 public chain1; + uint256 public chain2; + string public LOCALHOST_RPC_URL = vm.envString("LOCALHOST_RPC_URL"); + string public LOCALHOST2_RPC_URL = vm.envString("LOCALHOST2_RPC_URL"); + uint256 privateKeyDeployer = 0xff22437ccbedfffafa93a9f1da2e8c19c1711052799acf3b58ae5bebb5c6bd7b; + address deployer = vm.addr(privateKeyDeployer); + + uint32 holographIdChain1 = 4294967294; + uint32 holographIdChain2 = 4294967293; + + uint256 constant BLOCKTIME = 60; + uint256 constant GWEI = 1000000000; // 1 Gwei + uint256 constant TESTGASLIMIT = 10000000; // Gas limit + uint256 constant GASPRICE = 1000000000; // 1 Gwei as gas price + + uint256 msgBaseGas; + uint256 msgGasPerByte; + uint256 jobBaseGas; + uint256 jobGasPerByte; + + Holograph holographChain1; + Holograph holographChain2; + HolographOperator holographOperatorChain1; + HolographOperator holographOperatorChain2; + Holographer utilityTokenHolographerChain1; + Holographer utilityTokenHolographerChain2; + MockLZEndpoint mockLZEndpointChain1; + MockLZEndpoint mockLZEndpointChain2; + HolographFactory holographFactoryChain1; + HolographFactory holographFactoryChain2; + HolographBridge holographBridgeChain1; + HolographBridge holographBridgeChain2; + LayerZeroModule lzModuleChain1; + LayerZeroModule lzModuleChain2; + + HolographRegistry holographRegistryChain1; + HolographRegistry holographRegistryChain2; + + // address public deployer; + address public alice; + address public bob; + address public charlie; + + struct ERC20ConfigParams { + string network; + address deployer; + string contractName; + string tokenName; + string tokenSymbol; + string domainSeparator; + string domainVersion; + uint8 decimals; + bytes eventConfig; + bytes initCodeParam; + string salt; + } + + struct EstimatedGas { + bytes payload; + uint256 estimatedGas; + uint256 fee; + uint256 hlgFee; + uint256 msgFee; + uint256 dstGasPrice; + } + + function getLzMsgGas(bytes memory _payload) public view returns (uint256) { + uint256 payloadLength = _payload.length; + uint256 additionalGas = (payloadLength - 2) / 2; + uint256 totalGas = msgBaseGas + (additionalGas * msgGasPerByte); + return totalGas; + } + + function getHlgMsgGas(uint256 _gasLimit, bytes memory _payload) public view returns (uint256) { + uint256 payloadLength = _payload.length; + uint256 additionalGas = (payloadLength - 2) / 2; + uint256 totalGas = _gasLimit + jobBaseGas + (additionalGas * jobGasPerByte); + return totalGas; + } + + function getRequestPayload(address _target, bytes memory _data) public returns (bytes memory) { + vm.selectFork(chain1); + vm.prank(deployer); + return + holographBridgeChain1.getBridgeOutRequestPayload( + holographIdChain2, + _target, + type(uint256).max, + type(uint256).max, + _data + ); + } + + function getEstimatedGas( + address _target, + bytes memory _data, + bytes memory _payload + ) public returns (EstimatedGas memory) { + vm.selectFork(chain2); + (bool success, bytes memory result) = address(holographOperatorChain2).call{gas: TESTGASLIMIT}( + abi.encodeWithSelector(holographOperatorChain2.jobEstimator.selector, _payload) + ); + uint256 jobEstimatorGas = abi.decode(result, (uint256)); + uint256 estimatedGas = TESTGASLIMIT - jobEstimatorGas; + + vm.selectFork(chain1); + vm.prank(deployer); + bytes memory payload = holographBridgeChain1.getBridgeOutRequestPayload( + holographIdChain2, + _target, + estimatedGas, + GWEI, + _data + ); + + (uint256 fee1, uint256 fee2, uint256 fee3) = holographBridgeChain1.getMessageFee( + holographIdChain2, + estimatedGas, + GWEI, + payload + ); + + uint256 total = fee1 + fee2; + + vm.selectFork(chain2); + vm.prank(deployer); + (bool success2, bytes memory result2) = address(holographOperatorChain2).call{gas: TESTGASLIMIT, value: total}( + abi.encodeWithSelector(holographOperatorChain2.jobEstimator.selector, payload) + ); + + uint256 jobEstimatorGas2 = abi.decode(result2, (uint256)); + + estimatedGas = TESTGASLIMIT - jobEstimatorGas2; + + estimatedGas = getHlgMsgGas(estimatedGas, payload); + + return + EstimatedGas({ + payload: payload, + estimatedGas: estimatedGas, + fee: total, + hlgFee: fee1, + msgFee: fee2, + dstGasPrice: fee3 + }); + + // return EstimatedGas({ + // payload: _payload, + // estimatedGas: 0, + // fee: 0, + // hlgFee: 0, + // msgFee: 0, + // dstGasPrice: 0 + // }); + } + + function setUp() public { + chain1 = vm.createFork(LOCALHOST_RPC_URL); + chain2 = vm.createFork(LOCALHOST2_RPC_URL); + + vm.selectFork(chain1); + holographChain1 = Holograph(payable(Constants.getHolograph())); + holographOperatorChain1 = HolographOperator(payable(Constants.getHolographOperatorProxy())); + holographRegistryChain1 = HolographRegistry(payable(Constants.getHolographRegistryProxy())); + mockLZEndpointChain1 = MockLZEndpoint(payable(Constants.getMockLZEndpoint())); + holographFactoryChain1 = HolographFactory(payable(Constants.getHolographFactoryProxy())); + holographBridgeChain1 = HolographBridge(payable(Constants.getHolographBridgeProxy())); + lzModuleChain1 = LayerZeroModule(payable(Constants.getLayerZeroModuleProxy())); + + GasParameters memory gasParams = lzModuleChain1.getGasParameters(holographIdChain1); + msgBaseGas = gasParams.msgBaseGas; + msgGasPerByte = gasParams.msgGasPerByte; + jobBaseGas = gasParams.jobBaseGas; + jobGasPerByte = gasParams.jobGasPerByte; + + vm.selectFork(chain2); + holographChain2 = Holograph(payable(Constants.getHolograph())); + holographOperatorChain2 = HolographOperator(payable(Constants.getHolographOperatorProxy())); + holographRegistryChain2 = HolographRegistry(payable(Constants.getHolographRegistryProxy())); + mockLZEndpointChain2 = MockLZEndpoint(payable(Constants.getMockLZEndpoint())); + holographFactoryChain2 = HolographFactory(payable(Constants.getHolographFactoryProxy())); + holographBridgeChain2 = HolographBridge(payable(Constants.getHolographBridgeProxy())); + lzModuleChain2 = LayerZeroModule(payable(Constants.getLayerZeroModuleProxy())); + + _setupAccounts(); + } + + /// @dev Initializes testing accounts. + function _setupAccounts() private { + deployer = vm.addr(0xff22437ccbedfffafa93a9f1da2e8c19c1711052799acf3b58ae5bebb5c6bd7b); + alice = vm.addr(1); + bob = vm.addr(2); + } + + // Enable operators for chain1 and chain2 + + // should add 10 operator wallets for each chain + function testAddOperators() public { + vm.selectFork(chain1); + HolographERC20 HLGCHAIN1 = HolographERC20(payable(Constants.getHolographUtilityToken())); + vm.selectFork(chain2); + HolographERC20 HLGCHAIN2 = HolographERC20(payable(Constants.getHolographUtilityToken())); + + address[] memory wallets = new address[](10); // Array to hold operator addresses + + // generate 10 operator wallets + for (uint i = 0; i < 10; i++) { + wallets[i] = address(uint160(uint(keccak256(abi.encodePacked(block.timestamp, i))))); + } + + vm.selectFork(chain1); + (uint256 bondAmount, ) = holographOperatorChain1.getPodBondAmounts(1); + + for (uint i = 0; i < wallets.length; i++) { + address wallet = wallets[i]; + + vm.selectFork(chain1); + vm.prank(deployer); + HLGCHAIN1.transfer(wallet, bondAmount); + vm.startPrank(wallet); + HLGCHAIN1.approve(address(holographOperatorChain1), bondAmount); + holographOperatorChain1.bondUtilityToken(wallet, bondAmount, 1); + vm.stopPrank(); + + vm.selectFork(chain2); + vm.prank(deployer); + HLGCHAIN2.transfer(wallet, bondAmount); + vm.startPrank(wallet); + HLGCHAIN2.approve(address(holographOperatorChain2), bondAmount); + holographOperatorChain2.bondUtilityToken(wallet, bondAmount, 1); + vm.stopPrank(); + } + } + + function createERC20Config() internal view returns (DeploymentConfig memory, bytes32, Verification memory) { + bytes memory initCode = abi.encode(address(deployer), uint16(0)); + + DeploymentConfig memory erc20Config = DeploymentConfig({ + contractType: bytes32(0x000000000000000000000000000000000000486f6c6f67726170684552433230), + chainType: 4294967294, + salt: bytes32(0x00000000000000000000000000000000000000000000000000000000000003e8), + byteCode: vm.getCode("SampleERC20.sol:SampleERC20"), + initCode: abi.encode( + "Sample ERC20 Token (localhost)", //token name + "SMPL", //tokenSymbol + uint8(18), //decimals + bytes32(0x0000000000000000000000000000000000000000000000000000000000000006), //eventConfig + "Sample ERC20 Token", //domainSeparator + "1", //domainVersion + false, //skipInit, + initCode + ) + }); + + bytes32 erc20ConfigHash = keccak256( + abi.encodePacked( + erc20Config.contractType, + erc20Config.chainType, + erc20Config.salt, + keccak256(erc20Config.byteCode), + keccak256(erc20Config.initCode), + deployer + ) + ); + + console.log("original erc20ConfigHash:"); + console.logBytes32(0xa3a2316b8119471cb8f7f5d293ef00c9a2544864c2cc4ac7efaadfb71736b99e); + console.log("erc20ConfigHash:"); + console.logBytes32(erc20ConfigHash); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKeyDeployer, erc20ConfigHash); + Verification memory signature = Verification({r: r, s: s, v: v}); + + return (erc20Config, erc20ConfigHash, signature); +} + + // SampleERC20 + function testSampleERC20() public { + console.log("---------------------- SampleERC20 ----------------------"); + + (DeploymentConfig memory erc20Config, bytes32 erc20ConfigHash, Verification memory signature) = createERC20Config(); + + vm.selectFork(chain2); + address sampleErc20Address = holographRegistryChain2.getHolographedHashAddress(erc20ConfigHash); + console.log("Address 2:"); + console.logAddress(sampleErc20Address); + + assertEq(sampleErc20Address, address(0), "ERC20 contract not deployed on chain2"); + + vm.selectFork(chain1); + sampleErc20Address = holographRegistryChain1.getHolographedHashAddress(erc20ConfigHash); + console.log("Address 1:"); + console.logAddress(sampleErc20Address); + + vm.selectFork(chain2); + + // bytes memory data = abi.encodePacked(erc20ConfigHash); + // bytes32 erc20ConfigHashBytes = keccak256(data); + + // bytes memory signature = abi.encode(signatureStruct.r, signatureStruct.s, signatureStruct.v); + bytes memory data = abi.encode(erc20Config, signature, deployer); + + // (DeploymentConfig memory config2, Verification memory signature2, address signer2) = abi.decode( + // data, + // (DeploymentConfig, Verification, address) + // ); + + // console.log("config2:"); + // console.logBytes32(config2.contractType); + // console.logUint(config2.chainType); + // console.logBytes32(config2.salt); + // console.log("signer2:"); + // console.logAddress(signer2); + + + address originalMessagingModule = holographOperatorChain2.getMessagingModule(); + console.log("originalMessagingModule:"); + console.logAddress(originalMessagingModule); + + vm.prank(deployer); + holographOperatorChain2.setMessagingModule(Constants.getMockLZEndpoint()); + + bytes memory payload = getRequestPayload(Constants.getHolographFactoryProxy(), data); + + EstimatedGas memory estimatedGas = getEstimatedGas(Constants.getHolographFactoryProxy(), data, payload); + + payload = estimatedGas.payload; + bytes32 payloadHash = keccak256(payload); + + uint256 lzMsgGas = getLzMsgGas(payload); + + vm.selectFork(chain2); + vm.prank(deployer); + (bool success, bytes memory result) = address(mockLZEndpointChain2).call{gas: TESTGASLIMIT}( + abi.encodeWithSelector( + mockLZEndpointChain2.crossChainMessage.selector, + address(holographOperatorChain2), + lzMsgGas, + payload + ) + ); + + vm.prank(deployer); + holographOperatorChain2.setMessagingModule(originalMessagingModule); + + OperatorJob memory operatorJob = holographOperatorChain2.getJobDetails(payloadHash); + // console.log("operatorJob:"); + // console.logUint(operatorJob.pod); + // console.logUint(operatorJob.blockTimes); + // console.logAddress(operatorJob.operator); + // console.logUint(operatorJob.startBlock); + // console.logUint(operatorJob.startTimestamp); + // console.logUint(operatorJob.fallbackOperators[0]); + // console.logUint(operatorJob.fallbackOperators[1]); + // console.logUint(operatorJob.fallbackOperators[2]); + // console.logUint(operatorJob.fallbackOperators[3]); + // console.logUint(operatorJob.fallbackOperators[4]); + + + + // address operator = operatorJob.operator; + + vm.expectEmit(true, true, false, false); + emit BridgeableContractDeployed( + sampleErc20Address, + erc20ConfigHash + ); + + vm.prank(deployer); + (bool success2, bytes memory result2) = address(holographOperatorChain2).call{gas: estimatedGas.estimatedGas}( + abi.encodeWithSelector(holographOperatorChain2.executeJob.selector, payload) + ); + + // assertEq(sampleErc20Address, holographRegistryChain2.getHolographedHashAddress(erc20ConfigHash), "ERC20 contract not deployed on chain2"); + } +} diff --git a/test/foundry/utils/Constants.sol b/test/foundry/utils/Constants.sol index c27f87c6..782e1c57 100644 --- a/test/foundry/utils/Constants.sol +++ b/test/foundry/utils/Constants.sol @@ -139,4 +139,12 @@ library Constants { function getDropsEventConfig() internal pure returns (uint256) { return 0x0000000000000000000000000000000000000000000000000000000000040000; } + + function getMockLZEndpoint() internal pure returns (address) { + return address(0x4d186eac2A5F2ec7a16079B8b111ab2EfB8b4342); + } + + function getLayerZeroModuleProxy() internal pure returns (address) { + return address(0x350856f758d9A1b8c24540d8E10cd6AB45B1466d); + } } diff --git a/test/foundry/utils/HolographEvents.sol b/test/foundry/utils/HolographEvents.sol new file mode 100644 index 00000000..18b77acc --- /dev/null +++ b/test/foundry/utils/HolographEvents.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract HolographEvents { + enum HolographERC20Event { + bridgeIn, + bridgeOut, + afterApprove, + beforeApprove, + afterOnERC20Received, + beforeOnERC20Received, + afterBurn, + beforeBurn, + afterMint, + beforeMint, + afterSafeTransfer, + beforeSafeTransfer, + afterTransfer, + beforeTransfer, + onAllowance + } + + enum HolographERC721Event { + bridgeIn, + bridgeOut, + afterApprove, + beforeApprove, + afterApprovalAll, + beforeApprovalAll, + afterBurn, + beforeBurn, + afterMint, + beforeMint, + afterSafeTransfer, + beforeSafeTransfer, + afterTransfer, + beforeTransfer, + beforeOnERC721Received, + afterOnERC721Received, + onIsApprovedForAll, + customContractURI + } + + // enum HolographERC1155Event { + + // } + + function configureEvents(uint256[] memory config) public pure returns (bytes memory) { + bytes memory binary = new bytes(256); + for (uint256 i = 0; i < 256; i++) { + binary[i] = "0"; + } + + for (uint256 i = 0; i < config.length; i++) { + uint256 num = config[i]; + require(num >= 0 && num < 256, "Invalid event number"); + binary[num] = "1"; + } + + for (uint256 i = 0; i < 128; i++) { + (binary[i], binary[255 - i]) = (binary[255 - i], binary[i]); + } + + bytes memory hexString = new bytes(64); + for (uint256 i = 0; i < 32; i++) { + hexString[i * 2] = _toHexChar((uint8(binary[i * 8]) << 4) | uint8(binary[i * 8 + 1])); + hexString[i * 2 + 1] = _toHexChar((uint8(binary[i * 8 + 2]) << 4) | uint8(binary[i * 8 + 3])); + } + + return hexString; + } + + function _toHexChar(uint8 b) internal pure returns (bytes1) { + if (b < 10) { + return bytes1(b + 0x30); + } else { + return bytes1(b + 0x57); + } + } +}