Skip to content
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

update addresses.json file using vm.writeJson #84

Merged
merged 10 commits into from
Aug 15, 2024
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: 2 additions & 1 deletion .solhintrc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"no-unused-import": "error",
"explicit-types": "off",
"const-name-snakecase": "off",
"gas-custom-errors": "off"
"gas-custom-errors": "off",
"quotes": "off"
}
}
91 changes: 72 additions & 19 deletions addresses/Addresses.sol
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,34 @@ contract Addresses is IAddresses, Test {
/// @notice array of addresses deployed during a proposal
RecordedAddress[] private recordedAddresses;

// @notice array of addresses changed during a proposal
/// @notice array of addresses changed during a proposal
ChangedAddress[] private changedAddresses;

constructor(string memory addressesPath) {
/// @notice array of all address details
SavedAddresses[] private savedAddresses;

/// @notice path of addresses file
string private addressesPath;

constructor(string memory _addressesPath) {
addressesPath = _addressesPath;
string memory addressesData = string(
abi.encodePacked(vm.readFile(addressesPath))
);

bytes memory parsedJson = vm.parseJson(addressesData);

SavedAddresses[] memory savedAddresses = abi.decode(
SavedAddresses[] memory fileAddresses = abi.decode(
parsedJson,
(SavedAddresses[])
);

for (uint256 i = 0; i < savedAddresses.length; i++) {
for (uint256 i = 0; i < fileAddresses.length; i++) {
_addAddress(
savedAddresses[i].name,
savedAddresses[i].addr,
savedAddresses[i].chainId,
savedAddresses[i].isContract
fileAddresses[i].name,
fileAddresses[i].addr,
fileAddresses[i].chainId,
fileAddresses[i].isContract
);
}
}
Expand Down Expand Up @@ -178,6 +185,16 @@ contract Addresses is IAddresses, Test {
})
);

for (uint256 i; i < savedAddresses.length; i++) {
if (
keccak256(abi.encode(savedAddresses[i].name)) ==
keccak256(abi.encode(name)) &&
savedAddresses[i].chainId == chainId
) {
savedAddresses[i].addr = _addr;
}
}

ElliotFriedman marked this conversation as resolved.
Show resolved Hide resolved
data.addr = _addr;
data.isContract = isContract;
vm.label(_addr, name);
Expand Down Expand Up @@ -327,6 +344,12 @@ contract Addresses is IAddresses, Test {
}
}

/// @dev Update Address json
function updateJson() external {
string memory json = _constructJson();
vm.writeJson(json, addressesPath);
}

/// @notice add an address for a specific chainId
/// @param name the name of the address
/// @param addr the address to add
Expand Down Expand Up @@ -363,7 +386,7 @@ contract Addresses is IAddresses, Test {
string(
abi.encodePacked(
"Address: ",
addressToString(addr),
vm.toString(addr),
" already set on chain: ",
vm.toString(chainId)
)
Expand All @@ -377,6 +400,15 @@ contract Addresses is IAddresses, Test {
currentAddress.addr = addr;
currentAddress.isContract = isContract;

savedAddresses.push(
SavedAddresses({
name: name,
addr: addr,
chainId: chainId,
isContract: isContract
})
);

vm.label(addr, name);
}

Expand Down Expand Up @@ -445,16 +477,37 @@ contract Addresses is IAddresses, Test {
}
}

function addressToString(
address _addr
) internal pure returns (string memory) {
bytes memory alphabet = "0123456789abcdef";
bytes20 value = bytes20(_addr);
bytes memory str = new bytes(40); // An Ethereum address has 20 bytes, hence 40 characters in hex
for (uint256 i = 0; i < 20; i++) {
str[i * 2] = alphabet[uint8(value[i] >> 4)];
str[1 + i * 2] = alphabet[uint8(value[i] & 0x0f)];
/// @notice constructs json string data for address json from saved addresses array
function _constructJson() private view returns (string memory) {
string memory json = "[";

for (uint256 i = 0; i < savedAddresses.length; i++) {
json = string(
abi.encodePacked(
json,
"{",
'"addr": "',
vm.toString(savedAddresses[i].addr),
'",',
'"name": "',
savedAddresses[i].name,
'",',
'"chainId": ',
vm.toString(savedAddresses[i].chainId),
",",
'"isContract": ',
savedAddresses[i].isContract ? "true" : "false",
"}"
)
);

if (i < savedAddresses.length - 1) {
json = string(abi.encodePacked(json, ","));
}
}
return string(abi.encodePacked("0x", str));

json = string(abi.encodePacked(json, "]"));

return json;
}
}
8 changes: 8 additions & 0 deletions docs/overview/architecture/addresses.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ The `isAddressContract` function determines whether an address on the execution
addresses.isAddressContract("CONTRACT_NAME");
```

### Update addresses file

The `updateJson` function updates the `Addresses.json` file with the newly added and changed addresses. This is helpful as a user doesn't need to update the file manually after the proposal run.

```solidity
addresses.updateJson();
```

## Usage

When writing a proposal, set the `addresses` object using the `setAddresses` method. Ensure the correct path for `Addresses.json` file is passed inside the constructor while creating the `addresses` object. Use the `addresses` object to add, update, retrieve, and remove addresses.
Expand Down
13 changes: 12 additions & 1 deletion docs/overview/architecture/proposal-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,17 @@ FPS is flexible enough so that for any different governance model, governance pr

<a id="#run-function"></a>

- `run()`: This function serves as the entry point for proposal execution. It selects the `primaryForkId` which will be used to run the proposal simulation. It executes `deploy()`, `afterDeployMock()`, `build()`, `simulate()`, `validate()`, and `print()` in that order if the flag for a function is set to true. `deploy()` is encapsulated in start and stop broadcast. This is done so that contracts can be deployed on-chain. For further reading, see the [run function](../overview/architecture/proposal-functions.md#run-function).
- `run()`: This function serves as the entry point for proposal execution. It selects the `primaryForkId` which will be used to run the proposal simulation. It executes `deploy()`, `afterDeployMock()`, `build()`, `simulate()`, `validate()`, `print()` and `addresses.updateJson()` in that order if the flag for a function is set to true. `deploy()` is encapsulated in start and stop broadcast. This is done so that contracts can be deployed on-chain.

Flags used in `run()` function:

- **DO_DEPLOY**: When set to true, triggers the deployment of contracts on-chain. Default value is true.
- **DO_AFTER_DEPLOY_MOCK**: When set to true, initiates post-deployment mocking processes. Used to simulate an action that has not happened yet for testing such as dealing tokens for testing or simulating scenarios after deployment. Default value is true.
- **DO_BUILD**: When set to true, controls the build process and transforms plain solidity code into calldata encoded for the user's governance model. Default value is true.
- **DO_SIMULATE**: When set to true, allows for the simulation of saved actions during the `build` step. Default value is true.
- **DO_VALIDATE**: When set to true, validates the system state post-proposal simulation. Default value is true.
- **DO_PRINT**: When set to true, prints proposal description, actions, and calldata. Default value is true.
- **DO_UPDATE_ADDRESS_JSON**: When set to true, updates the `Addresses.json` file with the newly added and changed addresses. Default value is false.

```solidity
function run() public virtual {
Expand All @@ -307,6 +317,7 @@ FPS is flexible enough so that for any different governance model, governance pr
if (DO_SIMULATE) simulate();
if (DO_VALIDATE) validate();
if (DO_PRINT) print();
if (DO_UPDATE_ADDRESS_JSON) addresses.updateJson();
}
```

Expand Down
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ libs = ['lib']
test = 'test'
auto_detect_solc = true
# Require read access for 'addresses' and 'out' folder on root repo for bytecode verification
fs_permissions = [{ access = "read", path = "./"}]
fs_permissions = [{ access = "read-write", path = "./"}]
optimizer = true
optimizer_runs = 200

Expand Down
37 changes: 26 additions & 11 deletions src/interface/IGovernor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface IGovernor {
Executed
}

/**
/**
* @notice module:voting
* @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
* be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
Expand Down Expand Up @@ -69,20 +69,26 @@ interface IGovernor {
* snapshot is performed at the end of this block. Hence, voting for this proposal starts at the beginning of the
* following block.
*/
function proposalSnapshot(uint256 proposalId) external view returns (uint256);
function proposalSnapshot(
uint256 proposalId
) external view returns (uint256);

/**
* @notice module:core
* @dev Timepoint at which votes close. If using block number, votes close at the end of this block, so it is
* possible to cast a vote during this block.
*/
function proposalDeadline(uint256 proposalId) external view returns (uint256);
function proposalDeadline(
uint256 proposalId
) external view returns (uint256);

/**
* @notice module:core
* @dev The account that created a proposal.
*/
function proposalProposer(uint256 proposalId) external view returns (address);
function proposalProposer(
uint256 proposalId
) external view returns (address);

/**
* @notice module:core
Expand All @@ -96,7 +102,9 @@ interface IGovernor {
* @notice module:core
* @dev Whether a proposal needs to be queued before execution.
*/
function proposalNeedsQueuing(uint256 proposalId) external view returns (bool);
function proposalNeedsQueuing(
uint256 proposalId
) external view returns (bool);

/**
* @notice module:user-config
Expand Down Expand Up @@ -141,7 +149,10 @@ interface IGovernor {
* Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
* multiple), {ERC20Votes} tokens.
*/
function getVotes(address account, uint256 timepoint) external view returns (uint256);
function getVotes(
address account,
uint256 timepoint
) external view returns (uint256);

/**
* @notice module:reputation
Expand All @@ -157,7 +168,10 @@ interface IGovernor {
* @notice module:voting
* @dev Returns whether `account` has cast a vote on `proposalId`.
*/
function hasVoted(uint256 proposalId, address account) external view returns (bool);
function hasVoted(
uint256 proposalId,
address account
) external view returns (bool);

/**
* @dev Create a new proposal. Vote start after a delay specified by {IGovernor-votingDelay} and lasts for a
Expand Down Expand Up @@ -226,7 +240,10 @@ interface IGovernor {
*
* Emits a {VoteCast} event.
*/
function castVote(uint256 proposalId, uint8 support) external returns (uint256 balance);
function castVote(
uint256 proposalId,
uint8 support
) external returns (uint256 balance);

/**
* @dev Cast a vote with a reason
Expand Down Expand Up @@ -277,8 +294,7 @@ interface IGovernor {
bytes memory params,
bytes memory signature
) external returns (uint256 balance);

}
}

interface IGovernorTimelockControl {
/**
Expand All @@ -290,4 +306,3 @@ interface IGovernorTimelockControl {
interface IGovernorVotes {
function token() external view returns (address);
}

30 changes: 25 additions & 5 deletions src/interface/IVotes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ interface IVotes {
/**
* @dev Emitted when an account changes their delegate.
*/
event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);
event DelegateChanged(
address indexed delegator,
address indexed fromDelegate,
address indexed toDelegate
);

/**
* @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of voting units.
*/
event DelegateVotesChanged(address indexed delegate, uint256 previousVotes, uint256 newVotes);
event DelegateVotesChanged(
address indexed delegate,
uint256 previousVotes,
uint256 newVotes
);

/**
* @dev Returns the current amount of votes that `account` has.
Expand All @@ -30,7 +38,10 @@ interface IVotes {
* @dev Returns the amount of votes that `account` had at a specific moment in the past. If the `clock()` is
* configured to use block numbers, this will return the value at the end of the corresponding block.
*/
function getPastVotes(address account, uint256 timepoint) external view returns (uint256);
function getPastVotes(
address account,
uint256 timepoint
) external view returns (uint256);

/**
* @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is
Expand All @@ -40,7 +51,9 @@ interface IVotes {
* Votes that have not been delegated are still part of total supply, even though they would not participate in a
* vote.
*/
function getPastTotalSupply(uint256 timepoint) external view returns (uint256);
function getPastTotalSupply(
uint256 timepoint
) external view returns (uint256);

/**
* @dev Returns the delegate that `account` has chosen.
Expand All @@ -55,5 +68,12 @@ interface IVotes {
/**
* @dev Delegates votes from signer to `delegatee`.
*/
function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
function delegateBySig(
address delegatee,
uint256 nonce,
uint256 expiry,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
2 changes: 1 addition & 1 deletion src/proposals/GovernorBravoProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ abstract contract GovernorBravoProposal is Proposal {
/// @notice Getter function for `GovernorBravoDelegate.propose()` calldata
function getCalldata()
public
virtual
view
virtual
override
returns (bytes memory data)
{
Expand Down
Loading
Loading