Skip to content

Feat/handover #337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 8 additions & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ remappings = ['ds-test/=lib/forge-std/lib/ds-test/src/',
'@uniswap/v2-core/=node_modules/@uniswap/v2-core/contracts',
'@uniswap/lib/=node_modules/@uniswap/lib/contracts']
fs_permissions = [{ access = "read", path = "./"}]
solc = "0.8.24"

[profile.yul]
src = 'yul'
Expand Down Expand Up @@ -44,4 +45,11 @@ sort_imports = false
[fuzz]
runs = 1000

[rpc_endpoints]
base = "https://mainnet.base.org"


[profile.fork]
eth_chain_id = 8453

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
53 changes: 53 additions & 0 deletions script/DeployBridgeTransfer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import 'forge-std/Script.sol';
import '../src/bridge/BridgeTransfer.sol';
import '../src/bridge/BridgeUpgrade.sol';
import '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol';
import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol';

contract DeployBridgeTransfer is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint('PRIVATE_KEY');
vm.startBroadcast(deployerPrivateKey);

// Deploy new implementation
BridgeTransfer bridgeTransfer = new BridgeTransfer();
console.log(
'BridgeTransfer implementation deployed at:',
address(bridgeTransfer)
);

// Deploy upgrade contract
BridgeUpgrade bridgeUpgrade = new BridgeUpgrade();
console.log('BridgeUpgrade deployed at:', address(bridgeUpgrade));

// Get existing proxy and proxy admin addresses from environment
address proxyAddress = vm.envAddress('BRIDGE_PROXY');
address proxyAdminAddress = vm.envAddress('PROXY_ADMIN');
address upgradeExecutorAddress = vm.envAddress('UPGRADE_EXECUTOR');

// Encode the transfer call
bytes memory transferCalldata = abi.encodeWithSelector(
BridgeTransfer.transfer.selector
);

// Encode the upgrade and call
bytes memory upgradeCalldata = abi.encodeWithSelector(
BridgeUpgrade.upgradeAndCall.selector,
proxyAddress,
address(bridgeTransfer),
proxyAdminAddress,
transferCalldata
);

// Execute upgrade and transfer via UpgradeExecutor
(bool success, ) = upgradeExecutorAddress.call(upgradeCalldata);
require(success, 'Upgrade and transfer failed');

console.log('Upgrade and transfer completed successfully');

vm.stopBroadcast();
}
}
66 changes: 66 additions & 0 deletions script/TestBridgeTransfer.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import 'forge-std/Script.sol';
import '../src/bridge/BridgeTransfer.sol';
import '../src/bridge/BridgeUpgrade.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

contract TestBridgeTransfer is Script {
// Base mainnet addresses
address public constant BRIDGE_PROXY =
0x9F904Fea0efF79708B37B99960e05900fE310A8E; // Replace with actual bridge proxy
address public constant PROXY_ADMIN =
0xaDD83738fd8a1cdCccab49e761F36ED1C93805FD; // Base's default proxy admin
address public constant UPGRADE_EXECUTOR =
0x95E613a501a0AaB5a1C5Cbe682B29d4d300EAc3B; // Base's upgrade executor
address public constant GHST = 0xcD2F22236DD9Dfe2356D7C543161D4d260FD9BcB;

function run() external {
vm.startBroadcast();

// Deploy new implementation
BridgeTransfer bridgeTransfer = new BridgeTransfer();
console.log(
'BridgeTransfer implementation deployed at:',
address(bridgeTransfer)
);

// Deploy upgrade contract
BridgeUpgrade bridgeUpgrade = new BridgeUpgrade();
console.log('BridgeUpgrade deployed at:', address(bridgeUpgrade));

IERC20 ghst = IERC20(GHST);

uint256 initialBridgeBalance = ghst.balanceOf(BRIDGE_PROXY);
console.log('Initial bridge GHST balance:', initialBridgeBalance);

bytes memory transferCalldata = abi.encodeWithSelector(
BridgeTransfer.transfer.selector
);

bytes memory upgradeCalldata = abi.encodeWithSelector(
BridgeUpgrade.upgradeAndCall.selector,
BRIDGE_PROXY,
address(bridgeTransfer),
PROXY_ADMIN,
transferCalldata
);

// Impersonate the admin for the upgrade
vm.startPrank(PROXY_ADMIN);

// Execute upgrade and transfer via UpgradeExecutor
(bool success, ) = UPGRADE_EXECUTOR.call(upgradeCalldata);
require(success, 'Upgrade and transfer failed');

vm.stopPrank();

uint256 finalBridgeBalance = ghst.balanceOf(BRIDGE_PROXY);
uint256 adminBalance = ghst.balanceOf(PROXY_ADMIN);
console.log('Final bridge GHST balance:', finalBridgeBalance);
console.log('Admin GHST balance:', adminBalance);

vm.stopBroadcast();
}
}
34 changes: 34 additions & 0 deletions src/bridge/BridgeTransfer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';

interface IProxyAdmin {
function owner() external view returns (address);
}

contract BridgeTransfer is Initializable {
// GHST token address on Base
address public constant GHST = 0x7c6b91D9Be155A6Db01f749217d76fF02A7227F2;

function initialize() external initializer {
// No initialization needed
}

function transfer() external {
address admin = IProxyAdmin(_getProxyAdmin()).owner();
uint256 balance = IERC20(GHST).balanceOf(address(this));
require(balance > 0, 'No GHST to transfer');
require(IERC20(GHST).transfer(admin, balance), 'Transfer failed');
}

// Helper to get the ProxyAdmin address (ERC1967 standard)
function _getProxyAdmin() internal view returns (address admin) {
bytes32 slot = bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1);
// solhint-disable-next-line no-inline-assembly
assembly {
admin := sload(slot)
}
}
}
20 changes: 20 additions & 0 deletions src/bridge/BridgeUpgrade.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;

import '@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol';
import '@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol';

contract BridgeUpgrade {
function upgradeAndCall(
address proxy,
address newImplementation,
address proxyAdmin,
bytes calldata data
) external {
ProxyAdmin(proxyAdmin).upgradeAndCall(
TransparentUpgradeableProxy(payable(proxy)),
newImplementation,
data
);
}
}
Loading