Skip to content

Commit

Permalink
Post checks
Browse files Browse the repository at this point in the history
  • Loading branch information
anikaraghu committed Feb 23, 2024
1 parent f6fb0a4 commit be9c2b8
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 33 deletions.
11 changes: 5 additions & 6 deletions mainnet/2024-02-23-transfer-op/.env
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ 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

ALLIGATOR_PROXY=0x7f08F3095530B67CdF8466B7a923607944136Df0
UPFRONT_GRANT_TOKENS=10737418000000000000000000
TOKENS_TO_TRANSFER=26843545000000000000000000
CB_GOVERNANCE_WALLET=0x07114F6F815113729b579B4A233192BAEF0e0E18
BENEFICIARY= # TODO
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,59 @@
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";
import "@openzeppelin/contracts/token/ERC20/IERC20.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");
uint256 internal TOKENS_TO_TRANSFER = vm.envUint("TOKENS_TO_TRANSFER");

function _postCheck() internal override view {
// TODO
require(
OP_TOKEN.balanceOf(SMART_ESCROW) == TOKENS_TO_TRANSFER,
"TransferAndDelegateOPTokens: tokens not transferred to smart escrow"
);
// TODO: any other checks?
}

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

// Transfer collaboration grant tokens to smart escrow
// Double check that there aren't unaccounted for tokens in the nested safe
uint256 tokensToTransfer = OP_TOKEN.balanceOf(NESTED_SAFE) - UPFRONT_GRANT_TOKENS;
require(
tokensToTransfer == TOKENS_TO_TRANSFER,
"TransferAndDelegateOPTokens: tokens to transfer do not match expected amount"
);

// Transfer collaboration grant tokens which are in the nested safe to smart escrow
// Tokens are sent to the contract 1 year before they vest, so this will be some subset of the
// total collaboration grant tokens
calls[0] = IMulticall3.Call3({
target: address(this),
target: address(OP_TOKEN),
allowFailure: false,
callData: abi.encodeCall(
this.transferOPTokens, ()
IERC20.transfer,
(SMART_ESCROW, TOKENS_TO_TRANSFER)
)
});
// Delegate governance tokens for initial grant to Agora's Alligator proxy, which will allow for subdelegations
// 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)
(AlligatorOPV5(ALLIGATOR).proxyAddress(CB_GOVERNANCE_WALLET))
)
});

Expand All @@ -62,18 +74,13 @@ contract TransferAndDelegateOPTokens is NestedMultisigBuilder {
allowFailure: false,
callData: abi.encodeCall(
AlligatorOPV5.subdelegate,
(CB_GOVERNANCE_WALLET,
subdelegationRules)
(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;
}
Expand Down
25 changes: 15 additions & 10 deletions mainnet/2024-02-23-transfer-op/script/TransferUpfrontOPTokens.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,45 @@
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/IERC20.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
// TODO: double check there's no initial OP tokens at beneficiary address before running this
// task, otherwise this check will fail
require(
OP_TOKEN.balanceOf(BENEFICIARY) == UPFRONT_GRANT_TOKENS,
"TransferAndDelegateOPTokens: tokens not transferred to beneficiary"
);
}

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

require(
OP_TOKEN.balanceOf(NESTED_SAFE) == UPFRONT_GRANT_TOKENS,
"TransferOPTokens: unexpected token amount in nested safe"
);

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

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;
}
Expand Down

0 comments on commit be9c2b8

Please sign in to comment.