diff --git a/contracts/VoteWeighting.sol b/contracts/VoteWeighting.sol index dd378cc..d59f832 100644 --- a/contracts/VoteWeighting.sol +++ b/contracts/VoteWeighting.sol @@ -44,51 +44,53 @@ interface IVEOLAS { contract VoteWeighting is IErrors { event OwnerUpdated(address indexed owner); - event NewGaugeWeight(address indexed gauge_address, uint256 weight, uint256 total_weight); - event VoteForGauge(address indexed user, address indexed gauge_addr, uint256 weight); - event NewGauge(address addr, uint256 weight); + event NewNomineeWeight(address indexed nominee, uint256 chainId, uint256 weight, uint256 totalWeight); + event VoteForNominee(address indexed user, address indexed nominee, uint256 chainId, uint256 weight); + event NewNominee(address nominee, uint256 chainId); // 7 * 86400 seconds - all future times are rounded by week uint256 public constant WEEK = 604800; // Cannot change weight votes more often than once in 10 days uint256 public constant WEIGHT_VOTE_DELAY = 864000; + // Maximum chain Id as per EVM specs + uint256 public constant MAX_CHAIN_ID = type(uint64).max / 2 - 36; // veOLAS contract address address public immutable ve; // Contract owner address address public owner; // TODO: Convert both to cyclic map - // Set of gauges - address[] public gauges; - // mapping of gauges - mapping(address => bool) public mapGauges; + // Set of (chainId | nominee) + uint256[] public nomineeAccounts; + // Mapping of (chainId | nominee) + mapping(uint256 => bool) public mapNominees; - // user -> gauge_addr -> VotedSlope - mapping(address => mapping(address => VotedSlope)) public vote_user_slopes; + // user -> (chainId | nominee) -> VotedSlope + mapping(address => mapping(uint256 => VotedSlope)) public voteUserSlopes; // Total vote power used by user - mapping(address => uint256) public vote_user_power; - // Last user vote's timestamp for each gauge address - mapping(address => mapping(address => uint256)) public last_user_vote; + mapping(address => uint256) public voteUserPower; + // Last user vote's timestamp for each (chainId | nominee) + mapping(address => mapping(uint256 => uint256)) public lastUserVote; - // Past and scheduled points for gauge weight, sum of weights per type, total weight + // Past and scheduled points for nominee weight, sum of weights per type, total weight // Point is for bias+slope // changes_* are for changes in slope // time_* are for the last change timestamp // timestamps are rounded to whole weeks - // gauge_addr -> time -> Point - mapping(address => mapping(uint256 => Point)) public points_weight; - // gauge_addr -> time -> slope - mapping(address => mapping(uint256 => uint256)) public changes_weight; - // gauge_addr -> last scheduled time (next week) - mapping(address => uint256) public time_weight; + // (chainId | nominee) -> time -> Point + mapping(uint256 => mapping(uint256 => Point)) public pointsWeight; + // (chainId | nominee) -> time -> slope + mapping(uint256 => mapping(uint256 => uint256)) public changesWeight; + // (chainId | nominee) -> last scheduled time (next week) + mapping(uint256 => uint256) public timeWeight; // time -> Point - mapping(uint256 => Point) public points_sum; + mapping(uint256 => Point) public pointsSum; // time -> slope - mapping(uint256 => uint256) public changes_sum; + mapping(uint256 => uint256) public changesSum; // last scheduled time (next week) - uint256 public time_sum; + uint256 public timeSum; /// @notice Contract constructor. /// @param _ve `VotingEscrow` contract address. @@ -101,7 +103,7 @@ contract VoteWeighting is IErrors { // Set initial parameters owner = msg.sender; ve = _ve; - time_sum = block.timestamp / WEEK * WEEK; + timeSum = block.timestamp / WEEK * WEEK; } /// @dev Changes the owner address. @@ -121,12 +123,12 @@ contract VoteWeighting is IErrors { emit OwnerUpdated(newOwner); } - /// @notice Fill sum of gauge weights for the same type week-over-week for missed checkins and return the sum for the future week. + /// @notice Fill sum of nominee weights for the same type week-over-week for missed checkins and return the sum for the future week. /// @return Sum of weights. function _getSum() internal returns (uint256) { - uint256 t = time_sum; + uint256 t = timeSum; if (t > 0) { - Point memory pt = points_sum[t]; + Point memory pt = pointsSum[t]; for (uint256 i = 0; i < 500; i++) { if (t > block.timestamp) { break; @@ -135,16 +137,16 @@ contract VoteWeighting is IErrors { uint256 d_bias = pt.slope * WEEK; if (pt.bias > d_bias) { pt.bias -= d_bias; - uint256 d_slope = changes_sum[t]; + uint256 d_slope = changesSum[t]; pt.slope -= d_slope; } else { pt.bias = 0; pt.slope = 0; } - points_sum[t] = pt; + pointsSum[t] = pt; if (t > block.timestamp) { - time_sum = t; + timeSum = t; } } return pt.bias; @@ -153,18 +155,26 @@ contract VoteWeighting is IErrors { } } - /// @notice Fill historic gauge weights week-over-week for missed checkins and return the total for the future week. - /// @param gauge_addr Address of the gauge. - /// @return Gauge weight. - function _getWeight(address gauge_addr) internal returns (uint256) { - // Check that the gauge exists - if (!mapGauges[gauge_addr]) { + /// @notice Fill historic nominee weights week-over-week for missed checkins and return the total for the future week. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + /// @return Nominee weight. + function _getWeight(address nominee, uint256 chainId) internal returns (uint256) { + // Push a pair of key defining variables into one key + // Nominee address and chain Id + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; + + // Check that the nominee exists + if (!mapNominees[nomineeChainId]) { revert("Does not exist"); } - uint256 t = time_weight[gauge_addr]; + uint256 t = timeWeight[nomineeChainId]; if (t > 0) { - Point memory pt = points_weight[gauge_addr][t]; + Point memory pt = pointsWeight[nomineeChainId][t]; for (uint256 i = 0; i < 500; i++) { if (t > block.timestamp) { break; @@ -173,16 +183,16 @@ contract VoteWeighting is IErrors { uint256 d_bias = pt.slope * WEEK; if (pt.bias > d_bias) { pt.bias -= d_bias; - uint256 d_slope = changes_weight[gauge_addr][t]; + uint256 d_slope = changesWeight[nomineeChainId][t]; pt.slope -= d_slope; } else { pt.bias = 0; pt.slope = 0; } - points_weight[gauge_addr][t] = pt; + pointsWeight[nomineeChainId][t] = pt; if (t > block.timestamp) { - time_weight[gauge_addr] = t; + timeWeight[nomineeChainId] = t; } } return pt.bias; @@ -191,136 +201,171 @@ contract VoteWeighting is IErrors { } } - /// @notice Add gauge `addr` of type `gauge_type` with weight `weight`. - /// @param addr Gauge address. - function add_gauge(address addr) external { - if (mapGauges[addr]) { - revert("Cannot add the same gauge twice"); + /// @notice Add nominee address along with the chain Id. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + function addNominee(address nominee, uint256 chainId) external { + // Check for the zero address + if (nominee == address(0)) { + revert ZeroAddress(); + } + + // Check for the chain Id + if (chainId == 0 || chainId > MAX_CHAIN_ID) { + revert Overflow(chainId, MAX_CHAIN_ID); + } + + // Push a pair of key defining variables into one key + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; + + if (mapNominees[nomineeChainId]) { + revert("Cannot add the same nominee twice"); } - mapGauges[addr] = true; + mapNominees[nomineeChainId] = true; - gauges.push(addr); + nomineeAccounts.push(nomineeChainId); uint256 next_time = (block.timestamp + WEEK) / WEEK * WEEK; - if (time_sum == 0) { - time_sum = next_time; + if (timeSum == 0) { + timeSum = next_time; } - time_weight[addr] = next_time; + timeWeight[nomineeChainId] = next_time; - emit NewGauge(addr, weight); + emit NewNominee(nominee, chainId); } - /// @notice Checkpoint to fill data common for all gauges. + /// @notice Checkpoint to fill data common for all nominees. function checkpoint() external { _getSum(); } - /// @notice Checkpoint to fill data for both a specific gauge and common for all gauges. - /// @param addr Gauge address. - function checkpoint_gauge(address addr) external { - _getWeight(addr); + /// @notice Checkpoint to fill data for both a specific nominee and common for all nominees. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + function checkpointNominee(address nominee, uint256 chainId) external { + _getWeight(nominee, chainId); _getSum(); } - /// @notice Get Gauge relative weight (not more than 1.0) normalized to 1e18 (e.g. 1.0 == 1e18). - /// Inflation which will be received by it is inflation_rate * relative_weight / 1e18. - /// @param addr Gauge address. + /// @notice Get Nominee relative weight (not more than 1.0) normalized to 1e18 (e.g. 1.0 == 1e18). + /// Inflation which will be received by it is inflation_rate * relativeWeight / 1e18. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. /// @param time Relative weight at the specified timestamp in the past or present. /// @return Value of relative weight normalized to 1e18. - function _gauge_relative_weight(address addr, uint256 time) internal view returns (uint256) { + function _nomineeRelativeWeight(address nominee, uint256 chainId, uint256 time) internal view returns (uint256) { uint256 t = time / WEEK * WEEK; - uint256 _total_sum = points_sum[t].bias; + uint256 _totalSum = pointsSum[t].bias; - if (_total_sum > 0) { - uint256 _gauge_weight = points_weight[addr][t].bias; - return 1e18 * _gauge_weight / _total_sum; + // Push a pair of key defining variables into one key + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; + + if (_totalSum > 0) { + uint256 _nomineeWeight = pointsWeight[nomineeChainId][t].bias; + return 1e18 * _nomineeWeight / _totalSum; } else { return 0; } } - /// @notice Get Gauge relative weight (not more than 1.0) normalized to 1e18. + /// @notice Get Nominee relative weight (not more than 1.0) normalized to 1e18. /// (e.g. 1.0 == 1e18). Inflation which will be received by it is - /// inflation_rate * relative_weight / 1e18. - /// @param addr Gauge address. + /// inflation_rate * relativeWeight / 1e18. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. /// @param time Relative weight at the specified timestamp in the past or present. /// @return Value of relative weight normalized to 1e18. - function gauge_relative_weight(address addr, uint256 time) external view returns (uint256) { - return _gauge_relative_weight(addr, time); + function nomineeRelativeWeight(address nominee, uint256 chainId, uint256 time) external view returns (uint256) { + return _nomineeRelativeWeight(nominee, chainId, time); } - /// @notice Get gauge weight normalized to 1e18 and also fill all the unfilled values for type and gauge records. + /// @notice Get nominee weight normalized to 1e18 and also fill all the unfilled values for type and nominee records. /// @dev Any address can call, however nothing is recorded if the values are filled already. - /// @param addr Gauge address. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. /// @param time Relative weight at the specified timestamp in the past or present. /// @return Value of relative weight normalized to 1e18. - function gauge_relative_weight_write(address addr, uint256 time) external returns (uint256) { - _getWeight(addr); - _getSum(); - return _gauge_relative_weight(addr, time); - } - - /// @notice Get gauge weight normalized to 1e18 and also fill all the unfilled values for type and gauge records. - /// @dev Any address can call, however nothing is recorded if the values are filled already. - /// @param addr Gauge address. - /// @return Value of relative weight normalized to 1e18. - function gauge_relative_weight_write_now(address addr) external returns (uint256) { - _getWeight(addr); + function nomineeRelativeWeightWrite(address nominee, uint256 chainId, uint256 time) external returns (uint256) { + _getWeight(nominee, chainId); _getSum(); - return _gauge_relative_weight(addr, block.timestamp); + return _nomineeRelativeWeight(nominee, chainId, time); } // TODO: Supposedly this can only bring weight to zero if something went wrong with the contract - function _change_gauge_weight(address addr, uint256 weight) internal { - // Change gauge weight + /// @dev Change weight of `nominee` to `weight`. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + /// @param weight New nominee weight. + function _changeNomineeWeight(address nominee, uint256 chainId, uint256 weight) internal { + // Change nominee weight // Only needed when testing in reality - uint256 old_gauge_weight = _getWeight(addr); - uint256 old_sum = _getSum(); + uint256 old_nomineeWeight = _getWeight(nominee, chainId); + uint256 oldSum = _getSum(); uint256 next_time = (block.timestamp + WEEK) / WEEK * WEEK; - points_weight[addr][next_time].bias = weight; - time_weight[addr] = next_time; + // Push a pair of key defining variables into one key + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; - uint256 new_sum = old_sum + weight - old_gauge_weight; - points_sum[next_time].bias = new_sum; - time_sum = next_time; + pointsWeight[nomineeChainId][next_time].bias = weight; + timeWeight[nomineeChainId] = next_time; - emit NewGaugeWeight(addr, weight, new_sum); + uint256 newSum = oldSum + weight - old_nomineeWeight; + pointsSum[next_time].bias = newSum; + timeSum = next_time; + + emit NewNomineeWeight(nominee, chainId, weight, newSum); } - /// @notice Change weight of gauge `addr` to `weight`. - /// @param addr `GaugeController` contract address. - /// @param weight New Gauge weight. - function change_gauge_weight(address addr, uint256 weight) external { - require(msg.sender == owner, "Only owner can change gauge weight"); - _change_gauge_weight(addr, weight); + /// @notice Change weight of nominee `addr` to `weight`. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + /// @param weight New nominee weight. + function changeNomineeWeight(address nominee, uint256 chainId, uint256 weight) external { + require(msg.sender == owner, "Only owner can change nominee weight"); + _changeNomineeWeight(nominee, chainId, weight); } /// @notice Allocate voting power for changing pool weights. - /// @param _gauge_addr Gauge which `msg.sender` votes for. - /// @param _user_weight Weight for a gauge in bps (units of 0.01%). Minimal is 0.01%. Ignored if 0. - function vote_for_gauge_weights(address _gauge_addr, uint256 _user_weight) external { + /// @param nominee Address of the nominee the `msg.sender` votes for. + /// @param chainId Chain Id. + /// @param weight Weight for a nominee in bps (units of 0.01%). Minimal is 0.01%. Ignored if 0. + function voteForNomineeWeights(address nominee, uint256 chainId, uint256 weight) public { + // Push a pair of key defining variables into one key + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; + PointVoting memory pv = IVEOLAS(ve).getLastUserPoint(msg.sender); uint256 slope = uint256(uint128(pv.slope)); uint256 lock_end = IVEOLAS(ve).lockedEnd(msg.sender); uint256 next_time = (block.timestamp + WEEK) / WEEK * WEEK; require(lock_end > next_time, "Your token lock expires too soon"); - require(_user_weight >= 0 && _user_weight <= 10000, "You used all your voting power"); - require(block.timestamp >= last_user_vote[msg.sender][_gauge_addr] + WEIGHT_VOTE_DELAY, "Cannot vote so often"); + require(weight >= 0 && weight <= 10000, "You used all your voting power"); + require(block.timestamp >= lastUserVote[msg.sender][nomineeChainId] + WEIGHT_VOTE_DELAY, "Cannot vote so often"); // Prepare old and new slopes and biases - VotedSlope memory old_slope = vote_user_slopes[msg.sender][_gauge_addr]; + VotedSlope memory old_slope = voteUserSlopes[msg.sender][nomineeChainId]; uint256 old_bias; if (old_slope.end > next_time) { old_bias = old_slope.slope * (old_slope.end - next_time); } VotedSlope memory new_slope = VotedSlope({ - slope: slope * _user_weight / 10000, + slope: slope * weight / 10000, end: lock_end, - power: _user_weight + power: weight }); // Check for the lock end expiration @@ -329,68 +374,80 @@ contract VoteWeighting is IErrors { } uint256 new_bias = new_slope.slope * (lock_end - next_time); - uint256 power_used = vote_user_power[msg.sender]; + uint256 power_used = voteUserPower[msg.sender]; power_used = power_used + new_slope.power - old_slope.power; - vote_user_power[msg.sender] = power_used; + voteUserPower[msg.sender] = power_used; require(power_used >= 0 && power_used <= 10000, 'Used too much power'); // Remove old and schedule new slope changes // Remove slope changes for old slopes // Schedule recording of initial slope for next_time - points_weight[_gauge_addr][next_time].bias = _maxAndSub(_getWeight(_gauge_addr) + new_bias, old_bias); - points_sum[next_time].bias = _maxAndSub(_getSum() + new_bias, old_bias); + pointsWeight[nomineeChainId][next_time].bias = _maxAndSub(_getWeight(nominee, chainId) + new_bias, old_bias); + pointsSum[next_time].bias = _maxAndSub(_getSum() + new_bias, old_bias); if (old_slope.end > next_time) { - points_weight[_gauge_addr][next_time].slope = _maxAndSub(points_weight[_gauge_addr][next_time].slope + new_slope.slope, old_slope.slope); - points_sum[next_time].slope = _maxAndSub(points_sum[next_time].slope + new_slope.slope, old_slope.slope); + pointsWeight[nomineeChainId][next_time].slope = _maxAndSub(pointsWeight[nomineeChainId][next_time].slope + new_slope.slope, old_slope.slope); + pointsSum[next_time].slope = _maxAndSub(pointsSum[next_time].slope + new_slope.slope, old_slope.slope); } else { - points_weight[_gauge_addr][next_time].slope += new_slope.slope; - points_sum[next_time].slope += new_slope.slope; + pointsWeight[nomineeChainId][next_time].slope += new_slope.slope; + pointsSum[next_time].slope += new_slope.slope; } if (old_slope.end > block.timestamp) { // Cancel old slope changes if they still didn't happen - changes_weight[_gauge_addr][old_slope.end] -= old_slope.slope; - changes_sum[old_slope.end] -= old_slope.slope; + changesWeight[nomineeChainId][old_slope.end] -= old_slope.slope; + changesSum[old_slope.end] -= old_slope.slope; } // Add slope changes for new slopes - changes_weight[_gauge_addr][new_slope.end] += new_slope.slope; - changes_sum[new_slope.end] += new_slope.slope; + changesWeight[nomineeChainId][new_slope.end] += new_slope.slope; + changesSum[new_slope.end] += new_slope.slope; - vote_user_slopes[msg.sender][_gauge_addr] = new_slope; + voteUserSlopes[msg.sender][nomineeChainId] = new_slope; // Record last action time - last_user_vote[msg.sender][_gauge_addr] = block.timestamp; + lastUserVote[msg.sender][nomineeChainId] = block.timestamp; + + emit VoteForNominee(msg.sender, nominee, chainId, weight); + } - emit VoteForGauge(msg.sender, _gauge_addr, _user_weight); + /// @notice Allocate voting power for changing pool weights in batch. + /// @param nominees Set of nominees the `msg.sender` votes for. + /// @param chainIds Set of corresponding chain Ids. + /// @param weights Weights for a nominees in bps (units of 0.01%). Minimal is 0.01%. Ignored if 0. + function voteForNomineeWeightsBatch( + address[] memory nominees, + uint256[] memory chainIds, + uint256[] memory weights + ) external { + if (nominees.length != chainIds.length || nominees.length != weights.length) { + revert WrongArrayLength(nominees.length, weights.length); + } + + // Traverse all accounts and weights + for (uint256 i = 0; i < nominees.length; ++i) { + voteForNomineeWeights(nominees[i], chainIds[i], weights[i]); + } } function _maxAndSub(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? a - b : 0; } - /// @notice Get current gauge weight. - /// @param addr Gauge address. - /// @return Gauge weight. - function getGaugeWeight(address addr) external view returns (uint256) { - return points_weight[addr][time_weight[addr]].bias; + /// @notice Get current nominee weight. + /// @param nominee Address of the nominee. + /// @param chainId Chain Id. + /// @return Nominee weight. + function getNomineeWeight(address nominee, uint256 chainId) external view returns (uint256) { + // Push a pair of key defining variables into one key + // nominee occupies first 160 bits + uint256 nomineeChainId = uint256(uint160(nominee)); + // chain Id occupies no more than next 64 bits + nomineeChainId |= chainId << 160; + + return pointsWeight[nomineeChainId][timeWeight[nomineeChainId]].bias; } - //@notice Get sum of gauge weights. - //@return Sum of gauge weights. + /// @notice Get sum of nominee weights. + /// @return Sum of nominee weights. function getWeightsSum() external view returns (uint256) { - return points_sum[time_sum].bias; - } - - /// @notice Gets Gauge relative weight normalized to 1e18 at the last available timestamp. - /// @param addr Gauge address. - /// @return Value of relative weight normalized to 1e18. - function gauge_relative_weight_last(address addr) external view returns (uint256) { - return _gauge_relative_weight(addr, time_sum); - } - - /// @notice Gets Gauge relative weight normalized to 1e18 at the block timestamp. - /// @param addr Gauge address. - /// @return Value of relative weight normalized to 1e18. - function gauge_relative_weight_now(address addr) external view returns (uint256) { - return _gauge_relative_weight(addr, block.timestamp); + return pointsSum[timeSum].bias; } } \ No newline at end of file diff --git a/scripts/deployment/bridges/gnosis/test/mediator_goerli_chiado_change_governor.js b/scripts/deployment/bridges/gnosis/test/mediator_goerli_chiado_change_governor.js new file mode 100644 index 0000000..48ed523 --- /dev/null +++ b/scripts/deployment/bridges/gnosis/test/mediator_goerli_chiado_change_governor.js @@ -0,0 +1,80 @@ +/*global process*/ + +const { ethers } = require("ethers"); + +async function main() { + const ALCHEMY_API_KEY_GOERLI = process.env.ALCHEMY_API_KEY_GOERLI; + const goerliURL = "https://eth-goerli.g.alchemy.com/v2/" + ALCHEMY_API_KEY_GOERLI; + const goerliProvider = new ethers.providers.JsonRpcProvider(goerliURL); + await goerliProvider.getBlockNumber().then((result) => { + console.log("Current block number goerli: " + result); + }); + + const chiadoURL = "https://rpc.chiadochain.net"; + const chiadoProvider = new ethers.providers.JsonRpcProvider(chiadoURL); + await chiadoProvider.getBlockNumber().then((result) => { + console.log("Current block number chiado: " + result); + }); + + const fs = require("fs"); + // AMBProxy address on goerli + const AMBProxyAddress = "0x87A19d769D875964E9Cd41dDBfc397B2543764E6"; + const AMBProxyJSON = "abis/test/EternalStorageProxy.json"; + let contractFromJSON = fs.readFileSync(AMBProxyJSON, "utf8"); + const AMBProxyABI = JSON.parse(contractFromJSON); + const AMBProxy = new ethers.Contract(AMBProxyAddress, AMBProxyABI, goerliProvider); + + // Test deployed HomeMediator address on chiado + const homeMediatorAddress = "0x0a50009D55Ed5700ac8FF713709d5Ad5fa843896"; + const homeMediatorJSON = "artifacts/contracts/bridges/HomeMediator.sol/HomeMediator.json"; + contractFromJSON = fs.readFileSync(homeMediatorJSON, "utf8"); + let parsedFile = JSON.parse(contractFromJSON); + const homeMediatorABI = parsedFile["abi"]; + const homeMediator = new ethers.Contract(homeMediatorAddress, homeMediatorABI, chiadoProvider); + + // Mock Timelock contract address on goerli (has AMBProxy address in it already) + const mockTimelockAddress = "0x5b03476a21e9c7cEB8dB1Bd9F24664e480FDcc43"; + const mockTimelockJSON = "artifacts/contracts/bridges/test/MockTimelock.sol/MockTimelock.json"; + contractFromJSON = fs.readFileSync(mockTimelockJSON, "utf8"); + parsedFile = JSON.parse(contractFromJSON); + const mockTimelockABI = parsedFile["abi"]; + const mockTimelock = new ethers.Contract(mockTimelockAddress, mockTimelockABI, goerliProvider); + + // Get the EOA + const account = ethers.utils.HDNode.fromMnemonic(process.env.TESTNET_MNEMONIC).derivePath("m/44'/60'/0'/0/0"); + const EOAgoerli = new ethers.Wallet(account, goerliProvider); + const EOAchiado = new ethers.Wallet(account, chiadoProvider); + console.log("EOA address",EOAgoerli.address); + if (EOAchiado.address == EOAgoerli.address) { + console.log("Correct wallet setup"); + } + + // Home Mediator to change the foreign governor address + const rawPayload = homeMediator.interface.encodeFunctionData("changeForeignGovernor", [EOAchiado.address]); + // Pack the second part of data + target = homeMediatorAddress; + value = 0; + const payload = ethers.utils.arrayify(rawPayload); + data = ethers.utils.solidityPack( + ["address", "uint96", "uint32", "bytes"], + [target, value, payload.length, payload] + ); + + // Build the final payload to be passed from the imaginary Timelock + const mediatorPayload = await homeMediator.interface.encodeFunctionData("processMessageFromForeign", [data]); + const requestGasLimit = "2000000"; + const timelockPayload = await AMBProxy.interface.encodeFunctionData("requireToPassMessage", [homeMediatorAddress, + mediatorPayload, requestGasLimit]); + + // Send the message to chiado receiver + tx = await mockTimelock.connect(EOAgoerli).execute(timelockPayload); + console.log("Timelock data execution hash", tx.hash); + await tx.wait(); +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + });