Add proposal and tests solidity code

This commit is contained in:
Theo 2023-10-27 00:41:47 -07:00
parent 8c97665093
commit 51a0b178bf
9 changed files with 92 additions and 45 deletions

@ -1,4 +1,4 @@
# Proposal title # Proposal to compensate relayer attack losses
### Changes / effect description ### Changes / effect description
@ -10,15 +10,14 @@
- Rust ([Need only for Windows](https://doc.rust-lang.org/cargo/getting-started/installation.html)) - Rust ([Need only for Windows](https://doc.rust-lang.org/cargo/getting-started/installation.html))
- Foundryup ([Windows](https://github.com/altugbakan/foundryup-windows), [Linux](https://book.getfoundry.sh/getting-started/installation)) - Foundryup ([Windows](https://github.com/altugbakan/foundryup-windows), [Linux](https://book.getfoundry.sh/getting-started/installation))
- Node 14 or higher ([Windows](https://github.com/coreybutler/nvm-windows), [Linux](https://github.com/nvm-sh/nvm)) - Node 18 or higher ([Windows](https://github.com/coreybutler/nvm-windows), [Linux](https://github.com/nvm-sh/nvm))
### Installation ### Installation
```text ```text
git clone --recurse-submodules <proposal-repo-link> git clone --recurse-submodules https://git.tornado.ws/Theo/proposal-33-compensate-relayer-losses
cd <proposal-name> cd proposal-33-compensate-relayer-losses
npm install npm install
npm run init
``` ```
### Testing ### Testing

1
lib/forge-std Submodule

@ -0,0 +1 @@
Subproject commit f73c73d2018eb6a111f35e4dae7b4f27401e9421

@ -19,6 +19,7 @@
"@openzeppelin/upgrades-core": "^1.26.2", "@openzeppelin/upgrades-core": "^1.26.2",
"axios": "^1.5.1", "axios": "^1.5.1",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"env-cmd": "^10.1.0",
"web3": "^4.2.0", "web3": "^4.2.0",
"web3-utils": "^4.0.7" "web3-utils": "^4.0.7"
}, },

@ -15,11 +15,7 @@ async function fetchFailedWithdrawals() {
let failedWithdrawalTransactions = []; let failedWithdrawalTransactions = [];
for (let blockNumber = attackStartBlock; blockNumber <= attackEndBlock; blockNumber++) { for (let blockNumber = attackStartBlock; blockNumber <= attackEndBlock; blockNumber++) {
let block = null; const block = await web3.eth.getBlock(blockNumber);
while (block == null)
try {
block = await web3.eth.getBlock(blockNumber);
} catch (e) {}
const results = await Promise.allSettled(block.transactions.map((tx) => web3.eth.getTransactionReceipt(tx as string))); const results = await Promise.allSettled(block.transactions.map((tx) => web3.eth.getTransactionReceipt(tx as string)));
const transactions = results.filter((r) => r.status === "fulfilled").map((r) => (r as PromiseFulfilledResult<TxReceipt>).value); const transactions = results.filter((r) => r.status === "fulfilled").map((r) => (r as PromiseFulfilledResult<TxReceipt>).value);
failedWithdrawalTransactions.push(...transactions.filter((tx) => tx.to === routerAddress.toLowerCase() && tx.status == 0)); failedWithdrawalTransactions.push(...transactions.filter((tx) => tx.to === routerAddress.toLowerCase() && tx.status == 0));

@ -1,11 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { IGovernance } from "@interfaces/IGovernance.sol";
contract ExampleProposal {
function executeProposal() public {
/* ... */
}
}

@ -0,0 +1,29 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { IGovernance } from "@interfaces/IGovernance.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
contract RelayerCompensationProposal {
IERC20 public constant TORN = IERC20(0x77777FeDdddFfC19Ff86DB637967013e6C6A116C);
struct RelayerLoss {
address relayer;
uint256 lostAmountInTorn;
}
function executeProposal() public {
// Data from 'data/relayerLosses.txt', generated by 'scripts/calculateLosses.ts'
RelayerLoss[4] memory relayerLosses = [
RelayerLoss(0x864DF9CD806D58341f13602103Bf853066ff962a, 625_894_225_496_155_734_516),
RelayerLoss(0x5555555731006f71f121144534Ca7C8799F66AA3, 43_970_301_082_908_267_318),
RelayerLoss(0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C, 189_640_345_451_160_934_437),
RelayerLoss(0x03392600086874456E08D2bAc104380BCdEBCfC0, 129_757_783_603_193_410_350)
];
for (uint256 i = 0; i < relayerLosses.length; i++) {
TORN.transfer(relayerLosses[i].relayer, relayerLosses[i].lostAmountInTorn);
}
}
}

@ -1,24 +0,0 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { ProposalUtils } from "./utils/ProposalUtils.sol";
import { ExampleProposal } from "@root/ExampleProposal.sol";
import { console2 } from "@forge-std/console2.sol";
contract TestExampleProposal is ProposalUtils {
modifier executeCurrentProposalBefore() {
createAndExecuteProposal();
_;
}
function createAndExecuteProposal() public {
address proposalAddress = address(new ExampleProposal()); /* your proposal initialization */
proposeAndExecute(proposalAddress);
}
/* your tests */
function testProposal() public executeCurrentProposalBefore { }
}

@ -0,0 +1,56 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import { ProposalUtils } from "./utils/ProposalUtils.sol";
import { RelayerCompensationProposal } from "@root/RelayerCompensationProposal.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { console2 } from "@forge-std/console2.sol";
contract TestExampleProposal is ProposalUtils, RelayerCompensationProposal {
modifier executeCurrentProposalBefore() {
createAndExecuteProposal();
_;
}
function createAndExecuteProposal() public {
address proposalAddress = address(new RelayerCompensationProposal());
proposeAndExecute(proposalAddress);
}
function getRelayerLosses() internal pure returns (RelayerLoss[4] memory) {
return [
RelayerLoss(0x864DF9CD806D58341f13602103Bf853066ff962a, 625_894_225_496_155_734_516),
RelayerLoss(0x5555555731006f71f121144534Ca7C8799F66AA3, 43_970_301_082_908_267_318),
RelayerLoss(0x2Ee39Ff05643bC7cc9ed31B71e142429044A425C, 189_640_345_451_160_934_437),
RelayerLoss(0x03392600086874456E08D2bAc104380BCdEBCfC0, 129_757_783_603_193_410_350)
];
}
function testRelayerGotCompensation() public {
RelayerLoss[4] memory relayerLosses = getRelayerLosses();
uint256[4] memory balancesBeforeProposal;
for (uint256 i = 0; i < relayerLosses.length; i++) {
balancesBeforeProposal[i] = TORN.balanceOf(relayerLosses[i].relayer);
}
createAndExecuteProposal();
for (uint256 i = 0; i < relayerLosses.length; i++) {
uint256 updatedBalance = TORN.balanceOf(relayerLosses[i].relayer);
require(balancesBeforeProposal[i] + relayerLosses[i].lostAmountInTorn == updatedBalance, "Compensation failed");
}
}
function testLossesDataIsValid() public pure {
RelayerLoss[4] memory relayerLosses = getRelayerLosses();
uint256 tornDecimals = 1e18;
require(relayerLosses[0].lostAmountInTorn / tornDecimals == 625);
require(relayerLosses[1].lostAmountInTorn / tornDecimals == 43);
require(relayerLosses[2].lostAmountInTorn / tornDecimals == 189);
require(relayerLosses[3].lostAmountInTorn / tornDecimals == 129);
}
}