Skip to content
Merged
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
3 changes: 3 additions & 0 deletions helpers/SeamlessAddressBook.sol
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,7 @@ library SeamlessAddressBook {
0x003D47ddDdb070822B35ae5cc4F0066Cf9E89753;
address constant BRETT_TRANSFER_STRATEGY =
0xD90EaC90f5f067283954b96BBc3d28E34ebE55Bb;

address constant BASE_LEVERAGE_MANAGER_PROXY = 0x38Ba21C6Bf31dF1b1798FCEd07B4e9b07C5ec3a8;
address constant BASE_LEVERAGE_TOKEN_FACTORY_PROXY = 0xE0b2e40EDeb53B96C923381509a25a615c1Abe57;
}
1 change: 0 additions & 1 deletion proposals/sip_36_listing_weETH/TestProposal.t.sol

This file was deleted.

30 changes: 30 additions & 0 deletions proposals/sip_49/DeployProposal.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import { Script, console } from "forge-std/Script.sol";
import { Proposal } from "./Proposal.sol";
import { IGovernor } from "@openzeppelin/contracts/governance/IGovernor.sol";
import { SeamlessAddressBook } from "../../helpers/SeamlessAddressBook.sol";

contract DeployProposal is Script {
function setUp() public { }

function run(string memory descriptionPath) public {
Proposal proposal = new Proposal();

// Change this to GOVERNOR_LONG if you want to make proposal on the long governor
IGovernor governance = IGovernor(SeamlessAddressBook.GOVERNOR_SHORT);

string memory description = vm.readFile(descriptionPath);

address proposerAddress = vm.envAddress("PROPOSER_ADDRESS");
vm.startBroadcast(proposerAddress);
governance.propose(
proposal.getTargets(),
proposal.getValues(),
proposal.getCalldatas(),
description
);
vm.stopBroadcast();
}
}
63 changes: 63 additions & 0 deletions proposals/sip_49/Proposal.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.25;

import {
SeamlessGovProposal,
SeamlessAddressBook
} from "../../helpers/SeamlessGovProposal.sol";
import { UpgradeableBeacon } from
"@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol";
import { UUPSUpgradeable } from
"@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol";
import { IAccessControl } from
"@openzeppelin/contracts/access/IAccessControl.sol";

contract Proposal is SeamlessGovProposal {
address constant NEW_BASE_LEVERAGE_TOKEN_IMPLEMENTATION =
0x603Da735780e6bC7D04f3FB85C26dccCd4Ff0a82;
address constant NEW_BASE_LEVERAGE_MANAGER_IMPLEMENTATION =
0xfE9101349354E278970489F935a54905DE2E1856;

// Access control role required for upgrading
bytes32 public constant UPGRADER_ROLE = keccak256("UPGRADER_ROLE");

constructor() {
_makeProposal();
}

/// @dev This contract is not deployed onchain, do not make transactions to other contracts
/// or deploy a contract. Only the view/pure functions of deployed contracts can be called.
function _makeProposal() internal virtual override {
// First, grant the UPGRADER_ROLE to the timelock so it can perform the upgrade
_addAction(
SeamlessAddressBook.BASE_LEVERAGE_MANAGER_PROXY,
abi.encodeWithSelector(
IAccessControl.grantRole.selector,
UPGRADER_ROLE,
SeamlessAddressBook.TIMELOCK_SHORT
)
);

// Upgrade the Base Leverage Token implementation (beacon proxy)
_addAction(
SeamlessAddressBook.BASE_LEVERAGE_TOKEN_FACTORY_PROXY,
abi.encodeWithSelector(
UpgradeableBeacon.upgradeTo.selector,
NEW_BASE_LEVERAGE_TOKEN_IMPLEMENTATION
)
);

// Upgrade the Base Leverage Manager implementation (UUPS proxy)
_addAction(
SeamlessAddressBook.BASE_LEVERAGE_MANAGER_PROXY,
abi.encodeWithSelector(
UUPSUpgradeable.upgradeToAndCall.selector,
NEW_BASE_LEVERAGE_MANAGER_IMPLEMENTATION,
""
)
);

// Note: UPGRADER_ROLE is NOT revoked after the upgrade
// The timelock will retain this role for future upgrades
}
}
159 changes: 159 additions & 0 deletions proposals/sip_49/TenderlySimulation.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.21;

import { Script, console } from "forge-std/Script.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IVotes } from "@openzeppelin/contracts/governance/utils/IVotes.sol";
import { Proposal } from "./Proposal.sol";
import { IGovernor } from "@openzeppelin/contracts/governance/IGovernor.sol";
import { SeamlessAddressBook } from "../../helpers/SeamlessAddressBook.sol";
import { IVotes } from "@openzeppelin/contracts/governance/utils/IVotes.sol";

contract TenderlySimulation is Script {
// Change this to GOVERNOR_LONG if the proposal is made on the long governor
IGovernor governance = IGovernor(SeamlessAddressBook.GOVERNOR_SHORT);
IVotes seam = IVotes(SeamlessAddressBook.SEAM);

Proposal proposal = new Proposal();

address proposerAddress = 0x67b6dB42115d94Cc3FE27E92a3d12bB224041ac0;
uint256 proposerPk =
0x82fe25cccae9752b856c8857de74671320277f92e737b2116a5d9739dec59a26;

function _getProposalData(string memory descriptionPath)
internal
view
returns (uint256 proposalId, bytes32 descriptionHash)
{
string memory description = vm.readFile(descriptionPath);
descriptionHash = keccak256(bytes(description));

proposalId = governance.hashProposal(
proposal.getTargets(),
proposal.getValues(),
proposal.getCalldatas(),
descriptionHash
);
}

function setupProposer() public {
console.log("Setting up proposer");

_fundETH();
_fundSEAM();

moveOneBlockForwardOneSecond();
}

function delegateToProposer() public {
vm.startBroadcast(proposerPk);
seam.delegate(proposerAddress);
vm.stopBroadcast();
}

function moveOneBlockForwardOneSecond() public {
vm.rpc("evm_increaseTime", "[\"0x1\"]");
}

function _fundSEAM() public {
string memory params = string.concat(
"[\"",
Strings.toHexString(address(seam)),
"\",[\"",
Strings.toHexString(proposerAddress),
"\"],\"0x13DA329B6336471800000\"]" // 1.5M SEAM which is quorum
);
vm.rpc("tenderly_setErc20Balance", params);
}

function _fundETH() public {
string memory params = string.concat(
"[[\"",
Strings.toHexString(proposerAddress),
"\"],\"0xDE0B6B3A7640000\"]" // 1 ETH
);
vm.rpc("tenderly_setBalance", params);
}

function createProposal(string memory descriptionPath) public {
string memory description = vm.readFile(descriptionPath);

vm.startBroadcast(proposerPk);
governance.propose(
proposal.getTargets(),
proposal.getValues(),
proposal.getCalldatas(),
description
);
vm.stopBroadcast();
}

function increaseTimeVotingDelay() public {
console.log("Increasing voting delay");
string memory params = string.concat(
"[",
Strings.toString(block.timestamp + governance.votingDelay() + 1),
"]"
);
vm.rpc("evm_setNextBlockTimestamp", params);
vm.rpc("evm_mine", "[]");
}

function castVote(string memory descriptionPath) public {
console.log("Casting vote");
(uint256 proposalId,) = _getProposalData(descriptionPath);

vm.startBroadcast(proposerPk);
governance.castVote(proposalId, 1);
vm.stopBroadcast();
}

function increaseTimeVotingPeriod() public {
console.log("Increasing voting period");
string memory params = string.concat(
"[",
Strings.toString(block.timestamp + governance.votingPeriod() + 1),
"]"
);
vm.rpc("evm_setNextBlockTimestamp", params);
vm.rpc("evm_mine", "[]");
}

function queueProposal(string memory descriptionPath) public {
console.log("Queueing proposal");
(, bytes32 descriptionHash) = _getProposalData(descriptionPath);

vm.startBroadcast(proposerPk);
governance.queue(
proposal.getTargets(),
proposal.getValues(),
proposal.getCalldatas(),
descriptionHash
);
vm.stopBroadcast();
}

function setTimeToProposalEta(string memory descriptionPath) public {
console.log("Setting time to proposal eta");
(uint256 proposalId,) = _getProposalData(descriptionPath);
string memory params = string.concat(
"[", Strings.toString(governance.proposalEta(proposalId) + 1), "]"
);
vm.rpc("evm_setNextBlockTimestamp", params);
vm.rpc("evm_mine", "[]");
}

function executeProposal(string memory descriptionPath) public {
console.log("Executing proposal");
(, bytes32 descriptionHash) = _getProposalData(descriptionPath);

vm.startBroadcast(proposerPk);
governance.execute(
proposal.getTargets(),
proposal.getValues(),
proposal.getCalldatas(),
descriptionHash
);
vm.stopBroadcast();
}
}
Loading