Skip to content

Commit

Permalink
Transfer OP tokens and delegate
Browse files Browse the repository at this point in the history
  • Loading branch information
anikaraghu committed Feb 23, 2024
1 parent adb217c commit f6fb0a4
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
14 changes: 14 additions & 0 deletions mainnet/2024-02-23-transfer-op/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
OPTIMISM_RPC_URL=https://mainnet.optimism.io

OP_COMMIT=3580bf1b41d80fcb2b895d5610836bfad27fc989
BASE_CONTRACTS_COMMIT=a147139671c09923f78ae46a6ebedc91209bb076

OP_TOKEN=0x4200000000000000000000000000000000000042
NESTED_SAFE=0x0a7361e734cf3f0394B0FC4a45C74E7a4Ec70940
SMART_ESCROW_CONTRACT= # TODO
ALLIGATOR_PROXY= # TODO
COLLAB_GRANT_TOKENS=107374177
UPFRONT_GRANT_TOKENS=10737418
CB_GOVERNANCE_WALLET= # TODO
BENEFICIARY=0x07114fF6F815113729b579B4A233192BAEF0e0E18

23 changes: 23 additions & 0 deletions mainnet/2024-02-23-transfer-op/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
include ../../Makefile
include ../.env
include .env

install-agora:
forge install --no-git [email protected]:voteagora/optimism-gov.git

.PHONY: sign
sign:
$(GOPATH)/bin/eip712sign --ledger --hd-paths "m/44'/60'/$(LEDGER_ACCOUNT)'/0/0" -- \
forge script --rpc-url $(OPTIMISM_RPC_URL) TransferAndDelegateOPTokens \
--sig "sign(address)" $(SIGNER_SAFE_ADDR)

.PHONY: approve
approve:
forge script --rpc-url $(OPTIMISM_RPC_URL) TransferAndDelegateOPTokens \
--sig "approve(address,bytes)" $(SIGNER_SAFE_ADDR) $(SIGNATURES) \
--ledger --hd-paths "m/44'/60'/$(LEDGER_ACCOUNT)'/0/0"

.PHONY: execute
execute:
forge script --rpc-url $(OPTIMISM_RPC_URL) TransferAndDelegateOPTokens \
--sig "run()" --ledger --hd-paths "m/44'/60'/$(LEDGER_ACCOUNT)'/0/0"
21 changes: 21 additions & 0 deletions mainnet/2024-02-23-transfer-op/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[profile.default]
src = 'src'
out = 'out'
libs = ['lib']
broadcast = 'records'
fs_permissions = [ {access = "read-write", path = "./"} ]
optimizer = true
optimizer_runs = 999999
solc_version = "0.8.19"
via-ir = true
remappings = [
'@eth-optimism-bedrock/=lib/optimism/packages/contracts-bedrock/',
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts',
'@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts',
'@rari-capital/solmate/=lib/solmate/',
'@base-contracts/=lib/base-contracts',
'solady/=lib/solady/src/',
'@agora=lib/optimism-gov/src',
]

# See more config options https://github.com/foundry-rs/foundry/tree/master/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "@base-contracts/script/universal/NestedMultisigBuilder.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";
import "@agora/structs/RulesV3.sol";
import "@agora/structs/AllowanceType.sol";
import "@agora/alligator/AlligatorOP_V5.sol";

contract TransferAndDelegateOPTokens is NestedMultisigBuilder {
using SafeERC20 for IERC20;

IERC20 internal OP_TOKEN = IERC20(vm.envAddress("OP_TOKEN"));

address internal NESTED_SAFE = vm.envAddress("NESTED_SAFE");
address internal SMART_ESCROW = vm.envAddress("SMART_ESCROW_CONTRACT");
address internal ALLIGATOR_PROXY = vm.envAddress("ALLIGATOR_PROXY"); // Agora address which will allow for subdeletation
address internal CB_GOVERNANCE_WALLET = vm.envAddress("CB_GOVERNANCE_WALLET");

uint256 internal COLLAB_GRANT_TOKENS = vm.envUint("COLLAB_GRANT_TOKENS");
uint256 internal UPFRONT_GRANT_TOKENS = vm.envUint("UPFRONT_GRANT_TOKENS");

function _postCheck() internal override view {
// TODO
}

function _buildCalls() internal override view returns (IMulticall3.Call3[] memory) {
IMulticall3.Call3[] memory calls = new IMulticall3.Call3[](3);

// Transfer collaboration grant tokens to smart escrow
calls[0] = IMulticall3.Call3({
target: address(this),
allowFailure: false,
callData: abi.encodeCall(
this.transferOPTokens, ()
)
});
// Delegate governance tokens for initial grant to Agora's Alligator proxy, which will allow for subdelegations
calls[1] = IMulticall3.Call3({
target: address(OP_TOKEN),
allowFailure: false,
callData: abi.encodeCall(
ERC20Votes.delegate,
(ALLIGATOR_PROXY)
)
});

SubdelegationRules memory subdelegationRules = SubdelegationRules({
maxRedelegations: 2,
blocksBeforeVoteCloses: 0,
notValidBefore: 0,
notValidAfter: 0,
customRule: address(0),
allowanceType: AllowanceType.Absolute,
allowance: 1e18
});

// Delegate the tokens to the Coinbase owned address
calls[2] = IMulticall3.Call3({
target: ALLIGATOR_PROXY,
allowFailure: false,
callData: abi.encodeCall(
AlligatorOPV5.subdelegate,
(CB_GOVERNANCE_WALLET,
subdelegationRules)
)
});

return calls;
}

function transferOPTokens() public {
OP_TOKEN.safeTransfer(SMART_ESCROW, COLLAB_GRANT_TOKENS);
}

function _ownerSafe() internal override view returns (address) {
return NESTED_SAFE;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "@base-contracts/script/universal/NestedMultisigBuilder.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

// TODO: this script will be called after the upfront grant tokens have vested
contract TransferOPTokens is NestedMultisigBuilder {
using SafeERC20 for IERC20;

address internal NESTED_SAFE = vm.envAddress("NESTED_SAFE");
IERC20 public OP_TOKEN = IERC20(vm.envAddress("OP_TOKEN"));
address public BENEFICIARY = vm.envAddress("BENEFICIARY");
uint256 public UPFRONT_GRANT_TOKENS = vm.envUint("UPFRONT_GRANT_TOKENS");

function _postCheck() internal override view {
// TODO
}

function _buildCalls() internal override view returns (IMulticall3.Call3[] memory) {
IMulticall3.Call3[] memory calls = new IMulticall3.Call3[](1);

// Transfer upfront grant tokens when they vest
calls[0] = IMulticall3.Call3({
target: address(this),
allowFailure: false,
callData: abi.encodeCall(
this.transferOPTokens, ()
)
});

return calls;
}

function transferOPTokens() public {
OP_TOKEN.safeTransfer(BENEFICIARY, UPFRONT_GRANT_TOKENS); // or maybe just the whole balance?
}

function _ownerSafe() internal override view returns (address) {
return NESTED_SAFE;
}
}

0 comments on commit f6fb0a4

Please sign in to comment.