diff --git a/README.md b/README.md index 9265b45..14aa09e 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,26 @@ -## Foundry +## Tea Scripts -**Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.** +This repo contains scripts to run on a local devnet of the Layer Tea network to verify the network's functionality. -Foundry consists of: +### Prerequisites -- **Forge**: Ethereum testing framework (like Truffle, Hardhat and DappTools). -- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data. -- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. -- **Chisel**: Fast, utilitarian, and verbose solidity REPL. +- Run a local devnet, and save the L2 RPC URL. +- Set `PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80` in your environment (this corresponds to a prefunded address on the devnet) +- Set `OWNER_PRIVATE_KEY=???` in your environment (this is the address who can update the fallback price and oracle) +- Run the `Deploy.s.sol` and `Airdrop.s.sol` scripts on the `GPGWallet` repo (you must use the same `PREFUNDED_PRIVATE_KEY` for these transactions so signatures are consistent). -## Documentation +### GPG Wallet Script -https://book.getfoundry.sh/ +- Copy the address of the wallet with the `0x49CEB217B43F2378` Key ID to `AddSigner.s.sol` (which corresponds to the GPG key used to provide the signature in that script) +- Run `forge script --rpc-url [L2RPC] script/GPGWallet/AddSigner.s.sol:AddSignerScript --broadcast` +- Verify that the transaction succeeded and the terminal output confirms the signer was added -## Usage +### L1 Data Fee Script -### Build - -```shell -$ forge build -``` - -### Test - -```shell -$ forge test -``` - -### Format - -```shell -$ forge fmt -``` - -### Gas Snapshots - -```shell -$ forge snapshot -``` - -### Anvil - -```shell -$ anvil -``` - -### Deploy - -```shell -$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key -``` - -### Cast - -```shell -$ cast -``` - -### Help - -```shell -$ forge --help -$ anvil --help -$ cast --help -``` +- We want to test that the data fee is adjusted for the currency, is responsive to the fallback price changing, and is responsive to an oracle. +- Note that after these transactions go through, the updates aren't propagated until the next epoch, so we need to wait at least 15-20 seconds between transactions. +- First, fund the owner account with ETH for transactions by calling `forge script --rpc-url [L2RPC] script/L1DataFee/FundOwner.s.sol:FundOwnerScript --broadcast`. +- Wait approximately 5 minutes for the L1BaseFee to fall to the minimum. You can check this with `cast call --rpc-url [L2RPC] 0x4200000000000000000000000000000000000015 "basefee()"`. It should return `0x7`. +- Run `forge script --rpc-url [L2RPC] script/L1DataFee/SendL2Tx.s.sol:SendL2Tx --broadcast` to send a transaction. Once the transaction is completed, use the tx hash to get the receipt with `cast receipt --rpc-url [L2RPC] [TX_HASH]`. The L1 Data Fee should be 16.8 billion or `0x3e95ba800`. +- Now, let's set a fallback. Run `forge script --rpc-url [L2RPC] script/L1DataFee/UpdateFallback.s.sol:UpdateFallbackScript --broadcast`. Wait for at least 15-20 seconds for the update to push through to the oracle. Then call the SendL2Tx transaction again, and use the tx hash to get the receipt with `cast receipt --rpc-url [L2RPC] [TX_HASH]`. The fallback should be set to 11.2 billion or `0x29b927000`. +- Finally, let's set an oracle. Run `forge script --rpc-url [L2RPC] script/L1DataFee/UpdateOracle.s.sol:UpdateOracleScript --broadcast`. Wait for at least 15-20 seconds for the update to push through to the oracle. Then call the SendL2Tx transaction again, and use the tx hash to get the receipt with `cast receipt --rpc-url [L2RPC] [TX_HASH]`. The oracle should be set to 22.4 billion or `0x53724e000`. diff --git a/script/Counter.s.sol b/script/Counter.s.sol deleted file mode 100644 index cdc1fe9..0000000 --- a/script/Counter.s.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Script, console} from "forge-std/Script.sol"; -import {Counter} from "../src/Counter.sol"; - -contract CounterScript is Script { - Counter public counter; - - function setUp() public {} - - function run() public { - vm.startBroadcast(); - - counter = new Counter(); - - vm.stopBroadcast(); - } -} diff --git a/script/GPGWallet/AddSigner.s.sol b/script/GPGWallet/AddSigner.s.sol new file mode 100644 index 0000000..4f78581 --- /dev/null +++ b/script/GPGWallet/AddSigner.s.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.15; + +import {Script, console} from "forge-std/Script.sol"; +import {IGPGWallet} from "src/IGPGWalletImpl.sol"; + +contract AddSignerScript is Script { + // Add deployed GPG Wallet here. + IGPGWallet constant WALLET = IGPGWallet(payable(address(1))); + + address EOA = makeAddr("eoa"); + bytes PUBKEY = + hex"9833046768354e16092b06010401da470f0101074089ea06d9820134822b9ddaeef1929c50ddfd9bbcf7c0794f3082d864fecb30feb42f5a616368204f62726f6e7420287465612d676574682d7465737429203c7a6f62726f6e7440676d61696c2e636f6d3e88930413160a003b162104c4e971386f7e24899b765c6b49ceb217b43f237805026768354e021b03050b0908070202220206150a09080b020416020301021e07021780000a091049ceb217b43f2378e65600ff538b73b85fc29fe716c0857343ac1efb4ac2864fd346de79f00d0e0f6d6e8e970100cdaf800a4ea1c9fabe8c982a191bff567c16019dad016c06e643b689ff3fd60eb838046768354e120a2b060104019755010501010740cf010ab1e65c0a4560292d4f8faaf2c03b6e115f2482464404d12bed986c8f530301080788780418160a0020162104c4e971386f7e24899b765c6b49ceb217b43f237805026768354e021b0c000a091049ceb217b43f237866a900fe2d50d10d916ced462d925220880b538cc9ab4fde817aa5bb3928d4f2a46003a50100d420071637d56defa999a22bc43bf0b0b179cf288d9643a54e98c13eb346df0a"; + bytes SIGNATURE = + hex"88750400160a001d162104c4e971386f7e24899b765c6b49ceb217b43f237805026793d29c000a091049ceb217b43f2378221b0100f01127f4494ccba47c7c177dfc84fd37e2521e4cdca171ff68220a36156d2a1300ff5cdff84af9d791cc03bf3d1098c97f858810d4858f4fed7bbc3c19ef166dda0c"; + + function run() external { + uint256 prefundedPrivateKey = vm.envUint("PREFUNDED_PRIVATE_KEY"); + vm.startBroadcast(prefundedPrivateKey); + + WALLET.addSigner(EOA, 0, 0, bytes32(0), PUBKEY, SIGNATURE); + + console.log("Is EOA now signer?"); + console.log(WALLET.signers(EOA)); + + vm.stopBroadcast(); + } +} diff --git a/script/L1DataFee/.DS_Store b/script/L1DataFee/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/script/L1DataFee/.DS_Store differ diff --git a/script/L1DataFee/FundOwner.s.sol b/script/L1DataFee/FundOwner.s.sol new file mode 100644 index 0000000..5d914a1 --- /dev/null +++ b/script/L1DataFee/FundOwner.s.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script, console} from "forge-std/Script.sol"; +import {IProxyAdmin} from "src/IProxyAdmin.sol"; + +contract FundOwnerScript is Script { + IProxyAdmin constant PROXY_ADMIN = IProxyAdmin(0x4200000000000000000000000000000000000018); + + function run() external { + uint256 prefundedPrivateKey = vm.envUint("PRIVATE_KEY"); + + vm.startBroadcast(prefundedPrivateKey); + + payable(PROXY_ADMIN.owner()).transfer(1 ether); + + vm.stopBroadcast(); + } +} diff --git a/script/L1DataFee/SendL2Tx.s.sol b/script/L1DataFee/SendL2Tx.s.sol new file mode 100644 index 0000000..6bcfccf --- /dev/null +++ b/script/L1DataFee/SendL2Tx.s.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script, console} from "forge-std/Script.sol"; + +contract SendL2Tx is Script { + address immutable EOA = makeAddr("eoa"); + + function run() external { + uint256 ownerPrivateKey = vm.envUint("OWNER_PRIVATE_KEY"); + vm.startBroadcast(ownerPrivateKey); + + // 4 words * 32 bytes = 128 bytes + bytes32 h = keccak256("hello"); + bytes memory cd = abi.encode(h, h, h, h); + (bool s,) = EOA.call(cd); + require(s); + + vm.stopBroadcast(); + } +} diff --git a/script/L1DataFee/UpdateFallback.s.sol b/script/L1DataFee/UpdateFallback.s.sol new file mode 100644 index 0000000..25efd95 --- /dev/null +++ b/script/L1DataFee/UpdateFallback.s.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script, console} from "forge-std/Script.sol"; +import {IGasPriceOracle} from "src/IGasPriceOracle.sol"; + +contract UpdateFallbackScript is Script { + IGasPriceOracle constant GAS_PRICE_ORACLE = IGasPriceOracle(0x420000000000000000000000000000000000000F); + + function run() external { + uint256 ownerPrivateKey = vm.envUint("OWNER_PRIVATE_KEY"); + vm.startBroadcast(ownerPrivateKey); + + GAS_PRICE_ORACLE.setFallbackPrice(1_000_000e18); + + // It shouldn't update until the next system tx. + (, uint160 latestPrice) = GAS_PRICE_ORACLE.getLatestPrice(); + require(latestPrice == 1_500_000e18); + + vm.stopBroadcast(); + } +} diff --git a/script/L1DataFee/UpdateOracle.s.sol b/script/L1DataFee/UpdateOracle.s.sol new file mode 100644 index 0000000..355c668 --- /dev/null +++ b/script/L1DataFee/UpdateOracle.s.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Script, console} from "forge-std/Script.sol"; +import {FakeWETH, MockOracle} from "src/MockOracle.sol"; +import {IGasPriceOracle} from "src/IGasPriceOracle.sol"; + +contract UpdateOracleScript is Script { + IGasPriceOracle constant GAS_PRICE_ORACLE = IGasPriceOracle(0x420000000000000000000000000000000000000F); + + function run() external { + uint256 ownerPrivateKey = vm.envUint("OWNER_PRIVATE_KEY"); + vm.startBroadcast(ownerPrivateKey); + + address weth = address(new FakeWETH()); + MockOracle oracle = new MockOracle(weth); + + GAS_PRICE_ORACLE.setOracleConfig(10, address(oracle)); + + vm.stopBroadcast(); + } +} diff --git a/src/Counter.sol b/src/Counter.sol deleted file mode 100644 index aded799..0000000 --- a/src/Counter.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -contract Counter { - uint256 public number; - - function setNumber(uint256 newNumber) public { - number = newNumber; - } - - function increment() public { - number++; - } -} diff --git a/src/IGPGWallet.sol b/src/IGPGWallet.sol new file mode 100644 index 0000000..318b182 --- /dev/null +++ b/src/IGPGWallet.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IGPGWallet { + function addSigner( + address signer, + uint256 paymasterFee, + uint256 deadline, + bytes32 salt, + bytes memory pubKey, + bytes memory signature + ) external; +} diff --git a/src/IGasPriceOracle.sol b/src/IGasPriceOracle.sol new file mode 100644 index 0000000..3c2bb36 --- /dev/null +++ b/src/IGasPriceOracle.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IGasPriceOracle { + function setFallbackPrice(uint160) external; + function getLatestPrice() external returns (uint96, uint160); + function setOracleConfig(uint96, address) external; +} diff --git a/src/IProxyAdmin.sol b/src/IProxyAdmin.sol new file mode 100644 index 0000000..60073b3 --- /dev/null +++ b/src/IProxyAdmin.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +interface IProxyAdmin { + function owner() external view returns (address); + function transferOwnership(address newOwner) external; +} diff --git a/src/MockOracle.sol b/src/MockOracle.sol new file mode 100644 index 0000000..35adf54 --- /dev/null +++ b/src/MockOracle.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.15; + +contract FakeWETH { + function name() public pure returns (string memory) { + return "Wrapped Ether"; + } +} + +contract MockOracle { + address weth; + + constructor(address _weth) { + weth = _weth; + } + + function getReserves() public pure returns (uint256, uint256, uint256) { + return (4_000_000e18, 2e18, 0); + } + + function tokens() public view returns (address, address) { + return (0x4200000000000000000000000000000000000006, weth); + } + + function quote(address token, uint256 amount, uint256) external pure returns (uint256) { + if (token == 0x4200000000000000000000000000000000000006) { + return amount / 2_000_000; + } else { + return amount * 2_000_000; + } + } +} diff --git a/test/Counter.t.sol b/test/Counter.t.sol deleted file mode 100644 index 54b724f..0000000 --- a/test/Counter.t.sol +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: UNLICENSED -pragma solidity ^0.8.13; - -import {Test, console} from "forge-std/Test.sol"; -import {Counter} from "../src/Counter.sol"; - -contract CounterTest is Test { - Counter public counter; - - function setUp() public { - counter = new Counter(); - counter.setNumber(0); - } - - function test_Increment() public { - counter.increment(); - assertEq(counter.number(), 1); - } - - function testFuzz_SetNumber(uint256 x) public { - counter.setNumber(x); - assertEq(counter.number(), x); - } -}