feat: add guarded Base Sepolia encore
This commit is contained in:
@@ -20,6 +20,12 @@ contract CheckState is DemoScript {
|
||||
_printEducationalWarning();
|
||||
bool deployedStage = keccak256(bytes(stage)) == keccak256("deployed");
|
||||
Manifest memory manifest = _readManifest(manifestPath, !deployedStage);
|
||||
if (block.chainid == BASE_SEPOLIA_CHAIN_ID) {
|
||||
address expectedSender = vm.envAddress("BASE_SEPOLIA_SENDER");
|
||||
(address presenter, address recipient,) = _requireBaseConfig(expectedSender);
|
||||
_assertAddress("Presenter", manifest.actors[0].address_, presenter);
|
||||
_assertAddress("Recipient", manifest.actors[1].address_, recipient);
|
||||
}
|
||||
BankV1 bank = BankV1(manifest.proxy);
|
||||
MockUSDC token = MockUSDC(manifest.token);
|
||||
|
||||
|
||||
+13
-5
@@ -11,6 +11,12 @@ contract DeployV1 is DemoScript {
|
||||
_requireSupportedChain(block.chainid);
|
||||
_printEducationalWarning();
|
||||
address sender = vm.envAddress("SCRIPT_SENDER");
|
||||
address recipient;
|
||||
string memory publicRpcUrl;
|
||||
|
||||
if (block.chainid == BASE_SEPOLIA_CHAIN_ID) {
|
||||
(, recipient, publicRpcUrl) = _requireBaseConfig(sender);
|
||||
}
|
||||
|
||||
if (block.chainid == ANVIL_CHAIN_ID) {
|
||||
(uint256 ownerKey, address derivedOwner) = _deriveLocalActor(block.chainid, 0);
|
||||
@@ -40,17 +46,18 @@ contract DeployV1 is DemoScript {
|
||||
manifest.network = block.chainid == ANVIL_CHAIN_ID ? "anvil" : "baseSepolia";
|
||||
manifest.chainId = block.chainid;
|
||||
manifest.deploymentBlock = 0;
|
||||
manifest.rpcUrl = block.chainid == ANVIL_CHAIN_ID ? "http://127.0.0.1:8545" : "";
|
||||
manifest.rpcUrl = block.chainid == ANVIL_CHAIN_ID ? "http://127.0.0.1:8545" : publicRpcUrl;
|
||||
manifest.explorerBaseUrl = block.chainid == BASE_SEPOLIA_CHAIN_ID ? "https://sepolia.basescan.org" : "";
|
||||
manifest.token = tokenAddress;
|
||||
manifest.proxy = proxy;
|
||||
manifest.implementation = implementation;
|
||||
manifest.owner = sender;
|
||||
manifest.actors = _actors(sender);
|
||||
manifest.actors = _actors(sender, recipient);
|
||||
|
||||
_writeManifest(_manifestPath(PENDING_MANIFEST_PATH), manifest);
|
||||
}
|
||||
|
||||
function _actors(address sender) private view returns (Actor[] memory actors) {
|
||||
function _actors(address sender, address recipient) private view returns (Actor[] memory actors) {
|
||||
if (block.chainid == ANVIL_CHAIN_ID) {
|
||||
actors = new Actor[](3);
|
||||
actors[0] = Actor({label: "owner", address_: sender});
|
||||
@@ -59,8 +66,9 @@ contract DeployV1 is DemoScript {
|
||||
actors[1].label = "Alice";
|
||||
actors[2].label = "Bob";
|
||||
} else {
|
||||
actors = new Actor[](1);
|
||||
actors[0] = Actor({label: "owner", address_: sender});
|
||||
actors = new Actor[](2);
|
||||
actors[0] = Actor({label: "Presenter", address_: sender});
|
||||
actors[1] = Actor({label: "Recipient", address_: recipient});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.35;
|
||||
|
||||
import {BankV1} from "../src/BankV1.sol";
|
||||
import {MockUSDC} from "../src/MockUSDC.sol";
|
||||
import {DemoScript} from "./lib/DemoScript.sol";
|
||||
|
||||
contract SeedBaseSepolia is DemoScript {
|
||||
uint256 internal constant SEED_AMOUNT = 1_000e6;
|
||||
|
||||
function run() external {
|
||||
if (block.chainid != BASE_SEPOLIA_CHAIN_ID) revert UnsupportedChain(block.chainid);
|
||||
_printEducationalWarning();
|
||||
address scriptSender = vm.envAddress("SCRIPT_SENDER");
|
||||
(address presenter, address recipient,) = _requireBaseConfig(scriptSender);
|
||||
Manifest memory manifest = _readManifest(_manifestPath(ACTIVE_MANIFEST_PATH), true);
|
||||
_assertAddress("Presenter", manifest.actors[0].address_, presenter);
|
||||
_assertAddress("Recipient", manifest.actors[1].address_, recipient);
|
||||
|
||||
BankV1 bank = BankV1(manifest.proxy);
|
||||
MockUSDC token = MockUSDC(manifest.token);
|
||||
_assertDeployedState(manifest);
|
||||
|
||||
vm.startBroadcast(presenter);
|
||||
token.mint(presenter, SEED_AMOUNT);
|
||||
token.approve(manifest.proxy, SEED_AMOUNT);
|
||||
bank.deposit(SEED_AMOUNT);
|
||||
vm.stopBroadcast();
|
||||
|
||||
_assertUint("Presenter internal balance", SEED_AMOUNT, bank.balanceOf(presenter));
|
||||
_assertUint("Recipient internal balance", 0, bank.balanceOf(recipient));
|
||||
_assertUint("liabilities", SEED_AMOUNT, bank.totalLiabilities());
|
||||
_assertUint("reserves", SEED_AMOUNT, token.balanceOf(manifest.proxy));
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,18 @@ contract TransferV2Demo is DemoScript {
|
||||
}
|
||||
|
||||
function _run(string memory manifestPath) internal {
|
||||
if (block.chainid != ANVIL_CHAIN_ID) revert UnsupportedChain(block.chainid);
|
||||
_requireSupportedChain(block.chainid);
|
||||
_printEducationalWarning();
|
||||
Manifest memory manifest = _readManifest(manifestPath, true);
|
||||
if (block.chainid == BASE_SEPOLIA_CHAIN_ID) {
|
||||
_runBase(manifest);
|
||||
return;
|
||||
}
|
||||
|
||||
_runLocal(manifest);
|
||||
}
|
||||
|
||||
function _runLocal(Manifest memory manifest) private {
|
||||
(uint256 aliceKey, address alice) = _deriveLocalActor(block.chainid, 1);
|
||||
address bob = manifest.actors[2].address_;
|
||||
_assertAddress("Alice actor", manifest.actors[1].address_, alice);
|
||||
@@ -38,4 +47,31 @@ contract TransferV2Demo is DemoScript {
|
||||
_assertUint("reserves", reserves, token.balanceOf(manifest.proxy));
|
||||
_assertUint("surplus", 0, token.balanceOf(manifest.proxy) - bank.totalLiabilities());
|
||||
}
|
||||
|
||||
function _runBase(Manifest memory manifest) private {
|
||||
address scriptSender = vm.envAddress("SCRIPT_SENDER");
|
||||
(address presenter, address recipient,) = _requireBaseConfig(scriptSender);
|
||||
_assertAddress("Presenter", manifest.actors[0].address_, presenter);
|
||||
_assertAddress("Recipient", manifest.actors[1].address_, recipient);
|
||||
|
||||
BankV2 bank = BankV2(manifest.proxy);
|
||||
MockUSDC token = MockUSDC(manifest.token);
|
||||
_assertUint("version", 2, bank.contractVersion());
|
||||
_assertUint("Presenter internal balance", 1_000e6, bank.balanceOf(presenter));
|
||||
_assertUint("Recipient internal balance", 0, bank.balanceOf(recipient));
|
||||
uint256 liabilities = bank.totalLiabilities();
|
||||
uint256 reserves = token.balanceOf(manifest.proxy);
|
||||
_assertUint("liabilities", 1_000e6, liabilities);
|
||||
_assertUint("reserves", 1_000e6, reserves);
|
||||
|
||||
vm.startBroadcast(presenter);
|
||||
bank.transferBalance(recipient, 250e6);
|
||||
vm.stopBroadcast();
|
||||
|
||||
_assertUint("Presenter internal balance", 750e6, bank.balanceOf(presenter));
|
||||
_assertUint("Recipient internal balance", 250e6, bank.balanceOf(recipient));
|
||||
_assertUint("liabilities", liabilities, bank.totalLiabilities());
|
||||
_assertUint("reserves", reserves, token.balanceOf(manifest.proxy));
|
||||
_assertUint("surplus", 0, token.balanceOf(manifest.proxy) - bank.totalLiabilities());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,15 @@ contract UpgradeV2 is DemoScript {
|
||||
internal
|
||||
returns (bool upgraded, address implementation)
|
||||
{
|
||||
address configuredRecipient;
|
||||
if (block.chainid == BASE_SEPOLIA_CHAIN_ID) {
|
||||
(, configuredRecipient,) = _requireBaseConfig(sender);
|
||||
}
|
||||
Manifest memory manifest = _readManifest(activePath, true);
|
||||
if (block.chainid == BASE_SEPOLIA_CHAIN_ID) {
|
||||
_assertAddress("Presenter", manifest.actors[0].address_, sender);
|
||||
_assertAddress("Recipient", manifest.actors[1].address_, configuredRecipient);
|
||||
}
|
||||
BankV1 bank = BankV1(manifest.proxy);
|
||||
|
||||
address actualImplementation = Upgrades.getImplementationAddress(manifest.proxy);
|
||||
|
||||
@@ -20,6 +20,7 @@ abstract contract DemoScript is Script {
|
||||
error InvalidDeploymentBlock();
|
||||
error InvalidManifestSchema(uint256 schemaVersion);
|
||||
error InvalidActorConfiguration();
|
||||
error InvalidPublicRpcUrl();
|
||||
error UnexpectedState(string label, uint256 expected, uint256 actual);
|
||||
error UnexpectedAddress(string label, address expected, address actual);
|
||||
|
||||
@@ -60,6 +61,72 @@ abstract contract DemoScript is Script {
|
||||
return vm.envOr("DEPLOYMENT_MANIFEST_PATH", defaultPath);
|
||||
}
|
||||
|
||||
function _requireBaseSender(address scriptSender) internal view returns (address sender) {
|
||||
sender = vm.envAddress("BASE_SEPOLIA_SENDER");
|
||||
_assertAddress("BASE_SEPOLIA_SENDER", scriptSender, sender);
|
||||
}
|
||||
|
||||
function _requireBaseConfig(address scriptSender)
|
||||
internal
|
||||
view
|
||||
returns (address sender, address recipient, string memory publicRpcUrl)
|
||||
{
|
||||
sender = _requireBaseSender(scriptSender);
|
||||
recipient = vm.envAddress("BASE_SEPOLIA_RECIPIENT");
|
||||
if (sender == address(0) || recipient == address(0) || sender == recipient) revert InvalidActorConfiguration();
|
||||
publicRpcUrl = vm.envString("BASE_SEPOLIA_PUBLIC_RPC_URL");
|
||||
_requirePublicHttpsUrl(publicRpcUrl);
|
||||
}
|
||||
|
||||
function _requirePublicHttpsUrl(string memory value) internal pure {
|
||||
bytes memory url = bytes(value);
|
||||
bytes memory prefix = bytes("https://");
|
||||
if (url.length <= prefix.length) revert InvalidPublicRpcUrl();
|
||||
for (uint256 i; i < prefix.length; ++i) {
|
||||
if (url[i] != prefix[i]) revert InvalidPublicRpcUrl();
|
||||
}
|
||||
|
||||
bool query;
|
||||
uint256 queryStart;
|
||||
for (uint256 i = prefix.length; i < url.length; ++i) {
|
||||
bytes1 character = url[i];
|
||||
if (!query && character == "@") revert InvalidPublicRpcUrl();
|
||||
if (character == "?") {
|
||||
query = true;
|
||||
queryStart = i + 1;
|
||||
break;
|
||||
}
|
||||
if (character == "#") break;
|
||||
}
|
||||
if (!query) return;
|
||||
|
||||
bytes memory lowered = new bytes(url.length - queryStart);
|
||||
for (uint256 i; i < lowered.length; ++i) {
|
||||
uint8 character = uint8(url[queryStart + i]);
|
||||
lowered[i] = character >= 65 && character <= 90 ? bytes1(character + 32) : bytes1(character);
|
||||
}
|
||||
if (
|
||||
_containsBytes(lowered, bytes("key=")) || _containsBytes(lowered, bytes("token="))
|
||||
|| _containsBytes(lowered, bytes("secret=")) || _containsBytes(lowered, bytes("password="))
|
||||
|| _containsBytes(lowered, bytes("credential="))
|
||||
) revert InvalidPublicRpcUrl();
|
||||
}
|
||||
|
||||
function _containsBytes(bytes memory haystack, bytes memory needle) private pure returns (bool) {
|
||||
if (needle.length > haystack.length) return false;
|
||||
for (uint256 i; i + needle.length <= haystack.length; ++i) {
|
||||
bool matches = true;
|
||||
for (uint256 j; j < needle.length; ++j) {
|
||||
if (haystack[i + j] != needle[j]) {
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matches) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function _readManifest(string memory path, bool active) internal view returns (Manifest memory manifest) {
|
||||
string memory json = vm.readFile(path);
|
||||
_assertExactManifestSchema(json);
|
||||
@@ -112,7 +179,7 @@ abstract contract DemoScript is Script {
|
||||
}
|
||||
|
||||
function _parseActors(string memory json, uint256 chainId) private view returns (Actor[] memory actors) {
|
||||
uint256 actorCount = chainId == ANVIL_CHAIN_ID ? 3 : 1;
|
||||
uint256 actorCount = chainId == ANVIL_CHAIN_ID ? 3 : 2;
|
||||
actors = new Actor[](actorCount);
|
||||
for (uint256 i; i < actorCount; ++i) {
|
||||
string memory index = vm.toString(i);
|
||||
@@ -157,9 +224,13 @@ abstract contract DemoScript is Script {
|
||||
}
|
||||
|
||||
if (
|
||||
manifest.chainId != BASE_SEPOLIA_CHAIN_ID || manifest.actors.length != 1
|
||||
|| !_equals(manifest.network, "baseSepolia") || !_equals(manifest.actors[0].label, "owner")
|
||||
|| manifest.actors[0].address_ != manifest.owner
|
||||
manifest.chainId != BASE_SEPOLIA_CHAIN_ID || manifest.actors.length != 2
|
||||
|| !_equals(manifest.network, "baseSepolia") || !_equals(manifest.actors[0].label, "Presenter")
|
||||
|| !_equals(manifest.actors[1].label, "Recipient") || manifest.actors[0].address_ != manifest.owner
|
||||
) revert InvalidActorConfiguration();
|
||||
if (
|
||||
manifest.actors[0].address_ == address(0) || manifest.actors[1].address_ == address(0)
|
||||
|| manifest.actors[0].address_ == manifest.actors[1].address_
|
||||
) revert InvalidActorConfiguration();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user