Celo's optimism
diff:
ignored:
+24223
-56
+703
-484
This is an overview of the changes in Celo’s optimism
implementation,
a fork of Optimism’s optimism
.
Changes are currently separated by sub-package or component. Check out the README for more details about each of these components and packages.
packages/*
+8875
-16
common-ts
contracts-bedrock
+8875
-16
diff --git OP/packages/contracts-bedrock/deploy-config/devnetL1-template.json CELO/packages/contracts-bedrock/deploy-config/devnetL1-template.json
index 11bc3557791da340df3ab721f88a888f97c28bd1..3b95ec96a8abf7215fbcc3a9c1fb50387398f4d2 100644
--- OP/packages/contracts-bedrock/deploy-config/devnetL1-template.json
+++ CELO/packages/contracts-bedrock/deploy-config/devnetL1-template.json
@@ -71,5 +71,6 @@ "daCommitmentType": "KeccakCommitment",
"daChallengeWindow": 16,
"daResolveWindow": 16,
"daBondSize": 1000000,
- "daResolverRefundPercentage": 0
+ "daResolverRefundPercentage": 0,
+ "deployCeloContracts": true
}
diff --git OP/packages/contracts-bedrock/deployments/31337-l2-deploy.json CELO/packages/contracts-bedrock/deployments/31337-l2-deploy.json
new file mode 100644
index 0000000000000000000000000000000000000000..e0d3b4311b98835db324e53b8e44441d92c66ca4
--- /dev/null
+++ CELO/packages/contracts-bedrock/deployments/31337-l2-deploy.json
@@ -0,0 +1,38 @@
+{
+ "BaseFeeVault": "0xC0d3c0D3c0d3C0D3C0D3C0d3c0D3C0D3c0d30019",
+ "BaseFeeVaultProxy": "0x4200000000000000000000000000000000000019",
+ "DeployerWhitelist": "0xc0d3c0d3C0d3c0D3c0d3C0D3c0d3C0d3c0D30002",
+ "DeployerWhitelistProxy": "0x4200000000000000000000000000000000000002",
+ "EAS": "0xC0D3c0D3C0d3c0D3c0D3C0D3c0D3c0d3c0d30021",
+ "EASProxy": "0x4200000000000000000000000000000000000021",
+ "GasPriceOracle": "0xc0d3C0d3C0d3c0D3C0D3C0d3C0d3C0D3C0D3000f",
+ "GasPriceOracleProxy": "0x420000000000000000000000000000000000000F",
+ "GovernanceToken": "0x4200000000000000000000000000000000000042",
+ "L1Block": "0xc0d3C0D3C0D3c0D3C0D3C0d3C0D3c0D3c0d30015",
+ "L1BlockNumber": "0xC0D3C0d3C0D3c0D3C0d3c0D3C0d3c0d3C0d30013",
+ "L1BlockNumberProxy": "0x4200000000000000000000000000000000000013",
+ "L1BlockProxy": "0x4200000000000000000000000000000000000015",
+ "L1FeeVault": "0xc0D3c0D3C0d3c0d3c0d3C0d3c0d3C0d3C0D3001A",
+ "L1FeeVaultProxy": "0x420000000000000000000000000000000000001A",
+ "L2CrossDomainMessenger": "0xC0d3c0d3c0D3c0D3C0d3C0D3C0D3c0d3c0d30007",
+ "L2CrossDomainMessengerProxy": "0x4200000000000000000000000000000000000007",
+ "L2ERC721Bridge": "0xC0D3c0d3c0d3c0d3c0D3C0d3C0D3C0D3c0d30014",
+ "L2ERC721BridgeProxy": "0x4200000000000000000000000000000000000014",
+ "L2StandardBridge": "0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010",
+ "L2StandardBridgeProxy": "0x4200000000000000000000000000000000000010",
+ "L2ToL1MessagePasser": "0xC0D3C0d3C0d3c0d3C0d3C0D3c0D3c0d3c0D30016",
+ "L2ToL1MessagePasserProxy": "0x4200000000000000000000000000000000000016",
+ "LegacyMessagePasser": "0xc0D3C0d3C0d3C0D3c0d3C0d3c0D3C0d3c0d30000",
+ "LegacyMessagePasserProxy": "0x4200000000000000000000000000000000000000",
+ "OptimismMintableERC20Factory": "0xc0D3c0d3C0d3c0d3c0D3c0d3c0D3c0D3c0D30012",
+ "OptimismMintableERC20FactoryProxy": "0x4200000000000000000000000000000000000012",
+ "OptimismMintableERC721Factory": "0xc0d3C0d3C0d3C0d3C0d3c0d3C0D3C0d3C0D30017",
+ "OptimismMintableERC721FactoryProxy": "0x4200000000000000000000000000000000000017",
+ "ProxyAdmin": "0xC0d3C0D3c0d3C0d3c0d3c0D3C0D3C0d3C0D30018",
+ "ProxyAdminProxy": "0x4200000000000000000000000000000000000018",
+ "SchemaRegistry": "0xc0d3c0d3c0d3C0d3c0d3C0D3C0D3c0d3C0D30020",
+ "SchemaRegistryProxy": "0x4200000000000000000000000000000000000020",
+ "SequencerFeeVault": "0xC0D3C0d3c0d3c0d3C0D3c0d3C0D3c0d3c0D30011",
+ "SequencerFeeVaultProxy": "0x4200000000000000000000000000000000000011",
+ "WETH": "0x4200000000000000000000000000000000000006"
+}
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/foundry.toml CELO/packages/contracts-bedrock/foundry.toml
index cef9f85bbaebdf1f1fc521d0cadf0aa2a8c7261d..1e313778bddd3815036de4aae364cd544f2209fb 100644
--- OP/packages/contracts-bedrock/foundry.toml
+++ CELO/packages/contracts-bedrock/foundry.toml
@@ -12,6 +12,7 @@ optimizer = true
optimizer_runs = 999999
remappings = [
'@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts',
+ '@multicall/=lib/multicall/src',
'@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts',
'@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts',
'@rari-capital/solmate/=lib/solmate',
@@ -51,6 +52,7 @@ { access='write', path='./semver-lock.json' },
{ access='read-write', path='./.testdata/' },
{ access='read', path='./kout-deployment' },
{ access='read', path='./test/fixtures' },
+ { access='read-write', path='../../op-chain-ops/cmd/celo-migrate/testdata/' },
]
libs = ["node_modules", "lib"]
diff --git OP/packages/contracts-bedrock/lib/multicall/LICENSE CELO/packages/contracts-bedrock/lib/multicall/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..2cc7ab2d68b7e8160d2d12153b975ef327c94ae9
--- /dev/null
+++ CELO/packages/contracts-bedrock/lib/multicall/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Matt Solomon
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git OP/packages/contracts-bedrock/lib/multicall/README.md CELO/packages/contracts-bedrock/lib/multicall/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..a5b889b1157161fad3cd23a03316bca6fb80cada
--- /dev/null
+++ CELO/packages/contracts-bedrock/lib/multicall/README.md
@@ -0,0 +1,5 @@
+Multicall3 contract for local devnet.
+This is required by viem for using the op-stack functionality.
+
+Contract taken from:
+https://github.com/mds1/multicall/commit/d7b62458c99c650ce1efa7464ffad69d2059ad56
diff --git OP/packages/contracts-bedrock/scripts/L2Genesis.s.sol CELO/packages/contracts-bedrock/scripts/L2Genesis.s.sol
index ceae376ee5c2df2149d332e4e965e98ff2ef1e1f..8249b7287b7257a9af8d2708a3fe6ed7dfef5141 100644
--- OP/packages/contracts-bedrock/scripts/L2Genesis.s.sol
+++ CELO/packages/contracts-bedrock/scripts/L2Genesis.s.sol
@@ -3,6 +3,7 @@ pragma solidity 0.8.15;
// Testing
import { Script } from "forge-std/Script.sol";
+import { stdJson } from "forge-std/StdJson.sol";
import { console2 as console } from "forge-std/console2.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
@@ -36,6 +37,18 @@ import { ICrossDomainMessenger } from "src/universal/interfaces/ICrossDomainMessenger.sol";
import { IL2CrossDomainMessenger } from "src/L2/interfaces/IL2CrossDomainMessenger.sol";
import { IGasPriceOracle } from "src/L2/interfaces/IGasPriceOracle.sol";
import { IL1Block } from "src/L2/interfaces/IL1Block.sol";
+
+import { GoldToken } from "src/celo/GoldToken.sol";
+import { CeloPredeploys } from "src/celo/CeloPredeploys.sol";
+import { CeloRegistry } from "src/celo/CeloRegistry.sol";
+import { FeeHandler } from "src/celo/FeeHandler.sol";
+import { MentoFeeHandlerSeller } from "src/celo/MentoFeeHandlerSeller.sol";
+import { UniswapFeeHandlerSeller } from "src/celo/UniswapFeeHandlerSeller.sol";
+import { SortedOracles } from "src/celo/stability/SortedOracles.sol";
+import { FeeCurrencyDirectory } from "src/celo/FeeCurrencyDirectory.sol";
+import { FeeCurrency } from "src/celo/testing/FeeCurrency.sol";
+import { AddressSortedLinkedListWithMedian } from "src/celo/common/linkedlists/AddressSortedLinkedListWithMedian.sol";
+import { StableTokenV2 } from "src/celo/StableTokenV2.sol";
interface IInitializable {
function initialize(address _addr) external;
@@ -101,9 +114,43 @@
/// @notice The address of the deployer account.
address internal deployer;
+ // celo - create and write predeploy map
+ mapping(string => address) public deployedContractNamesToAddresses;
+ string internal _celoL2Outfile;
+
+ function celoL2Outfile() internal view returns (string memory _env) {
+ _env = vm.envOr(
+ "L2_OUTFILE",
+ string.concat(vm.projectRoot(), "/deployments/", vm.toString(block.chainid), "-l2-deploy.json")
+ );
+ }
+
+ function celoSave(string memory _name, address _impl, address _proxy) public {
+ if (deployedContractNamesToAddresses[_name] == address(0)) {
+ deployedContractNamesToAddresses[_name] = _impl;
+
+ _celoWrite(_name, _impl);
+ }
+
+ if (_proxy != address(0)) {
+ string memory _proxyName = string.concat(_name, "Proxy");
+ deployedContractNamesToAddresses[_proxyName] = _proxy;
+
+ _celoWrite(_proxyName, _proxy);
+ }
+ }
+
+ function _celoWrite(string memory _name, address _deployed) internal {
+ console.log("Writing l2 deploy %s: %s", _name, _deployed);
+
+ vm.writeJson({ json: stdJson.serialize("celo_l2_deploys", _name, _deployed), path: _celoL2Outfile });
+ }
+
/// @notice Sets up the script and ensures the deployer account is used to make calls.
function setUp() public override {
deployer = makeAddr("deployer");
+ _celoL2Outfile = celoL2Outfile();
+
super.setUp();
}
@@ -159,10 +206,15 @@ console.log("L2Genesis: outputMode: %s, fork: %s", _mode.toString(), _fork.toString());
vm.startPrank(deployer);
vm.chainId(cfg.l2ChainID());
- dealEthToPrecompiles();
+ if (cfg.deployCeloContracts()) {
+ dealEthToPrecompiles();
+ }
setPredeployProxies();
setPredeployImplementations(_l1Dependencies);
setPreinstalls();
+ if (cfg.deployCeloContracts()) {
+ setCeloPredeploys();
+ }
if (cfg.fundDevAccounts()) {
fundDevAccounts();
}
@@ -238,7 +290,10 @@
if (Predeploys.isSupportedPredeploy(addr, cfg.useInterop())) {
address implementation = Predeploys.predeployToCodeNamespace(addr);
console.log("Setting proxy %s implementation: %s", addr, implementation);
+ string memory name = Predeploys.getName(addr);
EIP1967Helper.setImplementation(addr, implementation);
+
+ celoSave(name, implementation, addr);
}
}
}
@@ -410,6 +465,7 @@ /// This contract is NOT proxied and the state that is set
/// in the constructor is set manually.
function setWETH() public {
console.log("Setting %s implementation at: %s", "WETH", Predeploys.WETH);
+ celoSave("WETH", Predeploys.WETH, address(0));
vm.etch(Predeploys.WETH, vm.getDeployedCode("WETH.sol:WETH"));
}
@@ -467,6 +523,7 @@
GovernanceToken token = new GovernanceToken();
console.log("Setting %s implementation at: %s", "GovernanceToken", Predeploys.GOVERNANCE_TOKEN);
vm.etch(Predeploys.GOVERNANCE_TOKEN, address(token).code);
+ celoSave("GovernanceToken", Predeploys.GOVERNANCE_TOKEN, address(0));
bytes32 _nameSlot = hex"0000000000000000000000000000000000000000000000000000000000000003";
bytes32 _symbolSlot = hex"0000000000000000000000000000000000000000000000000000000000000004";
@@ -618,5 +675,109 @@ for (uint256 i; i < devAccounts.length; i++) {
console.log("Funding dev account %s with %s ETH", devAccounts[i], DEV_ACCOUNT_FUND_AMT / 1e18);
vm.deal(devAccounts[i], DEV_ACCOUNT_FUND_AMT);
}
+ }
+
+ ///@notice Sets all proxies and implementations for Celo contracts
+ function setCeloPredeploys() internal {
+ console.log("Deploying Celo contracts");
+
+ setCeloRegistry();
+ setCeloGoldToken();
+ setCeloFeeHandler();
+ setCeloMentoFeeHandlerSeller();
+ setCeloUniswapFeeHandlerSeller();
+ setCeloFeeCurrency();
+ setFeeCurrencyDirectory();
+ }
+
+ /// @notice Sets up a proxy for the given impl address
+ function _setupProxy(address addr, address impl) internal returns (address) {
+ bytes memory code = vm.getDeployedCode("Proxy.sol:Proxy");
+ vm.etch(addr, code);
+ EIP1967Helper.setAdmin(addr, Predeploys.PROXY_ADMIN);
+
+ console.log("Setting proxy %s with implementation: %s", addr, impl);
+ EIP1967Helper.setImplementation(addr, impl);
+
+ return addr;
+ }
+
+ function setCeloRegistry() internal {
+ CeloRegistry kontract = new CeloRegistry({ test: false });
+
+ address precompile = CeloPredeploys.CELO_REGISTRY;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
+ }
+
+ function setCeloGoldToken() internal {
+ GoldToken kontract = new GoldToken({ test: false });
+
+ address precompile = CeloPredeploys.GOLD_TOKEN;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
+ }
+
+ function setCeloFeeHandler() internal {
+ FeeHandler kontract = new FeeHandler({ test: false });
+
+ address precompile = CeloPredeploys.FEE_HANDLER;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
+ }
+
+ function setCeloMentoFeeHandlerSeller() internal {
+ MentoFeeHandlerSeller kontract = new MentoFeeHandlerSeller({ test: false });
+
+ address precompile = CeloPredeploys.MENTO_FEE_HANDLER_SELLER;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
+ }
+
+ function setCeloUniswapFeeHandlerSeller() internal {
+ UniswapFeeHandlerSeller kontract = new UniswapFeeHandlerSeller({ test: false });
+
+ address precompile = CeloPredeploys.UNISWAP_FEE_HANDLER_SELLER;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
+ }
+
+ function setFeeCurrencyDirectory() internal {
+ FeeCurrencyDirectory feeCurrencyDirectory = new FeeCurrencyDirectory({ test: false });
+
+ address precompile = CeloPredeploys.FEE_CURRENCY_DIRECTORY;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(feeCurrencyDirectory));
+
+ vm.resetNonce(address(feeCurrencyDirectory));
+ _setupProxy(precompile, address(feeCurrencyDirectory));
+
+ vm.startPrank(devAccounts[0]);
+ FeeCurrencyDirectory(precompile).initialize();
+ vm.stopPrank();
+ }
+
+ function setCeloFeeCurrency() internal {
+ FeeCurrency kontract = new FeeCurrency({ name_: "Test", symbol_: "TST" });
+ address precompile = CeloPredeploys.FEE_CURRENCY;
+ string memory cname = CeloPredeploys.getName(precompile);
+ console.log("Deploying %s implementation at: %s", cname, address(kontract));
+ vm.resetNonce(address(kontract));
+ _setupProxy(precompile, address(kontract));
}
}
diff --git OP/packages/contracts-bedrock/scripts/checks/check-interfaces.sh CELO/packages/contracts-bedrock/scripts/checks/check-interfaces.sh
index ed2c8e798eb14a2b5d42116109059562b952500d..65cbfb85883308f88ff5bfe4e085baa1d9aca3aa 100755
--- OP/packages/contracts-bedrock/scripts/checks/check-interfaces.sh
+++ CELO/packages/contracts-bedrock/scripts/checks/check-interfaces.sh
@@ -68,6 +68,37 @@ "IL1StandardBridge"
"IL1CrossDomainMessenger"
"ISuperchainConfig"
"IOptimismPortal"
+
+ # Celo
+ "IExchange"
+ "IEscrow"
+ "IAccounts"
+ "IOracle"
+ "ICeloToken"
+ "ICeloRegistry"
+ "IStableTokenMento"
+ "ILockedGold"
+ "IBreakerBox"
+ "ISortedOracles"
+ "IElection"
+ "IStableTokenV2"
+ "IStableToken"
+ "IMetaTransactionWallet"
+ "IAttestations"
+ "IOdisPayments"
+ "IUniswapV2RouterMin"
+ "IFeeHandlerSeller"
+ "IRandom"
+ "IFreezer"
+ "IValidators"
+ "IReserve"
+ "IFeeHandler"
+ "ICeloVersionedContract"
+ "IMetaTransactionWalletDeployer"
+ "IGovernance"
+ "IReleaseGold"
+ "IUniswapV2FactoryMin"
+ "IFederatedAttestations"
)
# Find all JSON files in the forge-artifacts folder
diff --git OP/packages/contracts-bedrock/scripts/contract_map.sh CELO/packages/contracts-bedrock/scripts/contract_map.sh
new file mode 100755
index 0000000000000000000000000000000000000000..caa8a716a13baf252dfecd1ffdf447606a1b8983
--- /dev/null
+++ CELO/packages/contracts-bedrock/scripts/contract_map.sh
@@ -0,0 +1,140 @@
+#!/bin/bash
+set -o pipefail
+
+L1_URL="${1:?Must specify L1 RPC URL}"
+L1_ADDRESSES="${2:?Must specify L1 addresses json}"
+OUTPUT="${3:-relations}"
+
+addresses=$(jq -r '.[]' "$L1_ADDRESSES")
+
+contract_addresses=()
+processed_addresses=()
+dots=()
+
+while IFS= read -r address; do
+ contract_addresses+=("$address")
+done <<< "$addresses"
+
+address_exists() {
+ local addr="$1"
+ for processed_addr in "${processed_addresses[@]}"; do
+ if [[ "$processed_addr" == "$addr" ]]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+check_admin() {
+ local addr="$1"
+ admin=$(cast adm "$addr" --rpc-url "$L1_URL")
+
+ if [[ $? == 0 && "$admin" != "0x0000000000000000000000000000000000000000" ]]; then
+ contract_addresses+=( "$admin" )
+ echo " -> Admin: $admin"
+ add_relation "$admin" "$addr" "admin"
+ fi
+
+ return 0
+}
+
+check_owners() {
+ local addr="$1"
+
+ # suppressing stderr (and unset -e) as failure is expected when this abi does not exist
+ # getOwners defined in OwnerManager on GnosisSafe contract
+ if owners=$(cast call "$addr" --rpc-url "$L1_URL" 'getOwners()(address[])' 2>/dev/null) ; then
+ # trim pseudo json output
+ tr=$(echo "$owners" | tr -d '[],')
+ owners_arr=( "$tr" )
+
+ # Iterate over the values
+ for owner in "${owners_arr[@]}"; do
+ echo " -> Multisig Owner: $owner"
+ add_relation "$owner" "$addr" "multisig_owner"
+ contract_addresses+=( "$owner" )
+ done
+ fi
+
+ # owner defined in Ownable on OpenZeppelin abstract contract
+ if owner=$(cast call "$addr" --rpc-url "$L1_URL" 'owner()(address)' 2>/dev/null) ; then
+ echo " -> Owner: $owner"
+ add_relation "$owner" "$addr" "owner"
+ contract_addresses+=( "$owner" )
+ fi
+
+ return 0
+}
+
+check_implementation() {
+ local addr="$1"
+
+ impl=$(cast implementation "$addr" --rpc-url "$L1_URL")
+
+ if [[ $? == 0 && "$impl" != "0x0000000000000000000000000000000000000000" ]]; then
+ contract_addresses+=( "$impl" )
+ echo " -> Impl: $impl"
+ add_relation "$addr" "$impl" "proxies"
+ fi
+
+ return 0
+}
+
+get_name() {
+ local addr
+ local result
+
+ addr=$(cast to-check-sum-address "$1")
+ result=$(jq -r "to_entries | map(select(.value == \"$addr\")) | .[0].key" "$L1_ADDRESSES")
+
+ if [[ ${#result} -gt 4 ]]; then
+ printf "%s\n(%s)" "$addr" "$result"
+ else
+ echo "$addr"
+ fi
+}
+
+add_relation() {
+ local source="$1"
+ local destination="$2"
+ local label="$3"
+
+ local source_name
+ local destination_name
+
+ source_name=$(get_name "$source")
+ destination_name=$(get_name "$destination")
+
+ dots+=("\"$source_name\" -> \"$destination_name\"[label = \"$label\"];")
+}
+
+# while loop to allow for modification of the array during iteration
+i=0
+while [ $i -lt ${#contract_addresses[@]} ]; do
+ address="$(cast to-check-sum-address "${contract_addresses[$i]}")"
+ if address_exists "$address"; then
+ # already processed this address, skip iteration
+ i=$((i + 1))
+ continue
+ fi
+
+ echo "Checking $address"
+
+ check_admin "$address"
+ check_owners "$address"
+ check_implementation "$address"
+
+ processed_addresses+=("$address")
+ i=$((i + 1))
+done
+
+# write out chart
+echo "digraph {" > "$OUTPUT".dot
+echo "rankdir=\"LR\";" >> "$OUTPUT".dot
+for dot in "${dots[@]}"; do
+ echo "$dot" >> "$OUTPUT".dot
+done
+echo "}" >> "$OUTPUT".dot
+
+dot "$OUTPUT".dot -Tpng -o "$OUTPUT".png
+open "$OUTPUT".png
diff --git OP/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol CELO/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol
index 7e5a9164f46623c31a4fb4dabd9c144a3322ca31..4da9846867f48309b7a89304e2f7b9bb87f22af2 100644
--- OP/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol
+++ CELO/packages/contracts-bedrock/scripts/deploy/ChainAssertions.sol
@@ -33,6 +33,13 @@ import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol";
+import { CeloTokenL1 } from "src/celo/CeloTokenL1.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+
+interface IOptimismPortalBalance {
+ function balance() external view returns (uint256);
+}
+
library ChainAssertions {
Vm internal constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
@@ -356,6 +363,39 @@ require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
}
}
+ /// @notice Asserts the OptimismPortal custom gas token is setup correctly
+ function checkCustomGasTokenOptimismPortal(
+ Types.ContractSet memory _contracts,
+ DeployConfig _cfg,
+ bool _isProxy
+ )
+ internal
+ view
+ {
+ address payable portalAddress;
+ if (_cfg.useFaultProofs()) {
+ portalAddress = payable(_contracts.OptimismPortal2);
+ } else {
+ portalAddress = payable(_contracts.OptimismPortal);
+ }
+ IOptimismPortalBalance portal = IOptimismPortalBalance(portalAddress);
+
+ uint256 expectedInitialBalance = 0;
+ if (_isProxy && _cfg.useCustomGasToken()) {
+ address customGasTokenAddress = _cfg.customGasTokenAddress();
+ IERC20 token = IERC20(customGasTokenAddress);
+ expectedInitialBalance = token.balanceOf(address(portal));
+ console.log("custom gas token expectedInitialBalance", expectedInitialBalance);
+ }
+
+ if (_isProxy) {
+ require(portal.balance() == expectedInitialBalance);
+ } else {
+ require(portal.balance() == 0);
+ }
+ require(vm.load(address(portal), bytes32(uint256(61))) == bytes32(portal.balance()));
+ }
+
/// @notice Asserts the OptimismPortal2 is setup correctly
function checkOptimismPortal2(
Types.ContractSet memory _contracts,
@@ -392,7 +432,13 @@ require(portal.l2Sender() == Constants.DEFAULT_L2_SENDER);
}
// This slot is the custom gas token _balance and this check ensures
// that it stays unset for forwards compatibility with custom gas token.
- require(vm.load(address(portal), bytes32(uint256(61))) == bytes32(0));
+ // if we use the pre-locked storage modification, the comparison
+ // against 0 doesn't hold anymore.
+ // We do a check of the balance field downstream anyways, that's why we
+ // can disable this check
+ if (!_cfg.useCustomGasToken()) {
+ require(vm.load(address(portal), bytes32(uint256(61))) == bytes32(0));
+ }
}
/// @notice Asserts that the ProtocolVersions is setup correctly
@@ -447,5 +493,20 @@ require(
uint8((uint256(slotVal) >> (_offset * 8)) & 0xFF) == uint8(1),
"Storage value is not 1 at the given slot and offset"
);
+ }
+
+ /// @notice Asserts the CeloTokenL1 is setup correctly
+ function checkCeloTokenL1(Types.ContractSet memory _contracts, bool _isProxy) internal view {
+ console.log("Running chain assertions on the CeloTokenL1");
+
+ CeloTokenL1 celoToken = CeloTokenL1(payable(_contracts.CustomGasToken));
+
+ // Check that the contract is initialized
+ assertSlotValueIsOne({ _contractAddress: address(celoToken), _slot: 0, _offset: 0 });
+
+ if (_isProxy) {
+ require(celoToken.totalSupply() == 1000000000e18); // 1 billion CELO
+ require(celoToken.balanceOf(_contracts.OptimismPortal) == 1000000000e18);
+ }
}
}
diff --git OP/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol CELO/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol
index 722cd7c61ecff2e113cf4f27fc7241bec19dd4e1..d97bdfd587fa9c25b2b2c86c48fd9652de861394 100644
--- OP/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol
+++ CELO/packages/contracts-bedrock/scripts/deploy/Deploy.s.sol
@@ -63,6 +63,10 @@ import { IAnchorStateRegistry } from "src/dispute/interfaces/IAnchorStateRegistry.sol";
import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
import { IOptimismMintableERC20Factory } from "src/universal/interfaces/IOptimismMintableERC20Factory.sol";
+import { CeloTokenL1 } from "src/celo/CeloTokenL1.sol";
+import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
+import { Multicall3 } from "@multicall/Multicall3.sol";
+
/// @title Deploy
/// @notice Script used to deploy a bedrock system. The entire system is deployed within the `run` function.
/// To add a new contract to the system, add a public function that deploys that individual contract.
@@ -164,7 +168,10 @@ OptimismPortal2: mustGetAddress("OptimismPortalProxy"),
SystemConfig: mustGetAddress("SystemConfigProxy"),
L1ERC721Bridge: mustGetAddress("L1ERC721BridgeProxy"),
ProtocolVersions: mustGetAddress("ProtocolVersionsProxy"),
- SuperchainConfig: mustGetAddress("SuperchainConfigProxy")
+ SuperchainConfig: mustGetAddress("SuperchainConfigProxy"),
+ // allow for address(0) since it is not strictly required for all
+ // combinations of chain configs
+ CustomGasToken: getAddress("CustomGasTokenProxy")
});
}
@@ -184,7 +191,8 @@ OptimismPortal2: getAddress("OptimismPortalProxy"),
SystemConfig: getAddress("SystemConfigProxy"),
L1ERC721Bridge: getAddress("L1ERC721BridgeProxy"),
ProtocolVersions: getAddress("ProtocolVersionsProxy"),
- SuperchainConfig: getAddress("SuperchainConfigProxy")
+ SuperchainConfig: getAddress("SuperchainConfigProxy"),
+ CustomGasToken: getAddress("CustomGasTokenProxy")
});
}
@@ -446,11 +454,45 @@ deployDelayedWETH();
deployPreimageOracle();
deployMips();
deployAnchorStateRegistry();
+
+ // Multicall3
+ deployMulticall3();
+ }
+
+ function preInitializeOptimismPortalBalance() public broadcast {
+ address optimismPortalProxy = mustGetAddress("OptimismPortalProxy");
+ address storageSetter = mustGetAddress("StorageSetter");
+
+ // NOTE: the storage slot index should stay the same across versions
+ // (OptimismPortal, OptimismPortal2, ...) since slot spacers are used
+ // for legacy storage variables.
+ // We also assert correctness in a downstream ChainAssertion,
+ // so changing slot numbers should get detected for coming versions.
+ uint256 balanceStorageSlot = 61; // slot of _balance variable
+
+ address customGasTokenAddress = Constants.ETHER;
+ uint256 initialBalance = 0;
+ customGasTokenAddress = cfg.customGasTokenAddress();
+ IERC20 token = IERC20(customGasTokenAddress);
+ initialBalance = token.balanceOf(optimismPortalProxy);
+
+ _upgradeAndCallViaSafe({
+ _proxy: payable(optimismPortalProxy),
+ _implementation: storageSetter,
+ _innerCallData: abi.encodeCall(StorageSetter.setUint, (bytes32(balanceStorageSlot), initialBalance))
+ });
}
/// @notice Initialize all of the implementations
function initializeImplementations() public {
console.log("Initializing implementations");
+
+ if (cfg.useCustomGasToken()) {
+ setupCustomGasToken();
+ save("StorageSetter", deployStorageSetter());
+ preInitializeOptimismPortalBalance();
+ }
+
// Selectively initialize either the original OptimismPortal or the new OptimismPortal2. Since this will upgrade
// the proxy, we cannot initialize both.
if (cfg.useFaultProofs()) {
@@ -470,6 +512,8 @@ initializeDisputeGameFactory();
initializeDelayedWETH();
initializePermissionedDelayedWETH();
initializeAnchorStateRegistry();
+
+ ChainAssertions.checkCustomGasTokenOptimismPortal({ _contracts: _proxies(), _cfg: cfg, _isProxy: true });
}
/// @notice Add AltDA setup to the OP chain
@@ -1705,5 +1749,54 @@ }
require(addr_ != address(0), "deployment failed");
save(_nickname, addr_);
console.log("%s deployed at %s", _nickname, addr_);
+ }
+
+ function setupCustomGasToken() internal {
+ if (cfg.useCustomGasToken() && cfg.customGasTokenAddress() == address(0)) {
+ deployERC1967Proxy("CustomGasTokenProxy");
+
+ console.log("Setting up Custom gas token");
+ deployCustomGasToken();
+ initializeCustomGasToken();
+
+ address proxyAddress = mustGetAddress("CustomGasTokenProxy");
+ cfg.setUseCustomGasToken(proxyAddress);
+ }
+ }
+
+ function deployCustomGasToken() public broadcast returns (address addr_) {
+ console.log("Deploying CustomGasToken implementation");
+
+ CeloTokenL1 customGasToken = new CeloTokenL1{ salt: _implSalt() }();
+
+ save("CustomGasToken", address(customGasToken));
+ console.log("CustomGasToken deployed at %s", address(customGasToken));
+ addr_ = address(customGasToken);
+ }
+
+ /// @notice Initialize the CustomGasToken
+ function initializeCustomGasToken() public broadcast {
+ console.log("Upgrading and initializing CustomGasToken proxy");
+ address customGasTokenProxyAddress = mustGetAddress("CustomGasTokenProxy");
+ address customGasTokenAddress = mustGetAddress("CustomGasToken");
+ address portalProxyAddress = mustGetAddress("OptimismPortalProxy");
+
+ _upgradeAndCallViaSafe({
+ _proxy: payable(customGasTokenProxyAddress),
+ _implementation: customGasTokenAddress,
+ _innerCallData: abi.encodeCall(CeloTokenL1.initialize, (portalProxyAddress))
+ });
+
+ ChainAssertions.checkCeloTokenL1({ _contracts: _proxies(), _isProxy: false });
+ }
+
+ function deployMulticall3() internal onlyDevnet returns (address addr_) {
+ // Necessary to be deployed on the L1 for viems withdraw logic
+ // Only necessary on local devnet, since on the common public testnets
+ // the multicall3 is already deployed.
+ console.log("Deploying up Multicall3 contact");
+ Multicall3 mc3 = new Multicall3();
+ addr_ = address(mc3);
+ save("Multicall3", addr_);
}
}
diff --git OP/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol CELO/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol
index 6433509f6764f09edd837ba2ea4c2a5fb2d139be..013a7c806a82d57570f0a692e5d7086adc610b43 100644
--- OP/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol
+++ CELO/packages/contracts-bedrock/scripts/deploy/DeployConfig.s.sol
@@ -92,6 +92,8 @@ address public customGasTokenAddress;
bool public useInterop;
+ bool public deployCeloContracts;
+
function read(string memory _path) public {
console.log("DeployConfig: reading file %s", _path);
try vm.readFile(_path) returns (string memory data) {
@@ -176,6 +178,9 @@ useCustomGasToken = _readOr(_json, "$.useCustomGasToken", false);
customGasTokenAddress = _readOr(_json, "$.customGasTokenAddress", address(0));
useInterop = _readOr(_json, "$.useInterop", false);
+
+ // Celo specific config
+ deployCeloContracts = _readOr(_json, "$.deployCeloContracts", false);
}
function fork() public view returns (Fork fork_) {
@@ -236,6 +241,11 @@
/// @notice Allow the `fundDevAccounts` config to be overridden.
function setFundDevAccounts(bool _fundDevAccounts) public {
fundDevAccounts = _fundDevAccounts;
+ }
+
+ /// @notice Allow the `deployCeloContracts` config to be overridden.
+ function setDeployCeloContracts(bool _deployCeloContracts) public {
+ deployCeloContracts = _deployCeloContracts;
}
/// @notice Allow the `useCustomGasToken` config to be overridden in testing environments
diff --git OP/packages/contracts-bedrock/scripts/getting-started/config-vars-celo.sh CELO/packages/contracts-bedrock/scripts/getting-started/config-vars-celo.sh
new file mode 100755
index 0000000000000000000000000000000000000000..ad59b3c638022a2a5fd4be7b0b006ed42f10d96f
--- /dev/null
+++ CELO/packages/contracts-bedrock/scripts/getting-started/config-vars-celo.sh
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+
+# This script is used to generate the getting-started.json configuration file
+# used in the Getting Started quickstart guide on the docs site. Avoids the
+# need to have the getting-started.json committed to the repo since it's an
+# invalid JSON file when not filled in, which is annoying.
+
+SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
+CONTRACTS_BASE=$(dirname "$(dirname "$SCRIPT_DIR")")
+reqenv() {
+ if [ -z "${!1}" ]; then
+ echo "Error: environment variable '$1' is undefined"
+ exit 1
+ fi
+}
+
+append_with_default() {
+ json_key="$1"
+ env_var_name="$2"
+ default_value="$3"
+ var_value="${!env_var_name}"
+
+ if [ -z "$var_value" ] || [ "$var_value" == "None" ]; then
+ var_value="$default_value"
+ fi
+
+ echo " \"$json_key\": \"$var_value\"," >> tmp_config.json
+}
+
+# Check required environment variables
+reqenv "DEPLOYMENT_CONTEXT"
+reqenv "GS_ADMIN_ADDRESS"
+reqenv "GS_BATCHER_ADDRESS"
+reqenv "GS_PROPOSER_ADDRESS"
+reqenv "GS_SEQUENCER_ADDRESS"
+reqenv "L1_RPC_URL"
+reqenv "L1_CHAIN_ID"
+reqenv "L2_CHAIN_ID"
+reqenv "L1_BLOCK_TIME"
+reqenv "L2_BLOCK_TIME"
+reqenv "FUNDS_DEV_ACCOUNTS"
+reqenv "USE_ALTDA"
+reqenv "DEPLOY_CELO_CONTRACTS"
+reqenv "USE_CUSTOM_GAS_TOKEN"
+reqenv "CUSTOM_GAS_TOKEN_ADDRESS"
+
+# Get the finalized block timestamp and hash
+block=$(cast block finalized --rpc-url "$L1_RPC_URL")
+timestamp=$(echo "$block" | awk '/timestamp/ { print $2 }')
+blockhash=$(echo "$block" | awk '/hash/ { print $2 }')
+batchInboxAddressSuffix=$(printf "%0$((37 - ${#L2_CHAIN_ID}))d" 0)$L2_CHAIN_ID
+batchInboxAddress=0xfff$batchInboxAddressSuffix
+
+# Start generating the config file in a temporary file
+
+cat << EOL > tmp_config.json
+ {
+ "l1StartingBlockTag": "$blockhash",
+
+ "l1ChainID": $L1_CHAIN_ID,
+ "l2ChainID": $L2_CHAIN_ID,
+ "l2BlockTime": $L2_BLOCK_TIME,
+ "l1BlockTime": $L1_BLOCK_TIME,
+
+ "maxSequencerDrift": 600,
+ "sequencerWindowSize": 3600,
+ "channelTimeout": 300,
+
+ "p2pSequencerAddress": "$GS_SEQUENCER_ADDRESS",
+ "batchInboxAddress": "$batchInboxAddress",
+ "batchSenderAddress": "$GS_BATCHER_ADDRESS",
+
+ "l2OutputOracleSubmissionInterval": 120,
+ "l2OutputOracleStartingBlockNumber": 0,
+ "l2OutputOracleStartingTimestamp": $timestamp,
+
+ "l2OutputOracleProposer": "$GS_PROPOSER_ADDRESS",
+ "l2OutputOracleChallenger": "$GS_ADMIN_ADDRESS",
+
+ "finalizationPeriodSeconds": 12,
+
+ "proxyAdminOwner": "$GS_ADMIN_ADDRESS",
+ "baseFeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "l1FeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "sequencerFeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "finalSystemOwner": "$GS_ADMIN_ADDRESS",
+ "superchainConfigGuardian": "$GS_ADMIN_ADDRESS",
+
+ "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "baseFeeVaultWithdrawalNetwork": 0,
+ "l1FeeVaultWithdrawalNetwork": 0,
+ "sequencerFeeVaultWithdrawalNetwork": 0,
+
+ "gasPriceOracleOverhead": 0,
+ "gasPriceOracleScalar": 1000000,
+
+ "deployCeloContracts": $DEPLOY_CELO_CONTRACTS,
+
+ "enableGovernance": $ENABLE_GOVERNANCE,
+ "governanceTokenSymbol": "OP",
+ "governanceTokenName": "Optimism",
+ "governanceTokenOwner": "$GS_ADMIN_ADDRESS",
+
+ "l2GenesisBlockGasLimit": "0x1c9c380",
+ "l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
+
+ "eip1559Denominator": 400,
+ "eip1559DenominatorCanyon": 400,
+ "eip1559Elasticity": 5,
+ "eip1559BaseFeeFloor": 5000000000,
+EOL
+
+# Append conditional environment variables with their corresponding default values
+# Activate granite fork
+if [ -n "${GRANITE_TIME_OFFSET}" ]; then
+ append_with_default "l2GenesisGraniteTimeOffset" "GRANITE_TIME_OFFSET" "0x0"
+fi
+# Activate holocene fork
+if [ -n "${HOLOCENE_TIME_OFFSET}" ]; then
+ append_with_default "l2GenesisHoloceneTimeOffset" "HOLOCENE_TIME_OFFSET" "0x0"
+fi
+
+# Activate the interop fork
+if [ -n "${INTEROP_TIME_OFFSET}" ]; then
+ append_with_default "l2GenesisInteropTimeOffset" "INTEROP_TIME_OFFSET" "0x0"
+fi
+
+# Already forked updates
+append_with_default "l2GenesisFjordTimeOffset" "FJORD_TIME_OFFSET" "0x0"
+append_with_default "l2GenesisRegolithTimeOffset" "REGOLITH_TIME_OFFSET" "0x0"
+append_with_default "l2GenesisEcotoneTimeOffset" "ECOTONE_TIME_OFFSET" "0x0"
+append_with_default "l2GenesisDeltaTimeOffset" "DELTA_TIME_OFFSET" "0x0"
+append_with_default "l2GenesisCanyonTimeOffset" "CANYON_TIME_OFFSET" "0x0"
+append_with_default "l2GenesisGraniteTimeOffset" "GRANITE_TIME_OFFSET" "0x0"
+
+# Continue generating the config file
+cat << EOL >> tmp_config.json
+ "systemConfigStartBlock": 0,
+
+ "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+
+ "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
+ "faultGameMaxDepth": 44,
+ "faultGameClockExtension": 0,
+ "faultGameMaxClockDuration": 1200,
+ "faultGameGenesisBlock": 0,
+ "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "faultGameSplitDepth": 14,
+ "faultGameWithdrawalDelay": 600,
+
+ "preimageOracleMinProposalSize": 1800000,
+ "preimageOracleChallengePeriod": 300,
+
+ "fundDevAccounts": $FUNDS_DEV_ACCOUNTS,
+ "useFaultProofs": false,
+ "proofMaturityDelaySeconds": 604800,
+ "disputeGameFinalityDelaySeconds": 302400,
+ "respectedGameType": 0,
+
+ "useAltDA": $USE_ALTDA,
+ "daCommitmentType": "GenericCommitment",
+ "daChallengeWindow": 1,
+ "daResolveWindow": 1,
+
+ "useCustomGasToken": $USE_CUSTOM_GAS_TOKEN,
+ "customGasTokenAddress": "$CUSTOM_GAS_TOKEN_ADDRESS"
+}
+EOL
+
+# Write the final config file
+mv tmp_config.json "$CONTRACTS_BASE/deploy-config/$DEPLOYMENT_CONTEXT.json"
+
+echo "Wrote config file to $CONTRACTS_BASE/deploy-config/$DEPLOYMENT_CONTEXT.json"
diff --git OP/packages/contracts-bedrock/scripts/getting-started/config-vars-op-stack.sh CELO/packages/contracts-bedrock/scripts/getting-started/config-vars-op-stack.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2da9ac5039342a1a694c71955fa2409e7a2eab38
--- /dev/null
+++ CELO/packages/contracts-bedrock/scripts/getting-started/config-vars-op-stack.sh
@@ -0,0 +1,106 @@
+#!/usr/bin/env bash
+
+# This script is used to generate the getting-started.json configuration file
+# used in the Getting Started quickstart guide on the docs site. Avoids the
+# need to have the getting-started.json committed to the repo since it's an
+# invalid JSON file when not filled in, which is annoying.
+
+reqenv() {
+ if [ -z "${!1}" ]; then
+ echo "Error: environment variable '$1' is undefined"
+ exit 1
+ fi
+}
+
+# Check required environment variables
+reqenv "GS_ADMIN_ADDRESS"
+reqenv "GS_BATCHER_ADDRESS"
+reqenv "GS_PROPOSER_ADDRESS"
+reqenv "GS_SEQUENCER_ADDRESS"
+reqenv "L1_RPC_URL"
+
+# Get the finalized block timestamp and hash
+block=$(cast block finalized --rpc-url "$L1_RPC_URL")
+timestamp=$(echo "$block" | awk '/timestamp/ { print $2 }')
+blockhash=$(echo "$block" | awk '/hash/ { print $2 }')
+
+# Generate the config file
+config=$(cat << EOL
+{
+ "l1StartingBlockTag": "$blockhash",
+
+ "l1ChainID": $L1_CHAIN_ID,
+ "l2ChainID": $L2_CHAIN_ID,
+ "l2BlockTime": 2,
+ "l1BlockTime": 12,
+
+ "maxSequencerDrift": 600,
+ "sequencerWindowSize": 3600,
+ "channelTimeout": 300,
+
+ "p2pSequencerAddress": "$GS_SEQUENCER_ADDRESS",
+ "batchInboxAddress": "0xff00000000000000000000000000000000042069",
+ "batchSenderAddress": "$GS_BATCHER_ADDRESS",
+
+ "l2OutputOracleSubmissionInterval": 120,
+ "l2OutputOracleStartingBlockNumber": 0,
+ "l2OutputOracleStartingTimestamp": $timestamp,
+
+ "l2OutputOracleProposer": "$GS_PROPOSER_ADDRESS",
+ "l2OutputOracleChallenger": "$GS_ADMIN_ADDRESS",
+
+ "finalizationPeriodSeconds": 12,
+
+ "proxyAdminOwner": "$GS_ADMIN_ADDRESS",
+ "baseFeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "l1FeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "sequencerFeeVaultRecipient": "$GS_ADMIN_ADDRESS",
+ "finalSystemOwner": "$GS_ADMIN_ADDRESS",
+ "superchainConfigGuardian": "$GS_ADMIN_ADDRESS",
+
+ "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "baseFeeVaultWithdrawalNetwork": 0,
+ "l1FeeVaultWithdrawalNetwork": 0,
+ "sequencerFeeVaultWithdrawalNetwork": 0,
+
+ "gasPriceOracleOverhead": 2100,
+ "gasPriceOracleScalar": 1000000,
+
+ "enableGovernance": true,
+ "governanceTokenSymbol": "OP",
+ "governanceTokenName": "Optimism",
+ "governanceTokenOwner": "$GS_ADMIN_ADDRESS",
+
+ "l2GenesisBlockGasLimit": "0x1c9c380",
+ "l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
+ "l2GenesisRegolithTimeOffset": "0x0",
+
+ "eip1559Denominator": 50,
+ "eip1559DenominatorCanyon": 250,
+ "eip1559Elasticity": 6,
+
+ "l2GenesisDeltaTimeOffset": null,
+ "l2GenesisCanyonTimeOffset": "0x0",
+
+ "systemConfigStartBlock": 0,
+
+ "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+
+ "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
+ "faultGameMaxDepth": 44,
+ "faultGameMaxDuration": 1200,
+ "faultGameGenesisBlock": 0,
+ "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "faultGameSplitDepth": 14,
+
+ "preimageOracleMinProposalSize": 1800000,
+ "preimageOracleChallengePeriod": 86400
+}
+EOL
+)
+
+# Write the config file
+echo "$config" > deploy-config/"$DEPLOYMENT_CONTEXT".json
diff --git OP/packages/contracts-bedrock/scripts/libraries/Types.sol CELO/packages/contracts-bedrock/scripts/libraries/Types.sol
index 7733be34f3b57693afc0c67c9028d48ab16b3d88..e4120b7b148324a25cdd871920673f7237b40d65 100644
--- OP/packages/contracts-bedrock/scripts/libraries/Types.sol
+++ CELO/packages/contracts-bedrock/scripts/libraries/Types.sol
@@ -18,5 +18,6 @@ address SystemConfig;
address L1ERC721Bridge;
address ProtocolVersions;
address SuperchainConfig;
+ address CustomGasToken;
}
}
diff --git OP/packages/contracts-bedrock/semver-lock.json CELO/packages/contracts-bedrock/semver-lock.json
index b9962af979ccf8a0ec09b198facc14c6afb95be2..1c82bc73486b29ac4162f87db7f8053a823641cf 100644
--- OP/packages/contracts-bedrock/semver-lock.json
+++ CELO/packages/contracts-bedrock/semver-lock.json
@@ -208,12 +208,12 @@ "initCodeHash": "0xcfccdd9e423c95a0ddc6e09ccb6333d5fc8429ed2b8fc872f1290d392ae13aad",
"sourceCodeHash": "0xd1479c60087f352385b6d5379ef3cc07839f671d617626b4c94ece91da781ef2"
},
"src/universal/OptimismMintableERC20.sol": {
- "initCodeHash": "0x28c88484e1932253d6d12954492ac8a70744dc15c84429089af9944e5b158fd9",
- "sourceCodeHash": "0x740b4043436d1b314ee3ba145acfcde60b6abd8416ea594f2b8e890b5d0bce6b"
+ "initCodeHash": "0xdb0a592cb79de48c9aa288b8d73e7cacc6e8a1ae8d176a4a674f00d1ecf2b6a0",
+ "sourceCodeHash": "0x1f92d976177778b91c96ee83bdd953c9edb1382d05a504959a7ef9493dc703e3"
},
"src/universal/OptimismMintableERC20Factory.sol": {
- "initCodeHash": "0x9cd4102d3ca811d5dc67ae99ce7de95812264575a789f96a6057600e55dcab64",
- "sourceCodeHash": "0xc70c8c11d6e754eabe746bbee47a5e1051f71f7a83913f62ebcce8db989a1357"
+ "initCodeHash": "0x308024e05a9907f5ffb511145573f02b65cc6dc91dd824493f59bf7a1641ef43",
+ "sourceCodeHash": "0x7ba693786c41b2e60b49be65af2720855511a10c88276929d7bfd42ed79be6d1"
},
"src/universal/OptimismMintableERC721.sol": {
"initCodeHash": "0xec037be7fc28e072944b0a9e55d4278b92d6c68ccb41049ab52eafca59c6e023",
diff --git OP/packages/contracts-bedrock/snapshots/abi/CalledByVm.json CELO/packages/contracts-bedrock/snapshots/abi/CalledByVm.json
new file mode 100644
index 0000000000000000000000000000000000000000..0637a088a01e8ddab3bf3fa98dbe804cbde1a0dc
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/CalledByVm.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/CeloRegistry.json CELO/packages/contracts-bedrock/snapshots/abi/CeloRegistry.json
new file mode 100644
index 0000000000000000000000000000000000000000..1f095b33d3bb0171ba35dfdc18e2e5361b4f3e5a
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/CeloRegistry.json
@@ -0,0 +1,247 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "identifierHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getAddressFor",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "identifierHash",
+ "type": "bytes32"
+ }
+ ],
+ "name": "getAddressForOrDie",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "identifier",
+ "type": "string"
+ }
+ ],
+ "name": "getAddressForString",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "identifier",
+ "type": "string"
+ }
+ ],
+ "name": "getAddressForStringOrDie",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32[]",
+ "name": "identifierHashes",
+ "type": "bytes32[]"
+ },
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ }
+ ],
+ "name": "isOneOf",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "identifier",
+ "type": "string"
+ },
+ {
+ "internalType": "address",
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "setAddressFor",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "identifier",
+ "type": "string"
+ },
+ {
+ "indexed": true,
+ "internalType": "bytes32",
+ "name": "identifierHash",
+ "type": "bytes32"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "RegistryUpdated",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/CeloTokenL1.json CELO/packages/contracts-bedrock/snapshots/abi/CeloTokenL1.json
new file mode 100644
index 0000000000000000000000000000000000000000..ea1de6d1e20933c8e19576668fc8db6e98387cbd
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/CeloTokenL1.json
@@ -0,0 +1,298 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "subtractedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "addedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "portalProxyAddress",
+ "type": "address"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint8",
+ "name": "version",
+ "type": "uint8"
+ }
+ ],
+ "name": "Initialized",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/FeeCurrency.json CELO/packages/contracts-bedrock/snapshots/abi/FeeCurrency.json
new file mode 100644
index 0000000000000000000000000000000000000000..4bdf6bbac31f355f29ff9bfdcda463d77a7b6d8e
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/FeeCurrency.json
@@ -0,0 +1,354 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "name_",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "symbol_",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "feeRecipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "communityFund",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "refund",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tipTxFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "baseTxFee",
+ "type": "uint256"
+ }
+ ],
+ "name": "creditGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "debitGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "subtractedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "addedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/FeeCurrencyDirectory.json CELO/packages/contracts-bedrock/snapshots/abi/FeeCurrencyDirectory.json
new file mode 100644
index 0000000000000000000000000000000000000000..4c4ccb64968e89d61bc9081c7cfedc3c8bc471f4
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/FeeCurrencyDirectory.json
@@ -0,0 +1,246 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "currencies",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "oracle",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "intrinsicGas",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getCurrencies",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getCurrencyConfig",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "address",
+ "name": "oracle",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "intrinsicGas",
+ "type": "uint256"
+ }
+ ],
+ "internalType": "struct IFeeCurrencyDirectory.CurrencyConfig",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getExchangeRate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "numerator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "denominator",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "index",
+ "type": "uint256"
+ }
+ ],
+ "name": "removeCurrencies",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "oracle",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "intrinsicGas",
+ "type": "uint256"
+ }
+ ],
+ "name": "setCurrencyConfig",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/FeeHandler.json CELO/packages/contracts-bedrock/snapshots/abi/FeeHandler.json
new file mode 100644
index 0000000000000000000000000000000000000000..a584a53f686d0c6681b11a0bdbe857415bdc3774
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/FeeHandler.json
@@ -0,0 +1,813 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ },
+ {
+ "inputs": [],
+ "name": "FIXED1_UINT",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "MIN_BURN",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "activateToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "handlerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "addToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "burnCelo",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "burnFraction",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "celoToBeBurned",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amountToBurn",
+ "type": "uint256"
+ }
+ ],
+ "name": "dailySellLimitHit",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "deactivateToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "distribute",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "distributeAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "feeBeneficiary",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getActiveTokens",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getPastBurnForToken",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenActive",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenCurrentDaySellLimit",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenDailySellLimit",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenHandler",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenMaxSlippage",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenToDistribute",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "handle",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "handleAll",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_registryAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "newFeeBeneficiary",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "newBurnFraction",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address[]",
+ "name": "tokens",
+ "type": "address[]"
+ },
+ {
+ "internalType": "address[]",
+ "name": "handlers",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "newLimits",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "newMaxSlippages",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "lastLimitDay",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "removeToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "sell",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "fraction",
+ "type": "uint256"
+ }
+ ],
+ "name": "setBurnFraction",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "newLimit",
+ "type": "uint256"
+ }
+ ],
+ "name": "setDailySellLimit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "beneficiary",
+ "type": "address"
+ }
+ ],
+ "name": "setFeeBeneficiary",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "handlerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setHandler",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "newMax",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMaxSplippage",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "fraction",
+ "type": "uint256"
+ }
+ ],
+ "name": "BurnFractionSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "burning",
+ "type": "uint256"
+ }
+ ],
+ "name": "DailyLimitHit",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "newLimit",
+ "type": "uint256"
+ }
+ ],
+ "name": "DailyLimitSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "DailySellLimitUpdated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "newBeneficiary",
+ "type": "address"
+ }
+ ],
+ "name": "FeeBeneficiarySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "maxSlippage",
+ "type": "uint256"
+ }
+ ],
+ "name": "MaxSlippageSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "SoldAndBurnedToken",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "handlerAddress",
+ "type": "address"
+ }
+ ],
+ "name": "TokenAdded",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ }
+ ],
+ "name": "TokenRemoved",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/Freezable.json CELO/packages/contracts-bedrock/snapshots/abi/Freezable.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc8fa7e0f21ca37add36efa01627337c9521293c
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/Freezable.json
@@ -0,0 +1,93 @@
+[
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/GoldToken.json CELO/packages/contracts-bedrock/snapshots/abi/GoldToken.json
new file mode 100644
index 0000000000000000000000000000000000000000..a52ef10b6a528ba8b47235bebe82741ce20d5640
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/GoldToken.json
@@ -0,0 +1,552 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "burn",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "circulatingSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getBurnedAmount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseSupply",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "comment",
+ "type": "string"
+ }
+ ],
+ "name": "transferWithComment",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "comment",
+ "type": "string"
+ }
+ ],
+ "name": "TransferComment",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/Initializable.json CELO/packages/contracts-bedrock/snapshots/abi/Initializable.json
new file mode 100644
index 0000000000000000000000000000000000000000..aeef476ab67fdf303022548658b887d36bf6f042
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/Initializable.json
@@ -0,0 +1,26 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "testingDeployment",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/MentoFeeHandlerSeller.json CELO/packages/contracts-bedrock/snapshots/abi/MentoFeeHandlerSeller.json
new file mode 100644
index 0000000000000000000000000000000000000000..7190d528858e5ac8ec5feae77b968b6afaca1d0e
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/MentoFeeHandlerSeller.json
@@ -0,0 +1,350 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "midPriceNumerator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "midPriceDenominator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxSlippage",
+ "type": "uint256"
+ }
+ ],
+ "name": "calculateMinAmount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_registryAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address[]",
+ "name": "tokenAddresses",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "newMininumReports",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "minimumReports",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sellTokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "buyTokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxSlippage",
+ "type": "uint256"
+ }
+ ],
+ "name": "sell",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "newMininumReports",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMinimumReports",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "minimumReports",
+ "type": "uint256"
+ }
+ ],
+ "name": "MinimumReportsSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "soldTokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "boughtTokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenSold",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/MockSortedOracles.json CELO/packages/contracts-bedrock/snapshots/abi/MockSortedOracles.json
new file mode 100644
index 0000000000000000000000000000000000000000..f56f9b579aa578b992b3f8960a77db6c768cbac9
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/MockSortedOracles.json
@@ -0,0 +1,249 @@
+[
+ {
+ "inputs": [],
+ "name": "DENOMINATOR",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "expired",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getExchangeRate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "numerator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "denominator",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "isOldestReportExpired",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ },
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "medianRate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "medianTimestamp",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "numRates",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "numerators",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "numerator",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMedianRate",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "timestamp",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMedianTimestamp",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "setMedianTimestampToNow",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "rate",
+ "type": "uint256"
+ }
+ ],
+ "name": "setNumRates",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "setOldestReportExpired",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20.json CELO/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20.json
index 5a5763c73962b8b01e2a5f7573e33cbee5d90741..57523467d292e719efe14c05acd3804c55b6c232 100644
--- OP/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20.json
+++ CELO/packages/contracts-bedrock/snapshots/abi/OptimismMintableERC20.json
@@ -181,6 +181,90 @@ "stateMutability": "nonpayable",
"type": "function"
},
{
+ "inputs": [
+ {
+ "internalType": "address[]",
+ "name": "recipients",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "amounts",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "creditGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "feeRecipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "communityFund",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "refund",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tipTxFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "baseTxFee",
+ "type": "uint256"
+ }
+ ],
+ "name": "creditGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "debitGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
"inputs": [],
"name": "decimals",
"outputs": [
diff --git OP/packages/contracts-bedrock/snapshots/abi/SortedOracles.json CELO/packages/contracts-bedrock/snapshots/abi/SortedOracles.json
new file mode 100644
index 0000000000000000000000000000000000000000..12a253c5c08be2f7b7d727d99d56c5499b5ed43a
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/SortedOracles.json
@@ -0,0 +1,832 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "oracleAddress",
+ "type": "address"
+ }
+ ],
+ "name": "addOracle",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "breakerBox",
+ "outputs": [
+ {
+ "internalType": "contract IBreakerBox",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "deleteEquivalentToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "equivalentTokens",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getEquivalentToken",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getExchangeRate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "numerator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "denominator",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getOracles",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getRates",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]",
+ "name": "",
+ "type": "uint8[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getTimestamps",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "enum SortedLinkedListWithMedian.MedianRelation[]",
+ "name": "",
+ "type": "uint8[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getTokenReportExpirySeconds",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_reportExpirySeconds",
+ "type": "uint256"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "isOldestReportExpired",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ },
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "isOracle",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "medianRate",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "medianRateWithoutEquivalentMapping",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "medianTimestamp",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "numRates",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "numTimestamps",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "name": "oracles",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "n",
+ "type": "uint256"
+ }
+ ],
+ "name": "removeExpiredReports",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "oracleAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "index",
+ "type": "uint256"
+ }
+ ],
+ "name": "removeOracle",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "lesserKey",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "greaterKey",
+ "type": "address"
+ }
+ ],
+ "name": "report",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "reportExpirySeconds",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "contract IBreakerBox",
+ "name": "newBreakerBox",
+ "type": "address"
+ }
+ ],
+ "name": "setBreakerBox",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "equivalentToken",
+ "type": "address"
+ }
+ ],
+ "name": "setEquivalentToken",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_reportExpirySeconds",
+ "type": "uint256"
+ }
+ ],
+ "name": "setReportExpiry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_reportExpirySeconds",
+ "type": "uint256"
+ }
+ ],
+ "name": "setTokenReportExpiry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "tokenReportExpirySeconds",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newBreakerBox",
+ "type": "address"
+ }
+ ],
+ "name": "BreakerBoxUpdated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "equivalentToken",
+ "type": "address"
+ }
+ ],
+ "name": "EquivalentTokenSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "MedianUpdated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "oracleAddress",
+ "type": "address"
+ }
+ ],
+ "name": "OracleAdded",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "oracleAddress",
+ "type": "address"
+ }
+ ],
+ "name": "OracleRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "oracle",
+ "type": "address"
+ }
+ ],
+ "name": "OracleReportRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "oracle",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "timestamp",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "OracleReported",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "reportExpiry",
+ "type": "uint256"
+ }
+ ],
+ "name": "ReportExpirySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "reportExpiry",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenReportExpirySet",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/StableTokenV2.json CELO/packages/contracts-bedrock/snapshots/abi/StableTokenV2.json
new file mode 100644
index 0000000000000000000000000000000000000000..693b960cea99c0c7b6d9ab45341f3f56eda21853
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/StableTokenV2.json
@@ -0,0 +1,742 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "disable",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "inputs": [],
+ "name": "DOMAIN_SEPARATOR",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "broker",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "burn",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "feeRecipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "gatewayFeeRecipient",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "communityFund",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "refund",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "tipTxFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "gatewayFee",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "baseTxFee",
+ "type": "uint256"
+ }
+ ],
+ "name": "creditGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "debitGasFees",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "subtractedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "exchange",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "addedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_name",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_symbol",
+ "type": "string"
+ },
+ {
+ "internalType": "address[]",
+ "name": "initialBalanceAddresses",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "initialBalanceValues",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_broker",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_validators",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_exchange",
+ "type": "address"
+ }
+ ],
+ "name": "initializeV2",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ }
+ ],
+ "name": "nonces",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "deadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint8",
+ "name": "v",
+ "type": "uint8"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "r",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32",
+ "name": "s",
+ "type": "bytes32"
+ }
+ ],
+ "name": "permit",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_broker",
+ "type": "address"
+ }
+ ],
+ "name": "setBroker",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_exchange",
+ "type": "address"
+ }
+ ],
+ "name": "setExchange",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_validators",
+ "type": "address"
+ }
+ ],
+ "name": "setValidators",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ },
+ {
+ "internalType": "string",
+ "name": "comment",
+ "type": "string"
+ }
+ ],
+ "name": "transferWithComment",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "validators",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "broker",
+ "type": "address"
+ }
+ ],
+ "name": "BrokerUpdated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "exchange",
+ "type": "address"
+ }
+ ],
+ "name": "ExchangeUpdated",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "uint8",
+ "name": "version",
+ "type": "uint8"
+ }
+ ],
+ "name": "Initialized",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "comment",
+ "type": "string"
+ }
+ ],
+ "name": "TransferComment",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "validators",
+ "type": "address"
+ }
+ ],
+ "name": "ValidatorsUpdated",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/UniswapFeeHandlerSeller.json CELO/packages/contracts-bedrock/snapshots/abi/UniswapFeeHandlerSeller.json
new file mode 100644
index 0000000000000000000000000000000000000000..19c31c979af28ecd9ffcfcda9095f993e30b3ed1
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/UniswapFeeHandlerSeller.json
@@ -0,0 +1,481 @@
+[
+ {
+ "inputs": [
+ {
+ "internalType": "bool",
+ "name": "test",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "stateMutability": "payable",
+ "type": "receive"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "midPriceNumerator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "midPriceDenominator",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxSlippage",
+ "type": "uint256"
+ }
+ ],
+ "name": "calculateMinAmount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ }
+ ],
+ "name": "getRoutersForToken",
+ "outputs": [
+ {
+ "internalType": "address[]",
+ "name": "",
+ "type": "address[]"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getVersionNumber",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "pure",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_registryAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address[]",
+ "name": "tokenAddresses",
+ "type": "address[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "newMininumReports",
+ "type": "uint256[]"
+ }
+ ],
+ "name": "initialize",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "initialized",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "minimumReports",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ }
+ ],
+ "name": "removeRouter",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sellTokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "buyTokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "maxSlippage",
+ "type": "uint256"
+ }
+ ],
+ "name": "sell",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "newMininumReports",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMinimumReports",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ }
+ ],
+ "name": "setRouter",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ },
+ {
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "tokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "minimumReports",
+ "type": "uint256"
+ }
+ ],
+ "name": "MinimumReportsSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "tokneAddress",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "quote",
+ "type": "uint256"
+ }
+ ],
+ "name": "ReceivedQuote",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ }
+ ],
+ "name": "RouterAddressRemoved",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "token",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ }
+ ],
+ "name": "RouterAddressSet",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "router",
+ "type": "address"
+ }
+ ],
+ "name": "RouterUsed",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "soldTokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "address",
+ "name": "boughtTokenAddress",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "TokenSold",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/abi/UsingRegistry.json CELO/packages/contracts-bedrock/snapshots/abi/UsingRegistry.json
new file mode 100644
index 0000000000000000000000000000000000000000..dc8fa7e0f21ca37add36efa01627337c9521293c
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/abi/UsingRegistry.json
@@ -0,0 +1,93 @@
+[
+ {
+ "inputs": [],
+ "name": "owner",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "registry",
+ "outputs": [
+ {
+ "internalType": "contract ICeloRegistry",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "renounceOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "setRegistry",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "transferOwnership",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "previousOwner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "newOwner",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "registryAddress",
+ "type": "address"
+ }
+ ],
+ "name": "RegistrySet",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/CalledByVm.json CELO/packages/contracts-bedrock/snapshots/storageLayout/CalledByVm.json
new file mode 100644
index 0000000000000000000000000000000000000000..0637a088a01e8ddab3bf3fa98dbe804cbde1a0dc
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/CalledByVm.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/CeloRegistry.json CELO/packages/contracts-bedrock/snapshots/storageLayout/CeloRegistry.json
new file mode 100644
index 0000000000000000000000000000000000000000..17b0df2bd7f9e8254e7ac4730d34917b70b3063b
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/CeloRegistry.json
@@ -0,0 +1,23 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 20,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "32",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "mapping(bytes32 => address)"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/CeloTokenL1.json CELO/packages/contracts-bedrock/snapshots/storageLayout/CeloTokenL1.json
new file mode 100644
index 0000000000000000000000000000000000000000..e3c218589ca31c3e34d65496c25c72a83d999397
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/CeloTokenL1.json
@@ -0,0 +1,65 @@
+[
+ {
+ "bytes": "1",
+ "label": "_initialized",
+ "offset": 0,
+ "slot": "0",
+ "type": "uint8"
+ },
+ {
+ "bytes": "1",
+ "label": "_initializing",
+ "offset": 1,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "1600",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "1",
+ "type": "uint256[50]"
+ },
+ {
+ "bytes": "32",
+ "label": "_balances",
+ "offset": 0,
+ "slot": "51",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "_allowances",
+ "offset": 0,
+ "slot": "52",
+ "type": "mapping(address => mapping(address => uint256))"
+ },
+ {
+ "bytes": "32",
+ "label": "_totalSupply",
+ "offset": 0,
+ "slot": "53",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "_name",
+ "offset": 0,
+ "slot": "54",
+ "type": "string"
+ },
+ {
+ "bytes": "32",
+ "label": "_symbol",
+ "offset": 0,
+ "slot": "55",
+ "type": "string"
+ },
+ {
+ "bytes": "1440",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "56",
+ "type": "uint256[45]"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrency.json CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrency.json
new file mode 100644
index 0000000000000000000000000000000000000000..418a98546cf776bc340d3ebdd5775412a3e7986e
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrency.json
@@ -0,0 +1,37 @@
+[
+ {
+ "bytes": "32",
+ "label": "_balances",
+ "offset": 0,
+ "slot": "0",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "_allowances",
+ "offset": 0,
+ "slot": "1",
+ "type": "mapping(address => mapping(address => uint256))"
+ },
+ {
+ "bytes": "32",
+ "label": "_totalSupply",
+ "offset": 0,
+ "slot": "2",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "_name",
+ "offset": 0,
+ "slot": "3",
+ "type": "string"
+ },
+ {
+ "bytes": "32",
+ "label": "_symbol",
+ "offset": 0,
+ "slot": "4",
+ "type": "string"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrencyDirectory.json CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrencyDirectory.json
new file mode 100644
index 0000000000000000000000000000000000000000..61ccdc5fb15116df778992284198adbb9aeaa26b
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeCurrencyDirectory.json
@@ -0,0 +1,30 @@
+[
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 0,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 1,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "32",
+ "label": "currencies",
+ "offset": 0,
+ "slot": "1",
+ "type": "mapping(address => struct IFeeCurrencyDirectory.CurrencyConfig)"
+ },
+ {
+ "bytes": "32",
+ "label": "currencyList",
+ "offset": 0,
+ "slot": "2",
+ "type": "address[]"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/FeeHandler.json CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeHandler.json
new file mode 100644
index 0000000000000000000000000000000000000000..468bb7dc389218cc2a62ad57d94c340b31fa5a30
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/FeeHandler.json
@@ -0,0 +1,72 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 20,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ },
+ {
+ "bytes": "32",
+ "label": "_status",
+ "offset": 0,
+ "slot": "2",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "lastLimitDay",
+ "offset": 0,
+ "slot": "3",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "burnFraction",
+ "offset": 0,
+ "slot": "4",
+ "type": "struct FixidityLib.Fraction"
+ },
+ {
+ "bytes": "20",
+ "label": "feeBeneficiary",
+ "offset": 0,
+ "slot": "5",
+ "type": "address"
+ },
+ {
+ "bytes": "32",
+ "label": "celoToBeBurned",
+ "offset": 0,
+ "slot": "6",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "tokenStates",
+ "offset": 0,
+ "slot": "7",
+ "type": "mapping(address => struct FeeHandler.TokenState)"
+ },
+ {
+ "bytes": "64",
+ "label": "activeTokens",
+ "offset": 0,
+ "slot": "8",
+ "type": "struct EnumerableSet.AddressSet"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/Freezable.json CELO/packages/contracts-bedrock/snapshots/storageLayout/Freezable.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb89bbc7e1ab3904137e39358de306a828c60dac
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/Freezable.json
@@ -0,0 +1,16 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/GoldToken.json CELO/packages/contracts-bedrock/snapshots/storageLayout/GoldToken.json
new file mode 100644
index 0000000000000000000000000000000000000000..67b349856d86cdaab5dd67f9e9e413210d44ce63
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/GoldToken.json
@@ -0,0 +1,37 @@
+[
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 0,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 1,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ },
+ {
+ "bytes": "32",
+ "label": "totalSupply_",
+ "offset": 0,
+ "slot": "2",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "allowed",
+ "offset": 0,
+ "slot": "3",
+ "type": "mapping(address => mapping(address => uint256))"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/Initializable.json CELO/packages/contracts-bedrock/snapshots/storageLayout/Initializable.json
new file mode 100644
index 0000000000000000000000000000000000000000..b29972a4de8eb134c79b8e19e36619de89bfeb4b
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/Initializable.json
@@ -0,0 +1,9 @@
+[
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 0,
+ "slot": "0",
+ "type": "bool"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/MentoFeeHandlerSeller.json CELO/packages/contracts-bedrock/snapshots/storageLayout/MentoFeeHandlerSeller.json
new file mode 100644
index 0000000000000000000000000000000000000000..a66c44056e6d0350f83d4ee520bafeda4d5c2a58
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/MentoFeeHandlerSeller.json
@@ -0,0 +1,30 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 20,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ },
+ {
+ "bytes": "32",
+ "label": "minimumReports",
+ "offset": 0,
+ "slot": "2",
+ "type": "mapping(address => uint256)"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/MockSortedOracles.json CELO/packages/contracts-bedrock/snapshots/storageLayout/MockSortedOracles.json
new file mode 100644
index 0000000000000000000000000000000000000000..c44ef116af9505417a194688daf746a4c58cdcff
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/MockSortedOracles.json
@@ -0,0 +1,30 @@
+[
+ {
+ "bytes": "32",
+ "label": "numerators",
+ "offset": 0,
+ "slot": "0",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "medianTimestamp",
+ "offset": 0,
+ "slot": "1",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "numRates",
+ "offset": 0,
+ "slot": "2",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "expired",
+ "offset": 0,
+ "slot": "3",
+ "type": "mapping(address => bool)"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/SortedOracles.json CELO/packages/contracts-bedrock/snapshots/storageLayout/SortedOracles.json
new file mode 100644
index 0000000000000000000000000000000000000000..e1e5e1736aff6530fc2e9dbeeecc4a4c9a316365
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/SortedOracles.json
@@ -0,0 +1,72 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 20,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "32",
+ "label": "rates",
+ "offset": 0,
+ "slot": "1",
+ "type": "mapping(address => struct SortedLinkedListWithMedian.List)"
+ },
+ {
+ "bytes": "32",
+ "label": "timestamps",
+ "offset": 0,
+ "slot": "2",
+ "type": "mapping(address => struct SortedLinkedListWithMedian.List)"
+ },
+ {
+ "bytes": "32",
+ "label": "isOracle",
+ "offset": 0,
+ "slot": "3",
+ "type": "mapping(address => mapping(address => bool))"
+ },
+ {
+ "bytes": "32",
+ "label": "oracles",
+ "offset": 0,
+ "slot": "4",
+ "type": "mapping(address => address[])"
+ },
+ {
+ "bytes": "32",
+ "label": "reportExpirySeconds",
+ "offset": 0,
+ "slot": "5",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "tokenReportExpirySeconds",
+ "offset": 0,
+ "slot": "6",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "20",
+ "label": "breakerBox",
+ "offset": 0,
+ "slot": "7",
+ "type": "contract IBreakerBox"
+ },
+ {
+ "bytes": "32",
+ "label": "equivalentTokens",
+ "offset": 0,
+ "slot": "8",
+ "type": "mapping(address => struct SortedOracles.EquivalentToken)"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/StableTokenV2.json CELO/packages/contracts-bedrock/snapshots/storageLayout/StableTokenV2.json
new file mode 100644
index 0000000000000000000000000000000000000000..eea3cafe6e9025cb532486b1e9ff84f4246310ec
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/StableTokenV2.json
@@ -0,0 +1,142 @@
+[
+ {
+ "bytes": "1",
+ "label": "_initialized",
+ "offset": 0,
+ "slot": "0",
+ "type": "uint8"
+ },
+ {
+ "bytes": "1",
+ "label": "_initializing",
+ "offset": 1,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "1600",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "1",
+ "type": "uint256[50]"
+ },
+ {
+ "bytes": "32",
+ "label": "_balances",
+ "offset": 0,
+ "slot": "51",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "_allowances",
+ "offset": 0,
+ "slot": "52",
+ "type": "mapping(address => mapping(address => uint256))"
+ },
+ {
+ "bytes": "32",
+ "label": "_totalSupply",
+ "offset": 0,
+ "slot": "53",
+ "type": "uint256"
+ },
+ {
+ "bytes": "32",
+ "label": "_name",
+ "offset": 0,
+ "slot": "54",
+ "type": "string"
+ },
+ {
+ "bytes": "32",
+ "label": "_symbol",
+ "offset": 0,
+ "slot": "55",
+ "type": "string"
+ },
+ {
+ "bytes": "1440",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "56",
+ "type": "uint256[45]"
+ },
+ {
+ "bytes": "32",
+ "label": "_HASHED_NAME",
+ "offset": 0,
+ "slot": "101",
+ "type": "bytes32"
+ },
+ {
+ "bytes": "32",
+ "label": "_HASHED_VERSION",
+ "offset": 0,
+ "slot": "102",
+ "type": "bytes32"
+ },
+ {
+ "bytes": "1600",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "103",
+ "type": "uint256[50]"
+ },
+ {
+ "bytes": "32",
+ "label": "_nonces",
+ "offset": 0,
+ "slot": "153",
+ "type": "mapping(address => struct CountersUpgradeable.Counter)"
+ },
+ {
+ "bytes": "32",
+ "label": "_PERMIT_TYPEHASH_DEPRECATED_SLOT",
+ "offset": 0,
+ "slot": "154",
+ "type": "bytes32"
+ },
+ {
+ "bytes": "1568",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "155",
+ "type": "uint256[49]"
+ },
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "204",
+ "type": "address"
+ },
+ {
+ "bytes": "1568",
+ "label": "__gap",
+ "offset": 0,
+ "slot": "205",
+ "type": "uint256[49]"
+ },
+ {
+ "bytes": "20",
+ "label": "validators",
+ "offset": 0,
+ "slot": "254",
+ "type": "address"
+ },
+ {
+ "bytes": "20",
+ "label": "broker",
+ "offset": 0,
+ "slot": "255",
+ "type": "address"
+ },
+ {
+ "bytes": "20",
+ "label": "exchange",
+ "offset": 0,
+ "slot": "256",
+ "type": "address"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/UniswapFeeHandlerSeller.json CELO/packages/contracts-bedrock/snapshots/storageLayout/UniswapFeeHandlerSeller.json
new file mode 100644
index 0000000000000000000000000000000000000000..3688a3204dec12dbace7b35435f8d85cb1c9acb3
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/UniswapFeeHandlerSeller.json
@@ -0,0 +1,37 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "1",
+ "label": "initialized",
+ "offset": 20,
+ "slot": "0",
+ "type": "bool"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ },
+ {
+ "bytes": "32",
+ "label": "minimumReports",
+ "offset": 0,
+ "slot": "2",
+ "type": "mapping(address => uint256)"
+ },
+ {
+ "bytes": "32",
+ "label": "routerAddresses",
+ "offset": 0,
+ "slot": "3",
+ "type": "mapping(address => struct EnumerableSet.AddressSet)"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/snapshots/storageLayout/UsingRegistry.json CELO/packages/contracts-bedrock/snapshots/storageLayout/UsingRegistry.json
new file mode 100644
index 0000000000000000000000000000000000000000..fb89bbc7e1ab3904137e39358de306a828c60dac
--- /dev/null
+++ CELO/packages/contracts-bedrock/snapshots/storageLayout/UsingRegistry.json
@@ -0,0 +1,16 @@
+[
+ {
+ "bytes": "20",
+ "label": "_owner",
+ "offset": 0,
+ "slot": "0",
+ "type": "address"
+ },
+ {
+ "bytes": "20",
+ "label": "registry",
+ "offset": 0,
+ "slot": "1",
+ "type": "contract ICeloRegistry"
+ }
+]
\ No newline at end of file
diff --git OP/packages/contracts-bedrock/src/celo/AbstractFeeCurrency.sol CELO/packages/contracts-bedrock/src/celo/AbstractFeeCurrency.sol
new file mode 100644
index 0000000000000000000000000000000000000000..f67beaaf59a55ff6fc4022443b1179459a8bacbf
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/AbstractFeeCurrency.sol
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+
+abstract contract AbstractFeeCurrency is ERC20 {
+ modifier onlyVm() {
+ require(msg.sender == address(0), "Only VM can call");
+ _;
+ }
+
+ function debitGasFees(address from, uint256 value) external onlyVm {
+ _burn(from, value);
+ }
+
+ // New function signature, will be used when all fee currencies have migrated
+ function creditGasFees(address[] calldata recipients, uint256[] calldata amounts) public onlyVm {
+ require(recipients.length == amounts.length, "Recipients and amounts must be the same length.");
+
+ for (uint256 i = 0; i < recipients.length; i++) {
+ _mint(recipients[i], amounts[i]);
+ }
+ }
+
+ // Old function signature for backwards compatibility
+ function creditGasFees(
+ address from,
+ address feeRecipient,
+ address, // gatewayFeeRecipient, unused
+ address communityFund,
+ uint256 refund,
+ uint256 tipTxFee,
+ uint256, // gatewayFee, unused
+ uint256 baseTxFee
+ )
+ public
+ onlyVm
+ {
+ // Calling the new creditGasFees would make sense here, but that is not
+ // possible due to its calldata arguments.
+ _mint(from, refund);
+ _mint(feeRecipient, tipTxFee);
+ _mint(communityFund, baseTxFee);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/CalledByVm.sol CELO/packages/contracts-bedrock/src/celo/CalledByVm.sol
new file mode 100644
index 0000000000000000000000000000000000000000..c3f6efe12072ef8c87e213f9c29b0789c26cff0f
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/CalledByVm.sol
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+contract CalledByVm {
+ modifier onlyVm() {
+ require(msg.sender == address(0), "Only VM can call");
+ _;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/CeloPredeploys.sol CELO/packages/contracts-bedrock/src/celo/CeloPredeploys.sol
new file mode 100644
index 0000000000000000000000000000000000000000..91dc4cd4418914f2f857f9c1ded57cd45b5a9ba8
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/CeloPredeploys.sol
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import { console2 as console } from "forge-std/console2.sol";
+
+/// @title CeloPredeploys
+/// @notice Contains constant addresses for protocol contracts that are pre-deployed to the L2 system.
+library CeloPredeploys {
+ address internal constant CELO_REGISTRY = 0x000000000000000000000000000000000000ce10;
+ address internal constant GOLD_TOKEN = 0x471EcE3750Da237f93B8E339c536989b8978a438;
+ address internal constant FEE_HANDLER = 0xcD437749E43A154C07F3553504c68fBfD56B8778;
+ address internal constant MENTO_FEE_HANDLER_SELLER = 0x4eFa274B7e33476C961065000D58ee09F7921A74;
+ address internal constant UNISWAP_FEE_HANDLER_SELLER = 0xD3aeE28548Dbb65DF03981f0dC0713BfCBd10a97;
+ address internal constant SORTED_ORACLES = 0xefB84935239dAcdecF7c5bA76d8dE40b077B7b33;
+ address internal constant ADDRESS_SORTED_LINKED_LIST_WITH_MEDIAN = 0xED477A99035d0c1e11369F1D7A4e587893cc002B;
+ address internal constant FEE_CURRENCY = 0x4200000000000000000000000000000000001022;
+ address internal constant FEE_CURRENCY_DIRECTORY = 0x9212Fb72ae65367A7c887eC4Ad9bE310BAC611BF;
+ address internal constant cUSD = 0x765DE816845861e75A25fCA122bb6898B8B1282a;
+
+ /// @notice Returns the name of the predeploy at the given address.
+ function getName(address _addr) internal pure returns (string memory out_) {
+ // require(isPredeployNamespace(_addr), "Predeploys: address must be a predeploy");
+
+ if (_addr == CELO_REGISTRY) return "CeloRegistry";
+ if (_addr == GOLD_TOKEN) return "GoldToken";
+ if (_addr == FEE_HANDLER) return "FeeHandler";
+ if (_addr == MENTO_FEE_HANDLER_SELLER) return "MentoFeeHandlerSeller";
+ if (_addr == UNISWAP_FEE_HANDLER_SELLER) return "UniswapFeeHandlerSeller";
+ if (_addr == SORTED_ORACLES) return "SortedOracles";
+ if (_addr == ADDRESS_SORTED_LINKED_LIST_WITH_MEDIAN) return "AddressSortedLinkedListWithMedian";
+ if (_addr == FEE_CURRENCY) return "FeeCurrency";
+ if (_addr == FEE_CURRENCY_DIRECTORY) return "FeeCurrencyDirectory";
+ if (_addr == cUSD) return "cUSD";
+
+ revert("Predeploys: unnamed predeploy");
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/CeloRegistry.sol CELO/packages/contracts-bedrock/src/celo/CeloRegistry.sol
new file mode 100644
index 0000000000000000000000000000000000000000..7da4cfb35ddfef5c49183c7c3523f658e071aa33
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/CeloRegistry.sol
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+
+import "./interfaces/ICeloRegistry.sol";
+import "./Initializable.sol";
+
+/**
+ * @title Routes identifiers to addresses.
+ */
+contract CeloRegistry is ICeloRegistry, Ownable, Initializable {
+ mapping(bytes32 => address) public registry;
+
+ event RegistryUpdated(string identifier, bytes32 indexed identifierHash, address indexed addr);
+
+ /**
+ * @notice Sets initialized == true on implementation contracts
+ * @param test Set to true to skip implementation initialization
+ */
+ constructor(bool test) Initializable(test) { }
+
+ /**
+ * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
+ */
+ function initialize() external initializer {
+ _transferOwnership(msg.sender);
+ }
+
+ /**
+ * @notice Associates the given address with the given identifier.
+ * @param identifier Identifier of contract whose address we want to set.
+ * @param addr Address of contract.
+ */
+ function setAddressFor(string calldata identifier, address addr) external onlyOwner {
+ bytes32 identifierHash = keccak256(abi.encodePacked(identifier));
+ registry[identifierHash] = addr;
+ emit RegistryUpdated(identifier, identifierHash, addr);
+ }
+
+ /**
+ * @notice Gets address associated with the given identifierHash.
+ * @param identifierHash Identifier hash of contract whose address we want to look up.
+ * @dev Throws if address not set.
+ */
+ function getAddressForOrDie(bytes32 identifierHash) external view returns (address) {
+ require(registry[identifierHash] != address(0), "identifier has no registry entry");
+ return registry[identifierHash];
+ }
+
+ /**
+ * @notice Gets address associated with the given identifierHash.
+ * @param identifierHash Identifier hash of contract whose address we want to look up.
+ */
+ function getAddressFor(bytes32 identifierHash) external view returns (address) {
+ return registry[identifierHash];
+ }
+
+ /**
+ * @notice Gets address associated with the given identifier.
+ * @param identifier Identifier of contract whose address we want to look up.
+ * @dev Throws if address not set.
+ */
+ function getAddressForStringOrDie(string calldata identifier) external view returns (address) {
+ bytes32 identifierHash = keccak256(abi.encodePacked(identifier));
+ require(registry[identifierHash] != address(0), "identifier has no registry entry");
+ return registry[identifierHash];
+ }
+
+ /**
+ * @notice Gets address associated with the given identifier.
+ * @param identifier Identifier of contract whose address we want to look up.
+ */
+ function getAddressForString(string calldata identifier) external view returns (address) {
+ bytes32 identifierHash = keccak256(abi.encodePacked(identifier));
+ return registry[identifierHash];
+ }
+
+ /**
+ * @notice Iterates over provided array of identifiers, getting the address for each.
+ * Returns true if `sender` matches the address of one of the provided identifiers.
+ * @param identifierHashes Array of hashes of approved identifiers.
+ * @param sender Address in question to verify membership.
+ * @return True if `sender` corresponds to the address of any of `identifiers`
+ * registry entries.
+ */
+ function isOneOf(bytes32[] calldata identifierHashes, address sender) external view returns (bool) {
+ for (uint256 i = 0; i < identifierHashes.length; i++) {
+ if (registry[identifierHashes[i]] == sender) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/CeloTokenL1.sol CELO/packages/contracts-bedrock/src/celo/CeloTokenL1.sol
new file mode 100644
index 0000000000000000000000000000000000000000..8ef3fb5abd9bbf8355d72e95867827c7cb2d257e
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/CeloTokenL1.sol
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
+
+string constant NAME = "Celo native asset";
+string constant SYMBOL = "CELO";
+uint256 constant TOTAL_MARKET_CAP = 1000000000e18; // 1 billion CELO
+
+contract CeloTokenL1 is ERC20Upgradeable {
+ function initialize(address portalProxyAddress) public initializer {
+ __ERC20_init(NAME, SYMBOL);
+ _mint(portalProxyAddress, TOTAL_MARKET_CAP);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/FeeCurrencyDirectory.sol CELO/packages/contracts-bedrock/src/celo/FeeCurrencyDirectory.sol
new file mode 100644
index 0000000000000000000000000000000000000000..21fc7ff3181a15e8d87b7f3ab89f713870197d48
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/FeeCurrencyDirectory.sol
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+import "./Initializable.sol";
+import "./interfaces/IOracle.sol";
+import "./interfaces/IFeeCurrencyDirectory.sol";
+import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
+
+contract FeeCurrencyDirectory is IFeeCurrencyDirectory, Initializable, Ownable {
+ mapping(address => CurrencyConfig) public currencies;
+ address[] private currencyList;
+
+ constructor(bool test) Initializable(test) { }
+
+ /**
+ * @notice Initializes the contract with the owner set.
+ */
+ function initialize() public initializer {
+ _transferOwnership(msg.sender);
+ }
+
+ /**
+ * @notice Sets the currency configuration for a token.
+ * @dev This action can only be performed by the contract owner.
+ * @param token The token address.
+ * @param oracle The oracle address for price fetching.
+ * @param intrinsicGas The intrinsic gas value for transactions.
+ */
+ function setCurrencyConfig(address token, address oracle, uint256 intrinsicGas) external onlyOwner {
+ require(oracle != address(0), "Oracle address cannot be zero");
+ require(intrinsicGas > 0, "Intrinsic gas cannot be zero");
+ require(currencies[token].oracle == address(0), "Currency already in the directory");
+
+ currencies[token] = CurrencyConfig({ oracle: oracle, intrinsicGas: intrinsicGas });
+ currencyList.push(token);
+ }
+
+ /**
+ * @notice Removes a token from the directory.
+ * @dev This action can only be performed by the contract owner.
+ * @param token The token address to remove.
+ * @param index The index in the list of directory currencies.
+ */
+ function removeCurrencies(address token, uint256 index) external onlyOwner {
+ require(index < currencyList.length, "Index out of bounds");
+ require(currencyList[index] == token, "Index does not match token");
+
+ delete currencies[token];
+ currencyList[index] = currencyList[currencyList.length - 1];
+ currencyList.pop();
+ }
+
+ /**
+ * @notice Returns the list of all currency addresses.
+ * @return An array of addresses.
+ */
+ function getCurrencies() public view returns (address[] memory) {
+ return currencyList;
+ }
+
+ /**
+ * @notice Returns the configuration for a currency.
+ * @param token The address of the token.
+ * @return Currency configuration of the token.
+ */
+ function getCurrencyConfig(address token) public view returns (CurrencyConfig memory) {
+ return currencies[token];
+ }
+
+ /**
+ * @notice Retrieves exchange rate between token and CELO.
+ * @param token The token address whose price is to be fetched.
+ * @return numerator The exchange rate numerator.
+ * @return denominator The exchange rate denominator.
+ */
+ function getExchangeRate(address token) public view returns (uint256 numerator, uint256 denominator) {
+ require(currencies[token].oracle != address(0), "Currency not in the directory");
+ (numerator, denominator) = IOracle(currencies[token].oracle).getExchangeRate(token);
+ }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 0, 0);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/FeeHandler.sol CELO/packages/contracts-bedrock/src/celo/FeeHandler.sol
new file mode 100644
index 0000000000000000000000000000000000000000..00a1b0bde4fcb4af98c1cd85c71b2d45802d950c
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/FeeHandler.sol
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+
+import "./UsingRegistry.sol";
+import "./common/Freezable.sol";
+import "./common/FixidityLib.sol";
+import "./common/Initializable.sol";
+
+import "./common/interfaces/IFeeHandler.sol";
+import "./common/interfaces/IFeeHandlerSeller.sol";
+
+// TODO move to IStableToken when it adds method getExchangeRegistryId
+import "./interfaces/IStableTokenMento.sol";
+import "./common/interfaces/ICeloVersionedContract.sol";
+import "./common/interfaces/ICeloToken.sol";
+import "./stability/interfaces/ISortedOracles.sol";
+
+// Using the minimal required signatures in the interfaces so more contracts could be compatible
+import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
+
+// An implementation of FeeHandler as described in CIP-52
+// See https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0052.md
+contract FeeHandler is
+ Ownable,
+ Initializable,
+ UsingRegistry,
+ ICeloVersionedContract,
+ Freezable,
+ IFeeHandler,
+ ReentrancyGuard
+{
+ using FixidityLib for FixidityLib.Fraction;
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ uint256 public constant FIXED1_UINT = 1000000000000000000000000; // TODO move to FIX and add check
+
+ // Min units that can be burned
+ uint256 public constant MIN_BURN = 200;
+
+ // last day the daily limits were updated
+ uint256 public lastLimitDay;
+
+ FixidityLib.Fraction public burnFraction; // 80%
+
+ address public feeBeneficiary;
+
+ uint256 public celoToBeBurned;
+
+ // This mapping can not be public because it contains a FixidityLib.Fraction
+ // and that'd be only supported with experimental features in this
+ // compiler version
+ mapping(address => TokenState) private tokenStates;
+
+ struct TokenState {
+ address handler;
+ FixidityLib.Fraction maxSlippage;
+ // Max amounts that can be burned in a day for a token
+ uint256 dailySellLimit;
+ // Max amounts that can be burned today for a token
+ uint256 currentDaySellLimit;
+ uint256 toDistribute;
+ // Historical amounts burned by this contract
+ uint256 pastBurn;
+ }
+
+ EnumerableSet.AddressSet private activeTokens;
+
+ event SoldAndBurnedToken(address token, uint256 value);
+ event DailyLimitSet(address tokenAddress, uint256 newLimit);
+ event DailyLimitHit(address token, uint256 burning);
+ event MaxSlippageSet(address token, uint256 maxSlippage);
+ event DailySellLimitUpdated(uint256 amount);
+ event FeeBeneficiarySet(address newBeneficiary);
+ event BurnFractionSet(uint256 fraction);
+ event TokenAdded(address tokenAddress, address handlerAddress);
+ event TokenRemoved(address tokenAddress);
+
+ /**
+ * @notice Sets initialized == true on implementation contracts.
+ * @param test Set to true to skip implementation initialisation.
+ */
+ constructor(bool test) Initializable(test) { }
+
+ /**
+ * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
+ */
+ function initialize(
+ address _registryAddress,
+ address newFeeBeneficiary,
+ uint256 newBurnFraction,
+ address[] calldata tokens,
+ address[] calldata handlers,
+ uint256[] calldata newLimits,
+ uint256[] calldata newMaxSlippages
+ )
+ external
+ initializer
+ {
+ require(tokens.length == handlers.length, "handlers length should match tokens length");
+ require(tokens.length == newLimits.length, "limits length should match tokens length");
+ require(tokens.length == newMaxSlippages.length, "maxSlippage length should match tokens length");
+
+ _transferOwnership(msg.sender);
+ setRegistry(_registryAddress);
+ _setFeeBeneficiary(newFeeBeneficiary);
+ _setBurnFraction(newBurnFraction);
+
+ for (uint256 i = 0; i < tokens.length; i++) {
+ _addToken(tokens[i], handlers[i]);
+ _setDailySellLimit(tokens[i], newLimits[i]);
+ _setMaxSplippage(tokens[i], newMaxSlippages[i]);
+ }
+ }
+
+ // Without this the contract cant receive Celo as native transfer
+ receive() external payable { }
+
+ /**
+ * @dev Returns the handler address for the specified token.
+ * @param tokenAddress The address of the token for which to return the handler.
+ * @return The address of the handler contract for the specified token.
+ */
+ function getTokenHandler(address tokenAddress) external view returns (address) {
+ return tokenStates[tokenAddress].handler;
+ }
+
+ /**
+ * @dev Returns a boolean indicating whether the specified token is active or not.
+ * @param tokenAddress The address of the token for which to retrieve the active status.
+ * @return A boolean representing the active status of the specified token.
+ */
+ function getTokenActive(address tokenAddress) external view returns (bool) {
+ return activeTokens.contains(tokenAddress);
+ }
+
+ /**
+ * @dev Returns the maximum slippage percentage for the specified token.
+ * @param tokenAddress The address of the token for which to retrieve the maximum
+ * slippage percentage.
+ * @return The maximum slippage percentage as a uint256 value.
+ */
+ function getTokenMaxSlippage(address tokenAddress) external view returns (uint256) {
+ return FixidityLib.unwrap(tokenStates[tokenAddress].maxSlippage);
+ }
+
+ /**
+ * @dev Returns the daily burn limit for the specified token.
+ * @param tokenAddress The address of the token for which to retrieve the daily burn limit.
+ * @return The daily burn limit as a uint256 value.
+ */
+ function getTokenDailySellLimit(address tokenAddress) external view returns (uint256) {
+ return tokenStates[tokenAddress].dailySellLimit;
+ }
+
+ /**
+ * @dev Returns the current daily sell limit for the specified token.
+ * @param tokenAddress The address of the token for which to retrieve the current daily limit.
+ * @return The current daily limit as a uint256 value.
+ */
+ function getTokenCurrentDaySellLimit(address tokenAddress) external view returns (uint256) {
+ return tokenStates[tokenAddress].currentDaySellLimit;
+ }
+
+ /**
+ * @dev Returns the amount of tokens available to distribute for the specified token.
+ * @param tokenAddress The address of the token for which to retrieve the amount of
+ * tokens available to distribute.
+ * @return The amount of tokens available to distribute as a uint256 value.
+ */
+ function getTokenToDistribute(address tokenAddress) external view returns (uint256) {
+ return tokenStates[tokenAddress].toDistribute;
+ }
+
+ function getActiveTokens() public view returns (address[] memory) {
+ return activeTokens.values();
+ }
+
+ /**
+ * @dev Sets the fee beneficiary address to the specified address.
+ * @param beneficiary The address to set as the fee beneficiary.
+ */
+ function setFeeBeneficiary(address beneficiary) external onlyOwner {
+ return _setFeeBeneficiary(beneficiary);
+ }
+
+ function _setFeeBeneficiary(address beneficiary) private {
+ feeBeneficiary = beneficiary;
+ emit FeeBeneficiarySet(beneficiary);
+ }
+
+ /**
+ * @dev Sets the burn fraction to the specified value.
+ * @param fraction The value to set as the burn fraction.
+ */
+ function setBurnFraction(uint256 fraction) external onlyOwner {
+ return _setBurnFraction(fraction);
+ }
+
+ function _setBurnFraction(uint256 newFraction) private {
+ FixidityLib.Fraction memory fraction = FixidityLib.wrap(newFraction);
+ require(FixidityLib.lte(fraction, FixidityLib.fixed1()), "Burn fraction must be less than or equal to 1");
+ burnFraction = fraction;
+ emit BurnFractionSet(newFraction);
+ }
+
+ /**
+ * @dev Sets the burn fraction to the specified value. Token has to have a handler set.
+ * @param tokenAddress The address of the token to sell
+ */
+ function sell(address tokenAddress) external {
+ return _sell(tokenAddress);
+ }
+
+ /**
+ * @dev Adds a new token to the contract with the specified token and handler addresses.
+ * @param tokenAddress The address of the token to add.
+ * @param handlerAddress The address of the handler contract for the specified token.
+ */
+ function addToken(address tokenAddress, address handlerAddress) external onlyOwner {
+ _addToken(tokenAddress, handlerAddress);
+ }
+
+ function _addToken(address tokenAddress, address handlerAddress) private {
+ require(handlerAddress != address(0), "Can't set handler to zero");
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ tokenState.handler = handlerAddress;
+
+ activeTokens.add(tokenAddress);
+ emit TokenAdded(tokenAddress, handlerAddress);
+ }
+
+ /**
+ * @notice Allows the owner to activate a specified token.
+ * @param tokenAddress The address of the token to be activated.
+ */
+ function activateToken(address tokenAddress) external onlyOwner {
+ _activateToken(tokenAddress);
+ }
+
+ function _activateToken(address tokenAddress) private {
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ require(
+ tokenState.handler != address(0) || tokenAddress == registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID),
+ "Handler has to be set to activate token"
+ );
+ activeTokens.add(tokenAddress);
+ }
+
+ /**
+ * @dev Deactivates the specified token by marking it as inactive.
+ * @param tokenAddress The address of the token to deactivate.
+ */
+ function deactivateToken(address tokenAddress) external onlyOwner {
+ _deactivateToken(tokenAddress);
+ }
+
+ function _deactivateToken(address tokenAddress) private {
+ activeTokens.remove(tokenAddress);
+ }
+
+ /**
+ * @notice Allows the owner to set a handler contract for a specified token.
+ * @param tokenAddress The address of the token to set the handler for.
+ * @param handlerAddress The address of the handler contract to be set.
+ */
+ function setHandler(address tokenAddress, address handlerAddress) external onlyOwner {
+ _setHandler(tokenAddress, handlerAddress);
+ }
+
+ function _setHandler(address tokenAddress, address handlerAddress) private {
+ require(handlerAddress != address(0), "Can't set handler to zero, use deactivateToken");
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ tokenState.handler = handlerAddress;
+ }
+
+ function removeToken(address tokenAddress) external onlyOwner {
+ _removeToken(tokenAddress);
+ }
+
+ function _removeToken(address tokenAddress) private {
+ _deactivateToken(tokenAddress);
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ tokenState.handler = address(0);
+ emit TokenRemoved(tokenAddress);
+ }
+
+ function _sell(address tokenAddress) private onlyWhenNotFrozen nonReentrant {
+ IERC20 token = IERC20(tokenAddress);
+
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ require(tokenState.handler != address(0), "Handler has to be set to sell token");
+ require(FixidityLib.unwrap(tokenState.maxSlippage) != 0, "Max slippage has to be set to sell token");
+ FixidityLib.Fraction memory balanceToProcess =
+ FixidityLib.newFixed(token.balanceOf(address(this)) - tokenState.toDistribute);
+
+ uint256 balanceToBurn = (burnFraction.multiply(balanceToProcess).fromFixed());
+
+ tokenState.toDistribute = tokenState.toDistribute + balanceToProcess.fromFixed() - balanceToBurn;
+
+ // small numbers cause rounding errors and zero case should be skipped
+ if (balanceToBurn < MIN_BURN) {
+ return;
+ }
+
+ if (dailySellLimitHit(tokenAddress, balanceToBurn)) {
+ // in case the limit is hit, burn the max possible
+ balanceToBurn = tokenState.currentDaySellLimit;
+ emit DailyLimitHit(tokenAddress, balanceToBurn);
+ }
+
+ token.transfer(tokenState.handler, balanceToBurn);
+ IFeeHandlerSeller handler = IFeeHandlerSeller(tokenState.handler);
+
+ uint256 celoReceived = handler.sell(
+ tokenAddress,
+ registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID),
+ balanceToBurn,
+ FixidityLib.unwrap(tokenState.maxSlippage)
+ );
+
+ celoToBeBurned = celoToBeBurned + celoReceived;
+ tokenState.pastBurn = tokenState.pastBurn + balanceToBurn;
+ updateLimits(tokenAddress, balanceToBurn);
+
+ emit SoldAndBurnedToken(tokenAddress, balanceToBurn);
+ }
+
+ /**
+ * @dev Distributes the available tokens for the specified token address to the fee beneficiary.
+ * @param tokenAddress The address of the token for which to distribute the available tokens.
+ */
+ function distribute(address tokenAddress) external {
+ return _distribute(tokenAddress);
+ }
+
+ function _distribute(address tokenAddress) private onlyWhenNotFrozen nonReentrant {
+ require(feeBeneficiary != address(0), "Can't distribute to the zero address");
+ IERC20 token = IERC20(tokenAddress);
+ uint256 tokenBalance = token.balanceOf(address(this));
+
+ TokenState storage tokenState = tokenStates[tokenAddress];
+ require(
+ tokenState.handler != address(0) || tokenAddress == registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID),
+ "Handler has to be set to sell token"
+ );
+
+ // safty check to avoid a revert due balance
+ uint256 balanceToDistribute = Math.min(tokenBalance, tokenState.toDistribute);
+
+ if (balanceToDistribute == 0) {
+ // don't distribute with zero balance
+ return;
+ }
+
+ token.transfer(feeBeneficiary, balanceToDistribute);
+ tokenState.toDistribute = tokenState.toDistribute - balanceToDistribute;
+ }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 0, 0);
+ }
+
+ /**
+ * @notice Allows owner to set max slippage for a token.
+ * @param token Address of the token to set.
+ * @param newMax New sllipage to set, as Fixidity fraction.
+ */
+ function setMaxSplippage(address token, uint256 newMax) external onlyOwner {
+ _setMaxSplippage(token, newMax);
+ }
+
+ function _setMaxSplippage(address token, uint256 newMax) private {
+ TokenState storage tokenState = tokenStates[token];
+ require(newMax != 0, "Cannot set max slippage to zero");
+ tokenState.maxSlippage = FixidityLib.wrap(newMax);
+ require(
+ FixidityLib.lte(tokenState.maxSlippage, FixidityLib.fixed1()), "Splippage must be less than or equal to 1"
+ );
+ emit MaxSlippageSet(token, newMax);
+ }
+
+ /**
+ * @notice Allows owner to set the daily burn limit for a token.
+ * @param token Address of the token to set.
+ * @param newLimit The new limit to set, in the token units.
+ */
+ function setDailySellLimit(address token, uint256 newLimit) external onlyOwner {
+ _setDailySellLimit(token, newLimit);
+ }
+
+ function _setDailySellLimit(address token, uint256 newLimit) private {
+ TokenState storage tokenState = tokenStates[token];
+ tokenState.dailySellLimit = newLimit;
+ emit DailyLimitSet(token, newLimit);
+ }
+
+ /**
+ * @dev Burns CELO tokens according to burnFraction.
+ */
+ function burnCelo() external {
+ return _burnCelo();
+ }
+
+ /**
+ * @dev Distributes the available tokens for all registered tokens to the feeBeneficiary.
+ */
+ function distributeAll() external {
+ return _distributeAll();
+ }
+
+ function _distributeAll() private {
+ for (uint256 i = 0; i < EnumerableSet.length(activeTokens); i++) {
+ address token = activeTokens.at(i);
+ _distribute(token);
+ }
+ // distribute Celo
+ _distribute(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
+ }
+
+ /**
+ * @dev Distributes the available tokens for all registered tokens to the feeBeneficiary.
+ */
+ function handleAll() external {
+ return _handleAll();
+ }
+
+ function _handleAll() private {
+ for (uint256 i = 0; i < EnumerableSet.length(activeTokens); i++) {
+ // calling _handle would trigger may burn Celo and distributions
+ // that can be just batched at the end
+ address token = activeTokens.at(i);
+ _sell(token);
+ }
+ _distributeAll(); // distributes Celo as well
+ _burnCelo();
+ }
+
+ /**
+ * @dev Distributes the the token for to the feeBeneficiary.
+ */
+ function handle(address tokenAddress) external {
+ return _handle(tokenAddress);
+ }
+
+ function _handle(address tokenAddress) private {
+ // Celo doesn't have to be exchanged for anything
+ if (tokenAddress != registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)) {
+ _sell(tokenAddress);
+ }
+ _burnCelo();
+ _distribute(tokenAddress);
+ _distribute(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
+ }
+
+ /**
+ * @notice Burns all the Celo balance of this contract.
+ */
+ function _burnCelo() private {
+ TokenState storage tokenState = tokenStates[registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID)];
+ ICeloToken celo = ICeloToken(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
+
+ uint256 balanceOfCelo = address(this).balance;
+
+ uint256 balanceToProcess = balanceOfCelo - tokenState.toDistribute - celoToBeBurned;
+ uint256 currentBalanceToBurn = FixidityLib.newFixed(balanceToProcess).multiply(burnFraction).fromFixed();
+ uint256 totalBalanceToBurn = currentBalanceToBurn + celoToBeBurned;
+ celo.burn(totalBalanceToBurn);
+
+ celoToBeBurned = 0;
+ tokenState.toDistribute = tokenState.toDistribute + balanceToProcess - currentBalanceToBurn;
+ }
+
+ /**
+ * @param token The address of the token to query.
+ * @return The amount burned for a token.
+ */
+ function getPastBurnForToken(address token) external view returns (uint256) {
+ return tokenStates[token].pastBurn;
+ }
+
+ /**
+ * @param token The address of the token to query.
+ * @param amountToBurn The amount of the token to burn.
+ * @return Returns true if burning amountToBurn would exceed the daily limit.
+ */
+ function dailySellLimitHit(address token, uint256 amountToBurn) public returns (bool) {
+ TokenState storage tokenState = tokenStates[token];
+
+ if (tokenState.dailySellLimit == 0) {
+ // if no limit set, assume uncapped
+ return false;
+ }
+
+ uint256 currentDay = block.timestamp / 1 days;
+ // Pattern borrowed from Reserve.sol
+ if (currentDay > lastLimitDay) {
+ lastLimitDay = currentDay;
+ tokenState.currentDaySellLimit = tokenState.dailySellLimit;
+ }
+
+ return amountToBurn >= tokenState.currentDaySellLimit;
+ }
+
+ /**
+ * @notice Updates the current day limit for a token.
+ * @param token The address of the token to query.
+ * @param amountBurned the amount of the token that was burned.
+ */
+ function updateLimits(address token, uint256 amountBurned) private {
+ TokenState storage tokenState = tokenStates[token];
+
+ if (tokenState.dailySellLimit == 0) {
+ // if no limit set, assume uncapped
+ return;
+ }
+ tokenState.currentDaySellLimit = tokenState.currentDaySellLimit - amountBurned;
+ emit DailySellLimitUpdated(amountBurned);
+ }
+
+ /**
+ * @notice Allows owner to transfer tokens of this contract. It's meant for governance to
+ * trigger use cases not contemplated in this contract.
+ * @param token The address of the token to transfer.
+ * @param recipient The address of the recipient to transfer the tokens to.
+ * @param value The amount of tokens to transfer.
+ * @return A boolean indicating whether the transfer was successful or not.
+ */
+ function transfer(address token, address recipient, uint256 value) external onlyOwner returns (bool) {
+ return IERC20(token).transfer(recipient, value);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/FeeHandlerSeller.sol CELO/packages/contracts-bedrock/src/celo/FeeHandlerSeller.sol
new file mode 100644
index 0000000000000000000000000000000000000000..4d22125af4d647021d77e0ed4b59d09049dd6bac
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/FeeHandlerSeller.sol
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+import "./common/FixidityLib.sol";
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+import "./UsingRegistry.sol";
+import "./common/Initializable.sol";
+
+// Abstract class for a FeeHandlerSeller, as defined in CIP-52
+// https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0052.md
+abstract contract FeeHandlerSeller is Ownable, Initializable, UsingRegistry {
+ using FixidityLib for FixidityLib.Fraction;
+
+ // Address of the token
+ // Minimal number of reports in SortedOracles contract
+ mapping(address => uint256) public minimumReports;
+
+ event MinimumReportsSet(address tokenAddress, uint256 minimumReports);
+ event TokenSold(address soldTokenAddress, address boughtTokenAddress, uint256 amount);
+
+ constructor(bool testingDeployment) Initializable(testingDeployment) { }
+
+ function initialize(
+ address _registryAddress,
+ address[] calldata tokenAddresses,
+ uint256[] calldata newMininumReports
+ )
+ external
+ initializer
+ {
+ _transferOwnership(msg.sender);
+ setRegistry(_registryAddress);
+
+ for (uint256 i = 0; i < tokenAddresses.length; i++) {
+ _setMinimumReports(tokenAddresses[i], newMininumReports[i]);
+ }
+ }
+
+ /**
+ * @notice Allows owner to set the minimum number of reports required.
+ * @param newMininumReports The new update minimum number of reports required.
+ */
+ function setMinimumReports(address tokenAddress, uint256 newMininumReports) public onlyOwner {
+ _setMinimumReports(tokenAddress, newMininumReports);
+ }
+
+ function _setMinimumReports(address tokenAddress, uint256 newMininumReports) internal {
+ minimumReports[tokenAddress] = newMininumReports;
+ emit MinimumReportsSet(tokenAddress, newMininumReports);
+ }
+
+ /**
+ * @dev Calculates the minimum amount of tokens that should be received for the specified
+ * amount with the given mid-price and maximum slippage.
+ * @param midPriceNumerator The numerator of the mid-price for the token pair.
+ * @param midPriceDenominator The denominator of the mid-price for the token pair.
+ * @param amount The amount of tokens to be exchanged.
+ * @param maxSlippage The maximum slippage percentage as a fraction of the mid-price.
+ * @return The minimum amount of tokens that should be received as a uint256 value.
+ */
+ function calculateMinAmount(
+ uint256 midPriceNumerator,
+ uint256 midPriceDenominator,
+ uint256 amount,
+ uint256 maxSlippage // as fraction
+ )
+ public
+ pure
+ returns (uint256)
+ {
+ FixidityLib.Fraction memory maxSlippageFraction = FixidityLib.wrap(maxSlippage);
+
+ FixidityLib.Fraction memory price = FixidityLib.newFixedFraction(midPriceNumerator, midPriceDenominator);
+ FixidityLib.Fraction memory amountFraction = FixidityLib.newFixed(amount);
+ FixidityLib.Fraction memory totalAmount = price.multiply(amountFraction);
+
+ return totalAmount.subtract(price.multiply(maxSlippageFraction).multiply(amountFraction)).fromFixed();
+ }
+
+ /**
+ * @notice Allows owner to transfer tokens of this contract. It's meant for governance to
+ * trigger use cases not contemplated in this contract.
+ * @param token The address of the token to transfer.
+ * @param amount The amount of tokens to transfer.
+ * @param to The address of the recipient to transfer the tokens to.
+ * @return A boolean indicating whether the transfer was successful or not.
+ */
+ function transfer(address token, uint256 amount, address to) external onlyOwner returns (bool) {
+ return IERC20(token).transfer(to, amount);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/GoldToken.sol CELO/packages/contracts-bedrock/src/celo/GoldToken.sol
new file mode 100644
index 0000000000000000000000000000000000000000..e7236678670a7bedf86f7769ef74888dc5f2488c
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/GoldToken.sol
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+
+import "./UsingRegistry.sol";
+import "./CalledByVm.sol";
+import "./Initializable.sol";
+import "./interfaces/ICeloToken.sol";
+import "./common/interfaces/ICeloVersionedContract.sol";
+
+contract GoldToken is Initializable, CalledByVm, UsingRegistry, IERC20, ICeloToken, ICeloVersionedContract {
+ // Address of the TRANSFER precompiled contract.
+ // solhint-disable state-visibility
+ address constant TRANSFER = address(0xff - 2);
+ string constant NAME = "Celo native asset";
+ string constant SYMBOL = "CELO";
+ uint8 constant DECIMALS = 18;
+ uint256 internal totalSupply_;
+ // solhint-enable state-visibility
+
+ mapping(address => mapping(address => uint256)) internal allowed;
+
+ // Burn address is 0xdEaD because truffle is having buggy behaviour with the zero address
+ address constant BURN_ADDRESS = address(0x000000000000000000000000000000000000dEaD);
+
+ event TransferComment(string comment);
+
+ /**
+ * @notice Sets initialized == true on implementation contracts
+ * @param test Set to true to skip implementation initialization
+ */
+ constructor(bool test) Initializable(test) { }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 2, 0);
+ }
+
+ /**
+ * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
+ * @param registryAddress Address of the Registry contract.
+ */
+ function initialize(address registryAddress) external initializer {
+ totalSupply_ = 0;
+ _transferOwnership(msg.sender);
+ setRegistry(registryAddress);
+ }
+
+ /**
+ * @notice Transfers CELO from one address to another.
+ * @param to The address to transfer CELO to.
+ * @param value The amount of CELO to transfer.
+ * @return True if the transaction succeeds.
+ */
+ // solhint-disable-next-line no-simple-event-func-name
+ function transfer(address to, uint256 value) external returns (bool) {
+ return _transferWithCheck(to, value);
+ }
+
+ /**
+ * @notice Transfers CELO from one address to another with a comment.
+ * @param to The address to transfer CELO to.
+ * @param value The amount of CELO to transfer.
+ * @param comment The transfer comment
+ * @return True if the transaction succeeds.
+ */
+ function transferWithComment(address to, uint256 value, string calldata comment) external returns (bool) {
+ bool succeeded = _transferWithCheck(to, value);
+ emit TransferComment(comment);
+ return succeeded;
+ }
+
+ /**
+ * @notice This function allows a user to burn a specific amount of tokens.
+ * Burning is implemented by sending tokens to the burn address.
+ * @param value: The amount of CELO to burn.
+ * @return True if burn was successful.
+ */
+ function burn(uint256 value) external returns (bool) {
+ // not using transferWithCheck as the burn address can potentially be the zero address
+ return _transfer(BURN_ADDRESS, value);
+ }
+
+ /**
+ * @notice Approve a user to transfer CELO on behalf of another user.
+ * @param spender The address which is being approved to spend CELO.
+ * @param value The amount of CELO approved to the spender.
+ * @return True if the transaction succeeds.
+ */
+ function approve(address spender, uint256 value) external returns (bool) {
+ require(spender != address(0), "cannot set allowance for 0");
+ allowed[msg.sender][spender] = value;
+ emit Approval(msg.sender, spender, value);
+ return true;
+ }
+
+ /**
+ * @notice Increases the allowance of another user.
+ * @param spender The address which is being approved to spend CELO.
+ * @param value The increment of the amount of CELO approved to the spender.
+ * @return True if the transaction succeeds.
+ */
+ function increaseAllowance(address spender, uint256 value) external returns (bool) {
+ require(spender != address(0), "cannot set allowance for 0");
+ uint256 oldValue = allowed[msg.sender][spender];
+ uint256 newValue = oldValue + value;
+ allowed[msg.sender][spender] = newValue;
+ emit Approval(msg.sender, spender, newValue);
+ return true;
+ }
+
+ /**
+ * @notice Decreases the allowance of another user.
+ * @param spender The address which is being approved to spend CELO.
+ * @param value The decrement of the amount of CELO approved to the spender.
+ * @return True if the transaction succeeds.
+ */
+ function decreaseAllowance(address spender, uint256 value) external returns (bool) {
+ uint256 oldValue = allowed[msg.sender][spender];
+ uint256 newValue = oldValue - value;
+ allowed[msg.sender][spender] = newValue;
+ emit Approval(msg.sender, spender, newValue);
+ return true;
+ }
+
+ /**
+ * @notice Transfers CELO from one address to another on behalf of a user.
+ * @param from The address to transfer CELO from.
+ * @param to The address to transfer CELO to.
+ * @param value The amount of CELO to transfer.
+ * @return True if the transaction succeeds.
+ */
+ function transferFrom(address from, address to, uint256 value) external returns (bool) {
+ require(to != address(0), "transfer attempted to reserved address 0x0");
+ require(value <= balanceOf(from), "transfer value exceeded balance of sender");
+ require(value <= allowed[from][msg.sender], "transfer value exceeded sender's allowance for spender");
+
+ bool success;
+ (success,) = TRANSFER.call{ value: 0, gas: gasleft() }(abi.encode(from, to, value));
+ require(success, "CELO transfer failed");
+
+ allowed[from][msg.sender] = allowed[from][msg.sender] - value;
+ emit Transfer(from, to, value);
+ return true;
+ }
+
+ /**
+ * @notice Mints new CELO and gives it to 'to'.
+ * @param to The account for which to mint tokens.
+ * @param value The amount of CELO to mint.
+ */
+ function mint(address to, uint256 value) external onlyVm returns (bool) {
+ if (value == 0) {
+ return true;
+ }
+
+ require(to != address(0), "mint attempted to reserved address 0x0");
+ totalSupply_ = totalSupply_ + value;
+
+ bool success;
+ (success,) = TRANSFER.call{ value: 0, gas: gasleft() }(abi.encode(address(0), to, value));
+ require(success, "CELO transfer failed");
+
+ emit Transfer(address(0), to, value);
+ return true;
+ }
+
+ /**
+ * @return The name of the CELO token.
+ */
+ function name() external pure returns (string memory) {
+ return NAME;
+ }
+
+ /**
+ * @return The symbol of the CELO token.
+ */
+ function symbol() external pure returns (string memory) {
+ return SYMBOL;
+ }
+
+ /**
+ * @return The number of decimal places to which CELO is divisible.
+ */
+ function decimals() external pure returns (uint8) {
+ return DECIMALS;
+ }
+
+ /**
+ * @return The total amount of CELO in existence, including what the burn address holds.
+ */
+ function totalSupply() external view returns (uint256) {
+ return totalSupply_;
+ }
+
+ /**
+ * @return The total amount of CELO in existence, not including what the burn address holds.
+ */
+ function circulatingSupply() external view returns (uint256) {
+ return totalSupply_ - getBurnedAmount() - balanceOf(address(0));
+ }
+
+ /**
+ * @notice Gets the amount of owner's CELO allowed to be spent by spender.
+ * @param owner The owner of the CELO.
+ * @param spender The spender of the CELO.
+ * @return The amount of CELO owner is allowing spender to spend.
+ */
+ function allowance(address owner, address spender) external view returns (uint256) {
+ return allowed[owner][spender];
+ }
+
+ /**
+ * @notice Increases the variable for total amount of CELO in existence.
+ * @param amount The amount to increase counter by
+ */
+ function increaseSupply(uint256 amount) external onlyVm {
+ totalSupply_ = totalSupply_ + amount;
+ }
+
+ /**
+ * @notice Gets the amount of CELO that has been burned.
+ * @return The total amount of Celo that has been sent to the burn address.
+ */
+ function getBurnedAmount() public view returns (uint256) {
+ return balanceOf(BURN_ADDRESS);
+ }
+
+ /**
+ * @notice Gets the balance of the specified address.
+ * @param owner The address to query the balance of.
+ * @return The balance of the specified address.
+ */
+ function balanceOf(address owner) public view returns (uint256) {
+ return owner.balance;
+ }
+
+ /**
+ * @notice internal CELO transfer from one address to another.
+ * @param to The address to transfer CELO to.
+ * @param value The amount of CELO to transfer.
+ * @return True if the transaction succeeds.
+ */
+ function _transfer(address to, uint256 value) internal returns (bool) {
+ require(value <= balanceOf(msg.sender), "transfer value exceeded balance of sender");
+
+ bool success;
+ (success,) = TRANSFER.call{ value: 0, gas: gasleft() }(abi.encode(msg.sender, to, value));
+ require(success, "CELO transfer failed");
+ emit Transfer(msg.sender, to, value);
+ return true;
+ }
+
+ /**
+ * @notice Internal CELO transfer from one address to another.
+ * @param to The address to transfer CELO to. Zero address will revert.
+ * @param value The amount of CELO to transfer.
+ * @return True if the transaction succeeds.
+ */
+ function _transferWithCheck(address to, uint256 value) internal returns (bool) {
+ require(to != address(0), "transfer attempted to reserved address 0x0");
+ return _transfer(to, value);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/Initializable.sol CELO/packages/contracts-bedrock/src/celo/Initializable.sol
new file mode 100644
index 0000000000000000000000000000000000000000..7929728eef4ed9063c81aea6f2a0a1758d4ef728
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/Initializable.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+contract Initializable {
+ bool public initialized;
+
+ modifier initializer() {
+ require(!initialized, "contract already initialized");
+ initialized = true;
+ _;
+ }
+
+ constructor(bool testingDeployment) {
+ if (!testingDeployment) {
+ initialized = true;
+ }
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/MentoFeeHandlerSeller.sol CELO/packages/contracts-bedrock/src/celo/MentoFeeHandlerSeller.sol
new file mode 100644
index 0000000000000000000000000000000000000000..e5a9ff455f391f797bbc2ace5101c0ef58c3c192
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/MentoFeeHandlerSeller.sol
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+
+import "./interfaces/IStableTokenMento.sol";
+
+import "./common/interfaces/IFeeHandlerSeller.sol";
+import "./stability/interfaces/ISortedOracles.sol";
+import "./common/FixidityLib.sol";
+import "./common/Initializable.sol";
+
+import "./FeeHandlerSeller.sol";
+
+// An implementation of FeeHandlerSeller supporting interfaces compatible with
+// Mento
+// See https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0052.md
+contract MentoFeeHandlerSeller is FeeHandlerSeller {
+ using FixidityLib for FixidityLib.Fraction;
+
+ /**
+ * @notice Sets initialized == true on implementation contracts.
+ * @param test Set to true to skip implementation initialisation.
+ */
+ constructor(bool test) FeeHandlerSeller(test) { }
+
+ // without this line the contract can't receive native Celo transfers
+ receive() external payable { }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 0, 0);
+ }
+
+ function sell(
+ address sellTokenAddress,
+ address buyTokenAddress,
+ uint256 amount,
+ uint256 maxSlippage // as fraction,
+ )
+ external
+ returns (uint256)
+ {
+ require(
+ buyTokenAddress == registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID), "Buy token can only be gold token"
+ );
+
+ IStableTokenMento stableToken = IStableTokenMento(sellTokenAddress);
+ require(amount <= stableToken.balanceOf(address(this)), "Balance of token to burn not enough");
+
+ address exchangeAddress = registry.getAddressForOrDie(stableToken.getExchangeRegistryId());
+
+ IExchange exchange = IExchange(exchangeAddress);
+
+ uint256 minAmount = 0;
+
+ ISortedOracles sortedOracles = getSortedOracles();
+
+ require(
+ sortedOracles.numRates(sellTokenAddress) >= minimumReports[sellTokenAddress],
+ "Number of reports for token not enough"
+ );
+
+ (uint256 rateNumerator, uint256 rateDenominator) = sortedOracles.medianRate(sellTokenAddress);
+ minAmount = calculateMinAmount(rateNumerator, rateDenominator, amount, maxSlippage);
+
+ // TODO an upgrade would be to compare using routers as well
+ stableToken.approve(exchangeAddress, amount);
+ exchange.sell(amount, minAmount, false);
+
+ IERC20 goldToken = getGoldToken();
+ uint256 celoAmount = goldToken.balanceOf(address(this));
+ goldToken.transfer(msg.sender, celoAmount);
+
+ emit TokenSold(sellTokenAddress, buyTokenAddress, amount);
+ return celoAmount;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/StableTokenV2.sol CELO/packages/contracts-bedrock/src/celo/StableTokenV2.sol
new file mode 100644
index 0000000000000000000000000000000000000000..68632df65abc9d352de50b7f273afc491ff8a1b2
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/StableTokenV2.sol
@@ -0,0 +1,336 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import { ERC20PermitUpgradeable } from
+ "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-ERC20PermitUpgradeable.sol";
+import { ERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
+import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
+
+import { IStableTokenV2 } from "./interfaces/IStableToken.sol";
+import { CalledByVm } from "./CalledByVm.sol";
+
+/**
+ * @title ERC20 token with minting and burning permissioned to a broker and validators.
+ */
+contract StableTokenV2 is IStableTokenV2, ERC20PermitUpgradeable, CalledByVm, OwnableUpgradeable {
+ address public validators;
+ address public broker;
+ address public exchange;
+
+ event TransferComment(string comment);
+ event BrokerUpdated(address broker);
+ event ValidatorsUpdated(address validators);
+ event ExchangeUpdated(address exchange);
+
+ /**
+ * @dev Restricts a function so it can only be executed by an address that's allowed to mint.
+ * Currently that's the broker, validators, or exchange.
+ */
+ modifier onlyMinter() {
+ address sender = _msgSender();
+ require(sender == broker || sender == validators || sender == exchange, "StableTokenV2: not allowed to mint");
+ _;
+ }
+
+ /**
+ * @dev Restricts a function so it can only be executed by an address that's allowed to burn.
+ * Currently that's the broker or exchange.
+ */
+ modifier onlyBurner() {
+ address sender = _msgSender();
+ require(sender == broker || sender == exchange, "StableTokenV2: not allowed to burn");
+ _;
+ }
+
+ /**
+ * @notice The constructor for the StableTokenV2 contract.
+ * @dev Should be called with disable=true in deployments when
+ * it's accessed through a Proxy.
+ * Call this with disable=false during testing, when used
+ * without a proxy.
+ * @param disable Set to true to run `_disableInitializers()` inherited from
+ * openzeppelin-contracts-upgradeable/Initializable.sol
+ */
+ constructor(bool disable) {
+ if (disable) {
+ _disableInitializers();
+ }
+ }
+
+ /**
+ * @notice Initializes a StableTokenV2.
+ * It keeps the same signature as the original initialize() function
+ * in legacy/StableToken.sol
+ * @param _name The name of the stable token (English)
+ * @param _symbol A short symbol identifying the token (e.g. "cUSD")
+ * @param initialBalanceAddresses Array of addresses with an initial balance.
+ * @param initialBalanceValues Array of balance values corresponding to initialBalanceAddresses.
+ * deprecated-param exchangeIdentifier String identifier of exchange in registry (for specific fiat pairs)
+ */
+ function initialize(
+ // slither-disable-start shadowing-local
+ string calldata _name,
+ string calldata _symbol,
+ // slither-disable-end shadowing-local
+ address[] calldata initialBalanceAddresses,
+ uint256[] calldata initialBalanceValues
+ )
+ external
+ initializer
+ {
+ __ERC20_init_unchained(_name, _symbol);
+ __ERC20Permit_init(_symbol);
+ _transferOwnership(_msgSender());
+
+ require(initialBalanceAddresses.length == initialBalanceValues.length, "Array length mismatch");
+ for (uint256 i = 0; i < initialBalanceAddresses.length; i += 1) {
+ _mint(initialBalanceAddresses[i], initialBalanceValues[i]);
+ }
+ }
+
+ /**
+ * @notice Initializes a StableTokenV2 contract
+ * when upgrading from legacy/StableToken.sol.
+ * It sets the addresses that were previously read from the Registry.
+ * It runs the ERC20PermitUpgradeable initializer.
+ * @dev This function is only callable once.
+ * @param _broker The address of the Broker contract.
+ * @param _validators The address of the Validators contract.
+ * @param _exchange The address of the Exchange contract.
+ */
+ function initializeV2(
+ address _broker,
+ address _validators,
+ address _exchange
+ )
+ external
+ reinitializer(2)
+ onlyOwner
+ {
+ _setBroker(_broker);
+ _setValidators(_validators);
+ _setExchange(_exchange);
+ __ERC20Permit_init(symbol());
+ }
+
+ /**
+ * @notice Sets the address of the Broker contract.
+ * @dev This function is only callable by the owner.
+ * @param _broker The address of the Broker contract.
+ */
+ function setBroker(address _broker) external onlyOwner {
+ _setBroker(_broker);
+ }
+
+ /**
+ * @notice Sets the address of the Validators contract.
+ * @dev This function is only callable by the owner.
+ * @param _validators The address of the Validators contract.
+ */
+ function setValidators(address _validators) external onlyOwner {
+ _setValidators(_validators);
+ }
+
+ /**
+ * @notice Sets the address of the Exchange contract.
+ * @dev This function is only callable by the owner.
+ * @param _exchange The address of the Exchange contract.
+ */
+ function setExchange(address _exchange) external onlyOwner {
+ _setExchange(_exchange);
+ }
+
+ /**
+ * @notice Transfer token for a specified address
+ * @param to The address to transfer to.
+ * @param value The amount to be transferred.
+ * @param comment The transfer comment.
+ * @return True if the transaction succeeds.
+ */
+ function transferWithComment(address to, uint256 value, string calldata comment) external returns (bool) {
+ emit TransferComment(comment);
+ return transfer(to, value);
+ }
+
+ /**
+ * @notice Mints new StableToken and gives it to 'to'.
+ * @param to The account for which to mint tokens.
+ * @param value The amount of StableToken to mint.
+ */
+ function mint(address to, uint256 value) external onlyMinter returns (bool) {
+ _mint(to, value);
+ return true;
+ }
+
+ /**
+ * @notice Burns StableToken from the balance of msg.sender.
+ * @param value The amount of StableToken to burn.
+ */
+ function burn(uint256 value) external onlyBurner returns (bool) {
+ _burn(msg.sender, value);
+ return true;
+ }
+
+ /**
+ * @notice Set the address of the Broker contract and emit an event
+ * @param _broker The address of the Broker contract.
+ */
+ function _setBroker(address _broker) internal {
+ broker = _broker;
+ emit BrokerUpdated(_broker);
+ }
+
+ /**
+ * @notice Set the address of the Validators contract and emit an event
+ * @param _validators The address of the Validators contract.
+ */
+ function _setValidators(address _validators) internal {
+ validators = _validators;
+ emit ValidatorsUpdated(_validators);
+ }
+
+ /**
+ * @notice Set the address of the Exchange contract and emit an event
+ * @param _exchange The address of the Exchange contract.
+ */
+ function _setExchange(address _exchange) internal {
+ exchange = _exchange;
+ emit ExchangeUpdated(_exchange);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function transferFrom(
+ address from,
+ address to,
+ uint256 amount
+ )
+ public
+ override(ERC20Upgradeable, IStableTokenV2)
+ returns (bool)
+ {
+ return ERC20Upgradeable.transferFrom(from, to, amount);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function transfer(address to, uint256 amount) public override(ERC20Upgradeable, IStableTokenV2) returns (bool) {
+ return ERC20Upgradeable.transfer(to, amount);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function balanceOf(address account) public view override(ERC20Upgradeable, IStableTokenV2) returns (uint256) {
+ return ERC20Upgradeable.balanceOf(account);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function approve(
+ address spender,
+ uint256 amount
+ )
+ public
+ override(ERC20Upgradeable, IStableTokenV2)
+ returns (bool)
+ {
+ return ERC20Upgradeable.approve(spender, amount);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function allowance(
+ address owner,
+ address spender
+ )
+ public
+ view
+ override(ERC20Upgradeable, IStableTokenV2)
+ returns (uint256)
+ {
+ return ERC20Upgradeable.allowance(owner, spender);
+ }
+
+ /// @inheritdoc ERC20Upgradeable
+ function totalSupply() public view override(ERC20Upgradeable, IStableTokenV2) returns (uint256) {
+ return ERC20Upgradeable.totalSupply();
+ }
+
+ /// @inheritdoc ERC20PermitUpgradeable
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ )
+ public
+ override(ERC20PermitUpgradeable, IStableTokenV2)
+ {
+ ERC20PermitUpgradeable.permit(owner, spender, value, deadline, v, r, s);
+ }
+
+ /**
+ * @notice Reserve balance for making payments for gas in this StableToken currency.
+ * @param from The account to reserve balance from
+ * @param value The amount of balance to reserve
+ * @dev Note that this function is called by the protocol when paying for tx fees in this
+ * currency. After the tx is executed, gas is refunded to the sender and credited to the
+ * various tx fee recipients via a call to `creditGasFees`.
+ */
+ function debitGasFees(address from, uint256 value) external onlyVm {
+ _burn(from, value);
+ }
+
+ /**
+ * @notice Alternative function to credit balance after making payments
+ * for gas in this StableToken currency.
+ * @param from The account to debit balance from
+ * @param feeRecipient Coinbase address
+ * @param gatewayFeeRecipient Gateway address
+ * @param communityFund Community fund address
+ * @param refund amount to be refunded by the VM
+ * @param tipTxFee Coinbase fee
+ * @param baseTxFee Community fund fee
+ * @param gatewayFee Gateway fee
+ * @dev Note that this function is called by the protocol when paying for tx fees in this
+ * currency. Before the tx is executed, gas is debited from the sender via a call to
+ * `debitGasFees`.
+ */
+ function creditGasFees(
+ address from,
+ address feeRecipient,
+ address gatewayFeeRecipient,
+ address communityFund,
+ uint256 refund,
+ uint256 tipTxFee,
+ uint256 gatewayFee,
+ uint256 baseTxFee
+ )
+ external
+ onlyVm
+ {
+ // slither-disable-next-line uninitialized-local
+ uint256 amountToBurn;
+ _mint(from, refund + tipTxFee + gatewayFee + baseTxFee);
+
+ if (feeRecipient != address(0)) {
+ _transfer(from, feeRecipient, tipTxFee);
+ } else if (tipTxFee > 0) {
+ amountToBurn += tipTxFee;
+ }
+
+ if (gatewayFeeRecipient != address(0)) {
+ _transfer(from, gatewayFeeRecipient, gatewayFee);
+ } else if (gatewayFee > 0) {
+ amountToBurn += gatewayFee;
+ }
+
+ if (communityFund != address(0)) {
+ _transfer(from, communityFund, baseTxFee);
+ } else if (baseTxFee > 0) {
+ amountToBurn += baseTxFee;
+ }
+
+ if (amountToBurn > 0) {
+ _burn(from, amountToBurn);
+ }
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/UniswapFeeHandlerSeller.sol CELO/packages/contracts-bedrock/src/celo/UniswapFeeHandlerSeller.sol
new file mode 100644
index 0000000000000000000000000000000000000000..54ce14eaf37cfd30695729e4a2990b294d589b86
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/UniswapFeeHandlerSeller.sol
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/utils/math/Math.sol";
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+
+import "./UsingRegistry.sol";
+
+import "./common/interfaces/IFeeHandlerSeller.sol";
+import "./stability/interfaces/ISortedOracles.sol";
+import "./common/FixidityLib.sol";
+import "./common/Initializable.sol";
+import "./FeeHandlerSeller.sol";
+
+import "./uniswap/interfaces/IUniswapV2RouterMin.sol";
+import "./uniswap/interfaces/IUniswapV2FactoryMin.sol";
+
+// An implementation of FeeHandlerSeller supporting interfaces compatible with
+// Uniswap V2 API
+// See https://github.com/celo-org/celo-proposals/blob/master/CIPs/cip-0052.md
+contract UniswapFeeHandlerSeller is FeeHandlerSeller {
+ using FixidityLib for FixidityLib.Fraction;
+ using EnumerableSet for EnumerableSet.AddressSet;
+
+ uint256 constant MAX_TIMESTAMP_BLOCK_EXCHANGE = 20;
+ uint256 constant MAX_NUMBER_ROUTERS_PER_TOKEN = 3;
+ mapping(address => EnumerableSet.AddressSet) private routerAddresses;
+
+ event ReceivedQuote(address indexed tokneAddress, address indexed router, uint256 quote);
+ event RouterUsed(address router);
+ event RouterAddressSet(address token, address router);
+ event RouterAddressRemoved(address token, address router);
+
+ /**
+ * @notice Sets initialized == true on implementation contracts.
+ * @param test Set to true to skip implementation initialisation.
+ */
+ constructor(bool test) FeeHandlerSeller(test) { }
+
+ // without this line the contract can't receive native Celo transfers
+ receive() external payable { }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 0, 0);
+ }
+
+ /**
+ * @notice Allows owner to set the router for a token.
+ * @param token Address of the token to set.
+ * @param router The new router.
+ */
+ function setRouter(address token, address router) external onlyOwner {
+ _setRouter(token, router);
+ }
+
+ function _setRouter(address token, address router) private {
+ require(router != address(0), "Router can't be address zero");
+ routerAddresses[token].add(router);
+ require(routerAddresses[token].values().length <= MAX_NUMBER_ROUTERS_PER_TOKEN, "Max number of routers reached");
+ emit RouterAddressSet(token, router);
+ }
+
+ /**
+ * @notice Allows owner to remove a router for a token.
+ * @param token Address of the token.
+ * @param router Address of the router to remove.
+ */
+ function removeRouter(address token, address router) external onlyOwner {
+ routerAddresses[token].remove(router);
+ emit RouterAddressRemoved(token, router);
+ }
+
+ /**
+ * @notice Get the list of routers for a token.
+ * @param token The address of the token to query.
+ * @return An array of all the allowed router.
+ */
+ function getRoutersForToken(address token) external view returns (address[] memory) {
+ return routerAddresses[token].values();
+ }
+
+ /**
+ * @dev Calculates the minimum amount of tokens that can be received for a given amount of sell tokens,
+ * taking into account the slippage and the rates of the sell token and CELO token on the Uniswap V2 pair.
+ * @param sellTokenAddress The address of the sell token.
+ * @param maxSlippage The maximum slippage allowed.
+ * @param amount The amount of sell tokens to be traded.
+ * @param bestRouter The Uniswap V2 router with the best price.
+ * @return The minimum amount of tokens that can be received.
+ */
+ function calculateAllMinAmount(
+ address sellTokenAddress,
+ uint256 maxSlippage,
+ uint256 amount,
+ IUniswapV2RouterMin bestRouter
+ )
+ private
+ view
+ returns (uint256)
+ {
+ ISortedOracles sortedOracles = getSortedOracles();
+ uint256 minReports = minimumReports[sellTokenAddress];
+
+ require(sortedOracles.numRates(sellTokenAddress) >= minReports, "Number of reports for token not enough");
+
+ uint256 minimalSortedOracles = 0;
+ // if minimumReports for this token is zero, assume the check is not needed
+ if (minReports > 0) {
+ (uint256 rateNumerator, uint256 rateDenominator) = sortedOracles.medianRate(sellTokenAddress);
+
+ minimalSortedOracles = calculateMinAmount(rateNumerator, rateDenominator, amount, maxSlippage);
+ }
+
+ IERC20 celoToken = getGoldToken();
+ address pair = IUniswapV2FactoryMin(bestRouter.factory()).getPair(sellTokenAddress, address(celoToken));
+ uint256 minAmountPair =
+ calculateMinAmount(IERC20(sellTokenAddress).balanceOf(pair), celoToken.balanceOf(pair), amount, maxSlippage);
+
+ return Math.max(minAmountPair, minimalSortedOracles);
+ }
+
+ // This function explicitly defines few variables because it was getting error "stack too deep"
+ function sell(
+ address sellTokenAddress,
+ address buyTokenAddress,
+ uint256 amount,
+ uint256 maxSlippage // as fraction,
+ )
+ external
+ returns (uint256)
+ {
+ require(
+ buyTokenAddress == registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID), "Buy token can only be gold token"
+ );
+
+ require(routerAddresses[sellTokenAddress].values().length > 0, "routerAddresses should be non empty");
+
+ // An improvement to this function would be to allow the user to pass a path as argument
+ // and if it generates a better outcome that the ones enabled that gets used
+ // and the user gets a reward
+
+ IERC20 celoToken = getGoldToken();
+
+ IUniswapV2RouterMin bestRouter;
+ uint256 bestRouterQuote = 0;
+
+ address[] memory path = new address[](2);
+
+ path[0] = sellTokenAddress;
+ path[1] = address(celoToken);
+
+ for (uint256 i = 0; i < routerAddresses[sellTokenAddress].values().length; i++) {
+ address poolAddress = routerAddresses[sellTokenAddress].at(i);
+ IUniswapV2RouterMin router = IUniswapV2RouterMin(poolAddress);
+
+ // Using the second return value becuase it's the last argument,
+ // the previous values show how many tokens are exchanged in each path
+ // so the first value would be equivalent to balanceToBurn
+ uint256 wouldGet = router.getAmountsOut(amount, path)[1];
+
+ emit ReceivedQuote(sellTokenAddress, poolAddress, wouldGet);
+ if (wouldGet > bestRouterQuote) {
+ bestRouterQuote = wouldGet;
+ bestRouter = router;
+ }
+ }
+
+ require(bestRouterQuote != 0, "Can't exchange with zero quote");
+
+ uint256 minAmount = 0;
+ minAmount = calculateAllMinAmount(sellTokenAddress, maxSlippage, amount, bestRouter);
+
+ IERC20(sellTokenAddress).approve(address(bestRouter), amount);
+ bestRouter.swapExactTokensForTokens(
+ amount, minAmount, path, address(this), block.timestamp + MAX_TIMESTAMP_BLOCK_EXCHANGE
+ );
+
+ uint256 celoAmount = celoToken.balanceOf(address(this));
+ celoToken.transfer(msg.sender, celoAmount);
+ emit RouterUsed(address(bestRouter));
+ emit TokenSold(sellTokenAddress, buyTokenAddress, amount);
+ return celoAmount;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/UsingRegistry.sol CELO/packages/contracts-bedrock/src/celo/UsingRegistry.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b5bf928d11f22346afcada6a6f830ffb8f4eee8c
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/UsingRegistry.sol
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+
+import "./interfaces/IAccounts.sol";
+import "./interfaces/IFreezer.sol";
+import "./interfaces/ICeloRegistry.sol";
+
+import "./governance/interfaces/IElection.sol";
+import "./governance/interfaces/IGovernance.sol";
+import "./governance/interfaces/ILockedGold.sol";
+import "./governance/interfaces/IValidators.sol";
+
+import "./identity/interfaces/IRandom.sol";
+import "./identity/interfaces/IAttestations.sol";
+
+import "./stability/interfaces/ISortedOracles.sol";
+
+import "./mento/interfaces/IExchange.sol";
+import "./mento/interfaces/IReserve.sol";
+import "./mento/interfaces/IStableToken.sol";
+
+contract UsingRegistry is Ownable {
+ event RegistrySet(address indexed registryAddress);
+
+ // solhint-disable state-visibility
+ bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts"));
+ bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations"));
+ bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher"));
+ bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DoubleSigningSlasher"));
+ bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election"));
+ bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange"));
+ bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer"));
+ bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken"));
+ bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance"));
+ bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("GovernanceSlasher"));
+ bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold"));
+ bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve"));
+ bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random"));
+ bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles"));
+ bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken"));
+ bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
+ // solhint-enable state-visibility
+
+ ICeloRegistry public registry;
+
+ modifier onlyRegisteredContract(bytes32 identifierHash) {
+ require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract");
+ _;
+ }
+
+ modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) {
+ require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts");
+ _;
+ }
+
+ /**
+ * @notice Updates the address pointing to a Registry contract.
+ * @param registryAddress The address of a registry contract for routing to other contracts.
+ */
+ function setRegistry(address registryAddress) public onlyOwner {
+ require(registryAddress != address(0), "Cannot register the null address");
+ registry = ICeloRegistry(registryAddress);
+ emit RegistrySet(registryAddress);
+ }
+
+ function getAccounts() internal view returns (IAccounts) {
+ return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID));
+ }
+
+ function getAttestations() internal view returns (IAttestations) {
+ return IAttestations(registry.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID));
+ }
+
+ function getElection() internal view returns (IElection) {
+ return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID));
+ }
+
+ function getExchange() internal view returns (IExchange) {
+ return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID));
+ }
+
+ function getFreezer() internal view returns (IFreezer) {
+ return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID));
+ }
+
+ function getGoldToken() internal view returns (IERC20) {
+ return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
+ }
+
+ function getGovernance() internal view returns (IGovernance) {
+ return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));
+ }
+
+ function getLockedGold() internal view returns (ILockedGold) {
+ return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID));
+ }
+
+ function getRandom() internal view returns (IRandom) {
+ return IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID));
+ }
+
+ function getReserve() internal view returns (IReserve) {
+ return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID));
+ }
+
+ function getSortedOracles() internal view returns (ISortedOracles) {
+ return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID));
+ }
+
+ function getStableToken() internal view returns (IStableToken) {
+ return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID));
+ }
+
+ function getValidators() internal view returns (IValidators) {
+ return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID));
+ }
+}
diff --git OP/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol CELO/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol
index 838a21af5662693ad6cf219456571ac93590fc40..7744ff697ec484129e248909f9074a9c1877fa4d 100644
--- OP/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol
+++ CELO/packages/contracts-bedrock/src/universal/OptimismMintableERC20.sol
@@ -7,6 +7,7 @@ import { IERC165 } from "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import { ILegacyMintableERC20, IOptimismMintableERC20 } from "src/universal/interfaces/IOptimismMintableERC20.sol";
import { ISemver } from "src/universal/interfaces/ISemver.sol";
import { Preinstalls } from "src/libraries/Preinstalls.sol";
+import { AbstractFeeCurrency } from "src/celo/AbstractFeeCurrency.sol";
/// @title OptimismMintableERC20
/// @notice OptimismMintableERC20 is a standard extension of the base ERC20 token contract designed
@@ -14,7 +15,13 @@ /// to allow the StandardBridge contracts to mint and burn tokens. This makes it possible to
/// use an OptimismMintablERC20 as the L2 representation of an L1 token, or vice-versa.
/// Designed to be backwards compatible with the older StandardL2ERC20 token which was only
/// meant for use on L2.
-contract OptimismMintableERC20 is IOptimismMintableERC20, ILegacyMintableERC20, ERC20Permit, ISemver {
+contract OptimismMintableERC20 is
+ IOptimismMintableERC20,
+ ILegacyMintableERC20,
+ ERC20Permit,
+ ISemver,
+ AbstractFeeCurrency
+{
/// @notice Address of the corresponding version of this token on the remote chain.
address public immutable REMOTE_TOKEN;
@@ -41,8 +48,8 @@ _;
}
/// @notice Semantic version.
- /// @custom:semver 1.4.0-beta.1
- string public constant version = "1.4.0-beta.1";
+ /// @custom:semver 1.4.0-beta.1-celo
+ string public constant version = "1.4.0-beta.1-celo";
/// @notice Getter function for the permit2 address. It deterministically deployed
/// so it will always be at the same address. It is also included as a preinstall,
diff --git OP/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol CELO/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol
index e179c6408dad19373b1199c0f5e978a5f5f61ef6..429a490b60b88de6d4aeb6f0d33fd811763e7bc9 100644
--- OP/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol
+++ CELO/packages/contracts-bedrock/src/universal/OptimismMintableERC20Factory.sol
@@ -48,8 +48,8 @@ /// @notice The semver MUST be bumped any time that there is a change in
/// the OptimismMintableERC20 token contract since this contract
/// is responsible for deploying OptimismMintableERC20 contracts.
/// @notice Semantic version.
- /// @custom:semver 1.10.1-beta.3
- string public constant version = "1.10.1-beta.3";
+ /// @custom:semver 1.10.1-beta.3-celo
+ string public constant version = "1.10.1-beta.3-celo";
/// @notice Constructs the OptimismMintableERC20Factory contract.
constructor() {
diff --git OP/packages/contracts-bedrock/test/L2Genesis.t.sol CELO/packages/contracts-bedrock/test/L2Genesis.t.sol
index ee993fe1110cebd7d0d2b5836cf0d0bb6bcacd16..8bf49533a1ea6d0446c2bc3e6a8dc927b81bae55 100644
--- OP/packages/contracts-bedrock/test/L2Genesis.t.sol
+++ CELO/packages/contracts-bedrock/test/L2Genesis.t.sol
@@ -181,6 +181,7 @@
/// @notice Tests the number of accounts in the genesis setup
function _test_allocs_size(string memory _path) internal {
genesis.cfg().setFundDevAccounts(false);
+ genesis.cfg().setDeployCeloContracts(true);
genesis.runWithLatestLocal(_dummyL1Deps());
genesis.writeGenesisAllocs(_path);
@@ -190,6 +191,7 @@ expected += 21; // predeploy implementations (excl. legacy erc20-style eth and legacy message sender)
expected += 256; // precompiles
expected += 13; // preinstalls
expected += 1; // 4788 deployer account
+ expected += 14; // Celo contracts
// 16 prefunded dev accounts are excluded
assertEq(expected, getJSONKeyCount(_path), "key count check");
diff --git OP/packages/contracts-bedrock/test/libraries/SafeCall.t.sol CELO/packages/contracts-bedrock/test/libraries/SafeCall.t.sol
index 5bd3fb3a4ab7904660ab76b3242469501d3db01e..1010a569a5d3836fb836f572ae2e32abfaa15261 100644
--- OP/packages/contracts-bedrock/test/libraries/SafeCall.t.sol
+++ CELO/packages/contracts-bedrock/test/libraries/SafeCall.t.sol
@@ -4,6 +4,8 @@
// Testing utilities
import { Test } from "forge-std/Test.sol";
import { StdCheatsSafe } from "forge-std/StdCheats.sol";
+import { AddressSortedLinkedList } from "src/celo/common/linkedlists/AddressSortedLinkedList.sol";
+import { AddressSortedLinkedListWithMedian } from "src/celo/common/linkedlists/AddressSortedLinkedListWithMedian.sol";
// Target contract
import { SafeCall } from "src/libraries/SafeCall.sol";
@@ -14,7 +16,10 @@ function assumeNot(address _addr) internal {
vm.assume(_addr.balance == 0);
vm.assume(_addr != address(this));
vm.assume(uint256(uint160(_addr)) > uint256(256)); // TODO temp fix until new forge-std release with modern
- // precompiles: https://github.com/foundry-rs/forge-std/pull/594
+ // ignore address of library contract whose functions have 'public' or 'external' visibilities
+ vm.assume(_addr != address(AddressSortedLinkedList));
+ vm.assume(_addr != address(AddressSortedLinkedListWithMedian));
+ // precompiles: https://github.com/foundry-rs/forge-std/pull/594
assumeAddressIsNot(_addr, StdCheatsSafe.AddressType.ForgeAddress, StdCheatsSafe.AddressType.Precompile);
}
diff --git OP/packages/contracts-bedrock/test/vendor/Initializable.t.sol CELO/packages/contracts-bedrock/test/vendor/Initializable.t.sol
index 7b7596b9bafec20ccebda5cbf630a4919d073b44..c97d74ae632c22aed1cd2d6a7fd7d71ad954eb45 100644
--- OP/packages/contracts-bedrock/test/vendor/Initializable.t.sol
+++ CELO/packages/contracts-bedrock/test/vendor/Initializable.t.sol
@@ -394,7 +394,7 @@ /// 2. The `_initialized` flag of each contract is properly set.
/// 3. The `initialize()` function of each contract cannot be called again.
function test_cannotReinitialize_succeeds() public {
// Collect exclusions.
- string[] memory excludes = new string[](8);
+ string[] memory excludes = new string[](9);
// TODO: Neither of these contracts are labeled properly in the deployment script. Both are
// currently being labeled as their non-interop versions. Remove these exclusions once
// the deployment script is fixed.
@@ -413,6 +413,7 @@ excludes[5] = "src/dispute/PermissionedDisputeGame.sol";
// TODO: Eventually remove this exclusion. Same reason as above dispute contracts.
excludes[6] = "src/L1/OPContractsManager.sol";
excludes[7] = "src/L1/OPContractsManagerInterop.sol";
+ excludes[8] = "src/celo/*";
// Get all contract names in the src directory, minus the excluded contracts.
string[] memory contractNames = ForgeArtifacts.getContractNames("src/*", excludes);
core-utils
chain-mon
sdk
op-bindings
op-batcher
op-bootnode
op-chain-ops
+3109
-11
diff --git OP/op-chain-ops/Dockerfile CELO/op-chain-ops/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..5aa278ed6b27e78ab6648f3064a3fcce17a06476
--- /dev/null
+++ CELO/op-chain-ops/Dockerfile
@@ -0,0 +1,29 @@
+FROM golang:1.21.1-alpine3.18 AS builder
+
+RUN apk --no-cache add make
+
+COPY ./go.mod /app/go.mod
+COPY ./go.sum /app/go.sum
+
+WORKDIR /app
+
+RUN go mod download
+
+COPY ./op-service /app/op-service
+COPY ./op-node /app/op-node
+COPY ./op-alt-da /app/op-alt-da
+COPY ./op-chain-ops /app/op-chain-ops
+WORKDIR /app/op-chain-ops
+RUN make celo-migrate
+
+FROM alpine:3.18
+RUN apk --no-cache add ca-certificates bash rsync
+
+# RUN addgroup -S app && adduser -S app -G app
+# USER app
+WORKDIR /app
+
+COPY --from=builder /app/op-chain-ops/bin/celo-migrate /app
+ENV PATH="/app:${PATH}"
+
+ENTRYPOINT ["/app/celo-migrate"]
diff --git OP/op-chain-ops/Makefile CELO/op-chain-ops/Makefile
index fd3cc9ad67b345a7155fb0495ee570fe4835e1d7..6a173c05103120b58c159c8c8418ae9c9b31bcda 100644
--- OP/op-chain-ops/Makefile
+++ CELO/op-chain-ops/Makefile
@@ -32,6 +32,9 @@
receipt-reference-builder:
go build -o ./bin/receipt-reference-builder ./cmd/receipt-reference-builder/*.go
+celo-migrate:
+ go build -o ./bin/celo-migrate ./cmd/celo-migrate/*.go
+
test:
go test ./...
diff --git OP/op-chain-ops/cmd/celo-migrate/README.md CELO/op-chain-ops/cmd/celo-migrate/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..72b9f437c1bd27b0276d4e2d5bf1c00b60f3c588
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/README.md
@@ -0,0 +1,136 @@
+# Celo L2 Migration Script
+
+## Overview
+
+This script migrates a Celo L1 database (old datadir) into a new database compatible with Celo L2 (new datadir). It consists of 3 main processes that respectively migrate ancient blocks, non-ancient blocks and state. Migrated data is copied into a new datadir, leaving the old datadir unchanged.
+
+To minimize migration downtime, the script is designed to run in two stages:
+1. The `pre migration` stage can be run ahead of the `full migration` and will process as much of the migration as possible up to that point.
+2. The `full migration` can then be run to finish migrating new blocks that were created after the `pre migration` and apply necessary state changes on top of the migration block.
+
+### Pre migration
+
+The `pre migration` consists of two parts that are run in parallel:
+- Copy and transform the ancient / frozen blocks (i.e. all blocks before the last 90000).
+- Copy over the rest of the database using `rsync`.
+
+The ancients db is migrated sequentially because it is append-only, while the rest of the database is copied and then transformed in-place. We use `rsync` because it has flags for ignoring the ancients directory, skipping any already copied files and deleting any extra files in the new db, ensuring that we can run the script multiple times and only copy over actual updates.
+
+The `pre migration` step is still run during a `full migration` but it will be much quicker as only newly frozen blocks and recent file changes need to be migrated.
+
+### Full migration
+
+During the `full migration`, we re-run the `pre migration` step to capture any updates since the last `pre migration` and then apply in-place changes to non-ancient blocks and state. While this is happening, the script also checks for any stray ancient blocks that have remained in leveldb despite being frozen and removes them from the new db. Non-ancient blocks are then transformed to ensure compatibility with the L2 codebase.
+
+Finally after all blocks have been migrated, the script performs a series of modifications to the state db:
+1. First, it deploys the L2 smart contracts by iterating through the genesis allocs passed to the script and setting the nonce, balance, code and storage for each address accordingly, overwritting existing data if necessary.
+2. Finally, these changes are committed to the state db to produce a new state root and create the first Celo L2 block.
+
+### Notes
+
+> [!TIP]
+> See `--help` for how to run each portion of the script individually, along with other configuration options.
+
+The longest running section of the script is the ancients migration, followed by the `rsync` command. By running these together in a `pre migration` we greatly reduce how long they will take during the `full migration`. Changes made to non-ancient blocks and state during a `full migration` are erased by the next `rsync` command.
+
+The script outputs a `rollup-config.json` file that is passed to the sequencer in order to start the L2 network.
+
+### Running the script
+
+> [!NOTE]
+> You will need `rsync` to run this script if it's not already installed.
+
+From the `op-chain-ops` directory, first build the script by running:
+
+```bash
+make celo-migrate
+```
+
+You can then run the script as follows:
+
+```bash
+go run ./cmd/celo-migrate --help
+```
+
+#### Running with local test setup (Alfajores / Holesky)
+
+To test the script locally, we can migrate an Alfajores database and use Holesky as our L1. The input files needed for this can be found in `./testdata`. The necessary smart contracts have already been deployed on Holesky.
+
+##### Pull down the latest Alfajores database snapshot
+
+```bash
+gcloud alpha storage cp gs://celo-chain-backup/alfajores/chaindata-latest.tar.zst alfajores.tar.zst
+```
+
+Unzip and rename
+
+```bash
+tar --use-compress-program=unzstd -xvf alfajores.tar.zst
+mv chaindata ./data/alfajores_old
+```
+
+##### Generate test allocs file
+
+The state migration takes in an allocs file that specifies the l2 state changes to be made during the migration. This file can be generated from the deploy config and l1 contract addresses by running the following from the `contracts-bedrock` directory.
+
+```bash
+CONTRACT_ADDRESSES_PATH=../../op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-dango.json \
+DEPLOY_CONFIG_PATH=../../op-chain-ops/cmd/celo-migrate/testdata/deploy-config-dango.json \
+STATE_DUMP_PATH=../../op-chain-ops/cmd/celo-migrate/testdata/l2-allocs-dango.json \
+forge script ./scripts/L2Genesis.s.sol:L2Genesis \
+--sig 'runWithStateDump()'
+```
+
+This should output the allocs file to `./testdata/l2-allocs-dango.json`. If you encounter difficulties with this and want to just continue testing the script, you can alternatively find the allocs file [here](https://storage.googleapis.com/cel2-rollup-files/alfajores-mvp/l2-allocs.json).
+
+##### Run script with test configuration
+
+```bash
+go run ./cmd/celo-migrate pre \
+--old-db ./data/alfajores_old \
+--new-db ./data/alfajores_new
+```
+
+Running the pre-migration script should take ~5 minutes. This script copies and transforms ancient blocks and, in parallel, copies over all other chaindata without transforming it. This can be re-run mutliple times leading up to the full migration, and should only migrate updates to the old db between re-runs.
+
+```bash
+go run ./cmd/celo-migrate full \
+--deploy-config ./cmd/celo-migrate/testdata/deploy-config-dango.json \
+--l1-deployments ./cmd/celo-migrate/testdata/deployment-l1-dango.json \
+--l1-rpc https://ethereum-holesky-rpc.publicnode.com \
+--l2-allocs ./cmd/celo-migrate/testdata/l2-allocs-dango.json \
+--outfile.rollup-config ./cmd/celo-migrate/testdata/rollup-config-dango.json \
+--old-db ./data/alfajores_old \
+--new-db ./data/alfajores_new
+```
+
+Running the full migration script re-runs the pre-migration script once to migrate any new changes to the old db that have occurred since the last pre-migration. It then performs in-place transformations on the non-ancient blocks and performs the state migration as well.
+
+#### Running for Cel2 migration
+
+##### Generate allocs file
+
+You can generate the allocs file needed to run the migration with the following script in `contracts-bedrock`
+
+```bash
+CONTRACT_ADDRESSES_PATH=<PATH_TO_CONTRACT_ADDRESSES> \
+DEPLOY_CONFIG_PATH=<PATH_TO_MY_DEPLOY_CONFIG> \
+STATE_DUMP_PATH=<PATH_TO_WRITE_L2_ALLOCS> \
+forge script scripts/L2Genesis.s.sol:L2Genesis \
+--sig 'runWithStateDump()'
+```
+
+##### Dry-run / pre-migration
+
+To minimize downtime caused by the migration, node operators can prepare their Cel2 databases by running the pre-migration command a day ahead of the actual migration. This will pre-populate the new database with most of the ancient blocks needed for the final migration and copy over other chaindata without transforming it.
+
+If node operators would like to practice a `full migration` they can do so and reset their databases to the correct state by running another `pre migration` afterward.
+
+> [!IMPORTANT]
+> The pre-migration should be run using a chaindata snapshot, rather than a db that is being used by a node. To avoid network downtime, we recommend that node operators do not stop any nodes in order to perform the pre-migration.
+
+Node operators should inspect their migration logs after the dry-run to ensure the migration completed successfully and direct any questions to the Celo developer community on Discord before the actual migration.
+
+##### Final migration
+
+On the day of the actual Cel2 migration, the `full migration` script can be run using the datadir of a Celo L1 node that has halted on the migration block. Far in advance of the migration, a version of `celo-blockchain` will be distributed where a flag can specify a block to halt on. When the Celo community aligns on a migration block, node operators will start / restart their nodes with this flag specifying the migration block. Their nodes will halt when this block is reached, at which point they will be able to run `full migration` and begin syncing with the Celo L2 network.
diff --git OP/op-chain-ops/cmd/celo-migrate/ancients.go CELO/op-chain-ops/cmd/celo-migrate/ancients.go
new file mode 100644
index 0000000000000000000000000000000000000000..6f7549c10c2f8fbb313eeffa79b2fb2ed7cc0a25
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/ancients.go
@@ -0,0 +1,258 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "path/filepath"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/log"
+ "golang.org/x/sync/errgroup"
+)
+
+// NewChainFreezer is a small utility method around NewFreezer that sets the
+// default parameters for the chain storage.
+func NewChainFreezer(datadir string, namespace string, readonly bool) (*rawdb.Freezer, error) {
+ const freezerTableSize = 2 * 1000 * 1000 * 1000
+ // chainFreezerNoSnappy configures whether compression is disabled for the ancient-tables.
+ // Hashes and difficulties don't compress well.
+ var chainFreezerNoSnappy = map[string]bool{
+ rawdb.ChainFreezerHeaderTable: false,
+ rawdb.ChainFreezerHashTable: true,
+ rawdb.ChainFreezerBodiesTable: false,
+ rawdb.ChainFreezerReceiptTable: false,
+ rawdb.ChainFreezerDifficultyTable: true,
+ }
+ return rawdb.NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
+}
+
+func migrateAncientsDb(ctx context.Context, oldDBPath, newDBPath string, batchSize, bufferSize uint64) (numAncientsNewBefore uint64, numAncientsNewAfter uint64, err error) {
+ defer timer("ancients")()
+
+ oldFreezer, err := NewChainFreezer(filepath.Join(oldDBPath, "ancient"), "", false) // Can't be readonly because we need the .meta files to be created
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to open old freezer: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, oldFreezer.Close())
+ }()
+
+ newFreezer, err := NewChainFreezer(filepath.Join(newDBPath, "ancient"), "", false)
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to open new freezer: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, newFreezer.Close())
+ }()
+
+ numAncientsOld, err := oldFreezer.Ancients()
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to get number of ancients in old freezer: %w", err)
+ }
+
+ numAncientsNewBefore, err = newFreezer.Ancients()
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to get number of ancients in new freezer: %w", err)
+ }
+
+ if numAncientsNewBefore >= numAncientsOld {
+ log.Info("Ancient Block Migration Skipped", "process", "ancients", "ancientsInOldDB", numAncientsOld, "ancientsInNewDB", numAncientsNewBefore)
+ return numAncientsNewBefore, numAncientsNewBefore, nil
+ }
+
+ log.Info("Ancient Block Migration Started", "process", "ancients", "startBlock", numAncientsNewBefore, "endBlock", numAncientsOld-1, "count", numAncientsOld-numAncientsNewBefore, "step", batchSize)
+
+ g, ctx := errgroup.WithContext(ctx)
+ readChan := make(chan RLPBlockRange, bufferSize)
+ transformChan := make(chan RLPBlockRange, bufferSize)
+
+ g.Go(func() error {
+ return readAncientBlocks(ctx, oldFreezer, numAncientsNewBefore, numAncientsOld, batchSize, readChan)
+ })
+ g.Go(func() error { return transformBlocks(ctx, readChan, transformChan) })
+ g.Go(func() error { return writeAncientBlocks(ctx, newFreezer, transformChan, numAncientsOld) })
+
+ if err = g.Wait(); err != nil {
+ return 0, 0, fmt.Errorf("failed to migrate ancients: %w", err)
+ }
+
+ numAncientsNewAfter, err = newFreezer.Ancients()
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to get number of ancients in new freezer: %w", err)
+ }
+
+ if numAncientsNewAfter != numAncientsOld {
+ return 0, 0, fmt.Errorf("failed to migrate all ancients from old to new db. Expected %d, got %d", numAncientsOld, numAncientsNewAfter)
+ }
+
+ log.Info("Ancient Block Migration Ended", "process", "ancients", "ancientsInOldDB", numAncientsOld, "ancientsInNewDB", numAncientsNewAfter, "migrated", numAncientsNewAfter-numAncientsNewBefore)
+ return numAncientsNewBefore, numAncientsNewAfter, nil
+}
+
+func readAncientBlocks(ctx context.Context, freezer *rawdb.Freezer, startBlock, endBlock, batchSize uint64, out chan<- RLPBlockRange) error {
+ defer close(out)
+ for i := startBlock; i < endBlock; i += batchSize {
+ count := min(batchSize, endBlock-i)
+ start := i
+
+ blockRange, err := loadAncientRange(freezer, start, count)
+ if err != nil {
+ return fmt.Errorf("Failed to load ancient block range: %w", err)
+ }
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case out <- *blockRange:
+ }
+
+ log.Info("Read ancient blocks", "start", start, "end", start+count-1, "count", count)
+ }
+ return nil
+}
+
+func loadAncientRange(freezer *rawdb.Freezer, start, count uint64) (*RLPBlockRange, error) {
+ log.Info("Loading ancient block range", "start", start, "end", start+count-1, "count", count)
+
+ blockRange := &RLPBlockRange{
+ start: start,
+ hashes: make([][]byte, count),
+ headers: make([][]byte, count),
+ bodies: make([][]byte, count),
+ receipts: make([][]byte, count),
+ tds: make([][]byte, count),
+ }
+
+ var err error
+ blockRange.hashes, err = freezer.AncientRange(rawdb.ChainFreezerHashTable, start, count, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read hashes from freezer: %w", err)
+ }
+ blockRange.headers, err = freezer.AncientRange(rawdb.ChainFreezerHeaderTable, start, count, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read headers from freezer: %w", err)
+ }
+ blockRange.bodies, err = freezer.AncientRange(rawdb.ChainFreezerBodiesTable, start, count, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read bodies from freezer: %w", err)
+ }
+ blockRange.receipts, err = freezer.AncientRange(rawdb.ChainFreezerReceiptTable, start, count, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read receipts from freezer: %w", err)
+ }
+ blockRange.tds, err = freezer.AncientRange(rawdb.ChainFreezerDifficultyTable, start, count, 0)
+ if err != nil {
+ return nil, fmt.Errorf("failed to read tds from freezer: %w", err)
+ }
+
+ return blockRange, nil
+}
+
+func transformBlocks(ctx context.Context, in <-chan RLPBlockRange, out chan<- RLPBlockRange) error {
+ // Transform blocks from the in channel and send them to the out channel
+ defer close(out)
+
+ for blockRange := range in {
+ for i := range blockRange.hashes {
+ blockNumber := blockRange.start + uint64(i)
+
+ newHeader, err := transformHeader(blockRange.headers[i])
+ if err != nil {
+ return fmt.Errorf("can't transform header: %w", err)
+ }
+ newBody, err := transformBlockBody(blockRange.bodies[i])
+ if err != nil {
+ return fmt.Errorf("can't transform body: %w", err)
+ }
+
+ if yes, newHash := hasSameHash(newHeader, blockRange.hashes[i]); !yes {
+ log.Error("Hash mismatch", "block", blockNumber, "oldHash", common.BytesToHash(blockRange.hashes[i]), "newHash", newHash)
+ return fmt.Errorf("hash mismatch at block %d", blockNumber)
+ }
+
+ blockRange.headers[i] = newHeader
+ blockRange.bodies[i] = newBody
+ }
+
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ case out <- blockRange:
+ }
+ }
+ return nil
+}
+
+func writeAncientBlocks(ctx context.Context, freezer *rawdb.Freezer, in <-chan RLPBlockRange, totalAncientBlocks uint64) error {
+ // Write blocks from the in channel to the newDb
+ for blockRange := range in {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ _, err := freezer.ModifyAncients(func(aWriter ethdb.AncientWriteOp) error {
+ for i := range blockRange.hashes {
+ blockNumber := blockRange.start + uint64(i)
+ if err := aWriter.AppendRaw(rawdb.ChainFreezerHashTable, blockNumber, blockRange.hashes[i]); err != nil {
+ return fmt.Errorf("can't write hash to Freezer: %w", err)
+ }
+ if err := aWriter.AppendRaw(rawdb.ChainFreezerHeaderTable, blockNumber, blockRange.headers[i]); err != nil {
+ return fmt.Errorf("can't write header to Freezer: %w", err)
+ }
+ if err := aWriter.AppendRaw(rawdb.ChainFreezerBodiesTable, blockNumber, blockRange.bodies[i]); err != nil {
+ return fmt.Errorf("can't write body to Freezer: %w", err)
+ }
+ if err := aWriter.AppendRaw(rawdb.ChainFreezerReceiptTable, blockNumber, blockRange.receipts[i]); err != nil {
+ return fmt.Errorf("can't write receipts to Freezer: %w", err)
+ }
+ if err := aWriter.AppendRaw(rawdb.ChainFreezerDifficultyTable, blockNumber, blockRange.tds[i]); err != nil {
+ return fmt.Errorf("can't write td to Freezer: %w", err)
+ }
+ }
+ return nil
+ })
+ if err != nil {
+ return fmt.Errorf("failed to write block range: %w", err)
+ }
+ blockRangeEnd := blockRange.start + uint64(len(blockRange.hashes)) - 1
+ log.Info("Wrote ancient blocks", "start", blockRange.start, "end", blockRangeEnd, "count", len(blockRange.hashes), "remaining", totalAncientBlocks-(blockRangeEnd+1))
+ }
+ }
+ return nil
+}
+
+// getStrayAncientBlocks returns a list of ancient block numbers / hashes that somehow were not removed from leveldb
+func getStrayAncientBlocks(dbPath string) (blocks []*rawdb.NumberHash, err error) {
+ defer timer("getStrayAncientBlocks")()
+
+ db, err := openDB(dbPath, true)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open database: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, db.Close())
+ }()
+
+ numAncients, err := db.Ancients()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get number of ancients in database: %w", err)
+ }
+
+ return rawdb.ReadAllHashesInRange(db, 1, numAncients-1), nil
+}
+
+// Get the last ancient block data so we can check for continuity between ancients and non-ancients
+func loadLastAncient(freezer *rawdb.Freezer) (*RLPBlockElement, error) {
+ numAncients, err := freezer.Ancients()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get number of ancients in freezer: %w", err)
+ }
+ blockRange, err := loadAncientRange(freezer, numAncients-1, 1)
+ if err != nil {
+ return nil, err
+ }
+ return blockRange.Element(0)
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/continuity.go CELO/op-chain-ops/cmd/celo-migrate/continuity.go
new file mode 100644
index 0000000000000000000000000000000000000000..9b41c60d3e7dd021e0439971b7e7353b41d8d9b3
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/continuity.go
@@ -0,0 +1,131 @@
+package main
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+// RLPBlockRange is a range of blocks in RLP format
+type RLPBlockRange struct {
+ start uint64
+ hashes [][]byte
+ headers [][]byte
+ bodies [][]byte
+ receipts [][]byte
+ tds [][]byte
+}
+
+// RLPBlockElement contains all relevant block data in RLP format
+type RLPBlockElement struct {
+ decodedHeader *types.Header
+ hash []byte
+ header []byte
+ body []byte
+ receipts []byte
+ td []byte
+}
+
+// Follows checks if the current block has a number one greater than the previous block
+// and if the parent hash of the current block matches the hash of the previous block.
+func (e *RLPBlockElement) Follows(prev *RLPBlockElement) (err error) {
+ if e.Number() != prev.Number()+1 {
+ err = errors.Join(err, fmt.Errorf("header number mismatch indicating a gap in block numbers: expected %d, actual %d", prev.Number()+1, e.Number()))
+ }
+ // We compare the parent hash with the stored hash of the previous block because
+ // at this point the header object will not calculate the correct hash since it
+ // first needs to be transformed.
+ if e.Header().ParentHash != common.BytesToHash(prev.hash) {
+ err = errors.Join(err, fmt.Errorf("parent hash mismatch between blocks %d and %d", e.Number(), prev.Number()))
+ }
+ return err
+}
+
+func (e *RLPBlockElement) Header() *types.Header {
+ return e.decodedHeader
+}
+
+func (e *RLPBlockElement) Number() uint64 {
+ return e.Header().Number.Uint64()
+}
+
+func (r *RLPBlockRange) Element(i uint64) (*RLPBlockElement, error) {
+ header := types.Header{}
+ err := rlp.DecodeBytes(r.headers[i], &header)
+ if err != nil {
+ return nil, fmt.Errorf("can't decode header: %w", err)
+ }
+ return &RLPBlockElement{
+ decodedHeader: &header,
+ hash: r.hashes[i],
+ header: r.headers[i],
+ body: r.bodies[i],
+ receipts: r.receipts[i],
+ td: r.tds[i],
+ }, nil
+}
+
+// CheckContinuity checks if the block data in the range is continuous
+// by comparing the header number and parent hash of each block with the previous block,
+// and by checking if the number of elements retrieved from each table is the same.
+// It takes in the last element in the preceding range, and returns the last element
+// in the current range so that continuity can be checked across ranges.
+func (r *RLPBlockRange) CheckContinuity(prevElement *RLPBlockElement, expectedLength uint64) (*RLPBlockElement, error) {
+ log.Info("Checking data continuity for block range",
+ "start", r.start,
+ "end", r.start+expectedLength-1,
+ "count", expectedLength,
+ "prevElement", func() interface{} {
+ if prevElement != nil {
+ return prevElement.Number()
+ }
+ return "nil"
+ }(),
+ )
+
+ if err := r.CheckLengths(expectedLength); err != nil {
+ return nil, err
+ }
+ for i := range r.hashes {
+ currElement, err := r.Element(uint64(i))
+ if err != nil {
+ return nil, err
+ }
+ if currElement.Number() != r.start+uint64(i) {
+ return nil, fmt.Errorf("decoded header number mismatch indicating a gap in block numbers: expected %d, actual %d", r.start+uint64(i), currElement.Number())
+ }
+ if prevElement != nil {
+ log.Debug("Checking continuity", "block", currElement.Number(), "prev", prevElement.Number())
+ if err := currElement.Follows(prevElement); err != nil {
+ return nil, err
+ }
+ }
+ prevElement = currElement
+ }
+ return prevElement, nil
+}
+
+// CheckLengths makes sure the number of elements retrieved from each table is the same
+func (r *RLPBlockRange) CheckLengths(expectedLength uint64) error {
+ var err error
+ if uint64(len(r.hashes)) != expectedLength {
+ err = fmt.Errorf("Unexpected number of hashes for block range: expected %d, actual %d", expectedLength, len(r.hashes))
+ }
+ if uint64(len(r.bodies)) != expectedLength {
+ err = errors.Join(err, fmt.Errorf("Unexpected number of bodies for block range: expected %d, actual %d", expectedLength, len(r.bodies)))
+ }
+ if uint64(len(r.headers)) != expectedLength {
+ err = errors.Join(err, fmt.Errorf("Unexpected number of headers for block range: expected %d, actual %d", expectedLength, len(r.headers)))
+ }
+ if uint64(len(r.receipts)) != expectedLength {
+ err = errors.Join(err, fmt.Errorf("Unexpected number of receipts for block range: expected %d, actual %d", expectedLength, len(r.receipts)))
+ }
+ if uint64(len(r.tds)) != expectedLength {
+ err = errors.Join(err, fmt.Errorf("Unexpected number of total difficulties for block range: expected %d, actual %d", expectedLength, len(r.tds)))
+ }
+ return err
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/continuity_test.go CELO/op-chain-ops/cmd/celo-migrate/continuity_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..caa31fef7bf6984d7073a5854f0dbbd8e5d8efd3
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/continuity_test.go
@@ -0,0 +1,145 @@
+package main
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/rlp"
+ "github.com/stretchr/testify/require"
+)
+
+func makeRange(start int, bodies, receipts, tds, hashes, encodedHeaders [][]byte) *RLPBlockRange {
+ return &RLPBlockRange{
+ start: uint64(start),
+ hashes: hashes,
+ headers: encodedHeaders,
+ bodies: bodies,
+ receipts: receipts,
+ tds: tds,
+ }
+}
+
+func TestCheckContinuity(t *testing.T) {
+ hashes := [][]byte{[]byte("hash0"), []byte("hash1"), []byte("hash2"), []byte("hash3")}
+ bodies := [][]byte{[]byte("body0"), []byte("body1"), []byte("body2"), []byte("body3")}
+ receipts := [][]byte{[]byte("receipt0"), []byte("receipt1"), []byte("receipt2"), []byte("receipt3")}
+ tds := [][]byte{[]byte("td0"), []byte("td1"), []byte("td2"), []byte("td3")}
+ decodedHeaders := []*types.Header{
+ {Number: big.NewInt(0), ParentHash: common.Hash{}},
+ {Number: big.NewInt(1), ParentHash: common.BytesToHash(hashes[0])},
+ {Number: big.NewInt(2), ParentHash: common.BytesToHash(hashes[1])},
+ {Number: big.NewInt(3), ParentHash: common.BytesToHash(hashes[2])},
+ }
+ headers := make([][]byte, len(decodedHeaders))
+ for i, header := range decodedHeaders {
+ encodedHeader, err := rlp.EncodeToBytes(header)
+ if err != nil {
+ t.Fatalf("Failed to encode header: %v", err)
+ }
+ headers[i] = encodedHeader
+ }
+
+ tests := []struct {
+ name string
+ blockRange *RLPBlockRange
+ prevElement *RLPBlockElement
+ expectedLength uint64
+ expectErrorMsg string
+ }{
+ // Valid continuity tests
+ {
+ name: "Valid continuity w/ nil prevElement",
+ blockRange: makeRange(0, bodies, receipts, tds, hashes, headers),
+ prevElement: nil,
+ expectedLength: 4,
+ expectErrorMsg: "",
+ },
+ {
+ name: "Valid continuity w/ prevElement",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "",
+ },
+ // Length mismatch tests
+ {
+ name: "Length mismatch from expected",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 4,
+ expectErrorMsg: "Unexpected number of hashes for block range: expected 4, actual 3\nUnexpected number of bodies for block range: expected 4, actual 3\nUnexpected number of headers for block range: expected 4, actual 3\nUnexpected number of receipts for block range: expected 4, actual 3\nUnexpected number of total difficulties for block range: expected 4, actual 3",
+ },
+ {
+ name: "Length mismatch in hashes",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[2:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "Unexpected number of hashes for block range: expected 3, actual 2",
+ },
+ {
+ name: "Length mismatch in headers",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "Unexpected number of headers for block range: expected 3, actual 4",
+ },
+ {
+ name: "Length mismatch in bodies",
+ blockRange: makeRange(1, bodies[2:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "Unexpected number of bodies for block range: expected 3, actual 2",
+ },
+ {
+ name: "Length mismatch in receipts",
+ blockRange: makeRange(1, bodies[1:], receipts[2:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "Unexpected number of receipts for block range: expected 3, actual 2",
+ },
+ {
+ name: "Length mismatch in tds",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[2:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "Unexpected number of total difficulties for block range: expected 3, actual 2",
+ },
+ // Number mismatch tests
+ {
+ name: "Header number mismatch from range index",
+ blockRange: makeRange(2, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: hashes[0]},
+ expectedLength: 3,
+ expectErrorMsg: "decoded header number mismatch indicating a gap in block numbers: expected 2, actual 1",
+ },
+ {
+ name: "Header number mismatch from prevElement number",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[1], hash: hashes[1]},
+ expectedLength: 3,
+ expectErrorMsg: "header number mismatch indicating a gap in block numbers: expected 2, actual 1\nparent hash mismatch between blocks 1 and 1",
+ },
+ // Parent hash mismatch tests
+ {
+ name: "Parent hash mismatch",
+ blockRange: makeRange(1, bodies[1:], receipts[1:], tds[1:], hashes[1:], headers[1:]),
+ prevElement: &RLPBlockElement{decodedHeader: decodedHeaders[0], hash: []byte("wrong-hash")},
+ expectedLength: 3,
+ expectErrorMsg: "parent hash mismatch between blocks 1 and 0",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ _, err := tt.blockRange.CheckContinuity(tt.prevElement, tt.expectedLength)
+ if tt.expectErrorMsg == "" {
+ require.NoError(t, err, "CheckContinuity() unexpected error")
+ } else {
+ require.Error(t, err, "CheckContinuity() expected error")
+ require.EqualError(t, err, tt.expectErrorMsg, "CheckContinuity() error message")
+ }
+ })
+ }
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/db.go CELO/op-chain-ops/cmd/celo-migrate/db.go
new file mode 100644
index 0000000000000000000000000000000000000000..9fa68ed983105901d1b853d6a03ed16a2f990c4c
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/db.go
@@ -0,0 +1,167 @@
+package main
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+// Constants for the database
+const (
+ DBCache = 1024 // size of the cache in MB
+ DBHandles = 60 // number of handles
+)
+
+var (
+ headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
+ headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td
+ headerHashSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash
+ headerNumberPrefix = []byte("H") // headerNumberPrefix + hash -> num (uint64 big endian)
+
+ blockBodyPrefix = []byte("b") // blockBodyPrefix + num (uint64 big endian) + hash -> block body
+ blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
+)
+
+// encodeBlockNumber encodes a block number as big endian uint64
+func encodeBlockNumber(number uint64) []byte {
+ enc := make([]byte, 8)
+ binary.BigEndian.PutUint64(enc, number)
+ return enc
+}
+
+// headerKey = headerPrefix + num (uint64 big endian) + hash
+func headerKey(number uint64, hash common.Hash) []byte {
+ return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
+}
+
+// headerTDKey = headerPrefix + num (uint64 big endian) + hash + headerTDSuffix
+func headerTDKey(number uint64, hash common.Hash) []byte {
+ return append(headerKey(number, hash), headerTDSuffix...)
+}
+
+// headerHashKey = headerPrefix + num (uint64 big endian) + headerHashSuffix
+func headerHashKey(number uint64) []byte {
+ return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
+}
+
+// headerNumberKey = headerNumberPrefix + hash
+func headerNumberKey(hash common.Hash) []byte {
+ return append(headerNumberPrefix, hash.Bytes()...)
+}
+
+// blockBodyKey = blockBodyPrefix + num (uint64 big endian) + hash
+func blockBodyKey(number uint64, hash common.Hash) []byte {
+ return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
+}
+
+// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash
+func blockReceiptsKey(number uint64, hash common.Hash) []byte {
+ return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
+}
+
+// Opens a database with access to AncientsDb
+func openDB(chaindataPath string, readOnly bool) (ethdb.Database, error) {
+ // Will throw an error if the chaindataPath does not exist
+ if _, err := os.Stat(chaindataPath); err != nil {
+ return nil, err
+ }
+
+ db, err := rawdb.Open(rawdb.OpenOptions{
+ Type: "leveldb",
+ Directory: chaindataPath,
+ AncientsDirectory: filepath.Join(chaindataPath, "ancient"),
+ Namespace: "",
+ Cache: DBCache,
+ Handles: DBHandles,
+ ReadOnly: readOnly,
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ return db, nil
+}
+
+// Opens a database without access to AncientsDb
+func openDBWithoutFreezer(chaindataPath string, readOnly bool) (ethdb.Database, error) {
+ if _, err := os.Stat(chaindataPath); err != nil {
+ return nil, err
+ }
+
+ newDB, err := rawdb.NewLevelDBDatabase(chaindataPath, DBCache, DBHandles, "", readOnly)
+ if err != nil {
+ return nil, err
+ }
+
+ return newDB, nil
+}
+
+func createNewDbPathIfNotExists(newDBPath string) error {
+ if err := os.MkdirAll(newDBPath, 0755); err != nil {
+ return fmt.Errorf("failed to create new database directory: %w", err)
+ }
+ return nil
+}
+
+func removeBlocks(ldb ethdb.Database, numberHashes []*rawdb.NumberHash) error {
+ defer timer("removeBlocks")()
+
+ if len(numberHashes) == 0 {
+ return nil
+ }
+
+ batch := ldb.NewBatch()
+
+ for _, numberHash := range numberHashes {
+ log.Debug("Removing block", "block", numberHash.Number)
+ rawdb.DeleteBlockWithoutNumber(batch, numberHash.Hash, numberHash.Number)
+ rawdb.DeleteCanonicalHash(batch, numberHash.Number)
+ }
+ if err := batch.Write(); err != nil {
+ log.Error("Failed to write batch", "error", err)
+ }
+
+ return nil
+}
+
+func getHeadHeader(dbpath string) (headHeader *types.Header, err error) {
+ db, err := openDBWithoutFreezer(dbpath, true)
+ if err != nil {
+ return nil, fmt.Errorf("failed to open database at %q err: %w", dbpath, err)
+ }
+ defer func() {
+ err = errors.Join(err, db.Close())
+ }()
+
+ headHeader = rawdb.ReadHeadHeader(db)
+ if headHeader == nil {
+ return nil, fmt.Errorf("head header not in database at: %s", dbpath)
+ }
+ return headHeader, nil
+}
+
+func cleanupNonAncientDb(dir string) error {
+ log.Info("Cleaning up non-ancient data in new db")
+
+ files, err := os.ReadDir(dir)
+ if err != nil {
+ return fmt.Errorf("failed to read directory: %w", err)
+ }
+ for _, file := range files {
+ if file.Name() != "ancient" {
+ err := os.RemoveAll(filepath.Join(dir, file.Name()))
+ if err != nil {
+ return fmt.Errorf("failed to remove file: %w", err)
+ }
+ }
+ }
+ return nil
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/genesis.go CELO/op-chain-ops/cmd/celo-migrate/genesis.go
new file mode 100644
index 0000000000000000000000000000000000000000..b646b4c73ea532318a5e31ac66965b7db823b6ce
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/genesis.go
@@ -0,0 +1,649 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+// Constants containing the genesis allocation of built-in genesis blocks.
+// Copied from https://github.com/celo-org/celo-blockchain/blob/d4ac28c04d5b94855e1e72c9b4436fa3c73e16ad/core/genesis_alloc.go#L19
+
+const baklavaAllocJSON = `{
+ "fCf982bb4015852e706100B14E21f947a5Bb718E": {
+ "balance": "200000000000000000000000000"
+ },
+ "0xd71fea6b92d3f21f659152589223385a7329bb11": {
+ "balance": "1000000000000000000000"
+ },
+ "0x1e477fc9b6a49a561343cd16b2c541930f5da7d2": {
+ "balance": "1000000000000000000000"
+ },
+ "0x460b3f8d3c203363bb65b1a18d89d4ffb6b0c981": {
+ "balance": "1000000000000000000000"
+ },
+ "0x3b522230c454ca9720665d66e6335a72327291e8": {
+ "balance": "1000000000000000000000"
+ },
+ "0x0AFe167600a5542d10912f4A07DFc4EEe0769672": {
+ "balance": "1000000000000000000000"
+ },
+ "0x412ebe7859e9aa71ff5ce4038596f6878c359c96": {
+ "balance": "1000000000000000000000"
+ },
+ "0xbbfe73df8b346b3261b19ac91235888aba36d68c": {
+ "balance": "1000000000000000000000"
+ },
+ "0x02b1d1bea682fcab4448c0820f5db409cce4f702": {
+ "balance": "1000000000000000000000"
+ },
+ "0xe90f891710f625f18ecbf1e02efb4fd1ab236a10": {
+ "balance": "1000000000000000000000"
+ },
+ "0x28c52c722df87ed11c5d7665e585e84aa93d7964": {
+ "balance": "1000000000000000000000"
+ },
+ "0Cc59Ed03B3e763c02d54D695FFE353055f1502D": {
+ "balance": "103010030000000000000000000"
+ },
+ "3F5084d3D4692cf19b0C98A9b22De614e49e1470": {
+ "balance": "10011000000000000000000"
+ },
+ "EF0186B8eDA17BE7D1230eeB8389fA85e157E1fb": {
+ "balance": "10011000000000000000000"
+ },
+ "edDdb60EF5E90Fb09707246DF193a55Df3564c9d": {
+ "balance": "10011000000000000000000"
+ },
+ "d5e454462b3Fd98b85640977D7a5C783CA162228": {
+ "balance": "10011000000000000000000"
+ },
+ "a4f1bad7996f346c3E90b90b60a1Ca8B67B51E4B": {
+ "balance": "10011000000000000000000"
+ },
+ "5B991Cc1Da0b6D54F8befa9De701d8BC85C92324": {
+ "balance": "10011000000000000000000"
+ },
+ "6dfdAa51D146eCff3B97614EF05629EA83F4997E": {
+ "balance": "10011000000000000000000"
+ },
+ "D2b16050810600296c9580D947E9D919D0c332ed": {
+ "balance": "10011000000000000000000"
+ },
+ "Fe144D67068737628efFb701207B3eB30eF93C69": {
+ "balance": "10011000000000000000000"
+ },
+ "82E64996B355625efeAaD12120710706275b5b9A": {
+ "balance": "10011000000000000000000"
+ },
+ "241752a3f65890F4AC3eAeC518fF94567954e7b5": {
+ "balance": "10011000000000000000000"
+ },
+ "1bdDeaF571d5da96ce6a127fEb3CADaDB531f433": {
+ "balance": "10011000000000000000000"
+ },
+ "F86345e9c9b39aB1cbE82d7aD35854f905B8B835": {
+ "balance": "10011000000000000000000"
+ },
+ "5c3512b1697302c497B861CBfDA158f8a3c5122C": {
+ "balance": "10011000000000000000000"
+ },
+ "a02A692d70Fd9A5269397C044aEBDf1085ba090f": {
+ "balance": "10011000000000000000000"
+ },
+ "aC91f591F12a8B6531Be43E0ccF21cd5fA0E80b0": {
+ "balance": "10011000000000000000000"
+ },
+ "718A8AC0943a6D3FFa3Ec670086bfB03817ed540": {
+ "balance": "10011000000000000000000"
+ },
+ "b30980cE21679314E240DE5Cbf437C15ad459EB8": {
+ "balance": "10011000000000000000000"
+ },
+ "99eCa23623E59C795EceB0edB666eca9eC272339": {
+ "balance": "10011000000000000000000"
+ },
+ "c030e92d19229c3EfD708cf4B85876543ee1A3F7": {
+ "balance": "10011000000000000000000"
+ },
+ "5c98A3414Cb6Ff5c24d145F952Cd19F5f1f56643": {
+ "balance": "10011000000000000000000"
+ },
+ "1979b042Ae2272197f0b74170B3a6F44C3cC5c05": {
+ "balance": "10011000000000000000000"
+ },
+ "Db871070334b961804A15f3606fBB4fAc7C7f932": {
+ "balance": "10011000000000000000000"
+ },
+ "C656C97b765D61E0fbCb1197dC1F3a91CC80C2a4": {
+ "balance": "10011000000000000000000"
+ },
+ "aD95a2f518c197dc9b12eE6381D88bba11F2E0E5": {
+ "balance": "10011000000000000000000"
+ },
+ "4D4B5bF033E4A7359146C9ddb13B1C821FE1D0d3": {
+ "balance": "10011000000000000000000"
+ },
+ "9C64dA169d71C57f85B3d7A17DB27C1ce94FBDE4": {
+ "balance": "10011000000000000000000"
+ },
+ "B5f32e89ccaD3D396f50da32E0a599E43CE87dd7": {
+ "balance": "10011000000000000000000"
+ },
+ "Ba40Db8ab5325494C9E7e07A4c4720990A39305c": {
+ "balance": "10011000000000000000000"
+ },
+ "8B7852DA535df3D06D6ADc1906778afd9481588a": {
+ "balance": "10011000000000000000000"
+ },
+ "a8F41EA062C22dAFFc61e47cF15fc898517b86B1": {
+ "balance": "10011000000000000000000"
+ },
+ "66a3Fc7E8fd6932568cDB6610F5a67BeD9F5beF8": {
+ "balance": "10011000000000000000000"
+ },
+ "10301d9389653497F62876f450332467E07eEe1F": {
+ "balance": "10011000000000000000000"
+ },
+ "6c3ac5fcb13E8DCd908C405Ec6DAcF0EF575D8FC": {
+ "balance": "10011000000000000000000"
+ },
+ "85226637919D3d47E1A37b3AF989E9aE1a1C4790": {
+ "balance": "10011000000000000000000"
+ },
+ "43BCa16603c56cb681d1da3636B7a1A225598bfc": {
+ "balance": "10011000000000000000000"
+ },
+ "E55d8Bc08025BDDF8Da02eEB54882d0586f90700": {
+ "balance": "10011000000000000000000"
+ },
+ "40E1C73f6228a2c15e10aF2F3e890098b777ED15": {
+ "balance": "10011000000000000000000"
+ },
+ "DbbF476089a186a406EA13a4c46813f4BccC3660": {
+ "balance": "10011000000000000000000"
+ },
+ "7baCEA66a75dD974Ad549987768bF8d8908b4917": {
+ "balance": "10011000000000000000000"
+ },
+ "fbF4C2362a9EB672BAC39A46AFd919B3c12Ce44c": {
+ "balance": "10011000000000000000000"
+ },
+ "A8dB96136990be5B3d3bfe592e5A5a5223350A7A": {
+ "balance": "10011000000000000000000"
+ },
+ "1Dd21ED691195EBA816d59B3De7Fab8b3470Ae4B": {
+ "balance": "10011000000000000000000"
+ },
+ "058A778A6aeEfacc013afba92578A43e38cc012D": {
+ "balance": "10011000000000000000000"
+ },
+ "13f52Ab66871880DC8F2179d705281a4cf6a15fB": {
+ "balance": "10011000000000000000000"
+ },
+ "eD1Ed9a71E313d1BCe14aB998E0646F212230a33": {
+ "balance": "10011000000000000000000"
+ },
+ "c563F264f98e34A409C6a085da7510De8B6FE90B": {
+ "balance": "10011000000000000000000"
+ },
+ "c6D678fC6Cc1dA9D5eD1c0075cF7c679e7138e02": {
+ "balance": "10011000000000000000000"
+ },
+ "5179fc80CaB9BB20d5405a50ec0Fb9a36c1B367a": {
+ "balance": "10011000000000000000000"
+ },
+ "0d473f73AAf1C2bf7EBd2be7196C71dBa6C1724b": {
+ "balance": "100110000000000000000"
+ },
+ "6958c5b7E3D94B041d0d76Cac2e09378d31201bd": {
+ "balance": "10011000000000000000000"
+ },
+ "628d4A734d1a2647c67D254209e7B6471a11a5cb": {
+ "balance": "10011000000000000000000"
+ },
+ "E1601e3172F0ef0100e363B639Bd44420B7E5490": {
+ "balance": "10011000000000000000000"
+ },
+ "3337F2Cd103976F044b55D3E69aB06d1ebB142Db": {
+ "balance": "10011000000000000000000"
+ },
+ "8D0D5c57dC232Be15Df4A1a048EF36162C853b94": {
+ "balance": "10011000000000000000000"
+ },
+ "14800c28F3cF1Dd17AaC55263ef4e173b0e8e3Ef": {
+ "balance": "10011000000000000000000"
+ },
+ "f3996A0f0f593BfD5E39780059C5430fab7359FD": {
+ "balance": "10011000000000000000000"
+ },
+ "2217FeBe31Aea6C771AF163dCc453F9f060a4a00": {
+ "balance": "10011000000000000000000"
+ },
+ "f426CC817400766cd6b44F13Cb63Ca648e323484": {
+ "balance": "10011000000000000000000"
+ },
+ "B2C4913e257a34445Ec31685E625bb4060FB8e1f": {
+ "balance": "10011000000000000000000"
+ },
+ "9438dbD05dfC19F049a469185c7599daa82646e8": {
+ "balance": "10011000000000000000000"
+ },
+ "4BeD66Bf507f3CF524704267908Ea4ee3cDe3053": {
+ "balance": "10011000000000000000000"
+ },
+ "9a850fe8105e9CCfBD9d1D06D535BB4948f3f6Cf": {
+ "balance": "10011000000000000000000"
+ },
+ "1277eE554565542A8d0553E1e54006d006db75bd": {
+ "balance": "10011000000000000000000"
+ },
+ "D7e829bE8E374D3fBbd2F68D9A916cB2f769BA89": {
+ "balance": "10011000000000000000000"
+ },
+ "3691b847eD14E296afC90Ff3E37D21e518306170": {
+ "balance": "10011000000000000000000"
+ },
+ "c4C703357B01672cF95bFa0450a5717812Bc7ffb": {
+ "balance": "10011000000000000000000"
+ },
+ "0c9369077836353A8D92aeD29C72A7DfD300B354": {
+ "balance": "10011000000000000000000"
+ },
+ "856DF2A3bdBb8086cE406C469dDE94d12C1E3176": {
+ "balance": "10011000000000000000000"
+ },
+ "E40B3e5c59e2157037b699895329DBe4aA33C039": {
+ "balance": "10011000000000000000000"
+ },
+ "edb47aF3aC2325735722450D1E7DA082bDDad58c": {
+ "balance": "10011000000000000000000"
+ },
+ "315D669866E13fA302B76c85481F9181e06304Ce": {
+ "balance": "10011000000000000000000"
+ },
+ "A5185E3328592428d5989422e0339247dD77e10D": {
+ "balance": "10011000000000000000000"
+ },
+ "85Fd1d1Cd6655EbB89db7D6cA0a5C9c62F7a4CFf": {
+ "balance": "10011000000000000000000"
+ },
+ "ACC9E4430EC1011673547395A191C6b152763EA4": {
+ "balance": "10011000000000000000000"
+ },
+ "3824967C172D52128522dD257FE8f58C9099166B": {
+ "balance": "10011000000000000000000"
+ },
+ "5542aDEA3092da5541250d70a3Db28Ad9BE7Cfc7": {
+ "balance": "10011000000000000000000"
+ },
+ "c61Cd4477f0A98BfC97744481181730f7af7c14f": {
+ "balance": "10011000000000000000000"
+ },
+ "5D7Ffd0fC6DAA67AbF7d48ae69f09dbe53d86983": {
+ "balance": "10011000000000000000000"
+ },
+ "350914ABD4F095534823C1e8fA1cfD7EF79e7E4c": {
+ "balance": "10011000000000000000000"
+ },
+ "ECa6f058B718E320c1D45f5D1fb07947367C3D4B": {
+ "balance": "10011000000000000000000"
+ },
+ "9C577D0795Ed0cA88814d149c2DC61E8Fc48Ad81": {
+ "balance": "10011000000000000000000"
+ },
+ "72fE8bC8E3Ff1e56543c9c1F9834D6dfC31BEDDC": {
+ "balance": "10011000000000000000000"
+ },
+ "6Ff2CFa7899073CD029267fd821C9497811b5f7E": {
+ "balance": "10011000000000000000000"
+ },
+ "4685D123aE928a7912646681ba32035ad6F010a6": {
+ "balance": "10011000000000000000000"
+ },
+ "4799946c8B21fF5E58A225AeCB6F54ec17a94566": {
+ "balance": "10011000000000000000000"
+ },
+ "1D7dA5a23a99Fc33e2e94d502E4Fdb564eA0B24C": {
+ "balance": "10011000000000000000000"
+ },
+ "DFc9719cD9c7982e4A1FFB4B87cC3b861C40E367": {
+ "balance": "10011000000000000000000"
+ },
+ "0c1F0457ce3e87f5eA8F2C3A007dfe963A6Ff9a7": {
+ "balance": "10011000000000000000000"
+ },
+ "7dC23b30dFDc326B9a694c6f9723DC889fe16b7d": {
+ "balance": "10011000000000000000000"
+ },
+ "3F0c4cFDD40D16B7C15878AcCdc91Be9ca4DeE79": {
+ "balance": "10011000000000000000000"
+ },
+ "B984a83416F560437C7866e26CdDb94bDB821594": {
+ "balance": "10011000000000000000000"
+ },
+ "138EA4C57F5b3984EFacd944b3b85dfDd5A78Dcc": {
+ "balance": "10011000000000000000000"
+ },
+ "AD4f16F3435E849505C643714C9E5f40f73c4a5a": {
+ "balance": "10011000000000000000000"
+ },
+ "6b38E861ec0b65fd288d96d5630711C576362152": {
+ "balance": "10011000000000000000000"
+ },
+ "AE15D05100CE807d0aC93119f4ada8fa21441Fd2": {
+ "balance": "10011000000000000000000"
+ },
+ "e0e25c5734bef8b2Add633eAa2518B207DAa0D66": {
+ "balance": "10011000000000000000000"
+ },
+ "9039Ce107A9cD36Ed116958E50f8BDe090e2406f": {
+ "balance": "10011000000000000000000"
+ },
+ "089bE2dD42096ebA1d94aad20228b75df2BeeBC7": {
+ "balance": "10011000000000000000000"
+ },
+ "E3a79AEee437532313015892B52b65f52794F8a2": {
+ "balance": "10011000000000000000000"
+ },
+ "Cc38EE244819649C9DaB02e268306cED09B20672": {
+ "balance": "10011000000000000000000"
+ },
+ "eb0357140a1a0A6c1cB9c93Bf9354ef7365C97d9": {
+ "balance": "10011000000000000000000"
+ },
+ "44370D6b2d010C9eBFa280b6C00010AC99a45660": {
+ "balance": "10011000000000000000000"
+ },
+ "762438915209d038340C3Af9f8aAb8F93aDc8A9A": {
+ "balance": "10011000000000000000000"
+ },
+ "9CBa7aD50fa366Ff6fC2CAe468929eC9AD23Ea2B": {
+ "balance": "10011000000000000000000"
+ },
+ "4f4F159826b2B1eE903A811fCd86E450c9954396": {
+ "balance": "10011000000000000000000"
+ },
+ "3C132B8465e2D172BB7bab6654D85E398ee7c8AD": {
+ "balance": "10011000000000000000000"
+ },
+ "0582426C929B7e525c22201Bd4c143E45189C589": {
+ "balance": "10011000000000000000000"
+ },
+ "fb542740B34dDC0ADE383F2907a1e1E175E0BF5a": {
+ "balance": "10011000000000000000000"
+ },
+ "184Ca91AfE8F36bC5772b29cE2A76c90fCef34D0": {
+ "balance": "10011000000000000000000"
+ },
+ "0C6f48B50B166ddcE52CEE051acCAfFB8ecB4976": {
+ "balance": "10011000000000000000000"
+ },
+ "3aD2bE38fA3DFa7969E79B4053868FD1C368eAb2": {
+ "balance": "10011000000000000000000"
+ },
+ "a6A690637b088E9A1A89c44c9dC5e14eD4825053": {
+ "balance": "10011000000000000000000"
+ },
+ "C224B131Ea71e11E7DF38de3774AAAAe7E197BA4": {
+ "balance": "10011000000000000000000"
+ },
+ "d3C18531f0879B9FB8Ed45830C4ce6b54dC57128": {
+ "balance": "10011000000000000000000"
+ },
+ "02a272d17E1308beF21E783A93D1658f84F2D414": {
+ "balance": "10011000000000000000000"
+ },
+ "57A1aC8167d94b899b32C38Ff9D2B2bD0e55C10d": {
+ "balance": "10011000000000000000000"
+ },
+ "F8fc7D740929E5DD4eBA8fd5a6873Be6a4151087": {
+ "balance": "10011000000000000000000"
+ },
+ "B2AfC45838b364240dE17D3143AA6096d3340A91": {
+ "balance": "10011000000000000000000"
+ },
+ "eAf133d1e0Dd325721665B19f67C9b914EE2469F": {
+ "balance": "10011000000000000000000"
+ },
+ "B7660F1B075e56780e7E026ff66995765f5f1f7F": {
+ "balance": "10011000000000000000000"
+ },
+ "F25087E27B7a59003bb08d2cAc7A69E7c15a4be8": {
+ "balance": "10011000000000000000000"
+ },
+ "E65054681206658A845140331459A057C4EB3CA7": {
+ "balance": "10011000000000000000000"
+ },
+ "e7569A0F93E832a6633d133d23503B5175bEa5Db": {
+ "balance": "10011000000000000000000"
+ },
+ "a9f6102BCf5351dFdC7fA0CA4Fa0A711e16605c3": {
+ "balance": "10011000000000000000000"
+ },
+ "1AB9aA0E855DF953CF8d9cC166172799afD12a68": {
+ "balance": "10011000000000000000000"
+ },
+ "6C04aA35c377E65658EC3600Cab5E8FFa95567D9": {
+ "balance": "10011000000000000000000"
+ },
+ "6b82AD37e64c91c628305813B2DA82F18f8e2a2B": {
+ "balance": "10011000000000000000000"
+ },
+ "AD5D1DeD72F0e70a0a5500B26b82B1A2e8A63471": {
+ "balance": "10011000000000000000000"
+ },
+ "72B3589771Ec8e189a5d9Fe7a214e44085e89054": {
+ "balance": "10011000000000000000000"
+ },
+ "74F57dA8be3E9AB4463DD70319A06Fb5E3168211": {
+ "balance": "10011000000000000000000"
+ },
+ "b6f7F57b99DB21027875BEa3b8531d5925c346cE": {
+ "balance": "10011000000000000000000"
+ },
+ "279d05241d33Dc422d5AEcAc0e089B7f50f879c3": {
+ "balance": "10011000000000000000000"
+ },
+ "d57FEfe1B634ab451a6815Cd6769182EABA62779": {
+ "balance": "10011000000000000000000"
+ },
+ "e86C8538Bdfb253E8D6cC29ee24A330905324849": {
+ "balance": "10011000000000000000000"
+ },
+ "2C58D7f7f9CDF79CF3Cd5F4247761b93428A4E9e": {
+ "balance": "10011000000000000000000"
+ },
+ "37326cEfAFB1676f7Af1CcDcCD37A846Ec64F19d": {
+ "balance": "10011000000000000000000"
+ },
+ "f01DCf91d5f74BDB161F520e800c64F686Eb253F": {
+ "balance": "10011000000000000000000"
+ },
+ "Ba85246bc2A4fdaC1cB2e3C68383Fe79A6466fd9": {
+ "balance": "10011000000000000000000"
+ },
+ "4A76f81eA26381981a3B740975fb4F605989b585": {
+ "balance": "10011000000000000000000"
+ },
+ "00ee7168618BaE4F4d2900D5063c62948c6F0566": {
+ "balance": "10011000000000000000000"
+ },
+ "E1aD0B232B4262E4A279C91070417DAAF202623F": {
+ "balance": "10011000000000000000000"
+ },
+ "f611173319b22080E0F02eE724781d85f4b39Ae6": {
+ "balance": "10011000000000000000000"
+ },
+ "158659458dff3a9E5182cA0e8Ba08F53463FA5e7": {
+ "balance": "10011000000000000000000"
+ },
+ "FEB11610ad367b0c994274A8153E50F4557e473F": {
+ "balance": "10011000000000000000000"
+ },
+ "e1eB2279f45760Ab9D734782B1a0A8FD3d47D807": {
+ "balance": "10011000000000000000000"
+ },
+ "8667d005eCF50Eb247890a11FCdCfC321DC1Da9f": {
+ "balance": "10011000000000000000000"
+ },
+ "5Ce612A664C2f35558Dcab7edb999619e155CD07": {
+ "balance": "10011000000000000000000"
+ },
+ "aD95f88cCd3aBC12ddd6cD0b9a777B95339b747b": {
+ "balance": "10011000000000000000000"
+ },
+ "6E5a5A2963F6d0C2EA26682a152fE3ac7CBC1227": {
+ "balance": "10011000000000000000000"
+ },
+ "000000000000000000000000000000000000ce10": {
+ "code": "0x60806040526004361061004a5760003560e01c806303386ba3146101e757806342404e0714610280578063bb913f41146102d7578063d29d44ee14610328578063f7e6af8014610379575b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050600081549050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610136576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f20496d706c656d656e746174696f6e20736574000000000000000000000081525060200191505060405180910390fd5b61013f816103d0565b6101b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b60405136810160405236600082376000803683855af43d604051818101604052816000823e82600081146101e3578282f35b8282fd5b61027e600480360360408110156101fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561023a57600080fd5b82018360208201111561024c57600080fd5b8035906020019184600183028401116401000000008311171561026e57600080fd5b909192939192939050505061041b565b005b34801561028c57600080fd5b506102956105c1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156102e357600080fd5b50610326600480360360208110156102fa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061060d565b005b34801561033457600080fd5b506103776004803603602081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506107bd565b005b34801561038557600080fd5b5061038e610871565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f915080821415801561041257506000801b8214155b92505050919050565b610423610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6104cc8361060d565b600060608473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284378083019250505092505050600060405180830381855af49150503d8060008114610539576040519150601f19603f3d011682016040523d82523d6000602084013e61053e565b606091505b508092508193505050816105ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f696e697469616c697a6174696f6e2063616c6c6261636b206661696c6564000081525060200191505060405180910390fd5b5050505050565b600080600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050805491505090565b610615610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050610701826103d0565b610773576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b8181558173ffffffffffffffffffffffffffffffffffffffff167fab64f92ab780ecbf4f3866f57cee465ff36c89450dcce20237ca7a8d81fb7d1360405160405180910390a25050565b6107c5610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610865576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b61086e816108bd565b50565b600080600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b9050805491505090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610960576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f6f776e65722063616e6e6f74206265203000000000000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b90508181558173ffffffffffffffffffffffffffffffffffffffff167f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe260405160405180910390a2505056fea165627a7a72305820959a50d5df76f90bc1825042f47788ee27f1b4725f7ed5d37c5c05c0732ef44f0029",
+ "storage": {
+ "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "0x0Cc59Ed03B3e763c02d54D695FFE353055f1502D"
+ },
+ "balance": "0"
+ }
+}`
+
+const alfajoresAllocJSON = `{
+ "456f41406B32c45D59E539e4BBA3D7898c3584dA": {
+ "balance": "103010030000000000000000000"
+ },
+ "DD1F519F63423045F526b8c83edC0eB4BA6434a4": {
+ "balance": "10011000000000000000000"
+ },
+ "050f34537F5b2a00B9B9C752Cb8500a3fcE3DA7d": {
+ "balance": "10011000000000000000000"
+ },
+ "Cda518F6b5a797C3EC45D37c65b83e0b0748eDca": {
+ "balance": "10011000000000000000000"
+ },
+ "b4e92c94A2712e98c020A81868264bdE52C188Cb": {
+ "balance": "10011000000000000000000"
+ },
+ "Ae1ec841923811219b98ACeB1db297AADE2F46F3": {
+ "balance": "10011000000000000000000"
+ },
+ "621843731fe33418007C06ee48CfD71e0ea828d9": {
+ "balance": "10011000000000000000000"
+ },
+ "2A43f97f8BF959E31F69A894ebD80A88572C8553": {
+ "balance": "10011000000000000000000"
+ },
+ "AD682035bE6Ab6f06e478D2BDab0EAb6477B460E": {
+ "balance": "10011000000000000000000"
+ },
+ "30D060F129817c4DE5fBc1366d53e19f43c8c64f": {
+ "balance": "10011000000000000000000"
+ },
+ "22579CA45eE22E2E16dDF72D955D6cf4c767B0eF": {
+ "balance": "10011000000000000000000"
+ },
+ "1173C5A50bf025e8356823a068E396ccF2bE696C": {
+ "balance": "10011000000000000000000"
+ },
+ "40F71B525A96baa8d14Eaa7Bcd19929782659c64": {
+ "balance": "10011000000000000000000"
+ },
+ "b923626C6f1d237252793FB2aA12BA21328C51BC": {
+ "balance": "10011000000000000000000"
+ },
+ "B70f9ABf41F36B3ab60cc9aE1a85Ddda3C88D261": {
+ "balance": "10011000000000000000000"
+ },
+ "d4369DB59eaDc4Cfa089c0a3c1004ceAb1b318D8": {
+ "balance": "10011000000000000000000"
+ },
+ "2fd430d3a96eadc38cc1B38b6685C5f52Cf7a083": {
+ "balance": "10011000000000000000000"
+ },
+ "Fecc71C8f33Ca5952534fd346ADdeDC38DBb9cb7": {
+ "balance": "10011000000000000000000"
+ },
+ "0de78C89e7BF5060f28dd3f820C15C4A6A81AFB5": {
+ "balance": "10011000000000000000000"
+ },
+ "75411b92fcE120C1e7fd171b1c2bF802f2E3CF48": {
+ "balance": "10011000000000000000000"
+ },
+ "563433bD8357b06982Fe001df20B2b43393d21d2": {
+ "balance": "10011000000000000000000"
+ },
+ "79dfB9d2367E7921d4139D7841d24ED82F48907F": {
+ "balance": "10011000000000000000000"
+ },
+ "5809369FC5121a071eE67659a975e88ae40fBE3b": {
+ "balance": "10011000000000000000000"
+ },
+ "7517E54a456bcc6c5c695B5d9f97EBc05d29a824": {
+ "balance": "10011000000000000000000"
+ },
+ "B0a1A5Ffcb34E6Fa278D2b40613f0AE1042d32f8": {
+ "balance": "10011000000000000000000"
+ },
+ "EeE9f4DDf49976251E84182AbfD3300Ee58D12aa": {
+ "balance": "10011000000000000000000"
+ },
+ "Eb5Fd57f87a4e1c7bAa53ec1c0d021bb1710B743": {
+ "balance": "10011000000000000000000"
+ },
+ "B7Dd51bFb73c5753778e5Af56f1D9669BCe6777F": {
+ "balance": "10011000000000000000000"
+ },
+ "33C222BB13C63295AF32D6C91278AA34b573e776": {
+ "balance": "10011000000000000000000"
+ },
+ "83c58603bF72DA067D7f6238E7bF390d91B2f531": {
+ "balance": "10011000000000000000000"
+ },
+ "6651112198C0da05921355642a2B8dF1fA3Ede93": {
+ "balance": "10011000000000000000000"
+ },
+ "4EE72A98549eA7CF774C3E2E1b39fF166b4b68BE": {
+ "balance": "10011000000000000000000"
+ },
+ "840b32F30e1a3b2E8b9E6C0972eBa0148E22B847": {
+ "balance": "100000000000000000000"
+ },
+ "000000000000000000000000000000000000ce10": {
+ "code": "0x60806040526004361061004a5760003560e01c806303386ba3146101e757806342404e0714610280578063bb913f41146102d7578063d29d44ee14610328578063f7e6af8014610379575b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050600081549050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610136576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f20496d706c656d656e746174696f6e20736574000000000000000000000081525060200191505060405180910390fd5b61013f816103d0565b6101b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b60405136810160405236600082376000803683855af43d604051818101604052816000823e82600081146101e3578282f35b8282fd5b61027e600480360360408110156101fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561023a57600080fd5b82018360208201111561024c57600080fd5b8035906020019184600183028401116401000000008311171561026e57600080fd5b909192939192939050505061041b565b005b34801561028c57600080fd5b506102956105c1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156102e357600080fd5b50610326600480360360208110156102fa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061060d565b005b34801561033457600080fd5b506103776004803603602081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506107bd565b005b34801561038557600080fd5b5061038e610871565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f915080821415801561041257506000801b8214155b92505050919050565b610423610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6104cc8361060d565b600060608473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284378083019250505092505050600060405180830381855af49150503d8060008114610539576040519150601f19603f3d011682016040523d82523d6000602084013e61053e565b606091505b508092508193505050816105ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f696e697469616c697a6174696f6e2063616c6c6261636b206661696c6564000081525060200191505060405180910390fd5b5050505050565b600080600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050805491505090565b610615610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050610701826103d0565b610773576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b8181558173ffffffffffffffffffffffffffffffffffffffff167fab64f92ab780ecbf4f3866f57cee465ff36c89450dcce20237ca7a8d81fb7d1360405160405180910390a25050565b6107c5610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610865576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b61086e816108bd565b50565b600080600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b9050805491505090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610960576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f6f776e65722063616e6e6f74206265203000000000000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b90508181558173ffffffffffffffffffffffffffffffffffffffff167f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe260405160405180910390a2505056fea165627a7a723058202dbb6037e4381b4ad95015ed99441a23345cc2ae52ef27e2e91d34fb0acd277b0029",
+ "storage": {
+ "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103": "456f41406B32c45D59E539e4BBA3D7898c3584dA"
+ },
+ "balance": "0"
+ }
+}`
+
+const mainnetAllocJSON = "{\"0x11901cf7eEae1E2644995FB2E47Ce46bC7F33246\":{\"balance\":\"120000000000000000000000000\"},\"0xC1cDA18694F5B86cFB80c1B4f8Cc046B0d7E6326\":{\"balance\":\"20000000000000000000000000\"},\"0xa5d40D93b01AfBafec84E20018Aff427628F645E\":{\"balance\":\"20000000000000000000000000\"},\"0x8d485780E84E23437f8F6938D96B964645529127\":{\"balance\":\"20000000000000000000000000\"},\"0x5F857c501b73ddFA804234f1f1418D6f75554076\":{\"balance\":\"20000000000000000000000000\"},\"0xaa9064F57F8d7de4b3e08c35561E21Afd6341390\":{\"balance\":\"20000000000000000000000000\"},\"0x7FA26b50b3e9a2eC8AD1850a4c4FBBF94D806E95\":{\"balance\":\"20000000000000000000000000\"},\"0x08960Ce6b58BE32FBc6aC1489d04364B4f7dC216\":{\"balance\":\"20000000000000000000000000\"},\"0x77B68B2e7091D4F242a8Af89F200Af941433C6d8\":{\"balance\":\"20000000000000000000000000\"},\"0x75Bb69C002C43f5a26a2A620518775795Fd45ecf\":{\"balance\":\"20000000000000000000000000\"},\"0x19992AE48914a178Bf138665CffDD8CD79b99513\":{\"balance\":\"20000000000000000000000000\"},\"0xE23a4c6615669526Ab58E9c37088bee4eD2b2dEE\":{\"balance\":\"20000000000000000000000\"},\"0xDe22679dCA843B424FD0BBd70A22D5F5a4B94fe4\":{\"balance\":\"10200014000000000000000000\"},\"0x743D80810fe10c5C3346D2940997cC9647035B13\":{\"balance\":\"20513322000000000000000000\"},\"0x8e1c4355307F1A59E7eD4Ae057c51368b9338C38\":{\"balance\":\"7291740000000000000000000\"},\"0x417fe63186C388812e342c85FF87187Dc584C630\":{\"balance\":\"20000062000000000000000000\"},\"0xF5720c180a6Fa14ECcE82FB1bB060A39E93A263c\":{\"balance\":\"30000061000000000000000000\"},\"0xB80d1e7F9CEbe4b5E1B1Acf037d3a44871105041\":{\"balance\":\"9581366833333333333333335\"},\"0xf8ed78A113cD2a34dF451Ba3D540FFAE66829AA0\":{\"balance\":\"11218686833333333333333333\"},\"0x9033ff75af27222c8f36a148800c7331581933F3\":{\"balance\":\"11218686833333333333333333\"},\"0x8A07541C2eF161F4e3f8de7c7894718dA26626B2\":{\"balance\":\"11218686833333333333333333\"},\"0xB2fe7AFe178335CEc3564d7671EEbD7634C626B0\":{\"balance\":\"11218686833333333333333333\"},\"0xc471776eA02705004C451959129bF09423B56526\":{\"balance\":\"11218686833333333333333333\"},\"0xeF283eca68DE87E051D427b4be152A7403110647\":{\"balance\":\"14375000000000000000000000\"},\"0x7cf091C954ed7E9304452d31fd59999505Ddcb7a\":{\"balance\":\"14375000000000000000000000\"},\"0xa5d2944C32a8D7b284fF0b84c20fDcc46937Cf64\":{\"balance\":\"14375000000000000000000000\"},\"0xFC89C17525f08F2Bc9bA8cb77BcF05055B1F7059\":{\"balance\":\"14375000000000000000000000\"},\"0x3Fa7C646599F3174380BD9a7B6efCde90b5d129d\":{\"balance\":\"14375000000000000000000000\"},\"0x989e1a3B344A43911e02cCC609D469fbc15AB1F1\":{\"balance\":\"14375000000000000000000000\"},\"0xAe1d640648009DbE0Aa4485d3BfBB68C37710924\":{\"balance\":\"20025000000000000000000000\"},\"0x1B6C64779F42BA6B54C853Ab70171aCd81b072F7\":{\"balance\":\"20025000000000000000000000\"},\"000000000000000000000000000000000000ce10\":{\"code\":\"0x60806040526004361061004a5760003560e01c806303386ba3146101e757806342404e0714610280578063bb913f41146102d7578063d29d44ee14610328578063f7e6af8014610379575b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050600081549050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610136576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260158152602001807f4e6f20496d706c656d656e746174696f6e20736574000000000000000000000081525060200191505060405180910390fd5b61013f816103d0565b6101b1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b60405136810160405236600082376000803683855af43d604051818101604052816000823e82600081146101e3578282f35b8282fd5b61027e600480360360408110156101fd57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561023a57600080fd5b82018360208201111561024c57600080fd5b8035906020019184600183028401116401000000008311171561026e57600080fd5b909192939192939050505061041b565b005b34801561028c57600080fd5b506102956105c1565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156102e357600080fd5b50610326600480360360208110156102fa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061060d565b005b34801561033457600080fd5b506103776004803603602081101561034b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506107bd565b005b34801561038557600080fd5b5061038e610871565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60008060007fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47060001b9050833f915080821415801561041257506000801b8214155b92505050919050565b610423610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146104c3576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6104cc8361060d565b600060608473ffffffffffffffffffffffffffffffffffffffff168484604051808383808284378083019250505092505050600060405180830381855af49150503d8060008114610539576040519150601f19603f3d011682016040523d82523d6000602084013e61053e565b606091505b508092508193505050816105ba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f696e697469616c697a6174696f6e2063616c6c6261636b206661696c6564000081525060200191505060405180910390fd5b5050505050565b600080600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050805491505090565b610615610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146106b5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e696d706c656d656e746174696f6e00000000815250601c019050604051809103902060001c0360001b9050610701826103d0565b610773576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f496e76616c696420636f6e74726163742061646472657373000000000000000081525060200191505060405180910390fd5b8181558173ffffffffffffffffffffffffffffffffffffffff167fab64f92ab780ecbf4f3866f57cee465ff36c89450dcce20237ca7a8d81fb7d1360405160405180910390a25050565b6107c5610871565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610865576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260148152602001807f73656e64657220776173206e6f74206f776e657200000000000000000000000081525060200191505060405180910390fd5b61086e816108bd565b50565b600080600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b9050805491505090565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610960576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260118152602001807f6f776e65722063616e6e6f74206265203000000000000000000000000000000081525060200191505060405180910390fd5b6000600160405180807f656970313936372e70726f78792e61646d696e000000000000000000000000008152506013019050604051809103902060001c0360001b90508181558173ffffffffffffffffffffffffffffffffffffffff167f50146d0e3c60aa1d17a70635b05494f864e86144a2201275021014fbf08bafe260405160405180910390a2505056fea165627a7a723058206808dd43e7d765afca53fe439122bc5eac16d708ce7d463451be5042426f101f0029\",\"storage\":{\"0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103\":\"0xE23a4c6615669526Ab58E9c37088bee4eD2b2dEE\"},\"balance\":\"0\"}}"
+
+var celoL1GenesisAllocJSON = map[uint64]string{
+ MainnetNetworkID: mainnetAllocJSON,
+ AlfajoresNetworkID: alfajoresAllocJSON,
+ BaklavaNetworkID: baklavaAllocJSON,
+}
+
+// GetCeloL1GenesisAlloc returns the legacy Celo L1 genesis allocation JSON for the given network ID.
+func GetCeloL1GenesisAlloc(config *params.ChainConfig) ([]byte, error) {
+ chainID := config.ChainID.Uint64()
+ allocJSON, ok := celoL1GenesisAllocJSON[chainID]
+ if !ok {
+ return nil, fmt.Errorf("no genesis allocation JSON found for network ID %d", chainID)
+ }
+ return []byte(allocJSON), nil
+}
+
+// BuildGenesis creates a genesis block from the given parameters.
+func BuildGenesis(config *params.ChainConfig, allocs, extraData []byte, timestamp uint64) (*core.Genesis, error) {
+ genesisAlloc := &types.GenesisAlloc{}
+ if err := genesisAlloc.UnmarshalJSON(allocs); err != nil {
+ return nil, err
+ }
+ return &core.Genesis{
+ Config: config,
+ Timestamp: timestamp,
+ ExtraData: extraData,
+ Alloc: *genesisAlloc,
+ }, nil
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/main.go CELO/op-chain-ops/cmd/celo-migrate/main.go
new file mode 100644
index 0000000000000000000000000000000000000000..ff6a8375cb42d4835a5a14826a2f3bbd054f6e20
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/main.go
@@ -0,0 +1,637 @@
+package main
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "math/big"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "runtime/debug"
+ "sync"
+ "time"
+
+ "log/slog"
+
+ "github.com/ethereum-optimism/optimism/op-chain-ops/foundry"
+ "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
+ "github.com/ethereum-optimism/optimism/op-service/ioutil"
+ "github.com/ethereum-optimism/optimism/op-service/jsonutil"
+ oplog "github.com/ethereum-optimism/optimism/op-service/log"
+ "github.com/hashicorp/go-multierror"
+ "github.com/mattn/go-isatty"
+
+ "github.com/urfave/cli/v2"
+
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/ethclient"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/rpc"
+
+ "golang.org/x/sync/errgroup"
+)
+
+var (
+ deployConfigFlag = &cli.PathFlag{
+ Name: "deploy-config",
+ Usage: "Path to the JSON file that was used for the bedrock contracts deployment. A test example can be found here 'op-chain-ops/genesis/testdata/test-deploy-config-full.json' and documentation for the fields is at https://docs.optimism.io/builders/chain-operators/management/configuration",
+ Required: true,
+ }
+ l1DeploymentsFlag = &cli.PathFlag{
+ Name: "l1-deployments",
+ Usage: "Path to L1 deployments JSON file, the output of running the bedrock contracts deployment for the given 'deploy-config'",
+ Required: true,
+ }
+ l1RPCFlag = &cli.StringFlag{
+ Name: "l1-rpc",
+ Usage: "RPC URL for a node of the L1 defined in the 'deploy-config'",
+ Required: true,
+ }
+ l2AllocsFlag = &cli.PathFlag{
+ Name: "l2-allocs",
+ Usage: "Path to L2 genesis allocs file. You can find instructions on how to generate this file in the README",
+ Required: true,
+ }
+ outfileRollupConfigFlag = &cli.PathFlag{
+ Name: "outfile.rollup-config",
+ Usage: "Path to write the rollup config JSON file, to be provided to op-node with the 'rollup.config' flag",
+ Required: true,
+ }
+ outfileGenesisFlag = &cli.PathFlag{
+ Name: "outfile.genesis",
+ Usage: "Path to write the genesis JSON file, to be used to sync new nodes",
+ Required: true,
+ }
+ migrationBlockNumberFlag = &cli.Uint64Flag{
+ Name: "migration-block-number",
+ Usage: "Specifies the migration block number. If the source db is not synced exactly to the block immediately before this number (i.e. migration-block-number - 1), the migration will fail.",
+ Required: true,
+ }
+ migrationBlockTimeFlag = &cli.Uint64Flag{
+ Name: "migration-block-time",
+ Usage: "Specifies a unix timestamp to use for the migration block. This should be set to the same timestamp as was used for the sequencer migration. If performing the sequencer migration, this should set to a time in the future around when the migration script is expected to complete.",
+ Required: true,
+ }
+ oldDBPathFlag = &cli.PathFlag{
+ Name: "old-db",
+ Usage: "Path to the old Celo chaindata dir, can be found at '<datadir>/celo/chaindata'",
+ Required: true,
+ }
+ newDBPathFlag = &cli.PathFlag{
+ Name: "new-db",
+ Usage: "Path to write migrated Celo chaindata, note the new node implementation expects to find this chaindata at the following path '<datadir>/geth/chaindata",
+ Required: true,
+ }
+ batchSizeFlag = &cli.Uint64Flag{
+ Name: "batch-size",
+ Usage: "Batch size to use for block migration, larger batch sizes can speed up migration but require more memory. If increasing the batch size consider also increasing the memory-limit",
+ Value: 50000,
+ }
+ bufferSizeFlag = &cli.Uint64Flag{
+ Name: "buffer-size",
+ Usage: "Buffer size to use for ancient block migration channels. Defaults to 0. Included to facilitate testing for performance improvements.",
+ Value: 0,
+ }
+ memoryLimitFlag = &cli.Int64Flag{
+ Name: "memory-limit",
+ Usage: "Memory limit in MiB, should be set lower than the available amount of memory in your system to prevent out of memory errors",
+ Value: 7500,
+ }
+ reset = &cli.BoolFlag{
+ Name: "reset",
+ Usage: "Delete everything in the destination directory aside from /ancients. This is useful if you need to re-run the full migration but do not want to repeat the lengthy ancients migration. If you'd like to reset the entire destination directory, you can delete it manually.",
+ Value: false,
+ }
+ dbCheckPathFlag = &cli.PathFlag{
+ Name: "db-path",
+ Usage: "Path to the db to perform a continuity check on",
+ Required: true,
+ }
+ dbCheckFailFastFlag = &cli.BoolFlag{
+ Name: "fail-fast",
+ Usage: "Fail fast on the first error encountered. If set, the db check will stop on the first error encountered, otherwise it will continue to check all blocks and print out all errors at the end.",
+ Value: false,
+ }
+
+ preMigrationFlags = []cli.Flag{
+ oldDBPathFlag,
+ newDBPathFlag,
+ batchSizeFlag,
+ bufferSizeFlag,
+ memoryLimitFlag,
+ reset,
+ }
+ fullMigrationFlags = append(
+ preMigrationFlags,
+ deployConfigFlag,
+ l1DeploymentsFlag,
+ l1RPCFlag,
+ l2AllocsFlag,
+ outfileRollupConfigFlag,
+ outfileGenesisFlag,
+ migrationBlockTimeFlag,
+ migrationBlockNumberFlag,
+ )
+ dbCheckFlags = []cli.Flag{
+ dbCheckPathFlag,
+ batchSizeFlag,
+ dbCheckFailFastFlag,
+ }
+)
+
+type preMigrationOptions struct {
+ oldDBPath string
+ newDBPath string
+ batchSize uint64
+ bufferSize uint64
+ memoryLimit int64
+ resetNonAncients bool
+}
+
+type stateMigrationOptions struct {
+ deployConfig string
+ l1Deployments string
+ l1RPC string
+ l2AllocsPath string
+ outfileRollupConfig string
+ outfileGenesis string
+ migrationBlockTime uint64
+}
+
+type fullMigrationOptions struct {
+ preMigrationOptions
+ stateMigrationOptions
+ migrationBlockNumber uint64
+}
+
+type dbCheckOptions struct {
+ dbPath string
+ batchSize uint64
+ failFast bool
+}
+
+func parsePreMigrationOptions(ctx *cli.Context) preMigrationOptions {
+ return preMigrationOptions{
+ oldDBPath: ctx.String(oldDBPathFlag.Name),
+ newDBPath: ctx.String(newDBPathFlag.Name),
+ batchSize: ctx.Uint64(batchSizeFlag.Name),
+ bufferSize: ctx.Uint64(bufferSizeFlag.Name),
+ memoryLimit: ctx.Int64(memoryLimitFlag.Name),
+ resetNonAncients: ctx.Bool(reset.Name),
+ }
+}
+
+func parseStateMigrationOptions(ctx *cli.Context) stateMigrationOptions {
+ return stateMigrationOptions{
+ deployConfig: ctx.Path(deployConfigFlag.Name),
+ l1Deployments: ctx.Path(l1DeploymentsFlag.Name),
+ l1RPC: ctx.String(l1RPCFlag.Name),
+ l2AllocsPath: ctx.Path(l2AllocsFlag.Name),
+ outfileRollupConfig: ctx.Path(outfileRollupConfigFlag.Name),
+ outfileGenesis: ctx.Path(outfileGenesisFlag.Name),
+ migrationBlockTime: ctx.Uint64(migrationBlockTimeFlag.Name),
+ }
+}
+
+func parseFullMigrationOptions(ctx *cli.Context) fullMigrationOptions {
+ return fullMigrationOptions{
+ preMigrationOptions: parsePreMigrationOptions(ctx),
+ stateMigrationOptions: parseStateMigrationOptions(ctx),
+ migrationBlockNumber: ctx.Uint64(migrationBlockNumberFlag.Name),
+ }
+}
+
+func parseDBCheckOptions(ctx *cli.Context) dbCheckOptions {
+ return dbCheckOptions{
+ dbPath: ctx.String(dbCheckPathFlag.Name),
+ batchSize: ctx.Uint64(batchSizeFlag.Name),
+ failFast: ctx.Bool(dbCheckFailFastFlag.Name),
+ }
+}
+
+func main() {
+
+ color := isatty.IsTerminal(os.Stderr.Fd())
+ handler := log.NewTerminalHandlerWithLevel(os.Stderr, slog.LevelInfo, color)
+ oplog.SetGlobalLogHandler(handler)
+
+ app := &cli.App{
+ Name: "celo-migrate",
+ Usage: "Migrate Celo block and state data to a CeL2 DB",
+ Commands: []*cli.Command{
+ {
+ Name: "pre",
+ Usage: "Perform a pre-migration of ancient blocks and copy over all other data without transforming it. This should be run a day before the full migration command is run to minimize downtime.",
+ Flags: preMigrationFlags,
+ Action: func(ctx *cli.Context) error {
+ if _, _, err := runPreMigration(parsePreMigrationOptions(ctx)); err != nil {
+ return fmt.Errorf("failed to run pre-migration: %w", err)
+ }
+ log.Info("Finished pre migration successfully!")
+ return nil
+ },
+ },
+ {
+ Name: "full",
+ Usage: "Perform a full migration of both block and state data to a CeL2 DB",
+ Flags: fullMigrationFlags,
+ Action: func(ctx *cli.Context) error {
+ if err := runFullMigration(parseFullMigrationOptions(ctx)); err != nil {
+ return fmt.Errorf("failed to run full migration: %w", err)
+ }
+ log.Info("Finished full migration successfully!")
+ return nil
+ },
+ },
+ {
+ Name: "check-db",
+ Usage: "Perform a continuity check on the db, ensuring that all blocks are present and in order",
+ Flags: dbCheckFlags,
+ Action: func(ctx *cli.Context) error {
+ if err := runDBCheck(parseDBCheckOptions(ctx)); err != nil {
+ return fmt.Errorf("DB continuity check failed: %w", err)
+ }
+ log.Info("Finished db continuity check successfully!")
+ return nil
+ },
+ },
+ },
+ OnUsageError: func(ctx *cli.Context, err error, isSubcommand bool) error {
+ if isSubcommand {
+ return err
+ }
+ if err := cli.ShowAppHelp(ctx); err != nil {
+ log.Error("failed to show cli help", "err", err)
+ }
+ return fmt.Errorf("please provide a valid command")
+ },
+ }
+
+ if err := app.Run(os.Args); err != nil {
+ log.Crit("error in celo-migrate", "err", err)
+ }
+}
+
+func runFullMigration(opts fullMigrationOptions) error {
+ defer timer("full migration")()
+
+ log.Info("Full Migration Started", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath)
+
+ head, err := getHeadHeader(opts.oldDBPath)
+ if err != nil {
+ return fmt.Errorf("failed to get head header: %w", err)
+ }
+ if head.Number.Uint64() != opts.migrationBlockNumber-1 {
+ return fmt.Errorf("old-db head block number not synced to the block immediately before the migration block number: %d != %d", head.Number.Uint64(), opts.migrationBlockNumber-1)
+ }
+
+ log.Info("Source db is synced to correct height", "head", head.Number.Uint64(), "migrationBlock", opts.migrationBlockNumber)
+
+ var numAncients uint64
+ var strayAncientBlocks []*rawdb.NumberHash
+
+ if strayAncientBlocks, numAncients, err = runPreMigration(opts.preMigrationOptions); err != nil {
+ return fmt.Errorf("failed to run pre-migration: %w", err)
+ }
+
+ if err = runNonAncientMigration(opts.newDBPath, strayAncientBlocks, opts.batchSize, numAncients); err != nil {
+ return fmt.Errorf("failed to run non-ancient migration: %w", err)
+ }
+ if err = runStateMigration(opts.newDBPath, opts.stateMigrationOptions); err != nil {
+ return fmt.Errorf("failed to run state migration: %w", err)
+ }
+
+ log.Info("Full Migration Finished", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath)
+
+ return nil
+}
+
+func runPreMigration(opts preMigrationOptions) ([]*rawdb.NumberHash, uint64, error) {
+ defer timer("pre-migration")()
+
+ log.Info("Pre-Migration Started", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath, "batchSize", opts.batchSize, "memoryLimit", opts.memoryLimit)
+
+ // Check that `rsync` command is available. We use this to copy the db excluding ancients, which we will copy separately
+ if _, err := exec.LookPath("rsync"); err != nil {
+ return nil, 0, fmt.Errorf("please install `rsync` to run block migration")
+ }
+
+ debug.SetMemoryLimit(opts.memoryLimit * 1 << 20) // Set memory limit, converting from MiB to bytes
+
+ var err error
+
+ if err = createNewDbPathIfNotExists(opts.newDBPath); err != nil {
+ return nil, 0, fmt.Errorf("failed to create new db path: %w", err)
+ }
+
+ if opts.resetNonAncients {
+ if err = cleanupNonAncientDb(opts.newDBPath); err != nil {
+ return nil, 0, fmt.Errorf("failed to cleanup non-ancient db: %w", err)
+ }
+ }
+
+ var numAncientsNewBefore uint64
+ var numAncientsNewAfter uint64
+ var strayAncientBlocks []*rawdb.NumberHash
+ g, ctx := errgroup.WithContext(context.Background())
+ g.Go(func() error {
+ if numAncientsNewBefore, numAncientsNewAfter, err = migrateAncientsDb(ctx, opts.oldDBPath, opts.newDBPath, opts.batchSize, opts.bufferSize); err != nil {
+ return fmt.Errorf("failed to migrate ancients database: %w", err)
+ }
+ // Scanning for stray ancient blocks is slow, so we do it as soon as we can after the lock on oldDB is released by migrateAncientsDb
+ // Doing this in parallel with copyDbExceptAncients still saves time if ancients have already been pre-migrated
+ if strayAncientBlocks, err = getStrayAncientBlocks(opts.oldDBPath); err != nil {
+ return fmt.Errorf("failed to get stray ancient blocks: %w", err)
+ }
+ return nil
+ })
+ g.Go(func() error {
+ // By doing this once during the premigration, we get a speedup when we run it again in a full migration.
+ return copyDbExceptAncients(opts.oldDBPath, opts.newDBPath)
+ })
+
+ if err = g.Wait(); err != nil {
+ return nil, 0, fmt.Errorf("failed to migrate blocks: %w", err)
+ }
+
+ log.Info("Pre-Migration Finished", "oldDBPath", opts.oldDBPath, "newDBPath", opts.newDBPath, "migratedAncients", numAncientsNewAfter-numAncientsNewBefore, "strayAncientBlocks", len(strayAncientBlocks))
+
+ return strayAncientBlocks, numAncientsNewAfter, nil
+}
+
+func runNonAncientMigration(newDBPath string, strayAncientBlocks []*rawdb.NumberHash, batchSize, numAncients uint64) (err error) {
+ defer timer("non-ancient migration")()
+
+ newDB, err := openDBWithoutFreezer(newDBPath, false)
+ if err != nil {
+ return fmt.Errorf("failed to open new database: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, newDB.Close())
+ }()
+
+ // get the last block number
+ hash := rawdb.ReadHeadHeaderHash(newDB)
+ lastBlock := *rawdb.ReadHeaderNumber(newDB, hash)
+ lastAncient := numAncients - 1
+
+ log.Info("Non-Ancient Block Migration Started", "process", "non-ancients", "newDBPath", newDBPath, "batchSize", batchSize, "startBlock", numAncients, "endBlock", lastBlock, "count", lastBlock-lastAncient, "lastAncientBlock", lastAncient)
+
+ var numNonAncients uint64
+ if numNonAncients, err = migrateNonAncientsDb(newDB, lastBlock, numAncients, batchSize); err != nil {
+ return fmt.Errorf("failed to migrate non-ancients database: %w", err)
+ }
+
+ err = removeBlocks(newDB, strayAncientBlocks)
+ if err != nil {
+ return fmt.Errorf("failed to remove stray ancient blocks: %w", err)
+ }
+ log.Info("Removed stray ancient blocks still in leveldb", "process", "non-ancients", "removedBlocks", len(strayAncientBlocks))
+
+ log.Info("Non-Ancient Block Migration Completed", "process", "non-ancients", "migratedNonAncients", numNonAncients)
+
+ return nil
+}
+
+func runStateMigration(newDBPath string, opts stateMigrationOptions) error {
+ defer timer("state migration")()
+
+ log.Info("State Migration Started", "newDBPath", newDBPath, "deployConfig", opts.deployConfig, "l1Deployments", opts.l1Deployments, "l1RPC", opts.l1RPC, "l2AllocsPath", opts.l2AllocsPath, "outfileRollupConfig", opts.outfileRollupConfig)
+
+ // Read deployment configuration
+ config, err := genesis.NewDeployConfig(opts.deployConfig)
+ if err != nil {
+ return err
+ }
+
+ if config.DeployCeloContracts {
+ return errors.New("DeployCeloContracts is not supported in migration")
+ }
+ if config.FundDevAccounts {
+ return errors.New("FundDevAccounts is not supported in migration")
+ }
+
+ // Try reading the L1 deployment information
+ deployments, err := genesis.NewL1Deployments(opts.l1Deployments)
+ if err != nil {
+ return fmt.Errorf("cannot read L1 deployments at %s: %w", opts.l1Deployments, err)
+ }
+ config.SetDeployments(deployments)
+
+ // Get latest block information from L1
+ var l1StartBlock *types.Block
+ client, err := ethclient.Dial(opts.l1RPC)
+ if err != nil {
+ return fmt.Errorf("cannot dial %s: %w", opts.l1RPC, err)
+ }
+
+ if config.L1StartingBlockTag == nil {
+ l1StartBlock, err = client.BlockByNumber(context.Background(), nil)
+ if err != nil {
+ return fmt.Errorf("cannot fetch latest block: %w", err)
+ }
+ tag := rpc.BlockNumberOrHashWithHash(l1StartBlock.Hash(), true)
+ config.L1StartingBlockTag = (*genesis.MarshalableRPCBlockNumberOrHash)(&tag)
+ } else if config.L1StartingBlockTag.BlockHash != nil {
+ l1StartBlock, err = client.BlockByHash(context.Background(), *config.L1StartingBlockTag.BlockHash)
+ if err != nil {
+ return fmt.Errorf("cannot fetch block by hash: %w", err)
+ }
+ } else if config.L1StartingBlockTag.BlockNumber != nil {
+ l1StartBlock, err = client.BlockByNumber(context.Background(), big.NewInt(config.L1StartingBlockTag.BlockNumber.Int64()))
+ if err != nil {
+ return fmt.Errorf("cannot fetch block by number: %w", err)
+ }
+ }
+
+ // Ensure that there is a starting L1 block
+ if l1StartBlock == nil {
+ return fmt.Errorf("no starting L1 block")
+ }
+
+ // Sanity check the config. Do this after filling in the L1StartingBlockTag
+ // if it is not defined.
+ if err := config.Check(log.New()); err != nil {
+ return err
+ }
+
+ log.Info("Using L1 Start Block", "number", l1StartBlock.Number(), "hash", l1StartBlock.Hash().Hex())
+
+ // Build the L2 genesis block
+ l2Allocs, err := foundry.LoadForgeAllocs(opts.l2AllocsPath)
+ if err != nil {
+ return err
+ }
+
+ l2Genesis, err := genesis.BuildL2Genesis(config, l2Allocs, l1StartBlock.Header())
+ if err != nil {
+ return fmt.Errorf("error creating l2 genesis: %w", err)
+ }
+
+ // Write changes to state to actual state database
+ cel2Header, err := applyStateMigrationChanges(config, l2Genesis.Alloc, newDBPath, opts.outfileGenesis, opts.migrationBlockTime, l1StartBlock)
+ if err != nil {
+ return err
+ }
+ log.Info("Updated Cel2 state")
+
+ rollupConfig, err := config.RollupConfig(l1StartBlock.Header(), cel2Header.Hash(), cel2Header.Number.Uint64())
+ if err != nil {
+ return err
+ }
+ if err := rollupConfig.Check(); err != nil {
+ return fmt.Errorf("generated rollup config does not pass validation: %w", err)
+ }
+
+ log.Info("Writing rollup config", "file", opts.outfileRollupConfig)
+ if err := jsonutil.WriteJSON(rollupConfig, ioutil.ToStdOutOrFileOrNoop(opts.outfileRollupConfig, OutFilePerm)); err != nil {
+ return err
+ }
+
+ log.Info("State Migration Completed")
+
+ return nil
+}
+
+func runDBCheck(opts dbCheckOptions) (err error) {
+ defer timer("db continuity check")()
+
+ log.Info("DB Continuity Check Started", "dbPath", opts.dbPath)
+
+ ancientDB, err := NewChainFreezer(filepath.Join(opts.dbPath, "ancient"), "", true)
+ if err != nil {
+ return fmt.Errorf("failed to open ancient db: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, ancientDB.Close())
+ }()
+ nonAncientDB, err := openDBWithoutFreezer(opts.dbPath, true)
+ if err != nil {
+ return fmt.Errorf("failed to open non-ancient db: %w", err)
+ }
+ defer func() {
+ err = errors.Join(err, nonAncientDB.Close())
+ }()
+
+ lastAncient, err := loadLastAncient(ancientDB)
+ if err != nil {
+ return fmt.Errorf("failed to load last ancient block: %w", err)
+ }
+ lastAncientNumber := lastAncient.Number()
+ lastBlockNumber := *rawdb.ReadHeaderNumber(nonAncientDB, rawdb.ReadHeadHeaderHash(nonAncientDB))
+
+ var errResult *multierror.Error
+
+ // First, check continuity between ancients and non-ancients.
+ // Gaps in data will often halt the freezing process, so attempting to load the first non-ancient block
+ // will most likely fail if there is a gap.
+ firstNonAncientRange, err := loadNonAncientRange(nonAncientDB, lastAncientNumber+1, 1)
+ if err != nil {
+ if opts.failFast {
+ return fmt.Errorf("failed to load first non-ancient block: %w", err)
+ }
+ // We don't need to add the error to errResult here because it will be added below when we call checkContinuity on non-ancients
+ } else {
+ if _, err := firstNonAncientRange.CheckContinuity(lastAncient, 1); err != nil {
+ err = fmt.Errorf("failed continuity check between ancients and non-ancients: %w", err)
+ if opts.failFast {
+ return err
+ }
+ errResult = multierror.Append(errResult, err)
+ }
+ }
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ g, ctx := errgroup.WithContext(ctx)
+ // Use double the CPUs to account for the fact that each routine will block while reading from the db.
+ g.SetLimit(runtime.NumCPU() * 2)
+
+ var mu sync.Mutex
+
+ checkRange := func(start, count uint64, loadRangeFunc func(uint64, uint64) (*RLPBlockRange, error)) {
+ // If we are not at genesis or the first non-ancient block, include the last block of
+ // the previous range so we can check for continuity between ranges.
+ if start != 0 && start != lastAncientNumber+1 {
+ start = start - 1
+ count = count + 1
+ }
+ g.Go(func() error {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ blockRange, err := loadRangeFunc(start, count)
+ if err != nil {
+ err = fmt.Errorf("failed to load block range: %w", err)
+ if opts.failFast {
+ return err
+ }
+ log.Error(err.Error())
+ mu.Lock()
+ errResult = multierror.Append(errResult, err)
+ mu.Unlock()
+ return nil
+ }
+ if _, err := blockRange.CheckContinuity(nil, count); err != nil {
+ err = fmt.Errorf("failed continuity check: %w", err)
+ if opts.failFast {
+ return err
+ }
+ log.Error(err.Error())
+ mu.Lock()
+ errResult = multierror.Append(errResult, err)
+ mu.Unlock()
+ return nil
+ }
+ log.Info("Successfully checked block range continuity", "start", start, "end", start+count-1, "count", count)
+ return nil
+ }
+ })
+ }
+ checkContinuity := func(start, end uint64, loadRangeFunc func(uint64, uint64) (*RLPBlockRange, error)) error {
+ if (start <= lastAncientNumber && end > lastAncientNumber) || (end > lastBlockNumber) || (end < start) {
+ return fmt.Errorf("invalid range for continuity check: start=%d, end=%d, lastAncientNumber=%d, lastBlockNumber=%d", start, end, lastAncientNumber, lastBlockNumber)
+ }
+ for i := start; i <= end; i += opts.batchSize {
+ count := min(opts.batchSize, end-i+1)
+ checkRange(i, count, loadRangeFunc)
+ }
+ return nil
+ }
+
+ log.Info("Checking continuity of ancient blocks", "start", 0, "end", lastAncientNumber, "count", lastAncientNumber+1)
+ if err := checkContinuity(0, lastAncientNumber, func(start, count uint64) (*RLPBlockRange, error) {
+ return loadAncientRange(ancientDB, start, count)
+ }); err != nil {
+ return err
+ }
+ log.Info("Checking continuity of non-ancient blocks", "start", lastAncientNumber+1, "end", lastBlockNumber, "count", lastBlockNumber-lastAncientNumber)
+ if err := checkContinuity(lastAncientNumber+1, lastBlockNumber, func(start, count uint64) (*RLPBlockRange, error) {
+ return loadNonAncientRange(nonAncientDB, start, count)
+ }); err != nil {
+ return err
+ }
+
+ if err := g.Wait(); err != nil {
+ return err
+ }
+
+ if errResult.ErrorOrNil() != nil {
+ return errResult
+ }
+
+ log.Info("DB Continuity Check Finished", "dbPath", opts.dbPath)
+
+ return nil
+}
+
+func timer(name string) func() {
+ start := time.Now()
+ return func() {
+ log.Info("TIMER", "process", name, "duration", time.Since(start))
+ }
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/non-ancients.go CELO/op-chain-ops/cmd/celo-migrate/non-ancients.go
new file mode 100644
index 0000000000000000000000000000000000000000..9473edbe5a3aacdefba9ab2d3d01f195bd95bbeb
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/non-ancients.go
@@ -0,0 +1,196 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/log"
+)
+
+func copyDbExceptAncients(oldDbPath, newDbPath string) error {
+ defer timer("copyDbExceptAncients")()
+
+ log.Info("Copying files from old database (excluding ancients)", "process", "non-ancients")
+
+ // Get rsync help output
+ cmdHelp := exec.Command("rsync", "--help")
+ output, err := cmdHelp.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("failed to get rsync help output: %w", err)
+ }
+
+ // Convert output to string
+ outputStr := string(output)
+
+ opts := []string{"-v", "-a", "--exclude=ancient", "--checksum", "--delete"}
+
+ // Check for supported options
+ // Prefer --info=progress2 over --progress
+ if strings.Contains(outputStr, "--info") {
+ opts = append(opts, "--info=progress2")
+ } else if strings.Contains(outputStr, "--progress") {
+ opts = append(opts, "--progress")
+ }
+
+ cmd := exec.Command("rsync", append(opts, oldDbPath+"/", newDbPath)...)
+
+ // rsync copies any file with a different timestamp or size.
+ //
+ // '--exclude=ancient' excludes the ancient directory from the copy
+ //
+ // '--delete' Tells rsync to delete extraneous files from the receiving side (ones that aren’t on the sending side)
+ //
+ // '-a' archive mode; equals -rlptgoD. It is a quick way of saying you want recursion and want to preserve almost everything, including timestamps, ownerships, permissions, etc.
+ // Timestamps are important here because they are used to determine which files are newer and should be copied over.
+ //
+ // '--whole-file' This is the default when both the source and destination are specified as local paths, which they are here (oldDbPath and newDbPath).
+ // This option disables rsync’s delta-transfer algorithm, which causes all transferred files to be sent whole. The delta-transfer algorithm is normally used when the destination is a remote system.
+ //
+ // '--checksum' This forces rsync to compare the checksums of all files to determine if they are the same. This is slows down the transfer but ensures that source and destination directories end up with the same contents (excluding /ancients).
+
+ log.Info("Running rsync command", "command", cmd.String())
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ return fmt.Errorf("failed to copy old database to new database: %w", err)
+ }
+ return nil
+}
+
+func migrateNonAncientsDb(newDB ethdb.Database, lastBlock, numAncients, batchSize uint64) (uint64, error) {
+ defer timer("migrateNonAncientsDb")()
+
+ // Delete bad blocks, we could migrate them, but we have no need of the historical bad blocks. AFAICS bad blocks
+ // are stored solely so that they can be retrieved or traced via the debug API, but we are no longer interested
+ // in these old bad blocks.
+ rawdb.DeleteBadBlocks(newDB)
+
+ // The genesis block is the only block that should remain stored in the non-ancient db even after it is frozen.
+ if numAncients > 0 {
+ log.Info("Migrating genesis block in non-ancient db", "process", "non-ancients")
+ if err := migrateNonAncientBlock(0, rawdb.ReadCanonicalHash(newDB, 0), newDB); err != nil {
+ return 0, err
+ }
+ }
+
+ for i := numAncients; i <= lastBlock; i += batchSize {
+ numbersHash := rawdb.ReadAllHashesInRange(newDB, i, i+batchSize-1)
+
+ log.Info("Processing Block Range", "process", "non-ancients", "from", i, "to(inclusve)", i+batchSize-1, "count", len(numbersHash))
+ for _, numberHash := range numbersHash {
+ if err := migrateNonAncientBlock(numberHash.Number, numberHash.Hash, newDB); err != nil {
+ return 0, err
+ }
+ }
+ }
+
+ migratedCount := lastBlock - numAncients + 1
+ return migratedCount, nil
+}
+
+func migrateNonAncientBlock(number uint64, hash common.Hash, newDB ethdb.Database) error {
+ // read header and body
+ header := rawdb.ReadHeaderRLP(newDB, hash, number)
+ body := rawdb.ReadBodyRLP(newDB, hash, number)
+
+ // transform header and body
+ newHeader, err := transformHeader(header)
+ if err != nil {
+ return fmt.Errorf("failed to transform header: block %d - %x: %w", number, hash, err)
+ }
+ newBody, err := transformBlockBody(body)
+ if err != nil {
+ return fmt.Errorf("failed to transform body: block %d - %x: %w", number, hash, err)
+ }
+
+ if yes, newHash := hasSameHash(newHeader, hash[:]); !yes {
+ log.Error("Hash mismatch", "block", number, "oldHash", hash, "newHash", newHash)
+ return fmt.Errorf("hash mismatch at block %d - %x", number, hash)
+ }
+
+ // write header and body
+ batch := newDB.NewBatch()
+ rawdb.WriteBodyRLP(batch, hash, number, newBody)
+ if err := batch.Put(headerKey(number, hash), newHeader); err != nil {
+ return fmt.Errorf("failed to write header: block %d - %x: %w", number, hash, err)
+ }
+ if err := batch.Write(); err != nil {
+ return fmt.Errorf("failed to write header and body: block %d - %x: %w", number, hash, err)
+ }
+
+ return nil
+}
+
+func loadNonAncientRange(db ethdb.Database, start, count uint64) (*RLPBlockRange, error) {
+ blockRange := &RLPBlockRange{
+ start: start,
+ hashes: make([][]byte, count),
+ headers: make([][]byte, count),
+ bodies: make([][]byte, count),
+ receipts: make([][]byte, count),
+ tds: make([][]byte, count),
+ }
+ end := start + count - 1
+ log.Info("Loading non-ancient block range", "start", start, "end", end, "count", count)
+ numberHashes := rawdb.ReadAllHashesInRange(db, start, end)
+ err := checkNumberHashes(db, numberHashes)
+ if err != nil {
+ return nil, err
+ }
+
+ var combinedErr error
+
+ for i, numberHash := range numberHashes {
+ number := numberHash.Number
+ hash := numberHash.Hash
+
+ blockRange.hashes[i] = hash[:]
+ blockRange.headers[i], err = db.Get(headerKey(number, hash))
+ if err != nil {
+ combinedErr = errors.Join(combinedErr, fmt.Errorf("failed to find header in db for non-ancient block %d - %x: %w", number, hash, err))
+ }
+ blockRange.bodies[i], err = db.Get(blockBodyKey(number, hash))
+ if err != nil {
+ combinedErr = errors.Join(combinedErr, fmt.Errorf("failed to find body in db for non-ancient block %d - %x: %w", number, hash, err))
+ }
+ blockRange.receipts[i], err = db.Get(blockReceiptsKey(number, hash))
+ if err != nil {
+ combinedErr = errors.Join(combinedErr, fmt.Errorf("failed to find receipts in db for non-ancient block %d - %x: %w", number, hash, err))
+ }
+ blockRange.tds[i], err = db.Get(headerTDKey(number, hash))
+ if err != nil {
+ combinedErr = errors.Join(combinedErr, fmt.Errorf("failed to find total difficulty in db for non-ancient block %d - %x: %w", number, hash, err))
+ }
+ }
+
+ return blockRange, combinedErr
+}
+
+// checkNumberHashes checks that the contents of a NumberHash slice match the contents in the headerNumber and headerHash db tables.
+// We do this to account for any differences in the way NumberHashes are read from the db, and to ensure the slice only contains canonical data.
+func checkNumberHashes(db ethdb.Database, numberHashes []*rawdb.NumberHash) error {
+ for _, numberHash := range numberHashes {
+ numberRLP, err := db.Get(headerNumberKey(numberHash.Hash))
+ if err != nil {
+ return fmt.Errorf("failed to find number for hash in db for non-ancient block %d - %x: %w", numberHash.Number, numberHash.Hash, err)
+ }
+ hashRLP, err := db.Get(headerHashKey(numberHash.Number))
+ if err != nil {
+ return fmt.Errorf("failed to find canonical hash in db for non-ancient block %d - %x: %w", numberHash.Number, numberHash.Hash, err)
+ }
+ if !bytes.Equal(hashRLP, numberHash.Hash[:]) {
+ return fmt.Errorf("canonical hash mismatch in db for non-ancient block %d - %x: %w", numberHash.Number, numberHash.Hash, err)
+ }
+ if !bytes.Equal(numberRLP, encodeBlockNumber(numberHash.Number)) {
+ return fmt.Errorf("number for hash mismatch in db for non-ancient block %d - %x: %w", numberHash.Number, numberHash.Hash, err)
+ }
+ }
+ return nil
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/state.go CELO/op-chain-ops/cmd/celo-migrate/state.go
new file mode 100644
index 0000000000000000000000000000000000000000..74e6683d3bf86bea59d403334b2ed6bbcf0c5d0c
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/state.go
@@ -0,0 +1,460 @@
+package main
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math/big"
+ "os"
+
+ "github.com/ethereum-optimism/optimism/op-chain-ops/genesis"
+ "github.com/ethereum-optimism/optimism/op-service/ioutil"
+ "github.com/ethereum-optimism/optimism/op-service/jsonutil"
+ "github.com/ethereum-optimism/optimism/op-service/predeploys"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
+ "github.com/ethereum/go-ethereum/contracts/addresses"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/ethdb"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/trie"
+
+ "github.com/holiman/uint256"
+)
+
+const (
+ MainnetNetworkID = uint64(42220)
+ BaklavaNetworkID = uint64(62320)
+ AlfajoresNetworkID = uint64(44787)
+
+ OutFilePerm = os.FileMode(0o440)
+)
+
+var (
+ Big10 = uint256.NewInt(10)
+ Big9 = uint256.NewInt(9)
+ Big18 = uint256.NewInt(18)
+
+ // Allowlist of accounts that are allowed to be overwritten
+ // If the value for an account is set to true, the nonce and storage will be overwritten
+ // This must be checked for each account, as this might create issues with contracts
+ // calling `CREATE` or `CREATE2`
+ accountOverwriteAllowlist = map[uint64]map[common.Address]bool{
+ // Add any addresses that should be allowed to overwrite existing accounts here.
+ AlfajoresNetworkID: {
+ // Create2Deployer
+ // OP uses a version without an owner who can pause the contract,
+ // so we overwrite the existing contract during migration
+ common.HexToAddress("0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"): true,
+
+ // Same code as in allocs file
+ // EntryPoint_v070
+ common.HexToAddress("0x0000000071727De22E5E9d8BAf0edAc6f37da032"): false,
+ // Permit2
+ common.HexToAddress("0x000000000022D473030F116dDEE9F6B43aC78BA3"): false,
+ // EntryPoint_v060
+ common.HexToAddress("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"): false,
+ // DeterministicDeploymentProxy
+ common.HexToAddress("0x4e59b44847b379578588920cA78FbF26c0B4956C"): false,
+ // SafeL2_v130
+ common.HexToAddress("0xfb1bffC9d739B8D520DaF37dF666da4C687191EA"): false,
+ // MultiSend_v130
+ common.HexToAddress("0x998739BFdAAdde7C933B942a68053933098f9EDa"): false,
+ // SenderCreator_v070
+ common.HexToAddress("0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C"): false,
+ // SenderCreator_v060
+ common.HexToAddress("0x7fc98430eAEdbb6070B35B39D798725049088348"): false,
+ // MultiCall3
+ common.HexToAddress("0xcA11bde05977b3631167028862bE2a173976CA11"): false,
+ // Safe_v130
+ common.HexToAddress("0x69f4D1788e39c87893C980c06EdF4b7f686e2938"): false,
+ // MultiSendCallOnly_v130
+ common.HexToAddress("0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B"): false,
+ // SafeSingletonFactory
+ common.HexToAddress("0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7"): false,
+ // CreateX
+ common.HexToAddress("0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed"): false,
+ },
+ BaklavaNetworkID: {
+ // DeterministicDeploymentProxy
+ common.HexToAddress("0x4e59b44847b379578588920cA78FbF26c0B4956C"): false,
+ },
+ }
+ unreleasedTreasuryAddressMap = map[uint64]common.Address{
+ AlfajoresNetworkID: common.HexToAddress("0x07bf0b2461A0cb608D5CF9a82ba97dAbA850F79F"),
+ BaklavaNetworkID: common.HexToAddress("0x022c5d5837E177B6d145761feb4C5574e5b48F5e"),
+ }
+ celoTokenAddressMap = map[uint64]common.Address{
+ AlfajoresNetworkID: addresses.AlfajoresAddresses.CeloToken,
+ BaklavaNetworkID: addresses.BaklavaAddresses.CeloToken,
+ MainnetNetworkID: addresses.MainnetAddresses.CeloToken,
+ }
+)
+
+func applyStateMigrationChanges(config *genesis.DeployConfig, l2Allocs types.GenesisAlloc, dbPath, genesisOutPath string, migrationBlockTime uint64, l1StartBlock *types.Block) (*types.Header, error) {
+ log.Info("Opening Celo database", "dbPath", dbPath)
+
+ ldb, err := openDBWithoutFreezer(dbPath, false)
+ if err != nil {
+ return nil, fmt.Errorf("cannot open DB: %w", err)
+ }
+ log.Info("Loaded Celo L1 DB", "db", ldb)
+
+ // Grab the hash of the tip of the legacy chain.
+ hash := rawdb.ReadHeadHeaderHash(ldb)
+ log.Info("Reading chain tip from database", "hash", hash)
+
+ // Grab the header number.
+ num := rawdb.ReadHeaderNumber(ldb, hash)
+ if num == nil {
+ return nil, fmt.Errorf("cannot find header number for %s", hash)
+ }
+ log.Info("Reading chain tip num from database", "number", *num)
+
+ // Grab the full header.
+ header := rawdb.ReadHeader(ldb, hash, *num)
+ log.Info("Read header from database", "header", header)
+
+ // We need to update the chain config to set the correct hardforks.
+ genesisHash := rawdb.ReadCanonicalHash(ldb, 0)
+ cfg := rawdb.ReadChainConfig(ldb, genesisHash)
+ if cfg == nil {
+ log.Crit("chain config not found")
+ }
+ log.Info("Read chain config from database", "config", cfg)
+
+ // Set up the backing store.
+ underlyingDB := state.NewDatabase(ldb)
+
+ // Open up the state database.
+ db, err := state.New(header.Root, underlyingDB, nil)
+ if err != nil {
+ return nil, fmt.Errorf("cannot open StateDB: %w", err)
+ }
+
+ // Apply the changes to the state DB.
+ err = applyAllocsToState(db, l2Allocs, accountOverwriteAllowlist[cfg.ChainID.Uint64()])
+ if err != nil {
+ return nil, fmt.Errorf("cannot apply allocations to state: %w", err)
+ }
+
+ // Initialize the unreleased treasury contract
+ // This uses the original config which won't enable recent hardforks (and things like the PUSH0 opcode)
+ // This is fine, as the token uses solc 0.5.x and therefore compatible bytecode
+ err = setupUnreleasedTreasury(db, cfg)
+ if err != nil {
+ // An error here shouldn't stop the migration, just log it
+ log.Warn("Error setting up unreleased treasury", "error", err)
+ }
+
+ migrationBlockNumber := new(big.Int).Add(header.Number, common.Big1)
+
+ // We're done messing around with the database, so we can now commit the changes to the DB.
+ // Note that this doesn't actually write the changes to disk.
+ log.Info("Committing state DB")
+ newRoot, err := db.Commit(migrationBlockNumber.Uint64(), true)
+ if err != nil {
+ return nil, err
+ }
+
+ // Set the standard options.
+ cfg.LondonBlock = migrationBlockNumber
+ cfg.BerlinBlock = migrationBlockNumber
+ cfg.ArrowGlacierBlock = migrationBlockNumber
+ cfg.GrayGlacierBlock = migrationBlockNumber
+ cfg.MergeNetsplitBlock = migrationBlockNumber
+ cfg.TerminalTotalDifficulty = big.NewInt(0)
+ cfg.TerminalTotalDifficultyPassed = true
+ cfg.ShanghaiTime = &migrationBlockTime
+ cfg.CancunTime = &migrationBlockTime
+
+ // Set the Optimism options.
+ cfg.Optimism = ¶ms.OptimismConfig{
+ EIP1559Denominator: config.EIP1559Denominator,
+ EIP1559DenominatorCanyon: &config.EIP1559DenominatorCanyon,
+ EIP1559Elasticity: config.EIP1559Elasticity,
+ }
+
+ // Set the Celo options.
+ cfg.Celo = ¶ms.CeloConfig{
+ EIP1559BaseFeeFloor: config.EIP1559BaseFeeFloor,
+ }
+
+ // Set Optimism hardforks
+ cfg.BedrockBlock = migrationBlockNumber
+ cfg.RegolithTime = &migrationBlockTime
+ cfg.CanyonTime = &migrationBlockTime
+ cfg.EcotoneTime = &migrationBlockTime
+ cfg.FjordTime = &migrationBlockTime
+ cfg.GraniteTime = &migrationBlockTime
+ cfg.Cel2Time = &migrationBlockTime
+
+ // Calculate the base fee for the migration block.
+ baseFee := new(big.Int).SetUint64(params.InitialBaseFee)
+ if header.BaseFee != nil {
+ baseFee = eip1559.CalcBaseFee(cfg, header, migrationBlockTime)
+ }
+
+ // If gas limit was zero at the transition point use a default of 30M.
+ // Note that in op-geth we use gasLimit==0 to indicate a pre-gingerbread
+ // block and adjust encoding appropriately, so we must make sure that
+ // gasLimit is non-zero, because L2 blocks are all post gingerbread.
+ gasLimit := header.GasLimit
+ if gasLimit == 0 {
+ gasLimit = 30e6
+ }
+ // Create the header for the Cel2 transition block.
+ cel2Header := &types.Header{
+ ParentHash: header.Hash(),
+ UncleHash: types.EmptyUncleHash,
+ Coinbase: predeploys.SequencerFeeVaultAddr,
+ Root: newRoot,
+ TxHash: types.EmptyTxsHash,
+ ReceiptHash: types.EmptyReceiptsHash,
+ Bloom: types.Bloom{},
+ Difficulty: new(big.Int).Set(common.Big0),
+ Number: migrationBlockNumber,
+ GasLimit: gasLimit,
+ GasUsed: 0,
+ Time: migrationBlockTime,
+ Extra: []byte("Celo L2 migration"),
+ MixDigest: common.Hash{},
+ Nonce: types.BlockNonce{},
+ BaseFee: baseFee,
+ // Added during Shanghai hardfork
+ // As there're no withdrawals in L2, we set it to the empty hash
+ WithdrawalsHash: &types.EmptyWithdrawalsHash,
+ // Blobs are disabled in L2
+ BlobGasUsed: new(uint64),
+ ExcessBlobGas: new(uint64),
+ // This is set to the ParentBeaconRoot of the L1 origin (see `PreparePayloadAttributes`)
+ // Use the L1 start block's ParentBeaconRoot
+ ParentBeaconRoot: l1StartBlock.Header().ParentBeaconRoot,
+ }
+ log.Info("Build Cel2 migration header", "header", cel2Header)
+
+ // We need to set empty withdrawals in the body, otherwise types.NewBlock will nullify the withdrawals hash in the given header.
+ b := &types.Body{
+ Withdrawals: []*types.Withdrawal{},
+ }
+ // Create the Cel2 transition block from the header. Note that there are no transactions,
+ // uncle blocks, or receipts in the Cel2 transition block.
+ cel2Block := types.NewBlock(cel2Header, b, nil, trie.NewStackTrie(nil))
+
+ // We did it!
+ log.Info(
+ "Built Cel2 migration block",
+ "hash", cel2Block.Hash(),
+ "root", cel2Block.Root(),
+ "number", cel2Block.NumberU64(),
+ )
+
+ log.Info("Committing trie DB")
+ if err := db.Database().TrieDB().Commit(newRoot, true); err != nil {
+ return nil, err
+ }
+
+ // Next we write the Cel2 migration block to the database.
+ rawdb.WriteTd(ldb, cel2Block.Hash(), cel2Block.NumberU64(), cel2Block.Difficulty())
+ rawdb.WriteBlock(ldb, cel2Block)
+ rawdb.WriteReceipts(ldb, cel2Block.Hash(), cel2Block.NumberU64(), nil)
+ rawdb.WriteCanonicalHash(ldb, cel2Block.Hash(), cel2Block.NumberU64())
+ rawdb.WriteHeadBlockHash(ldb, cel2Block.Hash())
+ rawdb.WriteHeadFastBlockHash(ldb, cel2Block.Hash())
+ rawdb.WriteHeadHeaderHash(ldb, cel2Block.Hash())
+
+ // Mark the first CeL2 block as finalized
+ rawdb.WriteFinalizedBlockHash(ldb, cel2Block.Hash())
+
+ // Write the chain config to disk.
+ rawdb.WriteChainConfig(ldb, genesisHash, cfg)
+ marshalledConfig, err := json.Marshal(cfg)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal chain config to JSON: %w", err)
+ }
+ log.Info("Wrote updated chain config", "config", string(marshalledConfig))
+
+ // Write genesis JSON to outfile and store genesis state spec in the database.
+ if err = writeGenesis(cfg, ldb, genesisOutPath, genesisHash); err != nil {
+ return nil, err
+ }
+
+ // We're done!
+ log.Info(
+ "Wrote CeL2 migration block",
+ "height", cel2Header.Number,
+ "root", cel2Header.Root.String(),
+ "hash", cel2Header.Hash().String(),
+ "timestamp", cel2Header.Time,
+ )
+
+ // Close the database handle
+ if err := ldb.Close(); err != nil {
+ return nil, err
+ }
+
+ return cel2Header, nil
+}
+
+// applyAllocsToState applies the account allocations from the allocation file to the state database.
+// It creates new accounts, sets their nonce, balance, code, and storage values.
+// If an account already exists, it adds the balance of the new account to the existing balance.
+// If the code of an existing account is different from the code in the genesis block, it logs a warning.
+// This changes the state root, so `Commit` needs to be called after this function.
+func applyAllocsToState(db vm.StateDB, allocs types.GenesisAlloc, allowlist map[common.Address]bool) error {
+ log.Info("Starting to migrate OP contracts into state DB")
+
+ copyCounter := 0
+ overwriteCounter := 0
+
+ for k, v := range allocs {
+ // Check that the balance of the account to written is zero,
+ // as we must not create new CELO tokens
+ if v.Balance != nil && v.Balance.Cmp(big.NewInt(0)) != 0 {
+ return fmt.Errorf("account balance is not zero, would change celo supply: %s", k.Hex())
+ }
+
+ if db.Exist(k) {
+ writeNonceAndStorage := false
+ writeCode, allowed := allowlist[k]
+
+ // If the account is not allowed and has a non zero nonce or code size, bail out we will need to manually investigate how to handle this.
+ if !allowed && (db.GetCodeSize(k) > 0 || db.GetNonce(k) > 0) {
+ return fmt.Errorf("account exists and is not allowed, account: %s, nonce: %d, code: %d", k.Hex(), db.GetNonce(k), db.GetCode(k))
+ }
+
+ // This means that the account just has balance, in that case we wan to copy over the account
+ if db.GetCodeSize(k) == 0 && db.GetNonce(k) == 0 {
+ writeCode = true
+ writeNonceAndStorage = true
+ }
+
+ if writeCode {
+ overwriteCounter++
+
+ db.SetCode(k, v.Code)
+
+ if writeNonceAndStorage {
+ db.SetNonce(k, v.Nonce)
+ for key, value := range v.Storage {
+ db.SetState(k, key, value)
+ }
+ }
+ log.Info("Overwrote account", "address", k.Hex(), "writeNonceAndStorage", writeNonceAndStorage)
+ }
+ continue
+ }
+
+ // Account does not exist, create it
+ db.CreateAccount(k)
+ db.SetCode(k, v.Code)
+ db.SetNonce(k, v.Nonce)
+ for key, value := range v.Storage {
+ db.SetState(k, key, value)
+ }
+
+ copyCounter++
+ log.Info("Copied account", "address", k.Hex())
+ }
+
+ log.Info("Migrated OP contracts into state DB", "totalAllocs", len(allocs), "copiedAccounts", copyCounter, "overwrittenAccounts", overwriteCounter)
+ return nil
+}
+
+// setupUnreleasedTreasury sets up the unreleased treasury contract with the correct balance
+// The balance is set to the difference between the ceiling and the total supply of the token
+func setupUnreleasedTreasury(db *state.StateDB, config *params.ChainConfig) error {
+ log.Info("Setting up CeloUnreleasedTreasury balance")
+
+ celoUnreleasedTreasuryAddress, exists := unreleasedTreasuryAddressMap[config.ChainID.Uint64()]
+ if !exists {
+ return errors.New("CeloUnreleasedTreasury address not configured for this chain, skipping migration step")
+ }
+
+ if !db.Exist(celoUnreleasedTreasuryAddress) {
+ return errors.New("CeloUnreleasedTreasury account does not exist, skipping migration step")
+ }
+
+ tokenAddress, exists := celoTokenAddressMap[config.ChainID.Uint64()]
+ if !exists {
+ return errors.New("celo token address not configured for this chain, skipping migration step")
+ }
+ log.Info("Read contract addresses", "tokenAddress", tokenAddress, "celoUnreleasedTreasuryAddress", celoUnreleasedTreasuryAddress)
+
+ // totalSupply is stored in the third slot
+ totalSupply := db.GetState(tokenAddress, common.HexToHash("0x02")).Big()
+
+ // Get total supply of celo token
+ billion := new(uint256.Int).Exp(Big10, Big9)
+ ethInWei := new(uint256.Int).Exp(Big10, Big18)
+
+ ceiling := new(uint256.Int).Mul(billion, ethInWei)
+
+ supplyU256 := uint256.MustFromBig(totalSupply)
+ if supplyU256.Cmp(ceiling) > 0 {
+ return fmt.Errorf("supply %s is greater than ceiling %s", totalSupply, ceiling)
+ }
+
+ balance := new(uint256.Int).Sub(ceiling, supplyU256)
+ // Don't discard existing balance of the account
+ balance = new(uint256.Int).Add(balance, db.GetBalance(celoUnreleasedTreasuryAddress))
+ db.SetBalance(celoUnreleasedTreasuryAddress, balance, tracing.BalanceChangeUnspecified)
+
+ log.Info("Set up CeloUnreleasedTreasury balance", "celoUnreleasedTreasuryAddress", celoUnreleasedTreasuryAddress, "balance", balance, "total_supply", supplyU256, "ceiling", ceiling)
+ return nil
+}
+
+// writeGenesis writes the genesis json to --outfile.genesis and stores the genesis state spec (alloc) in the database.
+// Note that this is different than the cel2Block / migration block. Rather, this is the migrated genesis block of Celo from before the L2 transition.
+// Nodes will need the genesis json file in order to snap sync on the L2 chain.
+func writeGenesis(config *params.ChainConfig, db ethdb.Database, genesisOutPath string, genesisHash common.Hash) error {
+ // Derive the genesis object using hardcoded legacy alloc and the transformed extra data stored in the new db.
+ legacyGenesisAlloc, err := GetCeloL1GenesisAlloc(config)
+ if err != nil {
+ return err
+ }
+ genesisHeader := rawdb.ReadHeader(db, genesisHash, 0)
+ genesis, err := BuildGenesis(config, legacyGenesisAlloc, genesisHeader.Extra, genesisHeader.Time)
+ if err != nil {
+ return err
+ }
+
+ // Convert genesis to JSON byte slice
+ genesisBytes, err := json.Marshal(genesis)
+ if err != nil {
+ return fmt.Errorf("failed to marshal genesis to JSON: %w", err)
+ }
+
+ // Unmarshal JSON byte slice to map
+ var genesisMap map[string]interface{}
+ if err := json.Unmarshal(genesisBytes, &genesisMap); err != nil {
+ return fmt.Errorf("failed to unmarshal genesis JSON to map: %w", err)
+ }
+
+ // Delete fields that are not in Celo Legacy Genesis, otherwise genesis hashes won't match when syncing
+ delete(genesisMap, "difficulty")
+ delete(genesisMap, "gasLimit")
+ delete(genesisMap, "excessBlobGas")
+ delete(genesisMap, "blobGasUsed")
+ delete(genesisMap, "baseFeePerGas")
+ delete(genesisMap, "mixHash")
+ delete(genesisMap, "nonce")
+
+ // Write the modified JSON to the file
+ if err := jsonutil.WriteJSON(genesisMap, ioutil.ToStdOutOrFileOrNoop(genesisOutPath, OutFilePerm)); err != nil {
+ return fmt.Errorf("failed to write genesis JSON to file: %w", err)
+ }
+ log.Info("Wrote genesis file for syncing new nodes", "path", genesisOutPath)
+
+ // Legacy Celo did not store the genesis state spec (alloc) in the database.
+ // Write it now for forward compatibility.
+ rawdb.WriteGenesisStateSpec(db, genesisHash, legacyGenesisAlloc)
+ log.Info("Wrote genesis state spec (alloc) to database")
+
+ return nil
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/state_test.go CELO/op-chain-ops/cmd/celo-migrate/state_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..dbe6ce90ef4e51f31ade77933a6656b94dcad98a
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/state_test.go
@@ -0,0 +1,147 @@
+package main
+
+import (
+ "bytes"
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/holiman/uint256"
+ "github.com/stretchr/testify/assert"
+)
+
+var (
+ contractCode = []byte{0x01, 0x02}
+ defaultBalance int64 = 123
+ address = common.HexToAddress("a")
+)
+
+func TestApplyAllocsToState(t *testing.T) {
+ tests := []struct {
+ name string
+ existingAccount *types.Account
+ newAccount types.Account
+ allowlist map[common.Address]bool
+ wantErr bool
+ }{
+ {
+ name: "Write to empty account",
+ newAccount: types.Account{
+ Code: contractCode,
+ Nonce: 1,
+ },
+ wantErr: false,
+ },
+ {
+ name: "Copy account with non-zero balance fails",
+ existingAccount: &types.Account{
+ Balance: big.NewInt(defaultBalance),
+ },
+ newAccount: types.Account{
+ Balance: big.NewInt(1),
+ },
+ wantErr: true,
+ },
+ {
+ name: "Write to account with only balance should overwrite and keep balance",
+ existingAccount: &types.Account{
+ Balance: big.NewInt(defaultBalance),
+ },
+ newAccount: types.Account{
+ Code: contractCode,
+ Nonce: 5,
+ },
+ wantErr: false,
+ },
+ {
+ name: "Write to account with existing nonce fails",
+ existingAccount: &types.Account{
+ Balance: big.NewInt(defaultBalance),
+ Nonce: 5,
+ },
+ newAccount: types.Account{
+ Code: contractCode,
+ Nonce: 5,
+ },
+ wantErr: true,
+ },
+ {
+ name: "Write to account with contract code fails",
+ existingAccount: &types.Account{
+ Balance: big.NewInt(defaultBalance),
+ Code: bytes.Repeat([]byte{0x01}, 10),
+ },
+ newAccount: types.Account{
+ Code: contractCode,
+ Nonce: 5,
+ },
+ wantErr: true,
+ },
+ {
+ name: "Write account with allowlist overwrite, keeps nonce",
+ existingAccount: &types.Account{
+ Balance: big.NewInt(defaultBalance),
+ Nonce: 4,
+ Code: bytes.Repeat([]byte{0x01}, 10),
+ },
+ newAccount: types.Account{
+ Code: contractCode,
+ Nonce: 5,
+ },
+ allowlist: map[common.Address]bool{address: true},
+ wantErr: false,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ db := rawdb.NewMemoryDatabase()
+ tdb := state.NewDatabase(db)
+ sdb, _ := state.New(types.EmptyRootHash, tdb, nil)
+
+ if tt.existingAccount != nil {
+ sdb.CreateAccount(address)
+
+ if tt.existingAccount.Balance != nil {
+ sdb.SetBalance(address, uint256.MustFromBig(tt.existingAccount.Balance), tracing.BalanceChangeUnspecified)
+ }
+ if tt.existingAccount.Nonce != 0 {
+ sdb.SetNonce(address, tt.existingAccount.Nonce)
+ }
+ if tt.existingAccount.Code != nil {
+ sdb.SetCode(address, tt.existingAccount.Code)
+ }
+ }
+
+ if err := applyAllocsToState(sdb, types.GenesisAlloc{address: tt.newAccount}, tt.allowlist); (err != nil) != tt.wantErr {
+ t.Errorf("applyAllocsToState() error = %v, wantErr %v", err, tt.wantErr)
+ }
+
+ // Don't check account state if an error was thrown
+ if tt.wantErr {
+ return
+ }
+
+ if !sdb.Exist(address) {
+ t.Errorf("account does not exists as expected: %v", address.Hex())
+ }
+
+ assert.Equal(t, tt.newAccount.Code, sdb.GetCode(address))
+
+ if tt.existingAccount != nil && tt.existingAccount.Nonce != 0 {
+ assert.Equal(t, tt.existingAccount.Nonce, sdb.GetNonce(address))
+ } else {
+ assert.Equal(t, tt.newAccount.Nonce, sdb.GetNonce(address))
+ }
+
+ if tt.existingAccount != nil {
+ assert.True(t, big.NewInt(defaultBalance).Cmp(sdb.GetBalance(address).ToBig()) == 0)
+ } else {
+ assert.True(t, big.NewInt(0).Cmp(sdb.GetBalance(address).ToBig()) == 0)
+ }
+ })
+ }
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/transform.go CELO/op-chain-ops/cmd/celo-migrate/transform.go
new file mode 100644
index 0000000000000000000000000000000000000000..5a80e8a51566f47408976d16f94885e4937108d3
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/transform.go
@@ -0,0 +1,109 @@
+package main
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/rlp"
+)
+
+var (
+ IstanbulExtraVanity = 32 // Fixed number of extra-data bytes reserved for validator vanity
+)
+
+// IstanbulAggregatedSeal is the aggregated seal for Istanbul blocks
+type IstanbulAggregatedSeal struct {
+ // Bitmap is a bitmap having an active bit for each validator that signed this block
+ Bitmap *big.Int
+ // Signature is an aggregated BLS signature resulting from signatures by each validator that signed this block
+ Signature []byte
+ // Round is the round in which the signature was created.
+ Round *big.Int
+}
+
+// IstanbulExtra is the extra-data for Istanbul blocks
+type IstanbulExtra struct {
+ // AddedValidators are the validators that have been added in the block
+ AddedValidators []common.Address
+ // AddedValidatorsPublicKeys are the BLS public keys for the validators added in the block
+ AddedValidatorsPublicKeys [][96]byte
+ // RemovedValidators is a bitmap having an active bit for each removed validator in the block
+ RemovedValidators *big.Int
+ // Seal is an ECDSA signature by the proposer
+ Seal []byte
+ // AggregatedSeal contains the aggregated BLS signature created via IBFT consensus.
+ AggregatedSeal IstanbulAggregatedSeal
+ // ParentAggregatedSeal contains and aggregated BLS signature for the previous block.
+ ParentAggregatedSeal IstanbulAggregatedSeal
+}
+
+// transformHeader removes the aggregated seal from the header
+func transformHeader(header []byte) ([]byte, error) {
+ newHeader := new(types.Header)
+ err := rlp.DecodeBytes(header, &newHeader)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(newHeader.Extra) < IstanbulExtraVanity {
+ return nil, errors.New("invalid istanbul header extra-data")
+ }
+
+ istanbulExtra := IstanbulExtra{}
+ err = rlp.DecodeBytes(newHeader.Extra[IstanbulExtraVanity:], &istanbulExtra)
+ if err != nil {
+ return nil, err
+ }
+
+ istanbulExtra.AggregatedSeal = IstanbulAggregatedSeal{}
+
+ payload, err := rlp.EncodeToBytes(&istanbulExtra)
+ if err != nil {
+ return nil, err
+ }
+
+ newHeader.Extra = append(newHeader.Extra[:IstanbulExtraVanity], payload...)
+
+ return rlp.EncodeToBytes(newHeader)
+}
+
+func hasSameHash(newHeader, oldHash []byte) (bool, common.Hash) {
+ newHash := crypto.Keccak256Hash(newHeader)
+ return bytes.Equal(oldHash, newHash.Bytes()), newHash
+}
+
+// transformBlockBody migrates the block body from the old format to the new format (works with []byte input output)
+func transformBlockBody(oldBodyData []byte) ([]byte, error) {
+ // decode body into celo-blockchain Body structure
+ // remove epochSnarkData and randomness data
+ var celoBody struct {
+ Transactions types.Transactions
+ Randomness rlp.RawValue
+ EpochSnarkData rlp.RawValue
+ }
+ if err := rlp.DecodeBytes(oldBodyData, &celoBody); err != nil {
+ // body may have already been transformed in a previous migration
+ body := types.Body{}
+ if err := rlp.DecodeBytes(oldBodyData, &body); err == nil {
+ return oldBodyData, nil
+ }
+ return nil, fmt.Errorf("failed to RLP decode body: %w", err)
+ }
+
+ // transform into op-geth types.Body structure
+ newBody := types.Body{
+ Transactions: celoBody.Transactions,
+ Uncles: []*types.Header{},
+ }
+ newBodyData, err := rlp.EncodeToBytes(newBody)
+ if err != nil {
+ return nil, fmt.Errorf("failed to RLP encode body: %w", err)
+ }
+
+ return newBodyData, nil
+}
diff --git OP/op-chain-ops/cmd/check-derivation/main.go CELO/op-chain-ops/cmd/check-derivation/main.go
index 499b128f8767fe560d92ee66f3ed770c373d7bf4..5f846450138445c62ccb4b5194d634382fe24d2b 100644
--- OP/op-chain-ops/cmd/check-derivation/main.go
+++ CELO/op-chain-ops/cmd/check-derivation/main.go
@@ -225,7 +225,7 @@ data := testutils.RandomData(rng, 10)
var txData types.TxData
switch txType {
case types.LegacyTxType:
- gasLimit, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gasLimit, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get intrinsicGas: %w", err)
}
@@ -242,7 +242,7 @@ accessList := types.AccessList{types.AccessTuple{
Address: randomAddress,
StorageKeys: []common.Hash{common.HexToHash("0x1234")},
}}
- gasLimit, err := core.IntrinsicGas(data, accessList, false, true, true, false)
+ gasLimit, err := core.IntrinsicGas(data, accessList, false, true, true, false, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get intrinsicGas: %w", err)
}
@@ -257,7 +257,7 @@ AccessList: accessList,
Data: data,
}
case types.DynamicFeeTxType:
- gasLimit, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gasLimit, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
if err != nil {
return nil, fmt.Errorf("failed to get intrinsicGas: %w", err)
}
diff --git OP/op-chain-ops/cmd/op-simulate/main.go CELO/op-chain-ops/cmd/op-simulate/main.go
index 8b0986e4554ff71b441667e83cd69744315a8adc..19f4cb41a6aef872c4c0e3bdbfb3a7980d60bc63 100644
--- OP/op-chain-ops/cmd/op-simulate/main.go
+++ CELO/op-chain-ops/cmd/op-simulate/main.go
@@ -294,7 +294,8 @@ }
// run the transaction
start := time.Now()
- receipt, err := core.ApplyTransaction(conf, cCtx, &sender, &gp, state, header, tx, &usedGas, vmConfig)
+ feeCurrencyContext := core.GetFeeCurrencyContext(header, conf, state)
+ receipt, err := core.ApplyTransaction(conf, cCtx, &sender, &gp, state, header, tx, &usedGas, vmConfig, feeCurrencyContext)
if err != nil {
return fmt.Errorf("failed to apply tx: %w", err)
}
diff --git OP/op-chain-ops/deployer/broadcaster/keyed.go CELO/op-chain-ops/deployer/broadcaster/keyed.go
index 63b72010042b62b5ba56cf09f5e47d86c262e593..dda6221bb30532269d81ef4d89cade311ba1f0f2 100644
--- OP/op-chain-ops/deployer/broadcaster/keyed.go
+++ CELO/op-chain-ops/deployer/broadcaster/keyed.go
@@ -210,7 +210,7 @@ // the underlying call. Values are multiplied by a pad factor to account for any discrepancies. The output
// is clamped to the block gas limit since Geth will reject transactions that exceed it before letting them
// into the mempool.
func padGasLimit(data []byte, gasUsed uint64, creation bool, blockGasLimit uint64) uint64 {
- intrinsicGas, err := core.IntrinsicGas(data, nil, creation, true, true, false)
+ intrinsicGas, err := core.IntrinsicGas(data, nil, creation, true, true, false, nil, nil)
// This method never errors - we should look into it if it does.
if err != nil {
panic(err)
diff --git OP/op-chain-ops/genesis/config.go CELO/op-chain-ops/genesis/config.go
index 26f675b30e7fa38760fae9a676b6714f4ea1b6c0..0f0cfcf35951df6820982743c1a76672b5279cf7 100644
--- OP/op-chain-ops/genesis/config.go
+++ CELO/op-chain-ops/genesis/config.go
@@ -271,9 +271,11 @@ var _ ConfigChecker = (*GasTokenDeployConfig)(nil)
func (d *GasTokenDeployConfig) Check(log log.Logger) error {
if d.UseCustomGasToken {
- if d.CustomGasTokenAddress == (common.Address{}) {
- return fmt.Errorf("%w: CustomGasTokenAddress cannot be address(0)", ErrInvalidDeployConfig)
- }
+ // NOTE: we are using the address(0) as an instruction to deploy the L1 token,
+ // so this deploy-config validation has to be disabled
+ // if d.CustomGasTokenAddress == (common.Address{}) {
+ // return fmt.Errorf("%w: CustomGasTokenAddress cannot be address(0)", ErrInvalidDeployConfig)
+ // }
log.Info("Using custom gas token", "address", d.CustomGasTokenAddress)
}
return nil
@@ -308,6 +310,8 @@ // EIP1559Denominator is the denominator of EIP1559 base fee market.
EIP1559Denominator uint64 `json:"eip1559Denominator"`
// EIP1559DenominatorCanyon is the denominator of EIP1559 base fee market when Canyon is active.
EIP1559DenominatorCanyon uint64 `json:"eip1559DenominatorCanyon"`
+ // EIP1559BaseFeeFloor is the fixed floor for the EIP1559 base fee market.
+ EIP1559BaseFeeFloor uint64 `json:"eip1559BaseFeeFloor,omitempty"`
}
var _ ConfigChecker = (*EIP1559DeployConfig)(nil)
@@ -823,6 +827,9 @@ L1DependenciesConfig
// Legacy, ignored, here for strict-JSON decoding to be accepted.
LegacyDeployConfig `evm:"-"`
+
+ // DeployCeloContracts indicates whether to deploy Celo contracts.
+ DeployCeloContracts bool `json:"deployCeloContracts"`
}
// Copy will deeply copy the DeployConfig. This does a JSON roundtrip to copy
@@ -934,6 +941,7 @@ GraniteTime: d.GraniteTime(l1StartTime),
InteropTime: d.InteropTime(l1StartTime),
ProtocolVersionsAddress: d.ProtocolVersionsProxy,
AltDAConfig: altDA,
+ Cel2Time: d.RegolithTime(l1StartTime),
}, nil
}
diff --git OP/op-chain-ops/genesis/genesis.go CELO/op-chain-ops/genesis/genesis.go
index dc7a44ad7ddf5cb1a7492bc5ee7da1b06eb56399..846e393d5abab67df5fd1a463440f61388b4c5f7 100644
--- OP/op-chain-ops/genesis/genesis.go
+++ CELO/op-chain-ops/genesis/genesis.go
@@ -71,10 +71,14 @@ EcotoneTime: config.EcotoneTime(l1StartTime),
FjordTime: config.FjordTime(l1StartTime),
GraniteTime: config.GraniteTime(l1StartTime),
InteropTime: config.InteropTime(l1StartTime),
+ Cel2Time: config.RegolithTime(l1StartTime),
Optimism: ¶ms.OptimismConfig{
EIP1559Denominator: eip1559Denom,
EIP1559Elasticity: eip1559Elasticity,
EIP1559DenominatorCanyon: &eip1559DenomCanyon,
+ },
+ Celo: ¶ms.CeloConfig{
+ EIP1559BaseFeeFloor: config.EIP1559BaseFeeFloor,
},
}
diff --git OP/op-chain-ops/genesis/testdata/test-deploy-config-full.json CELO/op-chain-ops/genesis/testdata/test-deploy-config-full.json
index 1d0702e0218ee63a34a2540cc4979dfb2d8486db..7aaec4c95cf68ca38094ebae5e23b4c22e28bb9b 100644
--- OP/op-chain-ops/genesis/testdata/test-deploy-config-full.json
+++ CELO/op-chain-ops/genesis/testdata/test-deploy-config-full.json
@@ -93,5 +93,7 @@ "daCommitmentType": "KeccakCommitment",
"daChallengeProxy": "0x0000000000000000000000000000000000000000",
"daChallengeWindow": 0,
"daResolveWindow": 0,
- "daResolverRefundPercentage": 0
+ "daResolverRefundPercentage": 0,
+ "deployCeloContracts": false,
+ "eip1559BaseFeeFloor": 5000000000
}
diff --git OP/op-chain-ops/justfile CELO/op-chain-ops/justfile
new file mode 100644
index 0000000000000000000000000000000000000000..b4b6886b4e6411e49fc4c86f9fca7f5e176cd2a6
--- /dev/null
+++ CELO/op-chain-ops/justfile
@@ -0,0 +1,16 @@
+abis := '../packages/contracts-bedrock/snapshots/abi'
+
+bindings-celo-migrate:
+ #!/usr/bin/env bash
+ set -euxo pipefail
+
+ build_abi() {
+ local lowercase=$(echo "$2" | awk '{print tolower($0)}')
+ abigen \
+ --abi "{{abis}}/$1.json" \
+ --pkg bindings \
+ --out "cmd/celo-migrate/bindings/$lowercase.go" \
+ --type $2
+ }
+
+ build_abi GoldToken CeloToken
diff --git OP/op-chain-ops/script/cheatcodes_external.go CELO/op-chain-ops/script/cheatcodes_external.go
index afb42de58f65343e4bb5a860fd13ac7814e8a0d0..16f474e0863e956d223e460f67cd08c7f0c9bcc4 100644
--- OP/op-chain-ops/script/cheatcodes_external.go
+++ CELO/op-chain-ops/script/cheatcodes_external.go
@@ -516,11 +516,11 @@ }
// WriteJson implements https://book.getfoundry.sh/cheatcodes/write-json
func (c *CheatCodesPrecompile) WriteJson_e23cd19f(data string, path string) error {
- return vm.ErrExecutionReverted
+ return nil
}
func (c *CheatCodesPrecompile) WriteJson_35d6ad46(data string, path string, valueKey string) error {
- return vm.ErrExecutionReverted
+ return nil
}
// WriteToml implements https://book.getfoundry.sh/cheatcodes/write-toml
op-challenger
op-e2e
+7975
-11
diff --git OP/op-e2e/actions/batcher/l2_batcher_test.go CELO/op-e2e/actions/batcher/l2_batcher_test.go
index e0605f3fb121683cee4111c90fbf0f978c1208e8..9739a78b6c019336f3bbc62401e7cb093c2ed465 100644
--- OP/op-e2e/actions/batcher/l2_batcher_test.go
+++ CELO/op-e2e/actions/batcher/l2_batcher_test.go
@@ -467,7 +467,7 @@ signer := types.LatestSigner(sd.L2Cfg.Config)
data := make([]byte, 120_000) // very large L2 txs, as large as the tx-pool will accept
_, err := rng.Read(data[:]) // fill with random bytes, to make compression ineffective
require.NoError(t, err)
- gas, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gas, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
if gas > engine.EngineApi.RemainingBlockGas() {
break
diff --git OP/op-e2e/actions/helpers/l1_miner.go CELO/op-e2e/actions/helpers/l1_miner.go
index 5fe5c762d5c9f098874a6aeedc17417b6627e7b6..e4675a246305822caab0d63ce21652adba460b6d 100644
--- OP/op-e2e/actions/helpers/l1_miner.go
+++ CELO/op-e2e/actions/helpers/l1_miner.go
@@ -110,7 +110,8 @@ // Copied from op-program/client/l2/engineapi/block_processor.go
// TODO(client-pod#826)
// Unfortunately this is not part of any Geth environment setup,
// we just have to apply it, like how the Geth block-builder worker does.
- context := core.NewEVMBlockContext(header, s.l1Chain, nil, s.l1Chain.Config(), statedb)
+ feeCurrencyContext := core.GetFeeCurrencyContext(header, s.l1Chain.Config(), statedb)
+ context := core.NewEVMBlockContext(header, s.l1Chain, nil, s.l1Chain.Config(), statedb, feeCurrencyContext)
// NOTE: Unlikely to be needed for the beacon block root, but we setup any precompile overrides anyways for forwards-compatibility
var precompileOverrides vm.PrecompileOverrides
if vmConfig := s.l1Chain.GetVMConfig(); vmConfig != nil && vmConfig.PrecompileOverrides != nil {
@@ -176,8 +177,9 @@ t.InvalidAction("action takes too much gas: %d, only have %d", tx.Gas(), uint64(*s.L1GasPool))
return
}
s.l1BuildingState.SetTxContext(tx.Hash(), len(s.L1Transactions))
+ feeCurrencyContext := core.GetFeeCurrencyContext(s.l1BuildingHeader, s.l1Cfg.Config, s.l1BuildingState)
receipt, err := core.ApplyTransaction(s.l1Cfg.Config, s.l1Chain, &s.l1BuildingHeader.Coinbase,
- s.L1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx.WithoutBlobTxSidecar(), &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig())
+ s.L1GasPool, s.l1BuildingState, s.l1BuildingHeader, tx.WithoutBlobTxSidecar(), &s.l1BuildingHeader.GasUsed, *s.l1Chain.GetVMConfig(), feeCurrencyContext)
if err != nil {
s.l1TxFailed = append(s.l1TxFailed, tx)
t.Fatalf("failed to apply transaction to L1 block (tx %d): %v", len(s.L1Transactions), err)
diff --git OP/op-e2e/actions/helpers/l2_batcher.go CELO/op-e2e/actions/helpers/l2_batcher.go
index d9e6fe3dbec50c5e72f1c85488f295367e553db5..e9dfe4887f1096c5b6e5c07f45b245755dbe59c7 100644
--- OP/op-e2e/actions/helpers/l2_batcher.go
+++ CELO/op-e2e/actions/helpers/l2_batcher.go
@@ -302,7 +302,7 @@ for _, opt := range txOpts {
opt(rawTx)
}
- gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false)
+ gas, err := core.IntrinsicGas(rawTx.Data, nil, false, true, true, false, nil, nil)
require.NoError(t, err, "need to compute intrinsic gas")
rawTx.Gas = gas
txData = rawTx
diff --git OP/op-e2e/actions/sync/sync_test.go CELO/op-e2e/actions/sync/sync_test.go
index 523b68517afb6165511a22f22a22e01c3dc54f5d..a39185f627058be207b5cd622646c2036237f5c5 100644
--- OP/op-e2e/actions/sync/sync_test.go
+++ CELO/op-e2e/actions/sync/sync_test.go
@@ -956,7 +956,7 @@ // Create valid TX
aliceNonce, err := seqEng.EthClient().PendingNonceAt(t.Ctx(), dp.Addresses.Alice)
require.NoError(t, err)
data := make([]byte, rand.Intn(100))
- gas, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gas, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
baseFee := seqEng.L2Chain().CurrentBlock().BaseFee
tx := types.MustSignNewTx(dp.Secrets.Alice, signer, &types.DynamicFeeTx{
diff --git OP/op-e2e/actions/upgrades/span_batch_test.go CELO/op-e2e/actions/upgrades/span_batch_test.go
index fc1707b158a05c77384eeba62bfd391cd658bf62..3713f2fb62ce0ca72b4018cc55de5926a378c19b 100644
--- OP/op-e2e/actions/upgrades/span_batch_test.go
+++ CELO/op-e2e/actions/upgrades/span_batch_test.go
@@ -532,7 +532,7 @@ signer := types.LatestSigner(sd.L2Cfg.Config)
data := make([]byte, rand.Intn(100))
_, err := crand.Read(data[:]) // fill with random bytes
require.NoError(t, err)
- gas, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gas, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
baseFee := seqEngine.L2Chain().CurrentBlock().BaseFee
nonce, err := cl.PendingNonceAt(t.Ctx(), addrs[userIdx])
@@ -671,7 +671,7 @@ signer := types.LatestSigner(sdDeltaActivated.L2Cfg.Config)
data := make([]byte, rand.Intn(100))
_, err := crand.Read(data[:]) // fill with random bytes
require.NoError(t, err)
- gas, err := core.IntrinsicGas(data, nil, false, true, true, false)
+ gas, err := core.IntrinsicGas(data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
baseFee := seqEngine.L2Chain().CurrentBlock().BaseFee
nonce, err := seqEngCl.PendingNonceAt(t.Ctx(), addrs[userIdx])
diff --git OP/op-e2e/celo/.prettierrc.toml CELO/op-e2e/celo/.prettierrc.toml
new file mode 100644
index 0000000000000000000000000000000000000000..d5b43d58c0b8c7eba8fa0cb9e8d2673652e309e6
--- /dev/null
+++ CELO/op-e2e/celo/.prettierrc.toml
@@ -0,0 +1,4 @@
+trailingComma = "es5"
+tabWidth = 2
+semi = false
+singleQuote = true
diff --git OP/op-e2e/celo/babel.config.cjs CELO/op-e2e/celo/babel.config.cjs
new file mode 100644
index 0000000000000000000000000000000000000000..a76dfe63099c9948289ad9c3cad15a8e391e7e76
--- /dev/null
+++ CELO/op-e2e/celo/babel.config.cjs
@@ -0,0 +1,3 @@
+module.exports = {
+ presets: [['@babel/preset-env', { targets: { node: 'current' } }]],
+}
diff --git OP/op-e2e/celo/foundry.toml CELO/op-e2e/celo/foundry.toml
new file mode 100644
index 0000000000000000000000000000000000000000..8df5305625e49af8485993916160a3fe99512d1d
--- /dev/null
+++ CELO/op-e2e/celo/foundry.toml
@@ -0,0 +1,19 @@
+[profile.default]
+
+# Compilation settings
+src = '../../packages/contracts-bedrock/src/celo/'
+out = 'forge-artifacts'
+remappings = [
+ '@openzeppelin/contracts-upgradeable/=../../packages/contracts-bedrock/lib/openzeppelin-contracts-upgradeable/contracts',
+ '@openzeppelin/contracts/=../../packages/contracts-bedrock/lib/openzeppelin-contracts/contracts',
+ 'forge-std/=../../packages/contracts-bedrock/lib/forge-std/src',
+]
+allow_paths = ["../../packages/contracts-bedrock/"]
+extra_output = ['abi']
+bytecode_hash = 'none'
+evm_version = "cancun"
+fs_permissions = [
+ { access='read', path='../../packages/contracts-bedrock/' },
+]
+libs = ["lib"]
+
diff --git OP/op-e2e/celo/jest.config.json CELO/op-e2e/celo/jest.config.json
new file mode 100644
index 0000000000000000000000000000000000000000..aea28c9f68597eeaca251715ad80f924c20670e3
--- /dev/null
+++ CELO/op-e2e/celo/jest.config.json
@@ -0,0 +1,5 @@
+{
+ "transformIgnorePatterns": [
+ "node_modules/(?!(string-width|strip-ansi|ansi-regex|test-json-import)/)"
+ ]
+}
diff --git OP/op-e2e/celo/package-lock.json CELO/op-e2e/celo/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..fc39534dff450603e7d3df74d56844c733cbbf7d
--- /dev/null
+++ CELO/op-e2e/celo/package-lock.json
@@ -0,0 +1,6578 @@
+{
+ "name": "testsuite",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "testsuite",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "reverse-mirage": "^1.1.0",
+ "viem": "^2.13.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.24.7",
+ "@babel/preset-env": "^7.24.7",
+ "babel-jest": "^29.7.0",
+ "jest": "^29.7.0",
+ "prettier": "3.3.3"
+ }
+ },
+ "node_modules/@adraffy/ens-normalize": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.0.tgz",
+ "integrity": "sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg=="
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.24.7",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz",
+ "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz",
+ "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.9",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-module-transforms": "^7.24.9",
+ "@babel/helpers": "^7.24.8",
+ "@babel/parser": "^7.24.8",
+ "@babel/template": "^7.24.7",
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.9",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.24.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz",
+ "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.9",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
+ "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.24.7.tgz",
+ "integrity": "sha512-xZeCVVdwb4MsDBkkyZ64tReWYrLRHlMN72vP7Bdm3OUOuyFZExhsHUUnuWnm2/XOlAJzR0LfPpB56WXZn0X/lA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz",
+ "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.24.8",
+ "@babel/helper-validator-option": "^7.24.8",
+ "browserslist": "^4.23.1",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz",
+ "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.8",
+ "@babel/helper-optimise-call-expression": "^7.24.7",
+ "@babel/helper-replace-supers": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-regexp-features-plugin": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz",
+ "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "regexpu-core": "^5.3.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-define-polyfill-provider": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz",
+ "integrity": "sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.22.6",
+ "@babel/helper-plugin-utils": "^7.22.5",
+ "debug": "^4.1.1",
+ "lodash.debounce": "^4.0.8",
+ "resolve": "^1.14.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz",
+ "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
+ "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz",
+ "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-module-imports": "^7.24.7",
+ "@babel/helper-simple-access": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz",
+ "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz",
+ "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-remap-async-to-generator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz",
+ "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-wrap-function": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz",
+ "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
+ "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz",
+ "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
+ "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
+ "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-wrap-function": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz",
+ "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/template": "^7.24.7",
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz",
+ "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz",
+ "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz",
+ "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz",
+ "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.7.tgz",
+ "integrity": "sha512-+izXIbke1T33mY4MSNnrqhPXDz01WYhEf3yF5NbnUtkiNnm+XBZJl3kNfoK6NKmYlz/D07+l2GWVK/QfDkNCuQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/plugin-transform-optional-chaining": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.13.0"
+ }
+ },
+ "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz",
+ "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-private-property-in-object": {
+ "version": "7.21.0-placeholder-for-preset-env.2",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
+ "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-async-generators": {
+ "version": "7.8.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+ "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-bigint": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
+ "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-properties": {
+ "version": "7.12.13",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+ "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.12.13"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-class-static-block": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+ "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-dynamic-import": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+ "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-export-namespace-from": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
+ "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.3"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-assertions": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz",
+ "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-attributes": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.7.tgz",
+ "integrity": "sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-import-meta": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+ "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-json-strings": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+ "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz",
+ "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+ "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+ "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-numeric-separator": {
+ "version": "7.10.4",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+ "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.10.4"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-object-rest-spread": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+ "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+ "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-optional-chaining": {
+ "version": "7.8.3",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+ "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.8.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-private-property-in-object": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+ "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-top-level-await": {
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+ "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz",
+ "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-unicode-sets-regex": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
+ "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+ "@babel/helper-plugin-utils": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-arrow-functions": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz",
+ "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-generator-functions": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz",
+ "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-remap-async-to-generator": "^7.24.7",
+ "@babel/plugin-syntax-async-generators": "^7.8.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-async-to-generator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.7.tgz",
+ "integrity": "sha512-SQY01PcJfmQ+4Ash7NE+rpbLFbmqA2GPIgqzxfFTL4t1FKRq4zTms/7htKpoCUI9OcFYgzqfmCdH53s6/jn5fA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-remap-async-to-generator": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoped-functions": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz",
+ "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-block-scoping": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz",
+ "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-properties": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.7.tgz",
+ "integrity": "sha512-vKbfawVYayKcSeSR5YYzzyXvsDFWU2mD8U5TFeXtbCPLFUqe7GyCgvO6XDHzje862ODrOwy6WCPmKeWHbCFJ4w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-class-static-block": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.7.tgz",
+ "integrity": "sha512-HMXK3WbBPpZQufbMG4B46A90PkuuhN9vBCb5T8+VAHqvAqvcLi+2cKoukcpmUYkszLhScU3l1iudhrks3DggRQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-class-static-block": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.12.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-classes": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.8.tgz",
+ "integrity": "sha512-VXy91c47uujj758ud9wx+OMgheXm4qJfyhj1P18YvlrQkNOSrwsteHk+EFS3OMGfhMhpZa0A+81eE7G4QC+3CA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.8",
+ "@babel/helper-replace-supers": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-computed-properties": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz",
+ "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/template": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-destructuring": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz",
+ "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dotall-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.7.tgz",
+ "integrity": "sha512-ZOA3W+1RRTSWvyqcMJDLqbchh7U4NRGqwRfFSVbOLS/ePIP4vHB5e8T8eXcuqyN1QkgKyj5wuW0lcS85v4CrSw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-duplicate-keys": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.7.tgz",
+ "integrity": "sha512-JdYfXyCRihAe46jUIliuL2/s0x0wObgwwiGxw/UbgJBr20gQBThrokO4nYKgWkD7uBaqM7+9x5TU7NkExZJyzw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-dynamic-import": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz",
+ "integrity": "sha512-sc3X26PhZQDb3JhORmakcbvkeInvxz+A8oda99lj7J60QRuPZvNAk9wQlTBS1ZynelDrDmTU4pw1tyc5d5ZMUg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-exponentiation-operator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.7.tgz",
+ "integrity": "sha512-Rqe/vSc9OYgDajNIK35u7ot+KeCoetqQYFXM4Epf7M7ez3lWlOjrDjrwMei6caCVhfdw+mIKD4cgdGNy5JQotQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-builder-binary-assignment-operator-visitor": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-export-namespace-from": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.7.tgz",
+ "integrity": "sha512-v0K9uNYsPL3oXZ/7F9NNIbAj2jv1whUEtyA6aujhekLs56R++JDQuzRcP2/z4WX5Vg/c5lE9uWZA0/iUoFhLTA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-for-of": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz",
+ "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-function-name": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz",
+ "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-json-strings": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.7.tgz",
+ "integrity": "sha512-2yFnBGDvRuxAaE/f0vfBKvtnvvqU8tGpMHqMNpTN2oWMKIR3NqFkjaAgGwawhqK/pIN2T3XdjGPdaG0vDhOBGw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-json-strings": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-literals": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz",
+ "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-logical-assignment-operators": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.7.tgz",
+ "integrity": "sha512-4D2tpwlQ1odXmTEIFWy9ELJcZHqrStlzK/dAOWYyxX3zT0iXQB6banjgeOJQXzEc4S0E0a5A+hahxPaEFYftsw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-member-expression-literals": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz",
+ "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-amd": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.7.tgz",
+ "integrity": "sha512-9+pB1qxV3vs/8Hdmz/CulFB8w2tuu6EB94JZFsjdqxQokwGa9Unap7Bo2gGBGIvPmDIVvQrom7r5m/TCDMURhg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-commonjs": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz",
+ "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.24.8",
+ "@babel/helper-plugin-utils": "^7.24.8",
+ "@babel/helper-simple-access": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-systemjs": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz",
+ "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-module-transforms": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-modules-umd": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.7.tgz",
+ "integrity": "sha512-3aytQvqJ/h9z4g8AsKPLvD4Zqi2qT+L3j7XoFFu1XBlZWEl2/1kWnhmAbxpLgPrHSY0M6UA02jyTiwUVtiKR6A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-transforms": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.24.7.tgz",
+ "integrity": "sha512-/jr7h/EWeJtk1U/uz2jlsCioHkZk1JJZVcc8oQsJ1dUlaJD83f4/6Zeh2aHt9BIFokHIsSeDfhUmju0+1GPd6g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-new-target": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.7.tgz",
+ "integrity": "sha512-RNKwfRIXg4Ls/8mMTza5oPF5RkOW8Wy/WgMAp1/F1yZ8mMbtwXW+HDoJiOsagWrAhI5f57Vncrmr9XeT4CVapA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-nullish-coalescing-operator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.7.tgz",
+ "integrity": "sha512-Ts7xQVk1OEocqzm8rHMXHlxvsfZ0cEF2yomUqpKENHWMF4zKk175Y4q8H5knJes6PgYad50uuRmt3UJuhBw8pQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-numeric-separator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.7.tgz",
+ "integrity": "sha512-e6q1TiVUzvH9KRvicuxdBTUj4AdKSRwzIyFFnfnezpCfP2/7Qmbb8qbU2j7GODbl4JMkblitCQjKYUaX/qkkwA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-rest-spread": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.7.tgz",
+ "integrity": "sha512-4QrHAr0aXQCEFni2q4DqKLD31n2DL+RxcwnNjDFkSG0eNQ/xCavnRkfCUjsyqGC2OviNJvZOF/mQqZBw7i2C5Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-compilation-targets": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+ "@babel/plugin-transform-parameters": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-object-super": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz",
+ "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-replace-supers": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-catch-binding": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.7.tgz",
+ "integrity": "sha512-uLEndKqP5BfBbC/5jTwPxLh9kqPWWgzN/f8w6UwAIirAEqiIVJWWY312X72Eub09g5KF9+Zn7+hT7sDxmhRuKA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-optional-chaining": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz",
+ "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.8",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-parameters": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz",
+ "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-methods": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.7.tgz",
+ "integrity": "sha512-COTCOkG2hn4JKGEKBADkA8WNb35TGkkRbI5iT845dB+NyqgO8Hn+ajPbSnIQznneJTa3d30scb6iz/DhH8GsJQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-private-property-in-object": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz",
+ "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-property-literals": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz",
+ "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-regenerator": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz",
+ "integrity": "sha512-lq3fvXPdimDrlg6LWBoqj+r/DEWgONuwjuOuQCSYgRroXDH/IdM1C0IZf59fL5cHLpjEH/O6opIRBbqv7ELnuA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "regenerator-transform": "^0.15.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-reserved-words": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.7.tgz",
+ "integrity": "sha512-0DUq0pHcPKbjFZCfTss/pGkYMfy3vFWydkUBd9r0GHpIyfs2eCDENvqadMycRS9wZCXR41wucAfJHJmwA0UmoQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-shorthand-properties": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz",
+ "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-spread": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz",
+ "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-sticky-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.7.tgz",
+ "integrity": "sha512-kHPSIJc9v24zEml5geKg9Mjx5ULpfncj0wRpYtxbvKyTtHCYDkVE3aHQ03FrpEo4gEe2vrJJS1Y9CJTaThA52g==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-template-literals": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz",
+ "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typeof-symbol": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz",
+ "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-escapes": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.7.tgz",
+ "integrity": "sha512-U3ap1gm5+4edc2Q/P+9VrBNhGkfnf+8ZqppY71Bo/pzZmXhhLdqgaUl6cuB07O1+AQJtCLfaOmswiNbSQ9ivhw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-property-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.7.tgz",
+ "integrity": "sha512-uH2O4OV5M9FZYQrwc7NdVmMxQJOCCzFeYudlZSzUAHRFeOujQefa92E74TQDVskNHCzOXoigEuoyzHDhaEaK5w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.7.tgz",
+ "integrity": "sha512-hlQ96MBZSAXUq7ltkjtu3FJCCSMx/j629ns3hA3pXnBXjanNP0LHi+JpPeA81zaWgVK1VGH95Xuy7u0RyQ8kMg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-unicode-sets-regex": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.7.tgz",
+ "integrity": "sha512-2G8aAvF4wy1w/AGZkemprdGMRg5o6zPNhbHVImRz3lss55TYCBd6xStN19rt8XJHq20sqV0JbyWjOWwQRwV/wg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-regexp-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/preset-env": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.8.tgz",
+ "integrity": "sha512-vObvMZB6hNWuDxhSaEPTKCwcqkAIuDtE+bQGn4XMXne1DSLzFVY8Vmj1bm+mUQXYNN8NmaQEO+r8MMbzPr1jBQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.24.8",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-plugin-utils": "^7.24.8",
+ "@babel/helper-validator-option": "^7.24.8",
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7",
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7",
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7",
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7",
+ "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2",
+ "@babel/plugin-syntax-async-generators": "^7.8.4",
+ "@babel/plugin-syntax-class-properties": "^7.12.13",
+ "@babel/plugin-syntax-class-static-block": "^7.14.5",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+ "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+ "@babel/plugin-syntax-import-assertions": "^7.24.7",
+ "@babel/plugin-syntax-import-attributes": "^7.24.7",
+ "@babel/plugin-syntax-import-meta": "^7.10.4",
+ "@babel/plugin-syntax-json-strings": "^7.8.3",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+ "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+ "@babel/plugin-syntax-top-level-await": "^7.14.5",
+ "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6",
+ "@babel/plugin-transform-arrow-functions": "^7.24.7",
+ "@babel/plugin-transform-async-generator-functions": "^7.24.7",
+ "@babel/plugin-transform-async-to-generator": "^7.24.7",
+ "@babel/plugin-transform-block-scoped-functions": "^7.24.7",
+ "@babel/plugin-transform-block-scoping": "^7.24.7",
+ "@babel/plugin-transform-class-properties": "^7.24.7",
+ "@babel/plugin-transform-class-static-block": "^7.24.7",
+ "@babel/plugin-transform-classes": "^7.24.8",
+ "@babel/plugin-transform-computed-properties": "^7.24.7",
+ "@babel/plugin-transform-destructuring": "^7.24.8",
+ "@babel/plugin-transform-dotall-regex": "^7.24.7",
+ "@babel/plugin-transform-duplicate-keys": "^7.24.7",
+ "@babel/plugin-transform-dynamic-import": "^7.24.7",
+ "@babel/plugin-transform-exponentiation-operator": "^7.24.7",
+ "@babel/plugin-transform-export-namespace-from": "^7.24.7",
+ "@babel/plugin-transform-for-of": "^7.24.7",
+ "@babel/plugin-transform-function-name": "^7.24.7",
+ "@babel/plugin-transform-json-strings": "^7.24.7",
+ "@babel/plugin-transform-literals": "^7.24.7",
+ "@babel/plugin-transform-logical-assignment-operators": "^7.24.7",
+ "@babel/plugin-transform-member-expression-literals": "^7.24.7",
+ "@babel/plugin-transform-modules-amd": "^7.24.7",
+ "@babel/plugin-transform-modules-commonjs": "^7.24.8",
+ "@babel/plugin-transform-modules-systemjs": "^7.24.7",
+ "@babel/plugin-transform-modules-umd": "^7.24.7",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7",
+ "@babel/plugin-transform-new-target": "^7.24.7",
+ "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7",
+ "@babel/plugin-transform-numeric-separator": "^7.24.7",
+ "@babel/plugin-transform-object-rest-spread": "^7.24.7",
+ "@babel/plugin-transform-object-super": "^7.24.7",
+ "@babel/plugin-transform-optional-catch-binding": "^7.24.7",
+ "@babel/plugin-transform-optional-chaining": "^7.24.8",
+ "@babel/plugin-transform-parameters": "^7.24.7",
+ "@babel/plugin-transform-private-methods": "^7.24.7",
+ "@babel/plugin-transform-private-property-in-object": "^7.24.7",
+ "@babel/plugin-transform-property-literals": "^7.24.7",
+ "@babel/plugin-transform-regenerator": "^7.24.7",
+ "@babel/plugin-transform-reserved-words": "^7.24.7",
+ "@babel/plugin-transform-shorthand-properties": "^7.24.7",
+ "@babel/plugin-transform-spread": "^7.24.7",
+ "@babel/plugin-transform-sticky-regex": "^7.24.7",
+ "@babel/plugin-transform-template-literals": "^7.24.7",
+ "@babel/plugin-transform-typeof-symbol": "^7.24.8",
+ "@babel/plugin-transform-unicode-escapes": "^7.24.7",
+ "@babel/plugin-transform-unicode-property-regex": "^7.24.7",
+ "@babel/plugin-transform-unicode-regex": "^7.24.7",
+ "@babel/plugin-transform-unicode-sets-regex": "^7.24.7",
+ "@babel/preset-modules": "0.1.6-no-external-plugins",
+ "babel-plugin-polyfill-corejs2": "^0.4.10",
+ "babel-plugin-polyfill-corejs3": "^0.10.4",
+ "babel-plugin-polyfill-regenerator": "^0.6.1",
+ "core-js-compat": "^3.37.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/preset-modules": {
+ "version": "0.1.6-no-external-plugins",
+ "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
+ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@babel/types": "^7.4.4",
+ "esutils": "^2.0.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/@babel/regjsgen": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
+ "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
+ "dev": true
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz",
+ "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz",
+ "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.8",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/parser": "^7.24.8",
+ "@babel/types": "^7.24.8",
+ "debug": "^4.3.1",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz",
+ "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.24.8",
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@bcoe/v8-coverage": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz",
+ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==",
+ "dev": true
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+ "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+ "dev": true,
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "find-up": "^4.1.0",
+ "get-package-type": "^0.1.0",
+ "js-yaml": "^3.13.1",
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/console": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz",
+ "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/console/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/console/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@jest/console/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@jest/console/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@jest/console/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/console/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/core": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz",
+ "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==",
+ "dev": true,
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/reporters": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.2.9",
+ "jest-changed-files": "^29.7.0",
+ "jest-config": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-resolve-dependencies": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jest/core/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/core/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@jest/core/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@jest/core/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@jest/core/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/core/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/environment": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
+ "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==",
+ "dev": true,
+ "dependencies": {
+ "expect": "^29.7.0",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/expect-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz",
+ "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==",
+ "dev": true,
+ "dependencies": {
+ "jest-get-type": "^29.6.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/fake-timers": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz",
+ "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@sinonjs/fake-timers": "^10.0.2",
+ "@types/node": "*",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/globals": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
+ "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "jest-mock": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/reporters": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz",
+ "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==",
+ "dev": true,
+ "dependencies": {
+ "@bcoe/v8-coverage": "^0.2.3",
+ "@jest/console": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "collect-v8-coverage": "^1.0.0",
+ "exit": "^0.1.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-instrument": "^6.0.0",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.1.3",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "slash": "^3.0.0",
+ "string-length": "^4.0.1",
+ "strip-ansi": "^6.0.0",
+ "v8-to-istanbul": "^9.0.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@jest/reporters/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz",
+ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.23.9",
+ "@babel/parser": "^7.23.9",
+ "@istanbuljs/schema": "^0.1.3",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@jest/reporters/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/source-map": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
+ "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "callsites": "^3.0.0",
+ "graceful-fs": "^4.2.9"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/test-result": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz",
+ "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==",
+ "dev": true,
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "collect-v8-coverage": "^1.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/test-sequencer": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz",
+ "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/transform": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz",
+ "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/types": "^29.6.3",
+ "@jridgewell/trace-mapping": "^0.3.18",
+ "babel-plugin-istanbul": "^6.1.1",
+ "chalk": "^4.0.0",
+ "convert-source-map": "^2.0.0",
+ "fast-json-stable-stringify": "^2.1.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "pirates": "^4.0.4",
+ "slash": "^3.0.0",
+ "write-file-atomic": "^4.0.2"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/transform/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/transform/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@jest/transform/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@jest/transform/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@jest/transform/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/transform/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/types": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
+ "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^17.0.8",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@jest/types/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@jest/types/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@jest/types/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@jest/types/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@jest/types/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jest/types/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@noble/curves": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.6.0.tgz",
+ "integrity": "sha512-TlaHRXDehJuRNR9TfZDNQ45mMEd5dwUwmicsafcIX4SsNiqnCHKjE/1alYPd/lDRVhxdhUAlv8uEhMCI5zjIJQ==",
+ "dependencies": {
+ "@noble/hashes": "1.5.0"
+ },
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@noble/hashes": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz",
+ "integrity": "sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==",
+ "engines": {
+ "node": "^14.21.3 || >=16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@scure/base": {
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz",
+ "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==",
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@scure/bip32": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.5.0.tgz",
+ "integrity": "sha512-8EnFYkqEQdnkuGBVpCzKxyIwDCBLDVj3oiX0EKUFre/tOjL/Hqba1D6n/8RcmaQy4f95qQFrO2A8Sr6ybh4NRw==",
+ "dependencies": {
+ "@noble/curves": "~1.6.0",
+ "@noble/hashes": "~1.5.0",
+ "@scure/base": "~1.1.7"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@scure/bip39": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.4.0.tgz",
+ "integrity": "sha512-BEEm6p8IueV/ZTfQLp/0vhw4NPnT9oWf5+28nvmeUICjP99f4vr2d+qc7AVGDDtwRep6ifR43Yed9ERVmiITzw==",
+ "dependencies": {
+ "@noble/hashes": "~1.5.0",
+ "@scure/base": "~1.1.8"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
+ "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==",
+ "dev": true,
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "10.3.0",
+ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz",
+ "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==",
+ "dev": true,
+ "dependencies": {
+ "@sinonjs/commons": "^3.0.0"
+ }
+ },
+ "node_modules/@types/babel__core": {
+ "version": "7.20.5",
+ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
+ "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.20.7",
+ "@babel/types": "^7.20.7",
+ "@types/babel__generator": "*",
+ "@types/babel__template": "*",
+ "@types/babel__traverse": "*"
+ }
+ },
+ "node_modules/@types/babel__generator": {
+ "version": "7.6.8",
+ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz",
+ "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__template": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz",
+ "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/parser": "^7.1.0",
+ "@babel/types": "^7.0.0"
+ }
+ },
+ "node_modules/@types/babel__traverse": {
+ "version": "7.20.6",
+ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz",
+ "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.20.7"
+ }
+ },
+ "node_modules/@types/graceful-fs": {
+ "version": "4.1.9",
+ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz",
+ "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/istanbul-lib-coverage": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
+ "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==",
+ "dev": true
+ },
+ "node_modules/@types/istanbul-lib-report": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz",
+ "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==",
+ "dev": true,
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "*"
+ }
+ },
+ "node_modules/@types/istanbul-reports": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz",
+ "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/istanbul-lib-report": "*"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "20.14.11",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
+ "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/stack-utils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
+ "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
+ "dev": true
+ },
+ "node_modules/@types/yargs": {
+ "version": "17.0.32",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
+ "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
+ "dev": true,
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
+ "node_modules/@types/yargs-parser": {
+ "version": "21.0.3",
+ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz",
+ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==",
+ "dev": true
+ },
+ "node_modules/abitype": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz",
+ "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==",
+ "funding": {
+ "url": "https://github.com/sponsors/wevm"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.4",
+ "zod": "^3 >=3.22.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ansi-escapes": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz",
+ "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.21.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/babel-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz",
+ "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==",
+ "dev": true,
+ "dependencies": {
+ "@jest/transform": "^29.7.0",
+ "@types/babel__core": "^7.1.14",
+ "babel-plugin-istanbul": "^6.1.1",
+ "babel-preset-jest": "^29.6.3",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.8.0"
+ }
+ },
+ "node_modules/babel-jest/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/babel-jest/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/babel-jest/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/babel-jest/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/babel-jest/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-jest/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-plugin-istanbul": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+ "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.0.0",
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-instrument": "^5.0.4",
+ "test-exclude": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/babel-plugin-jest-hoist": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz",
+ "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.3.3",
+ "@babel/types": "^7.3.3",
+ "@types/babel__core": "^7.1.14",
+ "@types/babel__traverse": "^7.0.6"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs2": {
+ "version": "0.4.11",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz",
+ "integrity": "sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.22.6",
+ "@babel/helper-define-polyfill-provider": "^0.6.2",
+ "semver": "^6.3.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-corejs3": {
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz",
+ "integrity": "sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.1",
+ "core-js-compat": "^3.36.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-plugin-polyfill-regenerator": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz",
+ "integrity": "sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-define-polyfill-provider": "^0.6.2"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0"
+ }
+ },
+ "node_modules/babel-preset-current-node-syntax": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz",
+ "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/plugin-syntax-async-generators": "^7.8.4",
+ "@babel/plugin-syntax-bigint": "^7.8.3",
+ "@babel/plugin-syntax-class-properties": "^7.8.3",
+ "@babel/plugin-syntax-import-meta": "^7.8.3",
+ "@babel/plugin-syntax-json-strings": "^7.8.3",
+ "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+ "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+ "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+ "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+ "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+ "@babel/plugin-syntax-top-level-await": "^7.8.3"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/babel-preset-jest": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz",
+ "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-jest-hoist": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.23.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz",
+ "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001640",
+ "electron-to-chromium": "^1.4.820",
+ "node-releases": "^2.0.14",
+ "update-browserslist-db": "^1.1.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/bser": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz",
+ "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==",
+ "dev": true,
+ "dependencies": {
+ "node-int64": "^0.4.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001642",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz",
+ "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/char-regex": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ci-info": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz",
+ "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cjs-module-lexer": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz",
+ "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==",
+ "dev": true
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/co": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
+ "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==",
+ "dev": true,
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/collect-v8-coverage": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
+ "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==",
+ "dev": true
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ },
+ "node_modules/core-js-compat": {
+ "version": "3.37.1",
+ "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz",
+ "integrity": "sha512-9TNiImhKvQqSUkOvk/mMRZzOANTiEVC7WaBNhHcKM7x+/5E1l5NvsysR19zuDQScE8k+kfQXWRN3AtS/eOSHpg==",
+ "dev": true,
+ "dependencies": {
+ "browserslist": "^4.23.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/create-jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
+ "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "exit": "^0.1.2",
+ "graceful-fs": "^4.2.9",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "prompts": "^2.0.1"
+ },
+ "bin": {
+ "create-jest": "bin/create-jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/create-jest/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/create-jest/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/create-jest/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/create-jest/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/create-jest/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/create-jest/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/dedent": {
+ "version": "1.5.3",
+ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz",
+ "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==",
+ "dev": true,
+ "peerDependencies": {
+ "babel-plugin-macros": "^3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "babel-plugin-macros": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/detect-newline": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/diff-sequences": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+ "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.829",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.829.tgz",
+ "integrity": "sha512-5qp1N2POAfW0u1qGAxXEtz6P7bO1m6gpZr5hdf5ve6lxpLM7MpiM4jIPz7xcrNlClQMafbyUDDWjlIQZ1Mw0Rw==",
+ "dev": true
+ },
+ "node_modules/emittery": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
+ "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/emittery?sponsor=1"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "dependencies": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+ "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+ "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+ "dev": true,
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^6.0.0",
+ "human-signals": "^2.1.0",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.1",
+ "onetime": "^5.1.2",
+ "signal-exit": "^3.0.3",
+ "strip-final-newline": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/expect": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz",
+ "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/expect-utils": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fb-watchman": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz",
+ "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==",
+ "dev": true,
+ "dependencies": {
+ "bser": "2.1.1"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-package-type": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
+ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
+ "dev": true
+ },
+ "node_modules/human-signals": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.17.0"
+ }
+ },
+ "node_modules/import-local": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
+ "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==",
+ "dev": true,
+ "dependencies": {
+ "pkg-dir": "^4.2.0",
+ "resolve-cwd": "^3.0.0"
+ },
+ "bin": {
+ "import-local-fixture": "fixtures/cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+ "dev": true
+ },
+ "node_modules/is-core-module": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz",
+ "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-generator-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz",
+ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/isows": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.6.tgz",
+ "integrity": "sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/wevm"
+ }
+ ],
+ "peerDependencies": {
+ "ws": "*"
+ }
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz",
+ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+ "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.12.3",
+ "@babel/parser": "^7.14.7",
+ "@istanbuljs/schema": "^0.1.2",
+ "istanbul-lib-coverage": "^3.2.0",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz",
+ "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==",
+ "dev": true,
+ "dependencies": {
+ "istanbul-lib-coverage": "^3.0.0",
+ "make-dir": "^4.0.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz",
+ "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz",
+ "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==",
+ "dev": true,
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz",
+ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "import-local": "^3.0.2",
+ "jest-cli": "^29.7.0"
+ },
+ "bin": {
+ "jest": "bin/jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-changed-files": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz",
+ "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==",
+ "dev": true,
+ "dependencies": {
+ "execa": "^5.0.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-circus": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz",
+ "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/expect": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "co": "^4.6.0",
+ "dedent": "^1.0.0",
+ "is-generator-fn": "^2.0.0",
+ "jest-each": "^29.7.0",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "p-limit": "^3.1.0",
+ "pretty-format": "^29.7.0",
+ "pure-rand": "^6.0.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-circus/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-circus/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-circus/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-circus/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-circus/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-circus/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-cli": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz",
+ "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==",
+ "dev": true,
+ "dependencies": {
+ "@jest/core": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "create-jest": "^29.7.0",
+ "exit": "^0.1.2",
+ "import-local": "^3.0.2",
+ "jest-config": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "yargs": "^17.3.1"
+ },
+ "bin": {
+ "jest": "bin/jest.js"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0"
+ },
+ "peerDependenciesMeta": {
+ "node-notifier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-cli/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-cli/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-cli/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-cli/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-cli/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-cli/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-config": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz",
+ "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@jest/test-sequencer": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-jest": "^29.7.0",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "deepmerge": "^4.2.2",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "jest-circus": "^29.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-runner": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "parse-json": "^5.2.0",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "peerDependencies": {
+ "@types/node": "*",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-config/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-config/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-config/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-config/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-config/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-config/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-diff": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz",
+ "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "diff-sequences": "^29.6.3",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-diff/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-diff/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-diff/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-diff/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-diff/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-diff/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-docblock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz",
+ "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==",
+ "dev": true,
+ "dependencies": {
+ "detect-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-each": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz",
+ "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-each/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-each/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-each/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-each/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-each/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-each/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-environment-node": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz",
+ "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-mock": "^29.7.0",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-get-type": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz",
+ "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-haste-map": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz",
+ "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/graceful-fs": "^4.1.3",
+ "@types/node": "*",
+ "anymatch": "^3.0.3",
+ "fb-watchman": "^2.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-regex-util": "^29.6.3",
+ "jest-util": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "micromatch": "^4.0.4",
+ "walker": "^1.0.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ }
+ },
+ "node_modules/jest-leak-detector": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz",
+ "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==",
+ "dev": true,
+ "dependencies": {
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz",
+ "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-matcher-utils/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-matcher-utils/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-matcher-utils/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-matcher-utils/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-matcher-utils/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-message-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz",
+ "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.12.13",
+ "@jest/types": "^29.6.3",
+ "@types/stack-utils": "^2.0.0",
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "micromatch": "^4.0.4",
+ "pretty-format": "^29.7.0",
+ "slash": "^3.0.0",
+ "stack-utils": "^2.0.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-message-util/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-message-util/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-message-util/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-message-util/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-message-util/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-message-util/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-mock": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz",
+ "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "jest-util": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-pnp-resolver": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz",
+ "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "peerDependencies": {
+ "jest-resolve": "*"
+ },
+ "peerDependenciesMeta": {
+ "jest-resolve": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/jest-regex-util": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz",
+ "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==",
+ "dev": true,
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz",
+ "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.0.0",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-pnp-resolver": "^1.2.2",
+ "jest-util": "^29.7.0",
+ "jest-validate": "^29.7.0",
+ "resolve": "^1.20.0",
+ "resolve.exports": "^2.0.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve-dependencies": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz",
+ "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==",
+ "dev": true,
+ "dependencies": {
+ "jest-regex-util": "^29.6.3",
+ "jest-snapshot": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-resolve/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-resolve/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-resolve/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-resolve/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-resolve/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-resolve/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-runner": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz",
+ "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/console": "^29.7.0",
+ "@jest/environment": "^29.7.0",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "graceful-fs": "^4.2.9",
+ "jest-docblock": "^29.7.0",
+ "jest-environment-node": "^29.7.0",
+ "jest-haste-map": "^29.7.0",
+ "jest-leak-detector": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-resolve": "^29.7.0",
+ "jest-runtime": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "jest-watcher": "^29.7.0",
+ "jest-worker": "^29.7.0",
+ "p-limit": "^3.1.0",
+ "source-map-support": "0.5.13"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-runner/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-runner/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-runner/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-runner/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-runner/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-runner/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-runtime": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz",
+ "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/environment": "^29.7.0",
+ "@jest/fake-timers": "^29.7.0",
+ "@jest/globals": "^29.7.0",
+ "@jest/source-map": "^29.6.3",
+ "@jest/test-result": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "cjs-module-lexer": "^1.0.0",
+ "collect-v8-coverage": "^1.0.0",
+ "glob": "^7.1.3",
+ "graceful-fs": "^4.2.9",
+ "jest-haste-map": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-mock": "^29.7.0",
+ "jest-regex-util": "^29.6.3",
+ "jest-resolve": "^29.7.0",
+ "jest-snapshot": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "slash": "^3.0.0",
+ "strip-bom": "^4.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-runtime/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-runtime/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-runtime/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-runtime/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-runtime/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-runtime/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-snapshot": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
+ "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.11.6",
+ "@babel/generator": "^7.7.2",
+ "@babel/plugin-syntax-jsx": "^7.7.2",
+ "@babel/plugin-syntax-typescript": "^7.7.2",
+ "@babel/types": "^7.3.3",
+ "@jest/expect-utils": "^29.7.0",
+ "@jest/transform": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "babel-preset-current-node-syntax": "^1.0.0",
+ "chalk": "^4.0.0",
+ "expect": "^29.7.0",
+ "graceful-fs": "^4.2.9",
+ "jest-diff": "^29.7.0",
+ "jest-get-type": "^29.6.3",
+ "jest-matcher-utils": "^29.7.0",
+ "jest-message-util": "^29.7.0",
+ "jest-util": "^29.7.0",
+ "natural-compare": "^1.4.0",
+ "pretty-format": "^29.7.0",
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-snapshot/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/jest-snapshot/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-util": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz",
+ "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-util/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-util/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-util/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-util/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-util/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-util/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-validate": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz",
+ "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==",
+ "dev": true,
+ "dependencies": {
+ "@jest/types": "^29.6.3",
+ "camelcase": "^6.2.0",
+ "chalk": "^4.0.0",
+ "jest-get-type": "^29.6.3",
+ "leven": "^3.1.0",
+ "pretty-format": "^29.7.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-validate/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-validate/node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/jest-validate/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-validate/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-validate/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-validate/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-validate/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-watcher": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz",
+ "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==",
+ "dev": true,
+ "dependencies": {
+ "@jest/test-result": "^29.7.0",
+ "@jest/types": "^29.6.3",
+ "@types/node": "*",
+ "ansi-escapes": "^4.2.1",
+ "chalk": "^4.0.0",
+ "emittery": "^0.13.1",
+ "jest-util": "^29.7.0",
+ "string-length": "^4.0.1"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-watcher/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/jest-watcher/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/jest-watcher/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/jest-watcher/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/jest-watcher/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-watcher/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz",
+ "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "jest-util": "^29.7.0",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/leven": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+ "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/lines-and-columns": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "dev": true
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "dev": true
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
+ "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/make-dir/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/makeerror": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz",
+ "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==",
+ "dev": true,
+ "dependencies": {
+ "tmpl": "1.0.5"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
+ "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/node-int64": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
+ "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.17.tgz",
+ "integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==",
+ "dev": true
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-locate/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pirates": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
+ "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
+ "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "dev": true,
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/pure-rand": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz",
+ "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ]
+ },
+ "node_modules/react-is": {
+ "version": "18.3.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
+ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
+ "dev": true
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true
+ },
+ "node_modules/regenerate-unicode-properties": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz",
+ "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.4.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "dev": true
+ },
+ "node_modules/regenerator-transform": {
+ "version": "0.15.2",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz",
+ "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/runtime": "^7.8.4"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz",
+ "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/regjsgen": "^0.8.0",
+ "regenerate": "^1.4.2",
+ "regenerate-unicode-properties": "^10.1.0",
+ "regjsparser": "^0.9.1",
+ "unicode-match-property-ecmascript": "^2.0.0",
+ "unicode-match-property-value-ecmascript": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regjsparser": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
+ "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
+ "dev": true,
+ "dependencies": {
+ "jsesc": "~0.5.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-cwd": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz",
+ "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==",
+ "dev": true,
+ "dependencies": {
+ "resolve-from": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/resolve.exports": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz",
+ "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/reverse-mirage": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reverse-mirage/-/reverse-mirage-1.1.0.tgz",
+ "integrity": "sha512-cA1O7GR0pn4rMFoaiEG7Skms9GenuW91DtCxeR5hphyNhH90eowV4RmUVlVPVS11CPkezm/iUjnCfmxlHri05w==",
+ "peerDependencies": {
+ "typescript": ">=5.0.4",
+ "viem": ">=2"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
+ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
+ "dev": true
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.13",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz",
+ "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true
+ },
+ "node_modules/stack-utils": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz",
+ "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==",
+ "dev": true,
+ "dependencies": {
+ "escape-string-regexp": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/stack-utils/node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-length": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz",
+ "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==",
+ "dev": true,
+ "dependencies": {
+ "char-regex": "^1.0.2",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+ "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+ "dev": true,
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tmpl": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz",
+ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
+ "dev": true
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.21.3",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz",
+ "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "node_modules/unicode-canonical-property-names-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-ecmascript": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+ "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+ "dev": true,
+ "dependencies": {
+ "unicode-canonical-property-names-ecmascript": "^2.0.0",
+ "unicode-property-aliases-ecmascript": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-match-property-value-ecmascript": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
+ "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/unicode-property-aliases-ecmascript": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+ "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
+ "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/v8-to-istanbul": {
+ "version": "9.3.0",
+ "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
+ "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.12",
+ "@types/istanbul-lib-coverage": "^2.0.1",
+ "convert-source-map": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.12.0"
+ }
+ },
+ "node_modules/viem": {
+ "version": "2.21.19",
+ "resolved": "https://registry.npmjs.org/viem/-/viem-2.21.19.tgz",
+ "integrity": "sha512-FdlkN+UI1IU5sYOmzvygkxsUNjDRD5YHht3gZFu2X9xFv6Z3h9pXq9ycrYQ3F17lNfb41O2Ot4/aqbUkwOv9dA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/wevm"
+ }
+ ],
+ "dependencies": {
+ "@adraffy/ens-normalize": "1.11.0",
+ "@noble/curves": "1.6.0",
+ "@noble/hashes": "1.5.0",
+ "@scure/bip32": "1.5.0",
+ "@scure/bip39": "1.4.0",
+ "abitype": "1.0.6",
+ "isows": "1.0.6",
+ "webauthn-p256": "0.0.10",
+ "ws": "8.18.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.4"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/walker": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz",
+ "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==",
+ "dev": true,
+ "dependencies": {
+ "makeerror": "1.0.12"
+ }
+ },
+ "node_modules/webauthn-p256": {
+ "version": "0.0.10",
+ "resolved": "https://registry.npmjs.org/webauthn-p256/-/webauthn-p256-0.0.10.tgz",
+ "integrity": "sha512-EeYD+gmIT80YkSIDb2iWq0lq2zbHo1CxHlQTeJ+KkCILWpVy3zASH3ByD4bopzfk0uCwXxLqKGLqp2W4O28VFA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/wevm"
+ }
+ ],
+ "dependencies": {
+ "@noble/curves": "^1.4.0",
+ "@noble/hashes": "^1.4.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/write-file-atomic": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
+ "dev": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.7"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+ "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git OP/op-e2e/celo/package.json CELO/op-e2e/celo/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..ee0d66c7a7b5ce71517ccd992b2f81bc48e51f50
--- /dev/null
+++ CELO/op-e2e/celo/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "testsuite",
+ "version": "1.0.0",
+ "description": "",
+ "type": "module",
+ "main": "dist/test.js",
+ "scripts": {
+ "test": "jest tests --detectOpenHandles",
+ "format": "npx prettier . --write"
+ },
+ "author": "Celo Labs Inc.",
+ "license": "ISC",
+ "dependencies": {
+ "reverse-mirage": "^1.1.0",
+ "viem": "^2.13.1"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.24.7",
+ "@babel/preset-env": "^7.24.7",
+ "babel-jest": "^29.7.0",
+ "jest": "^29.7.0",
+ "prettier": "3.3.3"
+ }
+}
diff --git OP/op-e2e/celo/run_all_tests.sh CELO/op-e2e/celo/run_all_tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..0021e440e032bad1862e8fde8c0ebcce2ccf2b9d
--- /dev/null
+++ CELO/op-e2e/celo/run_all_tests.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+#shellcheck disable=SC1091
+set -eo pipefail
+
+SCRIPT_DIR=$(readlink -f "$(dirname "$0")")
+TEST_GLOB=$1
+spawn_devnet=${SPAWN_DEVNET:-true}
+
+if [[ $spawn_devnet != false ]]; then
+ ## Start geth
+ cd "$SCRIPT_DIR/../.." || exit 1
+ trap 'cd "$SCRIPT_DIR/../.." && make devnet-down' EXIT # kill bg job at exit
+ DEVNET_CELO=true make devnet-up
+fi
+
+cd "$SCRIPT_DIR" || exit 1
+source "$SCRIPT_DIR/shared.sh"
+
+# Wait for geth to be ready
+for _ in {1..10}; do
+ if cast block &>/dev/null; then
+ echo geth ready
+ break
+ fi
+ sleep 0.2
+done
+
+## Run tests
+echo Start tests
+failures=0
+tests=0
+for f in test_*"$TEST_GLOB"*; do
+ echo -e "\nRun $f"
+ if "./$f"; then
+ tput setaf 2 || true
+ echo "PASS $f"
+ else
+ tput setaf 1 || true
+ echo "FAIL $f ❌"
+ ((failures++)) || true
+ fi
+ tput sgr0 || true
+ ((tests++)) || true
+done
+
+## Final summary
+echo
+if [[ $failures -eq 0 ]]; then
+ tput setaf 2 || true
+ echo All tests succeeded!
+else
+ tput setaf 1 || true
+ echo "$failures/$tests" failed.
+fi
+tput sgr0 || true
+exit "$failures"
diff --git OP/op-e2e/celo/shared.sh CELO/op-e2e/celo/shared.sh
new file mode 100644
index 0000000000000000000000000000000000000000..7d15e83d45efe29ecdaa7789fdc84832340ed940
--- /dev/null
+++ CELO/op-e2e/celo/shared.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+#shellcheck disable=SC2034 # unused vars make sense in a shared file
+
+export ETH_RPC_URL=http://localhost:9545
+export ETH_RPC_URL_L1=http://localhost:8545
+
+export ACC_PRIVKEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
+ACC_ADDR=$(cast wallet address $ACC_PRIVKEY)
+export ACC_ADDR
+export REGISTRY_ADDR=0x000000000000000000000000000000000000ce10
+export TOKEN_ADDR=0x471ece3750da237f93b8e339c536989b8978a438
+export FEE_CURRENCY_DIRECTORY_ADDR=0x9212Fb72ae65367A7c887eC4Ad9bE310BAC611BF
diff --git OP/op-e2e/celo/src/OptimismPortal.js CELO/op-e2e/celo/src/OptimismPortal.js
new file mode 100644
index 0000000000000000000000000000000000000000..80b02f38341420bc72c43c39150aaf591dfa09fa
--- /dev/null
+++ CELO/op-e2e/celo/src/OptimismPortal.js
@@ -0,0 +1,658 @@
+export const OptimismPortalABI = [
+ {
+ type: 'constructor',
+ inputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'receive',
+ stateMutability: 'payable',
+ },
+ {
+ type: 'function',
+ name: 'balance',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'depositERC20Transaction',
+ inputs: [
+ {
+ name: '_to',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: '_mint',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: '_value',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: '_gasLimit',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ {
+ name: '_isCreation',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ {
+ name: '_data',
+ type: 'bytes',
+ internalType: 'bytes',
+ },
+ ],
+ outputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'depositTransaction',
+ inputs: [
+ {
+ name: '_to',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: '_value',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: '_gasLimit',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ {
+ name: '_isCreation',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ {
+ name: '_data',
+ type: 'bytes',
+ internalType: 'bytes',
+ },
+ ],
+ outputs: [],
+ stateMutability: 'payable',
+ },
+ {
+ type: 'function',
+ name: 'donateETH',
+ inputs: [],
+ outputs: [],
+ stateMutability: 'payable',
+ },
+ {
+ type: 'function',
+ name: 'finalizeWithdrawalTransaction',
+ inputs: [
+ {
+ name: '_tx',
+ type: 'tuple',
+ internalType: 'struct Types.WithdrawalTransaction',
+ components: [
+ {
+ name: 'nonce',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'sender',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'target',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'value',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'gasLimit',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'data',
+ type: 'bytes',
+ internalType: 'bytes',
+ },
+ ],
+ },
+ ],
+ outputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'finalizedWithdrawals',
+ inputs: [
+ {
+ name: '',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'guardian',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'address',
+ internalType: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'initialize',
+ inputs: [
+ {
+ name: '_l2Oracle',
+ type: 'address',
+ internalType: 'contract L2OutputOracle',
+ },
+ {
+ name: '_systemConfig',
+ type: 'address',
+ internalType: 'contract SystemConfig',
+ },
+ {
+ name: '_superchainConfig',
+ type: 'address',
+ internalType: 'contract SuperchainConfig',
+ },
+ {
+ name: '_initialBalance',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ ],
+ outputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'isOutputFinalized',
+ inputs: [
+ {
+ name: '_l2OutputIndex',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'l2Oracle',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'address',
+ internalType: 'contract L2OutputOracle',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'l2Sender',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'address',
+ internalType: 'address',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'minimumGasLimit',
+ inputs: [
+ {
+ name: '_byteCount',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ ],
+ outputs: [
+ {
+ name: '',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ ],
+ stateMutability: 'pure',
+ },
+ {
+ type: 'function',
+ name: 'params',
+ inputs: [],
+ outputs: [
+ {
+ name: 'prevBaseFee',
+ type: 'uint128',
+ internalType: 'uint128',
+ },
+ {
+ name: 'prevBoughtGas',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ {
+ name: 'prevBlockNum',
+ type: 'uint64',
+ internalType: 'uint64',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'paused',
+ inputs: [],
+ outputs: [
+ {
+ name: 'paused_',
+ type: 'bool',
+ internalType: 'bool',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'proveWithdrawalTransaction',
+ inputs: [
+ {
+ name: '_tx',
+ type: 'tuple',
+ internalType: 'struct Types.WithdrawalTransaction',
+ components: [
+ {
+ name: 'nonce',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'sender',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'target',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: 'value',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'gasLimit',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: 'data',
+ type: 'bytes',
+ internalType: 'bytes',
+ },
+ ],
+ },
+ {
+ name: '_l2OutputIndex',
+ type: 'uint256',
+ internalType: 'uint256',
+ },
+ {
+ name: '_outputRootProof',
+ type: 'tuple',
+ internalType: 'struct Types.OutputRootProof',
+ components: [
+ {
+ name: 'version',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ {
+ name: 'stateRoot',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ {
+ name: 'messagePasserStorageRoot',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ {
+ name: 'latestBlockhash',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ ],
+ },
+ {
+ name: '_withdrawalProof',
+ type: 'bytes[]',
+ internalType: 'bytes[]',
+ },
+ ],
+ outputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'provenWithdrawals',
+ inputs: [
+ {
+ name: '',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ ],
+ outputs: [
+ {
+ name: 'outputRoot',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ {
+ name: 'timestamp',
+ type: 'uint128',
+ internalType: 'uint128',
+ },
+ {
+ name: 'l2OutputIndex',
+ type: 'uint128',
+ internalType: 'uint128',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'setGasPayingToken',
+ inputs: [
+ {
+ name: '_token',
+ type: 'address',
+ internalType: 'address',
+ },
+ {
+ name: '_decimals',
+ type: 'uint8',
+ internalType: 'uint8',
+ },
+ {
+ name: '_name',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ {
+ name: '_symbol',
+ type: 'bytes32',
+ internalType: 'bytes32',
+ },
+ ],
+ outputs: [],
+ stateMutability: 'nonpayable',
+ },
+ {
+ type: 'function',
+ name: 'superchainConfig',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'address',
+ internalType: 'contract SuperchainConfig',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'systemConfig',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'address',
+ internalType: 'contract SystemConfig',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'function',
+ name: 'version',
+ inputs: [],
+ outputs: [
+ {
+ name: '',
+ type: 'string',
+ internalType: 'string',
+ },
+ ],
+ stateMutability: 'view',
+ },
+ {
+ type: 'event',
+ name: 'Initialized',
+ inputs: [
+ {
+ name: 'version',
+ type: 'uint8',
+ indexed: false,
+ internalType: 'uint8',
+ },
+ ],
+ anonymous: false,
+ },
+ {
+ type: 'event',
+ name: 'TransactionDeposited',
+ inputs: [
+ {
+ name: 'from',
+ type: 'address',
+ indexed: true,
+ internalType: 'address',
+ },
+ {
+ name: 'to',
+ type: 'address',
+ indexed: true,
+ internalType: 'address',
+ },
+ {
+ name: 'version',
+ type: 'uint256',
+ indexed: true,
+ internalType: 'uint256',
+ },
+ {
+ name: 'opaqueData',
+ type: 'bytes',
+ indexed: false,
+ internalType: 'bytes',
+ },
+ ],
+ anonymous: false,
+ },
+ {
+ type: 'event',
+ name: 'WithdrawalFinalized',
+ inputs: [
+ {
+ name: 'withdrawalHash',
+ type: 'bytes32',
+ indexed: true,
+ internalType: 'bytes32',
+ },
+ {
+ name: 'success',
+ type: 'bool',
+ indexed: false,
+ internalType: 'bool',
+ },
+ ],
+ anonymous: false,
+ },
+ {
+ type: 'event',
+ name: 'WithdrawalProven',
+ inputs: [
+ {
+ name: 'withdrawalHash',
+ type: 'bytes32',
+ indexed: true,
+ internalType: 'bytes32',
+ },
+ {
+ name: 'from',
+ type: 'address',
+ indexed: true,
+ internalType: 'address',
+ },
+ {
+ name: 'to',
+ type: 'address',
+ indexed: true,
+ internalType: 'address',
+ },
+ ],
+ anonymous: false,
+ },
+ {
+ type: 'error',
+ name: 'BadTarget',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'CallPaused',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'ContentLengthMismatch',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'EmptyItem',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'GasEstimation',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'InvalidDataRemainder',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'InvalidHeader',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'LargeCalldata',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'NoValue',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'NonReentrant',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'OnlyCustomGasToken',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'OutOfGas',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'SmallGasLimit',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'TransferFailed',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'Unauthorized',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'UnexpectedList',
+ inputs: [],
+ },
+ {
+ type: 'error',
+ name: 'UnexpectedString',
+ inputs: [],
+ },
+]
diff --git OP/op-e2e/celo/src/chain.js CELO/op-e2e/celo/src/chain.js
new file mode 100644
index 0000000000000000000000000000000000000000..25dac875054ddd90fd871937d6ee39946c60f81b
--- /dev/null
+++ CELO/op-e2e/celo/src/chain.js
@@ -0,0 +1,71 @@
+import { chainConfig } from 'viem/op-stack'
+import { defineChain } from 'viem'
+
+export function makeChainConfigs(l1ChainID, l2ChainID, contractAddresses) {
+ console.log(process.env)
+ return {
+ l2: defineChain({
+ formatters: {
+ ...chainConfig.formatters,
+ },
+ serializers: {
+ ...chainConfig.serializers,
+ },
+ id: l2ChainID,
+ name: 'Celo',
+ nativeCurrency: {
+ decimals: 18,
+ name: 'Celo - native currency',
+ symbol: 'CELO',
+ },
+ rpcUrls: {
+ default: {
+ http: [process.env.ETH_RPC_URL],
+ },
+ },
+ contracts: {
+ ...chainConfig.contracts,
+ l2OutputOracle: {
+ [l1ChainID]: {
+ address: contractAddresses.L2OutputOracleProxy,
+ },
+ },
+ disputeGameFactory: {
+ [l1ChainID]: {
+ address: contractAddresses.DisputeGameFactoryProxy,
+ },
+ },
+ portal: {
+ [l1ChainID]: {
+ address: contractAddresses.OptimismPortalProxy,
+ },
+ },
+ l1StandardBridge: {
+ [l1ChainID]: {
+ address: contractAddresses.L1StandardBridgeProxy,
+ },
+ },
+ },
+ }),
+ l1: defineChain({
+ id: l1ChainID,
+ testnet: true,
+ name: 'Ethereum L1',
+ nativeCurrency: {
+ decimals: 18,
+ name: 'Ether',
+ symbol: 'ETH',
+ },
+ rpcUrls: {
+ default: {
+ http: [process.env.ETH_RPC_URL_L1],
+ },
+ },
+ contracts: {
+ multicall3: {
+ address: contractAddresses.Multicall3,
+ },
+ },
+ }),
+ }
+}
diff --git OP/op-e2e/celo/src/config.js CELO/op-e2e/celo/src/config.js
new file mode 100644
index 0000000000000000000000000000000000000000..7e410dffbdd0de20f4dc8b781d6aabcd21f7448f
--- /dev/null
+++ CELO/op-e2e/celo/src/config.js
@@ -0,0 +1,98 @@
+import { createPublicClient, createWalletClient, http } from 'viem'
+import { readContract } from 'viem/actions'
+import { constructDepositCustomGas } from './deposit.js'
+import {
+ getERC20,
+ simulateERC20Transfer,
+ getERC20BalanceOf,
+ getERC20Symbol,
+ getERC20Decimals,
+ simulateERC20Approve,
+} from 'reverse-mirage'
+import {
+ publicActionsL1,
+ publicActionsL2,
+ walletActionsL1,
+ walletActionsL2,
+} from 'viem/op-stack'
+
+export function makeReadContract(contractAddress, contractABI) {
+ return (client) => {
+ return {
+ readContract: (args) => {
+ const rcArgs = {
+ address: contractAddress,
+ abi: contractABI,
+ functionName: args.functionName,
+ args: args.args,
+ }
+ return readContract(client, rcArgs)
+ },
+ }
+ }
+}
+
+export function erc20PublicActions(client) {
+ return {
+ getERC20: (args) => getERC20(client, args),
+ getERC20Symbol: (args) => getERC20Symbol(client, args),
+ getERC20BalanceOf: (args) => getERC20BalanceOf(client, args),
+ getERC20Decimals: (args) => getERC20Decimals(client, args),
+ }
+}
+export function erc20WalletActions(client) {
+ return {
+ simulateERC20Transfer: (args) => {
+ return simulateERC20Transfer(client, { args: args })
+ },
+ simulateERC20Approve: (args) => {
+ return simulateERC20Approve(client, { args: args })
+ },
+ }
+}
+
+export function celoL1PublicActions(client) {
+ return {
+ prepareDepositGasPayingTokenERC20: (args) => {
+ return constructDepositCustomGas(client, args)
+ },
+ }
+}
+
+export function setupClients(l1ChainConfig, l2ChainConfig, account) {
+ return {
+ l1: {
+ public: createPublicClient({
+ account,
+ chain: l1ChainConfig,
+ transport: http(),
+ })
+ .extend(publicActionsL1())
+ .extend(celoL1PublicActions)
+ .extend(erc20PublicActions),
+ wallet: createWalletClient({
+ account,
+ chain: l1ChainConfig,
+ transport: http(),
+ })
+ .extend(erc20WalletActions)
+ .extend(walletActionsL1()),
+ },
+ l2: {
+ public: createPublicClient({
+ account,
+ chain: l2ChainConfig,
+ transport: http(),
+ })
+ .extend(publicActionsL2())
+ .extend(erc20PublicActions),
+ wallet: createWalletClient({
+ account,
+ chain: l2ChainConfig,
+ transport: http(),
+ })
+ .extend(erc20WalletActions)
+ .extend(walletActionsL2()),
+ },
+ }
+}
diff --git OP/op-e2e/celo/src/deposit.js CELO/op-e2e/celo/src/deposit.js
new file mode 100644
index 0000000000000000000000000000000000000000..2e1f5ef17dbdf0eadd4fba293eba79712a1fd0b2
--- /dev/null
+++ CELO/op-e2e/celo/src/deposit.js
@@ -0,0 +1,127 @@
+import { getL2TransactionHashes } from 'viem/op-stack'
+import { OptimismPortalABI } from './OptimismPortal.js'
+
+// public client functionality
+export async function constructDepositCustomGas(client, parameters) {
+ const {
+ account,
+ chain = client.chain,
+ gas,
+ maxFeePerGas,
+ maxPriorityFeePerGas,
+ nonce,
+ request: {
+ data = '0x',
+ gas: l2Gas,
+ isCreation = false,
+ mint,
+ to = '0x',
+ value,
+ },
+ targetChain,
+ } = parameters
+
+ const portalAddress = (() => {
+ if (parameters.portalAddress) return parameters.portalAddress
+ if (chain) return targetChain.contracts.portal[chain.id].address
+ return Object.values(targetChain.contracts.portal)[0].address
+ })()
+ const callArgs = {
+ account: account,
+ abi: OptimismPortalABI,
+ address: portalAddress,
+ chain,
+ functionName: 'depositERC20Transaction',
+ /// @notice Entrypoint to depositing an ERC20 token as a custom gas token.
+ /// This function depends on a well formed ERC20 token. There are only
+ /// so many checks that can be done on chain for this so it is assumed
+ /// that chain operators will deploy chains with well formed ERC20 tokens.
+ /// @param _to Target address on L2.
+ /// @param _mint Units of ERC20 token to deposit into L2.
+ /// @param _value Units of ERC20 token to send on L2 to the recipient.
+ /// @param _gasLimit Amount of L2 gas to purchase by burning gas on L1.
+ /// @param _isCreation Whether or not the transaction is a contract creation.
+ /// @param _data Data to trigger the recipient with.
+ args: [
+ isCreation ? zeroAddress : to,
+ mint ?? value ?? 0n,
+ value ?? mint ?? 0n,
+ l2Gas,
+ isCreation,
+ data,
+ ],
+ maxFeePerGas,
+ maxPriorityFeePerGas,
+ nonce,
+ }
+ const gas_ =
+ typeof gas !== 'number' && gas !== null
+ ? await client.estimateContractGas(callArgs)
+ : undefined
+ callArgs.gas = gas_
+ const result = client.simulateContract(callArgs)
+ return { result: result, args: callArgs }
+}
+
+export async function deposit(args, config) {
+ var spentGas = BigInt(0)
+ const depositArgs = await config.client.l2.public.buildDepositTransaction({
+ mint: args.mint,
+ to: args.to,
+ })
+
+ const celoToken = await config.client.l1.public.getERC20({
+ erc20: {
+ address: config.addresses.CustomGasTokenProxy,
+ chainID: config.client.l1.public.chain.id,
+ },
+ })
+ const portalAddress =
+ config.client.l2.public.chain.contracts.portal[
+ config.client.l1.public.chain.id
+ ].address
+ const approve = await config.client.l1.wallet.simulateERC20Approve({
+ amount: { amount: args.mint, token: celoToken },
+ spender: portalAddress,
+ })
+ if (!approve.result) {
+ return {
+ success: false,
+ l1GasPayment: spentGas,
+ }
+ }
+
+ const approveHash = await config.client.l1.wallet.writeContract(
+ approve.request
+ )
+ // Wait for the L1 transaction to be processed.
+ const approveReceipt =
+ await config.client.l1.public.waitForTransactionReceipt({
+ hash: approveHash,
+ })
+
+ spentGas += approveReceipt.gasUsed * approveReceipt.effectiveGasPrice
+ const dep =
+ await config.client.l1.public.prepareDepositGasPayingTokenERC20(depositArgs)
+ const hash = await config.client.l1.wallet.writeContract(dep.args)
+
+ // Wait for the L1 transaction to be processed.
+ const receipt = await config.client.l1.public.waitForTransactionReceipt({
+ hash: hash,
+ })
+
+ spentGas += receipt.gasUsed * receipt.effectiveGasPrice
+
+ // Get the L2 transaction hash from the L1 transaction receipt.
+ const [l2Hash] = getL2TransactionHashes(receipt)
+
+ // Wait for the L2 transaction to be processed.
+ const l2Receipt = await config.client.l2.public.waitForTransactionReceipt({
+ hash: l2Hash,
+ })
+
+ return {
+ success: l2Receipt.status == 'success',
+ l1GasPayment: spentGas,
+ }
+}
diff --git OP/op-e2e/celo/src/withdraw.js CELO/op-e2e/celo/src/withdraw.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca98e43a5a6b93444d9f4eb82a0537c34b87a556
--- /dev/null
+++ CELO/op-e2e/celo/src/withdraw.js
@@ -0,0 +1,70 @@
+export const withdraw = async function (args, config) {
+ const initiateHash = await config.client.l2.wallet.initiateWithdrawal({
+ request: {
+ gas: args.gas,
+ to: args.to,
+ value: args.amount,
+ },
+ })
+ const receipt = await config.client.l2.public.waitForTransactionReceipt({
+ hash: initiateHash,
+ })
+ console.log('receipt', receipt)
+
+ const l2GasPayment =
+ receipt.gasUsed * receipt.effectiveGasPrice + receipt.l1fee
+
+ // FIXME: this blocks longer, the longer the devnet is running, see
+ // https://github.com/ethereum-optimism/optimism/issues/7668
+ // NOTE: this function requires the mulitcall contract to be deployed
+ // on the L1 chain.
+ const { output, withdrawal } = await config.client.l1.public.waitToProve({
+ receipt,
+ targetChain: config.client.l2.public.chain,
+ })
+ //
+
+ const proveWithdrawalArgs =
+ await config.client.l2.public.buildProveWithdrawal({
+ output,
+ withdrawal,
+ })
+ const proveHash =
+ await config.client.l1.wallet.proveWithdrawal(proveWithdrawalArgs)
+
+ const proveReceipt = await config.client.l1.public.waitForTransactionReceipt({
+ hash: proveHash,
+ })
+ if (proveReceipt.status != 'success') {
+ return {
+ success: false,
+ l2GasPayment: l2GasPayment,
+ }
+ }
+
+ await config.client.l1.public.waitToFinalize({
+ withdrawalHash: withdrawal.withdrawalHash,
+ targetChain: config.client.l2.public.chain,
+ })
+
+ // HACK: the waitToFinalize does not seem to calculate the wait time
+ // correctly..., lets hardcode a wait time for now to see if it can work.
+ // In theory viem is not waiting an additional DISPUTE_GAME_FINALITY_DELAY_SECONDS.
+ // The current default value for this is 6, but this was not enough in manual testing.
+ // TODO: fix this upstream in viem...
+ await new Promise((res) => setTimeout(res, 16 * 1000))
+ const finalizeHash = await config.client.l1.wallet.finalizeWithdrawal({
+ targetChain: config.client.l2.public.chain,
+ withdrawal,
+ })
+
+ const finalizeReceipt =
+ await config.client.l1.public.waitForTransactionReceipt({
+ hash: finalizeHash,
+ })
+
+ return {
+ success: finalizeReceipt.status == 'success',
+ l2GasPayment: l2GasPayment,
+ }
+}
diff --git OP/op-e2e/celo/test_npm.sh CELO/op-e2e/celo/test_npm.sh
new file mode 100755
index 0000000000000000000000000000000000000000..89783597300cf124d3091a535f3e01473998ae61
--- /dev/null
+++ CELO/op-e2e/celo/test_npm.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+#shellcheck disable=SC1091
+set -eo pipefail
+
+source shared.sh
+npm test
diff --git OP/op-e2e/celo/test_weth_bridge.sh CELO/op-e2e/celo/test_weth_bridge.sh
new file mode 100755
index 0000000000000000000000000000000000000000..19ff0ddb2cbb27acbe98c9a8db1be41a614fc499
--- /dev/null
+++ CELO/op-e2e/celo/test_weth_bridge.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#shellcheck disable=SC2086,SC1091
+set -eo pipefail
+set -x
+
+source shared.sh
+SCRIPT_DIR=$(readlink -f "$(dirname "$0")")
+CONTRACTS_DIR=$SCRIPT_DIR/../../packages/contracts-bedrock
+
+# Deploy WETH
+L1_WETH=$(
+ ETH_RPC_URL=$ETH_RPC_URL_L1 forge create --broadcast --private-key=$ACC_PRIVKEY --root $CONTRACTS_DIR $CONTRACTS_DIR/src/universal/WETH98.sol:WETH98 --json | jq .deployedTo -r
+)
+
+# create ERC20 token on L2
+L2_TOKEN=$(
+ cast send --private-key $ACC_PRIVKEY 0x4200000000000000000000000000000000000012 "createOptimismMintableERC20(address,string,string)" $L1_WETH "Wrapped Ether" "WETH" --json \
+ | jq -r '.logs[0].topics[2]' | cast parse-bytes32-address
+)
+
+# Wrap some ETH
+ETH_RPC_URL=$ETH_RPC_URL_L1 cast send --private-key $ACC_PRIVKEY $L1_WETH --value 1ether
+# Approve transfer to bridge
+L1_BRIDGE_ADDR=$(cast call 0x4200000000000000000000000000000000000010 'otherBridge() returns (address)')
+ETH_RPC_URL=$ETH_RPC_URL_L1 cast send --private-key $ACC_PRIVKEY $L1_WETH 'approve(address, uint256) returns (bool)' $L1_BRIDGE_ADDR 1ether
+# Bridge to L2
+ETH_RPC_URL=$ETH_RPC_URL_L1 cast send --private-key $ACC_PRIVKEY $L1_BRIDGE_ADDR 'bridgeERC20(address _localToken, address _remoteToken, uint256 _amount, uint32 _minGasLimit, bytes calldata _extraData)' $L1_WETH $L2_TOKEN 0.3ether 50000 0x --gas-limit 6000000
+
+# Setup up oracle and FeeCurrencyDirectory
+ORACLE=$(forge create --broadcast --private-key=$ACC_PRIVKEY --root $CONTRACTS_DIR $CONTRACTS_DIR/src/celo/testing/MockSortedOracles.sol:MockSortedOracles --json | jq .deployedTo -r)
+cast send --private-key $ACC_PRIVKEY $ORACLE 'setMedianRate(address, uint256)' $L2_TOKEN 100000000000000000
+cast send --private-key $ACC_PRIVKEY $FEE_CURRENCY_DIRECTORY_ADDR 'setCurrencyConfig(address, address, uint256)' $L2_TOKEN $ORACLE 60000
+
+# Check balance from bridging (we intentionally don't do this right after bridging, since it takes a bit)
+L2_BALANCE=$(cast call $L2_TOKEN 'balanceOf(address) returns (uint256)' $ACC_ADDR)
+echo L2 balance: $L2_BALANCE
+[[ $(echo $L2_BALANCE | awk '{print $1}') -gt 0 ]] || (echo "Bridging to L2 failed!"; exit 1)
+
+# Send fee currency tx!
+#TXHASH=$(~/op-geth/e2e_test/js-tests/send_tx.mjs 901 $ACC_PRIVKEY $L2_TOKEN)
+#cast receipt $TXHASH
+echo You can use privkey $ACC_PRIVKEY to pay for txs with $L2_TOKEN, now.
diff --git OP/op-e2e/celo/tests/setup.js CELO/op-e2e/celo/tests/setup.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7400420f6748a8f04bed56a47e6df58d6bdfbc1
--- /dev/null
+++ CELO/op-e2e/celo/tests/setup.js
@@ -0,0 +1,64 @@
+import { setupClients } from '../src/config.js'
+import { makeChainConfigs } from '../src/chain.js'
+import { privateKeyToAccount } from 'viem/accounts'
+import { readFileSync } from 'fs'
+
+// Default Anvil dev account that has a pre-allocation on the op-devnet:
+// "test test test test test test test test test test test junk" mnemonic account,
+// on path "m/44'/60'/0'/0/6".
+// Address: 0x976EA74026E726554dB657fA54763abd0C3a0aa9.
+const privKey =
+ '0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e'
+
+async function waitForNoError(func, timeout) {
+ const start = Date.now()
+ while (Date.now() - start < timeout) {
+ try {
+ await func()
+ return true
+ } catch (error) {}
+ await new Promise((r) => setTimeout(r, 1000))
+ }
+ return false
+}
+
+async function waitReachable(client, timeout) {
+ const f = async () => client.getChainId()
+ return waitForNoError(f, timeout)
+}
+
+async function waitForNextGame(client, l2ChainConfig, timeout) {
+ const f = async () =>
+ client.waitForNextGame({
+ pollingInterval: 500,
+ l2BlockNumber: 0,
+ targetChain: l2ChainConfig,
+ })
+ return waitForNoError(f, timeout)
+}
+
+export async function setup() {
+ const contractAddrs = JSON.parse(
+ readFileSync('../../.devnet/addresses.json', 'utf8')
+ )
+ const config = { account: privateKeyToAccount(privKey) }
+ const chainConfig = makeChainConfigs(900, 901, contractAddrs)
+
+ config.client = setupClients(
+ chainConfig.l1,
+ chainConfig.l2,
+ config.account,
+ contractAddrs
+ )
+ config.addresses = contractAddrs
+
+ const success = await Promise.all([
+ waitReachable(config.client.l1.public, 10_000),
+ waitReachable(config.client.l2.public, 10_000),
+ waitForNextGame(config.client.l1.public, chainConfig.l2, 60_000),
+ ])
+ if (success.every((v) => v == true)) {
+ return config
+ }
+ throw new Error('l1 and l2 clients not reachable within the deadline')
+}
diff --git OP/op-e2e/celo/tests/tokenduality.test.js CELO/op-e2e/celo/tests/tokenduality.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9980c81fece42a92f061e53be6cec62627a944f2
--- /dev/null
+++ CELO/op-e2e/celo/tests/tokenduality.test.js
@@ -0,0 +1,42 @@
+import { createAmountFromString } from 'reverse-mirage'
+import { setup } from './setup.js'
+
+const minute = 60 * 1000
+let config = {}
+
+beforeAll(async () => {
+ config = await setup()
+}, 30_000)
+
+test(
+ 'test token duality',
+ async () => {
+ const receiverAddr = '0x000000000000000000000000000000000000dEaD'
+ const dualityToken = await config.client.l2.public.getERC20({
+ erc20: {
+ address: '0x471ece3750da237f93b8e339c536989b8978a438',
+ chainID: config.client.l2.public.chain.id,
+ },
+ })
+ const balanceBefore = await config.client.l2.public.getBalance({
+ address: receiverAddr,
+ })
+
+ const sendAmount = createAmountFromString(dualityToken, '100')
+ const { request } = await config.client.l2.wallet.simulateERC20Transfer({
+ to: receiverAddr,
+ amount: sendAmount,
+ })
+ const transferHash = await config.client.l2.wallet.writeContract(request)
+ const receipt = await config.client.l2.public.waitForTransactionReceipt({
+ hash: transferHash,
+ })
+ expect(receipt.status).toBe('success')
+ const balanceAfter = await config.client.l2.public.getBalance({
+ address: receiverAddr,
+ })
+
+ expect(balanceAfter).toBe(balanceBefore + sendAmount.amount)
+ },
+ 1 * minute
+)
diff --git OP/op-e2e/celo/tests/withdraw_deposit.test.js CELO/op-e2e/celo/tests/withdraw_deposit.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..b7235239f4d1ff2653420f7406c322cbd4ceb83e
--- /dev/null
+++ CELO/op-e2e/celo/tests/withdraw_deposit.test.js
@@ -0,0 +1,77 @@
+import { withdraw } from '../src/withdraw.js'
+import { deposit } from '../src/deposit.js'
+import { parseEther } from 'viem'
+import { setup } from './setup.js'
+
+const minute = 60 * 1000
+var config = {}
+
+beforeAll(async () => {
+ config = await setup()
+}, minute)
+
+test(
+ 'execute a withdraw and a deposit in succession',
+ async () => {
+ const celoToken = await config.client.l1.public.getERC20({
+ erc20: {
+ address: config.addresses.CustomGasTokenProxy,
+ chainID: config.client.l1.public.chain.id,
+ },
+ })
+ const balanceL1Before = await config.client.l1.public.getERC20BalanceOf({
+ erc20: celoToken,
+ address: config.account.address,
+ })
+ const balanceL2Before = await config.client.l2.public.getBalance({
+ address: config.account.address,
+ })
+ const withdrawAmount = parseEther('1')
+ const withdrawResult = await withdraw(
+ {
+ amount: withdrawAmount,
+ to: config.account.address,
+ gas: 21_000n,
+ },
+ config
+ )
+ expect(withdrawResult.success).toBe(true)
+ const balanceL1AfterWithdraw =
+ await config.client.l1.public.getERC20BalanceOf({
+ erc20: celoToken,
+ address: config.account.address,
+ })
+ const balanceL2AfterWithdraw = await config.client.l2.public.getBalance({
+ address: config.account.address,
+ })
+ expect(balanceL1AfterWithdraw.amount).toBe(
+ balanceL1Before.amount + BigInt(withdrawAmount)
+ )
+ expect(balanceL2AfterWithdraw).toBe(
+ balanceL2Before - BigInt(withdrawAmount) - withdrawResult.l2GasPayment
+ )
+ const depositResult = await deposit(
+ {
+ mint: withdrawAmount,
+ to: config.account.address,
+ },
+ config
+ )
+ expect(depositResult.success).toBe(true)
+
+ const balanceL1AfterDeposit =
+ await config.client.l1.public.getERC20BalanceOf({
+ erc20: celoToken,
+ address: config.account.address,
+ })
+ const balanceL2AfterDeposit = await config.client.l2.public.getBalance({
+ address: config.account.address,
+ })
+
+ expect(balanceL1AfterDeposit.amount).toBe(balanceL1Before.amount)
+ expect(balanceL2AfterDeposit).toBe(
+ balanceL2Before - withdrawResult.l2GasPayment
+ )
+ },
+ 15 * minute
+)
diff --git OP/op-e2e/system/da/brotli_batcher_test.go CELO/op-e2e/system/da/brotli_batcher_test.go
index b44bd5af1623734f4ab8b20352a43071971a56b1..be8c289088f61b0120b4131ff183301707ce7b81 100644
--- OP/op-e2e/system/da/brotli_batcher_test.go
+++ CELO/op-e2e/system/da/brotli_batcher_test.go
@@ -85,7 +85,7 @@ receipt := helpers.SendL2Tx(t, cfg, l2Seq, ethPrivKey, func(opts *helpers.TxOpts) {
opts.Value = big.NewInt(1_000_000_000)
opts.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff}
- opts.Gas, err = core.IntrinsicGas(opts.Data, nil, false, true, true, false)
+ opts.Gas, err = core.IntrinsicGas(opts.Data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
opts.VerifyOnClients(l2Verif)
})
diff --git OP/op-e2e/system/da/eip4844_test.go CELO/op-e2e/system/da/eip4844_test.go
index 332da11f9d6f487d586b90a87b8a07a24dc72821..3ab4c59512a508f186ea35de7f8c8bc4faebfcf1 100644
--- OP/op-e2e/system/da/eip4844_test.go
+++ CELO/op-e2e/system/da/eip4844_test.go
@@ -131,7 +131,7 @@ opts.Nonce = 1 // Already have deposit
opts.ToAddr = &common.Address{0xff, 0xff}
// put some random data in the tx to make it fill up 6 blobs (multi-blob case)
opts.Data = testutils.RandomData(rand.New(rand.NewSource(420)), 400)
- opts.Gas, err = core.IntrinsicGas(opts.Data, nil, false, true, true, false)
+ opts.Gas, err = core.IntrinsicGas(opts.Data, nil, false, true, true, false, nil, nil)
require.NoError(t, err)
opts.VerifyOnClients(l2Verif)
})
diff --git OP/op-e2e/system/e2esys/setup.go CELO/op-e2e/system/e2esys/setup.go
index bc4364de9ad4b2b89d94268fce8e5ffbc2fc0ab2..7d6a51a64b9a195b79be133c70e078cdc7f17acf 100644
--- OP/op-e2e/system/e2esys/setup.go
+++ CELO/op-e2e/system/e2esys/setup.go
@@ -580,6 +580,7 @@ EcotoneTime: cfg.DeployConfig.EcotoneTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
FjordTime: cfg.DeployConfig.FjordTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
GraniteTime: cfg.DeployConfig.GraniteTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
InteropTime: cfg.DeployConfig.InteropTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
+ Cel2Time: cfg.DeployConfig.RegolithTime(uint64(cfg.DeployConfig.L1GenesisBlockTimestamp)),
ProtocolVersionsAddress: cfg.L1Deployments.ProtocolVersionsProxy,
AltDAConfig: rollupAltDAConfig,
}
diff --git OP/op-e2e/system/fees/fees_test.go CELO/op-e2e/system/fees/fees_test.go
index 61590313cbc4f6ca14fa1cc7330075468820a4c9..61ba48699b2bb09941a2209a35812d6a37388ef6 100644
--- OP/op-e2e/system/fees/fees_test.go
+++ CELO/op-e2e/system/fees/fees_test.go
@@ -16,6 +16,7 @@ "github.com/ethereum-optimism/optimism/op-service/predeploys"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/contracts/addresses"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"
@@ -135,8 +136,12 @@ require.Nil(t, err, "reading gpo decimals")
require.Equal(t, decimals.Uint64(), uint64(6), "wrong gpo decimals")
+ baseFeeRecipient := predeploys.BaseFeeVaultAddr
+ if sys.RollupConfig.IsCel2(sys.L2GenesisCfg.Timestamp) {
+ baseFeeRecipient = addresses.GetAddresses(cfg.L2ChainIDBig()).FeeHandler
+ }
// BaseFee Recipient
- baseFeeRecipientStartBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.BaseFeeVaultAddr, big.NewInt(rpc.EarliestBlockNumber.Int64()))
+ baseFeeRecipientStartBalance, err := l2Seq.BalanceAt(context.Background(), baseFeeRecipient, big.NewInt(rpc.EarliestBlockNumber.Int64()))
require.Nil(t, err)
// L1Fee Recipient
@@ -179,7 +184,7 @@
endBalance, err := l2Seq.BalanceAt(context.Background(), fromAddr, header.Number)
require.Nil(t, err)
- baseFeeRecipientEndBalance, err := l2Seq.BalanceAt(context.Background(), predeploys.BaseFeeVaultAddr, header.Number)
+ baseFeeRecipientEndBalance, err := l2Seq.BalanceAt(context.Background(), baseFeeRecipient, header.Number)
require.Nil(t, err)
l1Header, err := l1.HeaderByNumber(context.Background(), nil)
op-exporter
op-node
+139
-11
diff --git OP/op-node/flags/flags.go CELO/op-node/flags/flags.go
index 54334c150296aa9ea917a957e54a9715ed4f8759..6df7fea61db902e53f8fce8d4e1b0ec339b7546b 100644
--- OP/op-node/flags/flags.go
+++ CELO/op-node/flags/flags.go
@@ -236,6 +236,13 @@ EnvVars: prefixEnvVars("SEQUENCER_L1_CONFS"),
Value: 4,
Category: SequencerCategory,
}
+ SequencerUseFinalizedL1Flag = &cli.BoolFlag{
+ Name: "sequencer.use-finalized",
+ Usage: "Enable use of only finalized L1 blocks as L1 origin. Overwrites the value of 'sequencer.l1-confs'.",
+ EnvVars: prefixEnvVars("SEQUENCER_USE_FINALIZED"),
+ Value: false,
+ Category: SequencerCategory,
+ }
L1EpochPollIntervalFlag = &cli.DurationFlag{
Name: "l1.epoch-poll-interval",
Usage: "Poll interval for retrieving new L1 epoch updates such as safe and finalized block changes. Disabled if 0 or negative.",
@@ -396,6 +403,7 @@ L1RPCRateLimit,
L1RPCMaxBatchSize,
L1RPCMaxConcurrency,
L1HTTPPollInterval,
+ SequencerUseFinalizedL1Flag,
VerifierL1Confs,
SequencerEnabledFlag,
SequencerStoppedFlag,
diff --git OP/op-node/rollup/chain_spec.go CELO/op-node/rollup/chain_spec.go
index 66d2e526d0d12eb2f28a39d2ad6ce279548ece6e..74e32dad17cca58c12c9740e40aeed2dcfc68d5e 100644
--- OP/op-node/rollup/chain_spec.go
+++ CELO/op-node/rollup/chain_spec.go
@@ -29,6 +29,12 @@ // From Fjord, the max sequencer drift for a given block timestamp should be learned via the
// ChainSpec instead of reading the rollup configuration field directly.
const maxSequencerDriftFjord = 1800
+// Normal OP chains wait for five confirmations while Celo waits for finalization, which can take
+// up to 3 * 32 blocks. So we should allow for more drift to compensate.
+// 3 * 32 - 5 = 91 blocks
+// 91 * 12s block time = 1092
+const maxSequencerDriftCelo = maxSequencerDriftFjord + 1092
+
type ForkName string
const (
@@ -117,7 +123,11 @@ // this was a rollup configuration parameter. Since Fjord, it is a constant, so its effective value
// should always be queried via the ChainSpec.
func (s *ChainSpec) MaxSequencerDrift(t uint64) uint64 {
if s.IsFeatMaxSequencerDriftConstant(t) {
- return maxSequencerDriftFjord
+ if s.config.IsCel2(t) {
+ return maxSequencerDriftCelo
+ } else {
+ return maxSequencerDriftFjord
+ }
}
return s.config.MaxSequencerDrift
}
diff --git OP/op-node/rollup/derive/frame.go CELO/op-node/rollup/derive/frame.go
index 0baa1e120a14e3439b6b185fe97da5845424eeac..7547aca7531d95b2d212e069a24150a689715303 100644
--- OP/op-node/rollup/derive/frame.go
+++ CELO/op-node/rollup/derive/frame.go
@@ -8,10 +8,10 @@ "fmt"
"io"
)
-// Frames cannot be larger than 1 MB.
// Data transactions that carry frames are generally not larger than 128 KB due to L1 network conditions,
// but we leave space to grow larger anyway (gas limit allows for more data).
-const MaxFrameLen = 1_000_000
+// For AltDA, frames size can be larger. Setting to 16 MB as current blob limit for EigenDA.
+const MaxFrameLen = 16_000_000
// Data Format
//
@@ -85,7 +85,7 @@ if err := binary.Read(r, binary.BigEndian, &frameLength); err != nil {
return fmt.Errorf("reading frame_data_length: %w", eofAsUnexpectedMissing(err))
}
- // Cap frame length to MaxFrameLen (currently 1MB)
+ // Cap frame length to MaxFrameLen
if frameLength > MaxFrameLen {
return fmt.Errorf("frame_data_length is too large: %d", frameLength)
}
diff --git OP/op-node/rollup/driver/config.go CELO/op-node/rollup/driver/config.go
index f4013b95e1de67a3c00c6d01d2886d2dc065e56e..3353db1eabe4dfc34880c1b03bf0c3d11d824ccc 100644
--- OP/op-node/rollup/driver/config.go
+++ CELO/op-node/rollup/driver/config.go
@@ -20,4 +20,8 @@
// SequencerMaxSafeLag is the maximum number of L2 blocks for restricting the distance between L2 safe and unsafe.
// Disabled if 0.
SequencerMaxSafeLag uint64 `json:"sequencer_max_safe_lag"`
+
+ // SequencerUseFinalized is true when sequencer should use only finalized L1 blocks as origin.
+ // If this is set to true, the value of `SequencerConfDepth` is ignored.
+ SequencerUseFinalized bool `json:"sequencer_use_finalized"`
}
diff --git OP/op-node/rollup/driver/driver.go CELO/op-node/rollup/driver/driver.go
index 81607e612d5a255b728bf03a4b9f13e7adeef12e..c66dc9b46999c4973027e323f951abc5a0e52bd7 100644
--- OP/op-node/rollup/driver/driver.go
+++ CELO/op-node/rollup/driver/driver.go
@@ -17,6 +17,7 @@ "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
"github.com/ethereum-optimism/optimism/op-node/rollup/engine"
"github.com/ethereum-optimism/optimism/op-node/rollup/event"
"github.com/ethereum-optimism/optimism/op-node/rollup/finality"
+ "github.com/ethereum-optimism/optimism/op-node/rollup/finalized"
"github.com/ethereum-optimism/optimism/op-node/rollup/interop"
"github.com/ethereum-optimism/optimism/op-node/rollup/sequencing"
"github.com/ethereum-optimism/optimism/op-node/rollup/status"
@@ -244,8 +245,14 @@ var sequencer sequencing.SequencerIface
if driverCfg.SequencerEnabled {
asyncGossiper := async.NewAsyncGossiper(driverCtx, network, log, metrics)
attrBuilder := derive.NewFetchingAttributesBuilder(cfg, l1, l2)
- sequencerConfDepth := confdepth.NewConfDepth(driverCfg.SequencerConfDepth, statusTracker.L1Head, l1)
- findL1Origin := sequencing.NewL1OriginSelector(log, cfg, sequencerConfDepth)
+
+ var seqL1Blocks sequencing.L1Blocks
+ if driverCfg.SequencerUseFinalized {
+ seqL1Blocks = finalized.NewFinalized(statusTracker.L1Finalized, l1)
+ } else {
+ seqL1Blocks = confdepth.NewConfDepth(driverCfg.SequencerConfDepth, statusTracker.L1Head, l1)
+ }
+ findL1Origin := sequencing.NewL1OriginSelector(log, cfg, seqL1Blocks)
sequencer = sequencing.NewSequencer(driverCtx, log, cfg, attrBuilder, findL1Origin,
sequencerStateListener, sequencerConductor, asyncGossiper, metrics)
sys.Register("sequencer", sequencer, opts)
diff --git OP/op-node/rollup/finalized/finalized.go CELO/op-node/rollup/finalized/finalized.go
new file mode 100644
index 0000000000000000000000000000000000000000..47fbcc077e4f3726ce6ae66ad678ee3f5d21e149
--- /dev/null
+++ CELO/op-node/rollup/finalized/finalized.go
@@ -0,0 +1,29 @@
+package finalized
+
+import (
+ "context"
+
+ "github.com/ethereum/go-ethereum"
+
+ "github.com/ethereum-optimism/optimism/op-node/rollup/derive"
+ "github.com/ethereum-optimism/optimism/op-service/eth"
+)
+
+type finalized struct {
+ derive.L1Fetcher
+ l1Finalized func() eth.L1BlockRef
+}
+
+func NewFinalized(l1Finalized func() eth.L1BlockRef, fetcher derive.L1Fetcher) *finalized {
+ return &finalized{L1Fetcher: fetcher, l1Finalized: l1Finalized}
+}
+
+func (f *finalized) L1BlockRefByNumber(ctx context.Context, num uint64) (eth.L1BlockRef, error) {
+ l1Finalized := f.l1Finalized()
+ if num == 0 || num <= l1Finalized.Number {
+ return f.L1Fetcher.L1BlockRefByNumber(ctx, num)
+ }
+ return eth.L1BlockRef{}, ethereum.NotFound
+}
+
+var _ derive.L1Fetcher = (*finalized)(nil)
diff --git OP/op-node/rollup/finalized/finalized_test.go CELO/op-node/rollup/finalized/finalized_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8fa397bf076ce5bbe754438d56d0dd13664c0be7
--- /dev/null
+++ CELO/op-node/rollup/finalized/finalized_test.go
@@ -0,0 +1,58 @@
+package finalized
+
+import (
+ "context"
+ "testing"
+
+ "github.com/ethereum/go-ethereum"
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/stretchr/testify/require"
+
+ "github.com/ethereum-optimism/optimism/op-service/eth"
+ "github.com/ethereum-optimism/optimism/op-service/testutils"
+)
+
+var testFinalHash = common.Hash{0x01}
+
+type finalizedTest struct {
+ name string
+ final uint64
+ hash common.Hash // hash of finalized block
+ req uint64
+ pass bool
+}
+
+func (ft *finalizedTest) Run(t *testing.T) {
+ l1Fetcher := &testutils.MockL1Source{}
+ l1Finalized := eth.L1BlockRef{Number: ft.final, Hash: ft.hash}
+ l1FinalizedGetter := func() eth.L1BlockRef { return l1Finalized }
+
+ f := NewFinalized(l1FinalizedGetter, l1Fetcher)
+
+ if ft.pass {
+ // no calls to the l1Fetcher are made if the block number is not finalized yet
+ l1Fetcher.ExpectL1BlockRefByNumber(ft.req, eth.L1BlockRef{Number: ft.req}, nil)
+ }
+
+ out, err := f.L1BlockRefByNumber(context.Background(), ft.req)
+ l1Fetcher.AssertExpectations(t)
+
+ if ft.pass {
+ require.NoError(t, err)
+ require.Equal(t, out, eth.L1BlockRef{Number: ft.req})
+ } else {
+ require.Equal(t, ethereum.NotFound, err)
+ }
+}
+
+func TestFinalized(t *testing.T) {
+ testCases := []finalizedTest{
+ {name: "finalized", final: 10, hash: testFinalHash, req: 10, pass: true},
+ {name: "finalized past", final: 10, hash: testFinalHash, req: 8, pass: true},
+ {name: "not finalized", final: 10, hash: testFinalHash, req: 11, pass: false},
+ {name: "no L1 state", req: 10, pass: false},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, tc.Run)
+ }
+}
diff --git OP/op-node/rollup/status/status.go CELO/op-node/rollup/status/status.go
index 65121b1294aa4298fcca49431127e6fa1248d2d7..7b38f114de680889c57ba5275efd6f8148dc5fc1 100644
--- OP/op-node/rollup/status/status.go
+++ CELO/op-node/rollup/status/status.go
@@ -141,3 +141,8 @@ // L1Head is a helper function; the L1 head is closely monitored for confirmation-distance logic.
func (st *StatusTracker) L1Head() eth.L1BlockRef {
return st.SyncStatus().HeadL1
}
+
+// L1Finalized is a helper function to get the latest known finalized L1 block.
+func (st *StatusTracker) L1Finalized() eth.L1BlockRef {
+ return st.SyncStatus().FinalizedL1
+}
diff --git OP/op-node/rollup/types.go CELO/op-node/rollup/types.go
index 0c611a5d8d35a21d8b9c79a676af0501122bbde5..5dcb9fb961c1e326d05422d63cb992ea509c7101 100644
--- OP/op-node/rollup/types.go
+++ CELO/op-node/rollup/types.go
@@ -93,6 +93,7 @@ // a pre-mainnet Bedrock change that addresses findings of the Sherlock contest related to deposit attributes.
// "Regolith" is the loose deposited rock that sits on top of Bedrock.
// Active if RegolithTime != nil && L2 block timestamp >= *RegolithTime, inactive otherwise.
RegolithTime *uint64 `json:"regolith_time,omitempty"`
+ Cel2Time *uint64 `json:"cel2_time,omitempty"`
// CanyonTime sets the activation time of the Canyon network upgrade.
// Active if CanyonTime != nil && L2 block timestamp >= *CanyonTime, inactive otherwise.
@@ -407,6 +408,10 @@ func (c *Config) IsInterop(timestamp uint64) bool {
return c.InteropTime != nil && timestamp >= *c.InteropTime
}
+func (c *Config) IsCel2(timestamp uint64) bool {
+ return c.Cel2Time != nil && timestamp >= *c.Cel2Time
+}
+
func (c *Config) IsRegolithActivationBlock(l2BlockTime uint64) bool {
return c.IsRegolith(l2BlockTime) &&
l2BlockTime >= c.BlockTime &&
@@ -646,6 +651,7 @@ "granite_time", fmtForkTimeOrUnset(c.GraniteTime),
"holocene_time", fmtForkTimeOrUnset(c.HoloceneTime),
"interop_time", fmtForkTimeOrUnset(c.InteropTime),
"alt_da", c.AltDAConfig != nil,
+ "cel2_time", fmtForkTimeOrUnset(c.Cel2Time),
)
}
diff --git OP/op-node/service.go CELO/op-node/service.go
index b24e2a638335d5b034adde4f9f11eb5a3d1bdf8a..30a29fb98f3d8e38a7ce9b5d42bc119da8006407 100644
--- OP/op-node/service.go
+++ CELO/op-node/service.go
@@ -198,11 +198,12 @@ }
func NewDriverConfig(ctx *cli.Context) *driver.Config {
return &driver.Config{
- VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name),
- SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name),
- SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name),
- SequencerStopped: ctx.Bool(flags.SequencerStoppedFlag.Name),
- SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name),
+ VerifierConfDepth: ctx.Uint64(flags.VerifierL1Confs.Name),
+ SequencerConfDepth: ctx.Uint64(flags.SequencerL1Confs.Name),
+ SequencerEnabled: ctx.Bool(flags.SequencerEnabledFlag.Name),
+ SequencerStopped: ctx.Bool(flags.SequencerStoppedFlag.Name),
+ SequencerMaxSafeLag: ctx.Uint64(flags.SequencerMaxSafeLagFlag.Name),
+ SequencerUseFinalized: ctx.Bool(flags.SequencerUseFinalizedL1Flag.Name),
}
}
op-program
op-proposer
op-service
op-signer
op-wheel
ops-bedrock
+1
-1
diff --git OP/ops-bedrock/l2-op-geth.Dockerfile CELO/ops-bedrock/l2-op-geth.Dockerfile
index c66bac56da81bde5eeba4231b01a43d8ddff37a7..47f5fe81126c0acb0c832e4f23599e6690d362ec 100644
--- OP/ops-bedrock/l2-op-geth.Dockerfile
+++ CELO/ops-bedrock/l2-op-geth.Dockerfile
@@ -1,4 +1,4 @@
-FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:optimism
+FROM --platform=linux/amd64 us-west1-docker.pkg.dev/blockchaintestsglobaltestnet/dev-images/op-geth@sha256:2cbe7293f435d37312290c52784c3215559a4889dab686c25da677d088676fd3
RUN apk add --no-cache jq
proxyd
specs
indexer
Other changes
+4124
-6
diff --git OP/.dockerignore CELO/.dockerignore
index 11e5eb817c5abd64adc75501c422b968c4e28760..fef57cbe46cd94f3cf600319f4832c6f69146ab9 100644
--- OP/.dockerignore
+++ CELO/.dockerignore
@@ -11,3 +11,6 @@ build/_workspace
build/bin
build/_bin
tests/testdata
+
+# Ignore generated credentials from google-github-actions/auth
+gha-creds-*.json
diff --git OP/.envrc.example CELO/.envrc.example
index 43ccf74842b63f71531e4c96b429a5ebbb0e6ea6..f864390d22448d87a51bf6b6717b5e10a33a7e19 100644
--- OP/.envrc.example
+++ CELO/.envrc.example
@@ -66,3 +66,18 @@
# Private key to use for contract deployments, you don't need to worry about
# this for the Getting Started guide.
export PRIVATE_KEY=
+
+# CELO additional configuration
+export ENABLE_GOVERNANCE=false
+export FUNDS_DEV_ACCOUNTS=false
+export USE_ALTDA=false
+# Set to false if migrating state from a Celo L1. True for new testnets
+export DEPLOY_CELO_CONTRACTS=false
+
+export USE_CUSTOM_GAS_TOKEN=true
+# Set to "0x0000000000000000000000000000000000000000" when the contract
+# should get deployed (via create2) on L1 as part of the deploy script.
+# Set to the deployed contract address when already deployed on L1
+# This only works when USE_CUSTOM_GAS_TOKEN=true
+export CUSTOM_GAS_TOKEN_ADDRESS=0x0000000000000000000000000000000000000000
+
diff --git OP/.gitignore CELO/.gitignore
index 9751cc60898510519d6f938add9861b22a5b3166..a44168fae6f70ba875b1ea45568fdbdb473ca066 100644
--- OP/.gitignore
+++ CELO/.gitignore
@@ -46,3 +46,9 @@ __pycache__
# Ignore echidna artifacts
crytic-export
+
+# vscode
+.vscode/
+
+# Ignore generated credentials from google-github-actions/auth
+gha-creds-*.json
diff --git OP/bedrock-devnet/devnet/__init__.py CELO/bedrock-devnet/devnet/__init__.py
index 8a3fb0ee4c9946098367d1aedde524c4ac09002f..eec090bbc62cf294b96f2fa55547a05edc02d790 100644
--- OP/bedrock-devnet/devnet/__init__.py
+++ CELO/bedrock-devnet/devnet/__init__.py
@@ -31,6 +31,7 @@ DEVNET_NO_BUILD = os.getenv('DEVNET_NO_BUILD') == "true"
DEVNET_L2OO = os.getenv('DEVNET_L2OO') == "true"
DEVNET_ALTDA = os.getenv('DEVNET_ALTDA') == "true"
GENERIC_ALTDA = os.getenv('GENERIC_ALTDA') == "true"
+DEVNET_CELO = os.getenv('DEVNET_CELO') == "true"
class Bunch:
def __init__(self, **kwds):
@@ -129,6 +130,15 @@ if DEVNET_ALTDA:
deploy_config['useAltDA'] = True
if GENERIC_ALTDA:
deploy_config['daCommitmentType'] = "GenericCommitment"
+ if DEVNET_CELO:
+ deploy_config['useFaultProofs'] = True
+ deploy_config['useCustomGasToken'] = True
+ deploy_config['gasPriceOracleBlobBaseFeeScalar'] = 0
+ deploy_config['gasPriceOracleBaseFeeScalar'] = 0
+ deploy_config['deployCeloContracts'] = True
+ # Usage of the zero address in combination of the useCustomGasToken == True
+ # will deploy a new contract
+ deploy_config['customGasTokenAddress'] = "0x0000000000000000000000000000000000000000"
write_json(paths.devnet_config_path, deploy_config)
def devnet_l1_allocs(paths):
diff --git OP/cannon/mipsevm/testutil/evm.go CELO/cannon/mipsevm/testutil/evm.go
index dbe9970fdc24455e484c165ae8b31165eff763cb..d34b778aa6459b1ab83a296375820ab5d470519a 100644
--- OP/cannon/mipsevm/testutil/evm.go
+++ CELO/cannon/mipsevm/testutil/evm.go
@@ -100,7 +100,9 @@ state, err := state.New(types.EmptyRootHash, statedb, nil)
if err != nil {
panic(fmt.Errorf("failed to create memory state db: %w", err))
}
- blockContext := core.NewEVMBlockContext(header, bc, nil, chainCfg, state)
+
+ feeCurrencyContext := core.GetFeeCurrencyContext(header, chainCfg, state)
+ blockContext := core.NewEVMBlockContext(header, bc, nil, chainCfg, state, feeCurrencyContext)
vmCfg := vm.Config{}
env := vm.NewEVM(blockContext, vm.TxContext{}, state, chainCfg, vmCfg)
diff --git OP/funding.json CELO/funding.json
new file mode 100644
index 0000000000000000000000000000000000000000..a6b4c73180af2b2b92704b87bb978936a832cbbe
--- /dev/null
+++ CELO/funding.json
@@ -0,0 +1,5 @@
+{
+ "opRetro": {
+ "projectId": "0x839f24397fbcd261408f074eaf35aee98f500f5185a27e6c470c5307e967c017"
+ }
+}
diff --git OP/op-batcher/batcher/driver.go CELO/op-batcher/batcher/driver.go
index 968e6de3e71aedda621cc89cca2380f61d29cf2f..6b8b8b5e58060ca32c3fe08986a6cf06d8904932 100644
--- OP/op-batcher/batcher/driver.go
+++ CELO/op-batcher/batcher/driver.go
@@ -665,7 +665,7 @@
// sendTx uses the txmgr queue to send the given transaction candidate after setting its
// gaslimit. It will block if the txmgr queue has reached its MaxPendingTransactions limit.
func (l *BatchSubmitter) sendTx(txdata txData, isCancel bool, candidate *txmgr.TxCandidate, queue *txmgr.Queue[txRef], receiptsCh chan txmgr.TxReceipt[txRef]) {
- intrinsicGas, err := core.IntrinsicGas(candidate.TxData, nil, false, true, true, false)
+ intrinsicGas, err := core.IntrinsicGas(candidate.TxData, nil, false, true, true, false, nil, nil)
if err != nil {
// we log instead of return an error here because txmgr can do its own gas estimation
l.Log.Error("Failed to calculate intrinsic gas", "err", err)
diff --git OP/op-batcher/batcher/service.go CELO/op-batcher/batcher/service.go
index 6ed906af15aa1db3e17791f34f5aa59afa72d2a8..377bb7d41b39e9be978eb41d1ba90e1b62ee64e5 100644
--- OP/op-batcher/batcher/service.go
+++ CELO/op-batcher/batcher/service.go
@@ -218,6 +218,9 @@ default:
return fmt.Errorf("unknown data availability type: %v", cfg.DataAvailabilityType)
}
+ if bs.UseAltDA && cfg.DataAvailabilityType != flags.CalldataType {
+ return fmt.Errorf("cannot use Blobs with Alt DA")
+ }
if bs.UseAltDA && cc.MaxFrameSize > altda.MaxInputSize {
return fmt.Errorf("max frame size %d exceeds altDA max input size %d", cc.MaxFrameSize, altda.MaxInputSize)
}
diff --git OP/op-batcher/batcher/test_batch_submitter.go CELO/op-batcher/batcher/test_batch_submitter.go
index 9ff5ca69796fe4f6999dd0418bc480f71952f295..b959a8f3897c112a87b6bad703cdf506aff2d616 100644
--- OP/op-batcher/batcher/test_batch_submitter.go
+++ CELO/op-batcher/batcher/test_batch_submitter.go
@@ -33,7 +33,7 @@ candidate = l.calldataTxCandidate([]byte{})
} else if candidate, err = l.blobTxCandidate(emptyTxData); err != nil {
return err
}
- if candidate.GasLimit, err = core.IntrinsicGas(candidate.TxData, nil, false, true, true, false); err != nil {
+ if candidate.GasLimit, err = core.IntrinsicGas(candidate.TxData, nil, false, true, true, false, nil, nil); err != nil {
return err
}
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-dango.json CELO/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-dango.json
new file mode 100644
index 0000000000000000000000000000000000000000..dd69e13ab4f941e212e767152fdb6e2cfb315cfc
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-dango.json
@@ -0,0 +1,91 @@
+ {
+ "l1StartingBlockTag": "0xe18e94c26beea64e318e25c32303c9a1ee2bfcee4492337bb5ac14181e99bd0c",
+
+ "l1ChainID": 17000,
+ "l2ChainID": 44787,
+ "l2BlockTime": 2,
+ "l1BlockTime": 12,
+
+ "maxSequencerDrift": 600,
+ "sequencerWindowSize": 3600,
+ "channelTimeout": 300,
+
+ "p2pSequencerAddress": "0x644C82d76A43Fe9c76eda0EEd0f0DC17235c3005",
+ "batchInboxAddress": "0xff00000000000000000000000000000000044787",
+ "batchSenderAddress": "0x1660B1F70De0f32490b50f976e8983213dCF7FD5",
+
+ "l2OutputOracleSubmissionInterval": 120,
+ "l2OutputOracleStartingBlockNumber": 26216760,
+ "l2OutputOracleStartingTimestamp": 1726651200,
+
+ "l2OutputOracleProposer": "0x1BA11Ec6581FC8C3e35D6E345aEC977796Ffe89b",
+ "l2OutputOracleChallenger": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "finalizationPeriodSeconds": 12,
+
+ "proxyAdminOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "baseFeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "l1FeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "sequencerFeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "finalSystemOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "superchainConfigGuardian": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "baseFeeVaultWithdrawalNetwork": 0,
+ "l1FeeVaultWithdrawalNetwork": 0,
+ "sequencerFeeVaultWithdrawalNetwork": 0,
+
+ "gasPriceOracleOverhead": 0,
+ "gasPriceOracleScalar": 1000000,
+
+ "deployCeloContracts": false,
+
+ "enableGovernance": false,
+ "governanceTokenSymbol": "OP",
+ "governanceTokenName": "Optimism",
+ "governanceTokenOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "l2GenesisBlockGasLimit": "0x1c9c380",
+ "l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
+
+ "eip1559Denominator": 50,
+ "eip1559DenominatorCanyon": 250,
+ "eip1559Elasticity": 6,
+ "l2GenesisFjordTimeOffset": "0x0",
+ "l2GenesisRegolithTimeOffset": "0x0",
+ "l2GenesisEcotoneTimeOffset": "0x0",
+ "l2GenesisDeltaTimeOffset": "0x0",
+ "l2GenesisCanyonTimeOffset": "0x0",
+ "systemConfigStartBlock": 0,
+
+ "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+
+ "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
+ "faultGameMaxDepth": 44,
+ "faultGameClockExtension": 0,
+ "faultGameMaxClockDuration": 1200,
+ "faultGameGenesisBlock": 0,
+ "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "faultGameSplitDepth": 14,
+ "faultGameWithdrawalDelay": 600,
+
+ "preimageOracleMinProposalSize": 1800000,
+ "preimageOracleChallengePeriod": 300,
+
+ "fundDevAccounts": false,
+ "useFaultProofs": false,
+ "proofMaturityDelaySeconds": 604800,
+ "disputeGameFinalityDelaySeconds": 302400,
+ "respectedGameType": 0,
+
+ "useAltDA": true,
+ "daCommitmentType": "GenericCommitment",
+ "daChallengeWindow": 1,
+ "daResolveWindow": 1,
+
+ "useCustomGasToken": true,
+ "customGasTokenAddress": "0x0000000000000000000000000000000000000000"
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-holesky-alfajores.json CELO/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-holesky-alfajores.json
new file mode 100644
index 0000000000000000000000000000000000000000..0c8dee05d9c5b94f42bc97845fdf66da9b255a4c
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/deploy-config-holesky-alfajores.json
@@ -0,0 +1,90 @@
+{
+ "l1StartingBlockTag": "0xbbed3612407993e67f8ca7a423b181837ae164a531941e78f5ee48e766d39cad",
+
+ "l1ChainID": 17000,
+ "l2ChainID": 44787,
+ "l2BlockTime": 2,
+ "l1BlockTime": 12,
+
+ "maxSequencerDrift": 600,
+ "sequencerWindowSize": 3600,
+ "channelTimeout": 300,
+
+ "p2pSequencerAddress": "0x644C82d76A43Fe9c76eda0EEd0f0DC17235c3005",
+ "batchInboxAddress": "0xff00000000000000000000000000000000044787",
+ "batchSenderAddress": "0x1660B1F70De0f32490b50f976e8983213dCF7FD5",
+
+ "l2OutputOracleSubmissionInterval": 120,
+ "l2OutputOracleStartingBlockNumber": 0,
+ "l2OutputOracleStartingTimestamp": 1718312256,
+
+ "l2OutputOracleProposer": "0x1BA11Ec6581FC8C3e35D6E345aEC977796Ffe89b",
+ "l2OutputOracleChallenger": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "finalizationPeriodSeconds": 12,
+
+ "proxyAdminOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "baseFeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "l1FeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "sequencerFeeVaultRecipient": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "finalSystemOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+ "superchainConfigGuardian": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000",
+ "baseFeeVaultWithdrawalNetwork": 0,
+ "l1FeeVaultWithdrawalNetwork": 0,
+ "sequencerFeeVaultWithdrawalNetwork": 0,
+
+ "gasPriceOracleOverhead": 0,
+ "gasPriceOracleScalar": 1000000,
+
+ "enableGovernance": false,
+ "governanceTokenSymbol": "OP",
+ "governanceTokenName": "Optimism",
+ "governanceTokenOwner": "0xc07C5A1fBF6c7BC6b4f321E7dd031c0E1E98d32d",
+
+ "l2GenesisBlockGasLimit": "0x1c9c380",
+ "l2GenesisBlockBaseFeePerGas": "0x3b9aca00",
+ "l2GenesisRegolithTimeOffset": "0x0",
+
+ "eip1559Denominator": 50,
+ "eip1559DenominatorCanyon": 250,
+ "eip1559Elasticity": 6,
+
+ "l2GenesisGraniteTimeOffset": "0x0",
+ "l2GenesisEcotoneTimeOffset": "0x0",
+ "l2GenesisDeltaTimeOffset": "0x0",
+ "l2GenesisCanyonTimeOffset": "0x0",
+
+ "systemConfigStartBlock": 0,
+
+ "requiredProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "recommendedProtocolVersion": "0x0000000000000000000000000000000000000000000000000000000000000000",
+
+ "faultGameAbsolutePrestate": "0x03c7ae758795765c6664a5d39bf63841c71ff191e9189522bad8ebff5d4eca98",
+ "faultGameMaxDepth": 44,
+ "faultGameClockExtension": 0,
+ "faultGameMaxClockDuration": 600,
+ "faultGameGenesisBlock": 0,
+ "faultGameGenesisOutputRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "faultGameSplitDepth": 14,
+ "faultGameWithdrawalDelay": 604800,
+
+ "preimageOracleMinProposalSize": 1800000,
+ "preimageOracleChallengePeriod": 86400,
+
+ "fundDevAccounts": false,
+ "useFaultProofs": false,
+ "proofMaturityDelaySeconds": 604800,
+ "disputeGameFinalityDelaySeconds": 302400,
+ "respectedGameType": 0,
+
+ "usePlasma": false,
+ "daCommitmentType": "KeccakCommitment",
+ "daChallengeWindow": 160,
+ "daResolveWindow": 160,
+ "daBondSize": 1000000,
+ "daResolverRefundPercentage": 0
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-dango.json CELO/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-dango.json
new file mode 100644
index 0000000000000000000000000000000000000000..58c1f74772ed173da257ce7ab3fb5a03bad32d9a
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-dango.json
@@ -0,0 +1,37 @@
+{
+ "AddressManager": "0x5Ab3E4093B06a69954885caDAF29b280613c674f",
+ "AnchorStateRegistry": "0x5b530E1DD25513F0Da1CC39333f6fa91143884aB",
+ "AnchorStateRegistryProxy": "0xCCb982Cc00F9Cc970f71AF753Ff834e9AadADad6",
+ "CustomGasToken": "0xf7a83872810aBea270FAFF54206A522AB53f3df1",
+ "CustomGasTokenProxy": "0x3c300204B89F8A333350d9FfE72352D990DDA36f",
+ "DelayedWETH": "0x9eC20144141099E0c0581ABe0C507aCd2B07Da68",
+ "DelayedWETHProxy": "0xb0b158f73CF23c2edc220E586Bd043CB1b69c5Ad",
+ "DisputeGameFactory": "0x88ca8D6b24b691F617C9A02Ce8179F23C13e13Ae",
+ "DisputeGameFactoryProxy": "0x3889C8BA734148dec7A31472B4A370BC7fc3E50c",
+ "L1CrossDomainMessenger": "0xDb787d88Fa092d7144053138023137b01b2FB1af",
+ "L1CrossDomainMessengerProxy": "0x4401780183661b211a9ED386D56b400E430b0995",
+ "L1ERC721Bridge": "0x442Cc0A770Cd776930a14C0d3363a2931aBE273b",
+ "L1ERC721BridgeProxy": "0xC262D512A52D4F90D7Bc221979A584857Ab90dd9",
+ "L1StandardBridge": "0x3D4712d8cA71b8f5ae918213421e098761415898",
+ "L1StandardBridgeProxy": "0x59f2BDd9674c8C7c5750b12a004783da9a992e5A",
+ "L2OutputOracle": "0x1dd308d7e3aC77ea70f3c7069b29350665ab57F4",
+ "L2OutputOracleProxy": "0xD31bf46c090Ea08191fd11BFbf0758fAbeE468cC",
+ "Mips": "0x30f82aD995f412FBC3386022270AB071e616CaEA",
+ "OptimismMintableERC20Factory": "0x4626Da66AEE29bC145c7B04614437Aa6540D82F2",
+ "OptimismMintableERC20FactoryProxy": "0xabcd2bd6a5bc474287Fc460aD99F70d42711AA33",
+ "OptimismPortal": "0xD10c0833b38b47662200A026d60f0c891ea6C960",
+ "OptimismPortal2": "0xAAcC881F37e45CAb4C57A6757DE0334FC5b4DE7F",
+ "OptimismPortalProxy": "0xf550A0aEc6cD8fDFA904242d6e07F71E38BE5240",
+ "PermissionedDelayedWETHProxy": "0x85E318CE71dE55c19290Fa22149cC773526C8987",
+ "PreimageOracle": "0x2c010f9f6A63234d03baB647788633Fd5000410A",
+ "ProtocolVersions": "0x9233fCE30bfb57de432B1a8cf0Cad87A12011eFC",
+ "ProtocolVersionsProxy": "0x4CE6aDa5fef5BffD2f13257aAF5a40efd412C8E7",
+ "ProxyAdmin": "0x9f03734bE814De3652C757B3a5702BfE99BA0098",
+ "SafeProxyFactory": "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2",
+ "SafeSingleton": "0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552",
+ "SuperchainConfig": "0x05B71600Fe59197339837509F702da31F9fa5cf3",
+ "SuperchainConfigProxy": "0xDDfcA11fD8553C6Fc1185aD5f492230c3A0091E3",
+ "SystemConfig": "0x5b10806e8068B517eaBd8DeD5B872034f31878F9",
+ "SystemConfigProxy": "0xFbe6510A1E209d9E2148d54F134f4E5634bE7241",
+ "SystemOwnerSafe": "0xD751beb42dBcde9BDe9E2866c0490DccA6A11Ba9"
+}
\ No newline at end of file
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-holesky.json CELO/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-holesky.json
new file mode 100644
index 0000000000000000000000000000000000000000..b37b79f4d4c8f1ee70c7aae7e7f351713226b8a3
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/deployment-l1-holesky.json
@@ -0,0 +1,34 @@
+{
+ "AddressManager": "0x2d256f3b82f673Ee377C393fBF2Cf3DcA5D1D901",
+ "AnchorStateRegistry": "0x036fDE501893043825356Ce49dfd554809F07597",
+ "AnchorStateRegistryProxy": "0xe5077701c64782954d27384da76D95ABf320460f",
+ "DelayedWETH": "0x408Ad04Dd953958B080226025E17d6Ba12987EB7",
+ "DelayedWETHProxy": "0x27f7Ade64F031A39553Be8104bF8B0b410735845",
+ "DisputeGameFactory": "0xd7771F9687804Bba1D360B08AD9e4d8CB4523738",
+ "DisputeGameFactoryProxy": "0x193FdDF22D31c227f1Af1286cf2B051d701FF86E",
+ "L1CrossDomainMessenger": "0x1e3513a619AA4f2550CDD95709B92C1FE0397184",
+ "L1CrossDomainMessengerProxy": "0x35841aC1f5FdC5b812562adB17F6A0B9A178F643",
+ "L1ERC721Bridge": "0x695b01393f0539ec64AC316d4998E4130309efB0",
+ "L1ERC721BridgeProxy": "0x2b9C1e5b9a0D01256388cc4A0F8F290E839F2d82",
+ "L1StandardBridge": "0x2d1A818544b657Bc5d1E8c8B80F953bd0CA1C9B2",
+ "L1StandardBridgeProxy": "0xD10A531CB9b80BD507501F34D87Ad4083E9b7F98",
+ "L2OutputOracle": "0x04CD14625ff0Da62d6E0820a816b4dD3eCd0FF27",
+ "L2OutputOracleProxy": "0x5636f9D582DB69EAf1Eb9f05B0738225C91fBC1E",
+ "Mips": "0x60E1b8b535626Fc9fFCdf6147B45879634645771",
+ "OptimismMintableERC20Factory": "0x3fcd69a03857aA6e79AE9408fc7c887EE70FC145",
+ "OptimismMintableERC20FactoryProxy": "0x23c80F2503b93a58EC620D20b6b9B6AB8cCa2a12",
+ "OptimismPortal": "0xdF803FAC1d84a31Ff5aee841f11659f9a3787CE5",
+ "OptimismPortal2": "0x60bc423dDf0B24fa5104EcacAC5000674Ac3EBfB",
+ "OptimismPortalProxy": "0xa292B051eA58e2558243f4A9f74262B1796c9648",
+ "PreimageOracle": "0xEC19353B7364Fb85b9b0A57EaEEC6aCeBbFb6a53",
+ "ProtocolVersions": "0x077d61D4fb3378025950Bb60AD69179B38921107",
+ "ProtocolVersionsProxy": "0x791D5101840A547F1EE91148d34E061412A57ECD",
+ "ProxyAdmin": "0x4ddC758DA1697Ad58D86D03150872c042390dCa2",
+ "SafeProxyFactory": "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2",
+ "SafeSingleton": "0xd9Db270c1B5E3Bd161E8c8503c55cEABeE709552",
+ "SuperchainConfig": "0xA4f7dB67A6e098613B107be3F8441475Ec30FCC2",
+ "SuperchainConfigProxy": "0xB21214DA32a85A0d43372310D62095cf91d67765",
+ "SystemConfig": "0xeFA98Ba3ada6c6AC4bB84074820685E1F01C835d",
+ "SystemConfigProxy": "0x733043Aa78d25F6759d9e6Ce2B2897bE6d630E08",
+ "SystemOwnerSafe": "0xD2a6B91aB77691D6F8688eAFA7a5f188bc5baA3a"
+}
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/rollup-config-dango.json CELO/op-chain-ops/cmd/celo-migrate/testdata/rollup-config-dango.json
new file mode 100644
index 0000000000000000000000000000000000000000..83de52fa1acebe25c1489c6465bbe6a8a84155b8
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/rollup-config-dango.json
@@ -0,0 +1,42 @@
+{
+ "genesis": {
+ "l1": {
+ "hash": "0xe18e94c26beea64e318e25c32303c9a1ee2bfcee4492337bb5ac14181e99bd0c",
+ "number": 2358856
+ },
+ "l2": {
+ "hash": "0x0e1287f3eba321cb620a032d4d26978424e15b0533e1d19e870baeb1f0078e10",
+ "number": 25275061
+ },
+ "l2_time": 1726651200,
+ "system_config": {
+ "batcherAddr": "0x1660b1f70de0f32490b50f976e8983213dcf7fd5",
+ "overhead": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240",
+ "gasLimit": 30000000
+ }
+ },
+ "block_time": 2,
+ "max_sequencer_drift": 600,
+ "seq_window_size": 3600,
+ "channel_timeout": 300,
+ "l1_chain_id": 17000,
+ "l2_chain_id": 44787,
+ "regolith_time": 0,
+ "cel2_time": 0,
+ "canyon_time": 0,
+ "delta_time": 0,
+ "ecotone_time": 0,
+ "fjord_time": 0,
+ "batch_inbox_address": "0xff00000000000000000000000000000000044787",
+ "deposit_contract_address": "0xf550a0aec6cd8fdfa904242d6e07f71e38be5240",
+ "l1_system_config_address": "0xfbe6510a1e209d9e2148d54f134f4e5634be7241",
+ "protocol_versions_address": "0x0000000000000000000000000000000000000000",
+ "alt_da": {
+ "da_challenge_contract_address": "0x0000000000000000000000000000000000000000",
+ "da_commitment_type": "GenericCommitment",
+ "da_challenge_window": 1,
+ "da_resolve_window": 1
+ }
+}
+
diff --git OP/op-chain-ops/cmd/celo-migrate/testdata/rollup-config.json CELO/op-chain-ops/cmd/celo-migrate/testdata/rollup-config.json
new file mode 100644
index 0000000000000000000000000000000000000000..8dfd1f25e28d86be0d6188ab982c2439b077a2f0
--- /dev/null
+++ CELO/op-chain-ops/cmd/celo-migrate/testdata/rollup-config.json
@@ -0,0 +1,36 @@
+{
+ "genesis": {
+ "l1": {
+ "hash": "0xbbed3612407993e67f8ca7a423b181837ae164a531941e78f5ee48e766d39cad",
+ "number": 1729797
+ },
+ "l2": {
+ "hash": "0x2664d0a1f45dc9a010e553e815a25f33c6d949cbb0d38e179c6209fc0486aa41",
+ "number": 23912613
+ },
+ "l2_time": 1718312256,
+ "system_config": {
+ "batcherAddr": "0x1660b1f70de0f32490b50f976e8983213dcf7fd5",
+ "overhead": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240",
+ "gasLimit": 30000000
+ }
+ },
+ "block_time": 2,
+ "max_sequencer_drift": 600,
+ "seq_window_size": 3600,
+ "channel_timeout": 300,
+ "l1_chain_id": 17000,
+ "l2_chain_id": 44787,
+ "regolith_time": 0,
+ "cel2_time": 0,
+ "canyon_time": 0,
+ "delta_time": 0,
+ "ecotone_time": 0,
+ "batch_inbox_address": "0xff00000000000000000000000000000000044787",
+ "deposit_contract_address": "0xa292b051ea58e2558243f4a9f74262b1796c9648",
+ "l1_system_config_address": "0x733043aa78d25f6759d9e6ce2b2897be6d630e08",
+ "protocol_versions_address": "0x0000000000000000000000000000000000000000",
+ "da_challenge_contract_address": "0x0000000000000000000000000000000000000000"
+}
+
diff --git OP/op-program/client/l2/engineapi/block_processor.go CELO/op-program/client/l2/engineapi/block_processor.go
index 2e6cc5beade491f87298c8058fa2d635c37cb2cc..5798b317e5dbf093402310f5427fffe254c0b17f 100644
--- OP/op-program/client/l2/engineapi/block_processor.go
+++ CELO/op-program/client/l2/engineapi/block_processor.go
@@ -83,7 +83,8 @@ gasPool := new(core.GasPool).AddGas(header.GasLimit)
if h.ParentBeaconRoot != nil {
// Unfortunately this is not part of any Geth environment setup,
// we just have to apply it, like how the Geth block-builder worker does.
- context := core.NewEVMBlockContext(header, provider, nil, provider.Config(), statedb)
+ feeCurrencyContext := core.GetFeeCurrencyContext(header, provider.Config(), statedb)
+ context := core.NewEVMBlockContext(header, provider, nil, provider.Config(), statedb, feeCurrencyContext)
// NOTE: Unlikely to be needed for the beacon block root, but we setup any precompile overrides anyways for forwards-compatibility
var precompileOverrides vm.PrecompileOverrides
if vmConfig := provider.GetVMConfig(); vmConfig != nil && vmConfig.PrecompileOverrides != nil {
@@ -113,8 +114,9 @@
func (b *BlockProcessor) AddTx(tx *types.Transaction) error {
txIndex := len(b.transactions)
b.state.SetTxContext(tx.Hash(), txIndex)
+ feeCurrencyContext := core.GetFeeCurrencyContext(b.header, b.dataProvider.Config(), b.state)
receipt, err := core.ApplyTransaction(b.dataProvider.Config(), b.dataProvider, &b.header.Coinbase,
- b.gasPool, b.state, b.header, tx, &b.header.GasUsed, *b.dataProvider.GetVMConfig())
+ b.gasPool, b.state, b.header, tx, &b.header.GasUsed, *b.dataProvider.GetVMConfig(), feeCurrencyContext)
if err != nil {
return fmt.Errorf("failed to apply transaction to L2 block (tx %d): %w", txIndex, err)
}
diff --git OP/op-service/predeploys/addresses.go CELO/op-service/predeploys/addresses.go
index 0b69df3bb834387c64a626fa8d77c7374ffd66eb..53dc44500c06a815f7083145aefb725d1f61d93f 100644
--- OP/op-service/predeploys/addresses.go
+++ CELO/op-service/predeploys/addresses.go
@@ -42,6 +42,16 @@ SenderCreator_v060 = "0x7fc98430eaedbb6070b35b39d798725049088348"
EntryPoint_v060 = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"
SenderCreator_v070 = "0xEFC2c1444eBCC4Db75e7613d20C6a62fF67A167C"
EntryPoint_v070 = "0x0000000071727De22E5E9d8BAf0edAc6f37da032"
+
+ // Celo
+ CeloRegistry = "0x000000000000000000000000000000000000ce10"
+ GoldToken = "0x471ece3750da237f93b8e339c536989b8978a438"
+ FeeHandler = "0xcd437749e43a154c07f3553504c68fbfd56b8778"
+ MentoFeeHandlerSeller = "0x4efa274b7e33476c961065000d58ee09f7921a74"
+ UniswapFeeHandlerSeller = "0xd3aee28548dbb65df03981f0dc0713bfcbd10a97"
+ SortedOracles = "0xefb84935239dacdecf7c5ba76d8de40b077b7b33"
+ AddressSortedLinkedListWithMedian = "0xED477A99035d0c1e11369F1D7A4e587893cc002B"
+ FeeCurrency = "0x4200000000000000000000000000000000001022"
)
var (
@@ -84,6 +94,18 @@ EntryPoint_v070Addr = common.HexToAddress(EntryPoint_v070)
Predeploys = make(map[string]*Predeploy)
PredeploysByAddress = make(map[common.Address]*Predeploy)
+
+ // Celo
+ CeloRegistryAddr = common.HexToAddress(CeloRegistry)
+ GoldTokenAddr = common.HexToAddress(GoldToken)
+ FeeHandlerAddr = common.HexToAddress(FeeHandler)
+ MentoFeeHandlerSellerAddr = common.HexToAddress(MentoFeeHandlerSeller)
+ UniswapFeeHandlerSellerAddr = common.HexToAddress(UniswapFeeHandlerSeller)
+ SortedOraclesAddr = common.HexToAddress(SortedOracles)
+ AddressSortedLinkedListWithMedianAddr = common.HexToAddress(AddressSortedLinkedListWithMedian)
+ FeeCurrencyAddr = common.HexToAddress(FeeCurrency)
+
+ CeloPredeploys = make(map[string]*Predeploy)
)
func init() {
@@ -167,6 +189,19 @@ }
Predeploys["EntryPoint_v070"] = &Predeploy{
Address: EntryPoint_v070Addr,
ProxyDisabled: true,
+ }
+
+ // Celo
+ CeloPredeploys["CeloRegistry"] = &Predeploy{Address: CeloRegistryAddr}
+ CeloPredeploys["GoldToken"] = &Predeploy{Address: GoldTokenAddr}
+ CeloPredeploys["FeeHandler"] = &Predeploy{Address: FeeHandlerAddr}
+ CeloPredeploys["MentoFeeHandlerSeller"] = &Predeploy{Address: MentoFeeHandlerSellerAddr}
+ CeloPredeploys["UniswapFeeHandlerSeller"] = &Predeploy{Address: UniswapFeeHandlerSellerAddr}
+ CeloPredeploys["SortedOracles"] = &Predeploy{Address: SortedOraclesAddr}
+ CeloPredeploys["AddressSortedLinkedListWithMedian"] = &Predeploy{Address: AddressSortedLinkedListWithMedianAddr}
+ CeloPredeploys["FeeCurrency"] = &Predeploy{Address: FeeCurrencyAddr}
+ for key, predeploy := range CeloPredeploys {
+ Predeploys[key] = predeploy
}
for _, predeploy := range Predeploys {
diff --git OP/ops/celo/update-geth.sh CELO/ops/celo/update-geth.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2fe1683920b74d83504e6fbdb0c32dc911c81f25
--- /dev/null
+++ CELO/ops/celo/update-geth.sh
@@ -0,0 +1,61 @@
+#!/bin/bash
+set -eo pipefail
+
+branch="$1"
+if [ -z "$branch" ]; then
+ echo "No argument given. Please supply the ref in 'celo-org/op-geth' to be used " >&2
+ exit 1
+fi
+
+commit=$(git ls-remote https://github.com/celo-org/op-geth/ "$branch" | awk '{print $1}')
+if [ -z "$commit" ]; then
+ echo "Could not find branch '$branch' in 'celo-org/op-geth'" >&2
+ exit 1
+fi
+
+go_version=$(go list -m "github.com/celo-org/op-geth@$commit")
+if [ -z "$go_version" ]; then
+ echo "Failed to generate go version string fork '$commit' in 'celo-org/op-geth'" >&2
+ exit 1
+fi
+
+sha256digest=$(gcloud --format=json artifacts files list \
+ --project=blockchaintestsglobaltestnet \
+ --repository=dev-images \
+ --location=us-west1 \
+ --package=op-geth \
+ --limit=1 \
+ --tag="$commit" | jq ".[0].name" | grep -oE 'sha256:([0-9a-f]{64})' | sed 's/^sha256://')
+if [ -z "$sha256digest" ]; then
+ echo "Failed to find sha256digest for op-geth docker image 'celo-org/op-geth'" >&2
+ exit 1
+fi
+
+# We need to escape the '@' otherwise '@sha256' is interpreted as a global
+# Symbol by perl.
+docker_search_string="(.*op-geth\@sha256:)(.*)"
+gomod_search_string="^(replace github.com/ethereum/go-ethereum .*=> )github.com/.*/op-geth v.*"
+
+# Check that the searches are each matching a single line
+if [ "$(perl -ne "m|${docker_search_string}| && print" ops-bedrock/l2-op-geth.Dockerfile | wc -l)" != "1" ]; then
+ echo "Failed to find exactly one match for docker search string in ops-bedrock/l2-op-geth.Dockerfile" >&2
+ exit 1
+fi
+
+if [ "$(perl -ne "m|${gomod_search_string}| && print" go.mod | wc -l)" != "1" ]; then
+ echo "Failed to find exactly one match for go mod search string in go.mod" >&2
+ exit 1
+fi
+
+set -x
+perl -pi -e "s|${docker_search_string}|\${1}${sha256digest}|" ops-bedrock/l2-op-geth.Dockerfile
+set +x
+perl -pi -e "s|${gomod_search_string}|\${1}${go_version}|" go.mod
+
+go_mod_error=$(go mod tidy >/dev/null)
+if [ -n "$go_mod_error" ]; then
+ echo "$go_mod_error"
+ exit 1
+fi
+
+echo "$commit"
diff --git OP/ops/check-changed/requirements.txt CELO/ops/check-changed/requirements.txt
index 1d0c88d77f2db4c866d9357af998d974dc41dfea..52f22da4a72b74e8f830ac1a46061a4ad7e36f45 100644
--- OP/ops/check-changed/requirements.txt
+++ CELO/ops/check-changed/requirements.txt
@@ -1,5 +1,5 @@
certifi==2024.7.4
-cffi==1.15.1
+cffi==1.17.1
charset-normalizer==2.1.1
Deprecated==1.2.13
idna==3.7
diff --git OP/packages/contracts-bedrock/lib/multicall/src/Multicall3.sol CELO/packages/contracts-bedrock/lib/multicall/src/Multicall3.sol
new file mode 100644
index 0000000000000000000000000000000000000000..92195a5e91b974b51d163cdf29f56f02f2b149c9
--- /dev/null
+++ CELO/packages/contracts-bedrock/lib/multicall/src/Multicall3.sol
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.12;
+
+/// @title Multicall3
+/// @notice Aggregate results from multiple function calls
+/// @dev Multicall & Multicall2 backwards-compatible
+/// @dev Aggregate methods are marked `payable` to save 24 gas per call
+/// @author Michael Elliot <mike@makerdao.com>
+/// @author Joshua Levine <joshua@makerdao.com>
+/// @author Nick Johnson <arachnid@notdot.net>
+/// @author Andreas Bigger <andreas@nascent.xyz>
+/// @author Matt Solomon <matt@mattsolomon.dev>
+contract Multicall3 {
+ struct Call {
+ address target;
+ bytes callData;
+ }
+
+ struct Call3 {
+ address target;
+ bool allowFailure;
+ bytes callData;
+ }
+
+ struct Call3Value {
+ address target;
+ bool allowFailure;
+ uint256 value;
+ bytes callData;
+ }
+
+ struct Result {
+ bool success;
+ bytes returnData;
+ }
+
+ /// @notice Backwards-compatible call aggregation with Multicall
+ /// @param calls An array of Call structs
+ /// @return blockNumber The block number where the calls were executed
+ /// @return returnData An array of bytes containing the responses
+ function aggregate(
+ Call[] calldata calls
+ ) public payable returns (uint256 blockNumber, bytes[] memory returnData) {
+ blockNumber = block.number;
+ uint256 length = calls.length;
+ returnData = new bytes[](length);
+ Call calldata call;
+ for (uint256 i = 0; i < length; ) {
+ bool success;
+ call = calls[i];
+ (success, returnData[i]) = call.target.call(call.callData);
+ require(success, 'Multicall3: call failed');
+ unchecked {
+ ++i;
+ }
+ }
+ }
+
+ /// @notice Backwards-compatible with Multicall2
+ /// @notice Aggregate calls without requiring success
+ /// @param requireSuccess If true, require all calls to succeed
+ /// @param calls An array of Call structs
+ /// @return returnData An array of Result structs
+ function tryAggregate(
+ bool requireSuccess,
+ Call[] calldata calls
+ ) public payable returns (Result[] memory returnData) {
+ uint256 length = calls.length;
+ returnData = new Result[](length);
+ Call calldata call;
+ for (uint256 i = 0; i < length; ) {
+ Result memory result = returnData[i];
+ call = calls[i];
+ (result.success, result.returnData) = call.target.call(call.callData);
+ if (requireSuccess) require(result.success, 'Multicall3: call failed');
+ unchecked {
+ ++i;
+ }
+ }
+ }
+
+ /// @notice Backwards-compatible with Multicall2
+ /// @notice Aggregate calls and allow failures using tryAggregate
+ /// @param calls An array of Call structs
+ /// @return blockNumber The block number where the calls were executed
+ /// @return blockHash The hash of the block where the calls were executed
+ /// @return returnData An array of Result structs
+ function tryBlockAndAggregate(
+ bool requireSuccess,
+ Call[] calldata calls
+ )
+ public
+ payable
+ returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData)
+ {
+ blockNumber = block.number;
+ blockHash = blockhash(block.number);
+ returnData = tryAggregate(requireSuccess, calls);
+ }
+
+ /// @notice Backwards-compatible with Multicall2
+ /// @notice Aggregate calls and allow failures using tryAggregate
+ /// @param calls An array of Call structs
+ /// @return blockNumber The block number where the calls were executed
+ /// @return blockHash The hash of the block where the calls were executed
+ /// @return returnData An array of Result structs
+ function blockAndAggregate(
+ Call[] calldata calls
+ )
+ public
+ payable
+ returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData)
+ {
+ (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls);
+ }
+
+ /// @notice Aggregate calls, ensuring each returns success if required
+ /// @param calls An array of Call3 structs
+ /// @return returnData An array of Result structs
+ function aggregate3(
+ Call3[] calldata calls
+ ) public payable returns (Result[] memory returnData) {
+ uint256 length = calls.length;
+ returnData = new Result[](length);
+ Call3 calldata calli;
+ for (uint256 i = 0; i < length; ) {
+ Result memory result = returnData[i];
+ calli = calls[i];
+ (result.success, result.returnData) = calli.target.call(calli.callData);
+ assembly {
+ // Revert if the call fails and failure is not allowed
+ // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
+ if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
+ // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
+ mstore(
+ 0x00,
+ 0x08c379a000000000000000000000000000000000000000000000000000000000
+ )
+ // set data offset
+ mstore(
+ 0x04,
+ 0x0000000000000000000000000000000000000000000000000000000000000020
+ )
+ // set length of revert string
+ mstore(
+ 0x24,
+ 0x0000000000000000000000000000000000000000000000000000000000000017
+ )
+ // set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
+ mstore(
+ 0x44,
+ 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000
+ )
+ revert(0x00, 0x64)
+ }
+ }
+ unchecked {
+ ++i;
+ }
+ }
+ }
+
+ /// @notice Aggregate calls with a msg value
+ /// @notice Reverts if msg.value is less than the sum of the call values
+ /// @param calls An array of Call3Value structs
+ /// @return returnData An array of Result structs
+ function aggregate3Value(
+ Call3Value[] calldata calls
+ ) public payable returns (Result[] memory returnData) {
+ uint256 valAccumulator;
+ uint256 length = calls.length;
+ returnData = new Result[](length);
+ Call3Value calldata calli;
+ for (uint256 i = 0; i < length; ) {
+ Result memory result = returnData[i];
+ calli = calls[i];
+ uint256 val = calli.value;
+ // Humanity will be a Type V Kardashev Civilization before this overflows - andreas
+ // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
+ unchecked {
+ valAccumulator += val;
+ }
+ (result.success, result.returnData) = calli.target.call{value: val}(
+ calli.callData
+ );
+ assembly {
+ // Revert if the call fails and failure is not allowed
+ // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
+ if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
+ // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
+ mstore(
+ 0x00,
+ 0x08c379a000000000000000000000000000000000000000000000000000000000
+ )
+ // set data offset
+ mstore(
+ 0x04,
+ 0x0000000000000000000000000000000000000000000000000000000000000020
+ )
+ // set length of revert string
+ mstore(
+ 0x24,
+ 0x0000000000000000000000000000000000000000000000000000000000000017
+ )
+ // set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
+ mstore(
+ 0x44,
+ 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000
+ )
+ revert(0x00, 0x84)
+ }
+ }
+ unchecked {
+ ++i;
+ }
+ }
+ // Finally, make sure the msg.value = SUM(call[0...i].value)
+ require(msg.value == valAccumulator, 'Multicall3: value mismatch');
+ }
+
+ /// @notice Returns the block hash for the given block number
+ /// @param blockNumber The block number
+ function getBlockHash(
+ uint256 blockNumber
+ ) public view returns (bytes32 blockHash) {
+ blockHash = blockhash(blockNumber);
+ }
+
+ /// @notice Returns the block number
+ function getBlockNumber() public view returns (uint256 blockNumber) {
+ blockNumber = block.number;
+ }
+
+ /// @notice Returns the block coinbase
+ function getCurrentBlockCoinbase() public view returns (address coinbase) {
+ coinbase = block.coinbase;
+ }
+
+ /// @notice Returns the block difficulty
+ function getCurrentBlockDifficulty()
+ public
+ view
+ returns (uint256 difficulty)
+ {
+ difficulty = block.difficulty;
+ }
+
+ /// @notice Returns the block gas limit
+ function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {
+ gaslimit = block.gaslimit;
+ }
+
+ /// @notice Returns the block timestamp
+ function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
+ timestamp = block.timestamp;
+ }
+
+ /// @notice Returns the (ETH) balance of a given address
+ function getEthBalance(address addr) public view returns (uint256 balance) {
+ balance = addr.balance;
+ }
+
+ /// @notice Returns the block hash of the last block
+ function getLastBlockHash() public view returns (bytes32 blockHash) {
+ unchecked {
+ blockHash = blockhash(block.number - 1);
+ }
+ }
+
+ /// @notice Gets the base fee of the given block
+ /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain
+ function getBasefee() public view returns (uint256 basefee) {
+ basefee = block.basefee;
+ }
+
+ /// @notice Returns the chain id
+ function getChainId() public view returns (uint256 chainid) {
+ chainid = block.chainid;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/FixidityLib.sol CELO/packages/contracts-bedrock/src/celo/common/FixidityLib.sol
new file mode 100644
index 0000000000000000000000000000000000000000..613da18562198968356b17cffa9890cb364b2063
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/FixidityLib.sol
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+/**
+ * @title FixidityLib
+ * @author Gadi Guy, Alberto Cuesta Canada
+ * @notice This library provides fixed point arithmetic with protection against
+ * overflow.
+ * All operations are done with uint256 and the operands must have been created
+ * with any of the newFrom* functions, which shift the comma digits() to the
+ * right and check for limits, or with wrap() which expects a number already
+ * in the internal representation of a fraction.
+ * When using this library be sure to use maxNewFixed() as the upper limit for
+ * creation of fixed point numbers.
+ * @dev All contained functions are pure and thus marked internal to be inlined
+ * on consuming contracts at compile time for gas efficiency.
+ */
+library FixidityLib {
+ struct Fraction {
+ uint256 value;
+ }
+
+ /**
+ * @notice Number of positions that the comma is shifted to the right.
+ */
+ function digits() internal pure returns (uint8) {
+ return 24;
+ }
+
+ uint256 private constant FIXED1_UINT = 1000000000000000000000000;
+
+ /**
+ * @notice This is 1 in the fixed point units used in this library.
+ * @dev Test fixed1() equals 10^digits()
+ * Hardcoded to 24 digits.
+ */
+ function fixed1() internal pure returns (Fraction memory) {
+ return Fraction(FIXED1_UINT);
+ }
+
+ /**
+ * @notice Wrap a uint256 that represents a 24-decimal fraction in a Fraction
+ * struct.
+ * @param x Number that already represents a 24-decimal fraction.
+ * @return A Fraction struct with contents x.
+ */
+ function wrap(uint256 x) internal pure returns (Fraction memory) {
+ return Fraction(x);
+ }
+
+ /**
+ * @notice Unwraps the uint256 inside of a Fraction struct.
+ */
+ function unwrap(Fraction memory x) internal pure returns (uint256) {
+ return x.value;
+ }
+
+ /**
+ * @notice The amount of decimals lost on each multiplication operand.
+ * @dev Test mulPrecision() equals sqrt(fixed1)
+ */
+ function mulPrecision() internal pure returns (uint256) {
+ return 1000000000000;
+ }
+
+ /**
+ * @notice Maximum value that can be converted to fixed point. Optimize for deployment.
+ * @dev
+ * Test maxNewFixed() equals maxUint256() / fixed1()
+ */
+ function maxNewFixed() internal pure returns (uint256) {
+ return 115792089237316195423570985008687907853269984665640564;
+ }
+
+ /**
+ * @notice Converts a uint256 to fixed point Fraction
+ * @dev Test newFixed(0) returns 0
+ * Test newFixed(1) returns fixed1()
+ * Test newFixed(maxNewFixed()) returns maxNewFixed() * fixed1()
+ * Test newFixed(maxNewFixed()+1) fails
+ */
+ function newFixed(uint256 x) internal pure returns (Fraction memory) {
+ require(x <= maxNewFixed(), "can't create fixidity number larger than maxNewFixed()");
+ return Fraction(x * FIXED1_UINT);
+ }
+
+ /**
+ * @notice Converts a uint256 in the fixed point representation of this
+ * library to a non decimal. All decimal digits will be truncated.
+ */
+ function fromFixed(Fraction memory x) internal pure returns (uint256) {
+ return x.value / FIXED1_UINT;
+ }
+
+ /**
+ * @notice Converts two uint256 representing a fraction to fixed point units,
+ * equivalent to multiplying dividend and divisor by 10^digits().
+ * @param numerator numerator must be <= maxNewFixed()
+ * @param denominator denominator must be <= maxNewFixed() and denominator can't be 0
+ * @dev
+ * Test newFixedFraction(1,0) fails
+ * Test newFixedFraction(0,1) returns 0
+ * Test newFixedFraction(1,1) returns fixed1()
+ * Test newFixedFraction(1,fixed1()) returns 1
+ */
+ function newFixedFraction(uint256 numerator, uint256 denominator) internal pure returns (Fraction memory) {
+ Fraction memory convertedNumerator = newFixed(numerator);
+ Fraction memory convertedDenominator = newFixed(denominator);
+ return divide(convertedNumerator, convertedDenominator);
+ }
+
+ /**
+ * @notice Returns the integer part of a fixed point number.
+ * @dev
+ * Test integer(0) returns 0
+ * Test integer(fixed1()) returns fixed1()
+ * Test integer(newFixed(maxNewFixed())) returns maxNewFixed()*fixed1()
+ */
+ function integer(Fraction memory x) internal pure returns (Fraction memory) {
+ return Fraction((x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow
+ }
+
+ /**
+ * @notice Returns the fractional part of a fixed point number.
+ * In the case of a negative number the fractional is also negative.
+ * @dev
+ * Test fractional(0) returns 0
+ * Test fractional(fixed1()) returns 0
+ * Test fractional(fixed1()-1) returns 10^24-1
+ */
+ function fractional(Fraction memory x) internal pure returns (Fraction memory) {
+ return Fraction(x.value - (x.value / FIXED1_UINT) * FIXED1_UINT); // Can't overflow
+ }
+
+ /**
+ * @notice x+y.
+ * @dev The maximum value that can be safely used as an addition operator is defined as
+ * maxFixedAdd = maxUint256()-1 / 2, or
+ * 57896044618658097711785492504343953926634992332820282019728792003956564819967.
+ * Test add(maxFixedAdd,maxFixedAdd) equals maxFixedAdd + maxFixedAdd
+ * Test add(maxFixedAdd+1,maxFixedAdd+1) throws
+ */
+ function add(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
+ uint256 z = x.value + y.value;
+ require(z >= x.value, "add overflow detected");
+ return Fraction(z);
+ }
+
+ /**
+ * @notice x-y.
+ * @dev
+ * Test subtract(6, 10) fails
+ */
+ function subtract(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
+ require(x.value >= y.value, "substraction underflow detected");
+ return Fraction(x.value - y.value);
+ }
+
+ /**
+ * @notice x*y. If any of the operators is higher than the max multiplier value it
+ * might overflow.
+ * @dev The maximum value that can be safely used as a multiplication operator
+ * (maxFixedMul) is calculated as sqrt(maxUint256()*fixed1()),
+ * or 340282366920938463463374607431768211455999999999999
+ * Test multiply(0,0) returns 0
+ * Test multiply(maxFixedMul,0) returns 0
+ * Test multiply(0,maxFixedMul) returns 0
+ * Test multiply(fixed1()/mulPrecision(),fixed1()*mulPrecision()) returns fixed1()
+ * Test multiply(maxFixedMul,maxFixedMul) is around maxUint256()
+ * Test multiply(maxFixedMul+1,maxFixedMul+1) fails
+ */
+ function multiply(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
+ if (x.value == 0 || y.value == 0) return Fraction(0);
+ if (y.value == FIXED1_UINT) return x;
+ if (x.value == FIXED1_UINT) return y;
+
+ // Separate into integer and fractional parts
+ // x = x1 + x2, y = y1 + y2
+ uint256 x1 = integer(x).value / FIXED1_UINT;
+ uint256 x2 = fractional(x).value;
+ uint256 y1 = integer(y).value / FIXED1_UINT;
+ uint256 y2 = fractional(y).value;
+
+ // (x1 + x2) * (y1 + y2) = (x1 * y1) + (x1 * y2) + (x2 * y1) + (x2 * y2)
+ uint256 x1y1 = x1 * y1;
+ if (x1 != 0) require(x1y1 / x1 == y1, "overflow x1y1 detected");
+
+ // x1y1 needs to be multiplied back by fixed1
+ // solium-disable-next-line mixedcase
+ uint256 fixed_x1y1 = x1y1 * FIXED1_UINT;
+ if (x1y1 != 0) require(fixed_x1y1 / x1y1 == FIXED1_UINT, "overflow x1y1 * fixed1 detected");
+ x1y1 = fixed_x1y1;
+
+ uint256 x2y1 = x2 * y1;
+ if (x2 != 0) require(x2y1 / x2 == y1, "overflow x2y1 detected");
+
+ uint256 x1y2 = x1 * y2;
+ if (x1 != 0) require(x1y2 / x1 == y2, "overflow x1y2 detected");
+
+ x2 = x2 / mulPrecision();
+ y2 = y2 / mulPrecision();
+ uint256 x2y2 = x2 * y2;
+ if (x2 != 0) require(x2y2 / x2 == y2, "overflow x2y2 detected");
+
+ // result = fixed1() * x1 * y1 + x1 * y2 + x2 * y1 + x2 * y2 / fixed1();
+ Fraction memory result = Fraction(x1y1);
+ result = add(result, Fraction(x2y1)); // Add checks for overflow
+ result = add(result, Fraction(x1y2)); // Add checks for overflow
+ result = add(result, Fraction(x2y2)); // Add checks for overflow
+ return result;
+ }
+
+ /**
+ * @notice 1/x
+ * @dev
+ * Test reciprocal(0) fails
+ * Test reciprocal(fixed1()) returns fixed1()
+ * Test reciprocal(fixed1()*fixed1()) returns 1 // Testing how the fractional is truncated
+ * Test reciprocal(1+fixed1()*fixed1()) returns 0 // Testing how the fractional is truncated
+ * Test reciprocal(newFixedFraction(1, 1e24)) returns newFixed(1e24)
+ */
+ function reciprocal(Fraction memory x) internal pure returns (Fraction memory) {
+ require(x.value != 0, "can't call reciprocal(0)");
+ return Fraction((FIXED1_UINT * FIXED1_UINT) / x.value); // Can't overflow
+ }
+
+ /**
+ * @notice x/y. If the dividend is higher than the max dividend value, it
+ * might overflow. You can use multiply(x,reciprocal(y)) instead.
+ * @dev The maximum value that can be safely used as a dividend (maxNewFixed) is defined as
+ * divide(maxNewFixed,newFixedFraction(1,fixed1())) is around maxUint256().
+ * This yields the value 115792089237316195423570985008687907853269984665640564.
+ * Test maxNewFixed equals maxUint256()/fixed1()
+ * Test divide(maxNewFixed,1) equals maxNewFixed*(fixed1)
+ * Test divide(maxNewFixed+1,multiply(mulPrecision(),mulPrecision())) throws
+ * Test divide(fixed1(),0) fails
+ * Test divide(maxNewFixed,1) = maxNewFixed*(10^digits())
+ * Test divide(maxNewFixed+1,1) throws
+ */
+ function divide(Fraction memory x, Fraction memory y) internal pure returns (Fraction memory) {
+ require(y.value != 0, "can't divide by 0");
+ uint256 X = x.value * FIXED1_UINT;
+ require(X / FIXED1_UINT == x.value, "overflow at divide");
+ return Fraction(X / y.value);
+ }
+
+ /**
+ * @notice x > y
+ */
+ function gt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
+ return x.value > y.value;
+ }
+
+ /**
+ * @notice x >= y
+ */
+ function gte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
+ return x.value >= y.value;
+ }
+
+ /**
+ * @notice x < y
+ */
+ function lt(Fraction memory x, Fraction memory y) internal pure returns (bool) {
+ return x.value < y.value;
+ }
+
+ /**
+ * @notice x <= y
+ */
+ function lte(Fraction memory x, Fraction memory y) internal pure returns (bool) {
+ return x.value <= y.value;
+ }
+
+ /**
+ * @notice x == y
+ */
+ function equals(Fraction memory x, Fraction memory y) internal pure returns (bool) {
+ return x.value == y.value;
+ }
+
+ /**
+ * @notice x <= 1
+ */
+ function isProperFraction(Fraction memory x) internal pure returns (bool) {
+ return lte(x, fixed1());
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/Freezable.sol CELO/packages/contracts-bedrock/src/celo/common/Freezable.sol
new file mode 100644
index 0000000000000000000000000000000000000000..7541ea6fa5717fbe7905c58637c276771a63f9cb
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/Freezable.sol
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "../UsingRegistry.sol";
+
+contract Freezable is UsingRegistry {
+ // onlyWhenNotFrozen functions can only be called when `frozen` is false, otherwise they will
+ // revert.
+ modifier onlyWhenNotFrozen() {
+ require(!getFreezer().isFrozen(address(this)), "can't call when contract is frozen");
+ _;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/Initializable.sol CELO/packages/contracts-bedrock/src/celo/common/Initializable.sol
new file mode 100644
index 0000000000000000000000000000000000000000..92baac5494d3b0324d3d506d0607f38199028b30
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/Initializable.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+contract Initializable {
+ bool public initialized;
+
+ constructor(bool testingDeployment) {
+ if (!testingDeployment) {
+ initialized = true;
+ }
+ }
+
+ modifier initializer() {
+ require(!initialized, "contract already initialized");
+ initialized = true;
+ _;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/interfaces/ICeloToken.sol CELO/packages/contracts-bedrock/src/celo/common/interfaces/ICeloToken.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5bf2033f31726110e6504078561108cfee40a42d
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/interfaces/ICeloToken.sol
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+/**
+ * @title This interface describes the non- ERC20 shared interface for all Celo Tokens, and
+ * in the absence of interface inheritance is intended as a companion to IERC20.sol.
+ */
+interface ICeloToken {
+ function transferWithComment(address, uint256, string calldata) external returns (bool);
+ function name() external view returns (string memory);
+ function symbol() external view returns (string memory);
+ function decimals() external view returns (uint8);
+ function burn(uint256 value) external returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/interfaces/ICeloVersionedContract.sol CELO/packages/contracts-bedrock/src/celo/common/interfaces/ICeloVersionedContract.sol
new file mode 100644
index 0000000000000000000000000000000000000000..37b1538c2a121b4dd73b5762db9ba4a97364581c
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/interfaces/ICeloVersionedContract.sol
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface ICeloVersionedContract {
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandler.sol CELO/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandler.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b707a446a685ac27778cd547f44932a4d92c127b
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandler.sol
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+import "../FixidityLib.sol";
+
+interface IFeeHandler {
+ // sets the portion of the fee that should be burned.
+ function setBurnFraction(uint256 fraction) external;
+
+ function addToken(address tokenAddress, address handlerAddress) external;
+ function removeToken(address tokenAddress) external;
+
+ function setHandler(address tokenAddress, address handlerAddress) external;
+
+ // marks token to be handled in "handleAll())
+ function activateToken(address tokenAddress) external;
+ function deactivateToken(address tokenAddress) external;
+
+ function sell(address tokenAddress) external;
+
+ // calls exchange(tokenAddress), and distribute(tokenAddress)
+ function handle(address tokenAddress) external;
+
+ // main entrypoint for a burn, iterates over token and calles handle
+ function handleAll() external;
+
+ // Sends the balance of token at tokenAddress to feesBeneficiary,
+ // according to the entry tokensToDistribute[tokenAddress]
+ function distribute(address tokenAddress) external;
+
+ // burns the balance of Celo in the contract minus the entry of tokensToDistribute[CeloAddress]
+ function burnCelo() external;
+
+ // calls distribute for all the nonCeloTokens
+ function distributeAll() external;
+
+ // in case some funds need to be returned or moved to another contract
+ function transfer(address token, address recipient, uint256 value) external returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandlerSeller.sol CELO/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandlerSeller.sol
new file mode 100644
index 0000000000000000000000000000000000000000..c3a9df0ee324a675f00c5b49f9f615a42427e815
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/interfaces/IFeeHandlerSeller.sol
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+import "../FixidityLib.sol";
+
+interface IFeeHandlerSeller {
+ function sell(
+ address sellTokenAddress,
+ address buyTokenAddress,
+ uint256 amount,
+ uint256 minAmount
+ )
+ external
+ returns (uint256);
+ // in case some funds need to be returned or moved to another contract
+ function transfer(address token, uint256 amount, address to) external returns (bool);
+}
(new)
+267
-0
diff --git OP/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedList.sol CELO/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedList.sol
new file mode 100644
index 0000000000000000000000000000000000000000..38ae7359e0e069a46e616d774be857852d3a98a0
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedList.sol
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "@openzeppelin/contracts/utils/math/Math.sol";
+
+import "./SortedLinkedList.sol";
+
+/**
+ * @title Maintains a sorted list of unsigned ints keyed by address.
+ */
+library AddressSortedLinkedList {
+ using SortedLinkedList for SortedLinkedList.List;
+
+ /**
+ * @notice Inserts an element into a doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ * @param value The element value.
+ * @param lesserKey The key of the element less than the element to insert.
+ * @param greaterKey The key of the element greater than the element to insert.
+ */
+ function insert(
+ SortedLinkedList.List storage list,
+ address key,
+ uint256 value,
+ address lesserKey,
+ address greaterKey
+ )
+ public
+ {
+ list.insert(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
+ }
+
+ /**
+ * @notice Removes an element from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to remove.
+ */
+ function remove(SortedLinkedList.List storage list, address key) public {
+ list.remove(toBytes(key));
+ }
+
+ /**
+ * @notice Updates an element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @param value The element value.
+ * @param lesserKey The key of the element will be just left of `key` after the update.
+ * @param greaterKey The key of the element will be just right of `key` after the update.
+ * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
+ */
+ function update(
+ SortedLinkedList.List storage list,
+ address key,
+ uint256 value,
+ address lesserKey,
+ address greaterKey
+ )
+ public
+ {
+ list.update(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
+ }
+
+ /**
+ * @notice Returns whether or not a particular key is present in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function contains(SortedLinkedList.List storage list, address key) public view returns (bool) {
+ return list.contains(toBytes(key));
+ }
+
+ /**
+ * @notice Returns the value for a particular key in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return The element value.
+ */
+ function getValue(SortedLinkedList.List storage list, address key) public view returns (uint256) {
+ return list.getValue(toBytes(key));
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @return Array of all keys in the list.
+ * @return Values corresponding to keys, which will be ordered largest to smallest.
+ */
+ function getElements(SortedLinkedList.List storage list) public view returns (address[] memory, uint256[] memory) {
+ bytes32[] memory byteKeys = list.getKeys();
+ address[] memory keys = new address[](byteKeys.length);
+ uint256[] memory values = new uint256[](byteKeys.length);
+ for (uint256 i = 0; i < byteKeys.length; i = i + 1) {
+ keys[i] = toAddress(byteKeys[i]);
+ values[i] = list.values[byteKeys[i]];
+ }
+ return (keys, values);
+ }
+
+ /**
+ * @notice Returns the minimum of `max` and the number of elements in the list > threshold.
+ * @param list A storage pointer to the underlying list.
+ * @param threshold The number that the element must exceed to be included.
+ * @param max The maximum number returned by this function.
+ * @return The minimum of `max` and the number of elements in the list > threshold.
+ */
+ function numElementsGreaterThan(
+ SortedLinkedList.List storage list,
+ uint256 threshold,
+ uint256 max
+ )
+ public
+ view
+ returns (uint256)
+ {
+ uint256 revisedMax = Math.min(max, list.list.numElements);
+ bytes32 key = list.list.head;
+ for (uint256 i = 0; i < revisedMax; i = i + 1) {
+ if (list.getValue(key) < threshold) {
+ return i;
+ }
+ key = list.list.elements[key].previousKey;
+ }
+ return revisedMax;
+ }
+
+ /**
+ * @notice Returns the N greatest elements of the list.
+ * @param list A storage pointer to the underlying list.
+ * @param n The number of elements to return.
+ * @return The keys of the greatest elements.
+ */
+ function headN(SortedLinkedList.List storage list, uint256 n) public view returns (address[] memory) {
+ bytes32[] memory byteKeys = list.headN(n);
+ address[] memory keys = new address[](n);
+ for (uint256 i = 0; i < n; i = i + 1) {
+ keys[i] = toAddress(byteKeys[i]);
+ }
+ return keys;
+ }
+
+ /**
+ * @notice Gets all element keys from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return All element keys from head to tail.
+ */
+ function getKeys(SortedLinkedList.List storage list) public view returns (address[] memory) {
+ return headN(list, list.list.numElements);
+ }
+
+ /**
+ * @notice Returns the number of elements in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The number of elements in the list.
+ */
+ function getNumElements(SortedLinkedList.List storage list) public view returns (uint256) {
+ return list.list.numElements;
+ }
+
+ /**
+ * @notice Returns the key of the first element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the first element in the list.
+ */
+ function getHead(SortedLinkedList.List storage list) public view returns (address) {
+ return toAddress(list.list.head);
+ }
+
+ /**
+ * @notice Returns the key of the last element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the last element in the list.
+ */
+ function getTail(SortedLinkedList.List storage list) public view returns (address) {
+ return toAddress(list.list.tail);
+ }
+
+ /**
+ * @notice Gets lesser and greater for address that has increased it's value.
+ * @param list A storage pointer to the underlying list.
+ * @param group The original address.
+ * @param newValue New value that has to be bigger or equal than the previous one.
+ * @param loopLimit The max limit of loops that will be executed.
+ */
+ function getLesserAndGreaterOfAddressThatIncreasedValue(
+ SortedLinkedList.List storage list,
+ address group,
+ uint256 newValue,
+ uint256 loopLimit
+ )
+ public
+ view
+ returns (address previous, address next)
+ {
+ (, previous, next) = get(list, group);
+
+ while (next != address(0) && loopLimit != 0 && newValue > getValue(list, next)) {
+ previous = next;
+ (,, next) = get(list, previous);
+ loopLimit--;
+ }
+
+ if (loopLimit == 0) {
+ return (address(0), address(0));
+ }
+ }
+
+ /**
+ * @notice Gets lesser and greater for address that has decreased it's value.
+ * @param list A storage pointer to the underlying list.
+ * @param group The original address.
+ * @param newValue New value that has to be smaller or equal than the previous one.
+ * @param loopLimit The max limit of loops that will be executed.
+ */
+ function getLesserAndGreaterOfAddressThatDecreasedValue(
+ SortedLinkedList.List storage list,
+ address group,
+ uint256 newValue,
+ uint256 loopLimit
+ )
+ public
+ view
+ returns (address previous, address next)
+ {
+ (, previous, next) = get(list, group);
+ while (previous != address(0) && loopLimit != 0 && newValue < getValue(list, previous)) {
+ next = previous;
+ (, previous,) = get(list, next);
+ loopLimit--;
+ }
+ if (loopLimit == 0) {
+ return (address(0), address(0));
+ }
+ }
+
+ function toBytes(address a) public pure returns (bytes32) {
+ return bytes32(uint256(uint160(a)) << 96);
+ }
+
+ function toAddress(bytes32 b) public pure returns (address) {
+ return address(uint160(uint256(b) >> 96));
+ }
+
+ /**
+ * @notice Returns Element based on key.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return exists Whether or not the key exists.
+ * @return previousKey Previous key.
+ * @return nextKey Next key.
+ */
+ function get(
+ SortedLinkedList.List storage list,
+ address key
+ )
+ internal
+ view
+ returns (bool exists, address previousKey, address nextKey)
+ {
+ LinkedList.Element memory element = list.get(toBytes(key));
+ exists = element.exists;
+ if (element.exists) {
+ previousKey = toAddress(element.previousKey);
+ nextKey = toAddress(element.nextKey);
+ }
+ }
+}
(new)
+160
-0
diff --git OP/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedListWithMedian.sol CELO/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedListWithMedian.sol
new file mode 100644
index 0000000000000000000000000000000000000000..2ddf56612244e868dd6f3ba0aede4103c7569441
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/linkedlists/AddressSortedLinkedListWithMedian.sol
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "./SortedLinkedListWithMedian.sol";
+
+/**
+ * @title Maintains a sorted list of unsigned ints keyed by address.
+ */
+library AddressSortedLinkedListWithMedian {
+ using SortedLinkedListWithMedian for SortedLinkedListWithMedian.List;
+
+ function toBytes(address a) public pure returns (bytes32) {
+ return bytes32(uint256(uint160(a)) << 96);
+ }
+
+ function toAddress(bytes32 b) public pure returns (address) {
+ return address(uint160(uint256(b) >> 96));
+ }
+
+ /**
+ * @notice Inserts an element into a doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ * @param value The element value.
+ * @param lesserKey The key of the element less than the element to insert.
+ * @param greaterKey The key of the element greater than the element to insert.
+ */
+ function insert(
+ SortedLinkedListWithMedian.List storage list,
+ address key,
+ uint256 value,
+ address lesserKey,
+ address greaterKey
+ )
+ public
+ {
+ list.insert(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
+ }
+
+ /**
+ * @notice Removes an element from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to remove.
+ */
+ function remove(SortedLinkedListWithMedian.List storage list, address key) public {
+ list.remove(toBytes(key));
+ }
+
+ /**
+ * @notice Updates an element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @param value The element value.
+ * @param lesserKey The key of the element will be just left of `key` after the update.
+ * @param greaterKey The key of the element will be just right of `key` after the update.
+ * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
+ */
+ function update(
+ SortedLinkedListWithMedian.List storage list,
+ address key,
+ uint256 value,
+ address lesserKey,
+ address greaterKey
+ )
+ public
+ {
+ list.update(toBytes(key), value, toBytes(lesserKey), toBytes(greaterKey));
+ }
+
+ /**
+ * @notice Returns whether or not a particular key is present in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function contains(SortedLinkedListWithMedian.List storage list, address key) public view returns (bool) {
+ return list.contains(toBytes(key));
+ }
+
+ /**
+ * @notice Returns the value for a particular key in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return The element value.
+ */
+ function getValue(SortedLinkedListWithMedian.List storage list, address key) public view returns (uint256) {
+ return list.getValue(toBytes(key));
+ }
+
+ /**
+ * @notice Returns the median value of the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @return The median value.
+ */
+ function getMedianValue(SortedLinkedListWithMedian.List storage list) public view returns (uint256) {
+ return list.getValue(list.median);
+ }
+
+ /**
+ * @notice Returns the key of the first element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the first element in the list.
+ */
+ function getHead(SortedLinkedListWithMedian.List storage list) external view returns (address) {
+ return toAddress(list.getHead());
+ }
+
+ /**
+ * @notice Returns the key of the median element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the median element in the list.
+ */
+ function getMedian(SortedLinkedListWithMedian.List storage list) external view returns (address) {
+ return toAddress(list.getMedian());
+ }
+
+ /**
+ * @notice Returns the key of the last element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the last element in the list.
+ */
+ function getTail(SortedLinkedListWithMedian.List storage list) external view returns (address) {
+ return toAddress(list.getTail());
+ }
+
+ /**
+ * @notice Returns the number of elements in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The number of elements in the list.
+ */
+ function getNumElements(SortedLinkedListWithMedian.List storage list) external view returns (uint256) {
+ return list.getNumElements();
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return Array of all keys in the list.
+ * @return Values corresponding to keys, which will be ordered largest to smallest.
+ * @return Array of relations to median of corresponding list elements.
+ */
+ function getElements(SortedLinkedListWithMedian.List storage list)
+ public
+ view
+ returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
+ {
+ bytes32[] memory byteKeys = list.getKeys();
+ address[] memory keys = new address[](byteKeys.length);
+ uint256[] memory values = new uint256[](byteKeys.length);
+ // prettier-ignore
+ SortedLinkedListWithMedian.MedianRelation[] memory relations =
+ new SortedLinkedListWithMedian.MedianRelation[](keys.length);
+ for (uint256 i = 0; i < byteKeys.length; i++) {
+ keys[i] = toAddress(byteKeys[i]);
+ values[i] = list.getValue(byteKeys[i]);
+ relations[i] = list.relation[byteKeys[i]];
+ }
+ return (keys, values, relations);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/linkedlists/LinkedList.sol CELO/packages/contracts-bedrock/src/celo/common/linkedlists/LinkedList.sol
new file mode 100644
index 0000000000000000000000000000000000000000..d04e8b7e027cbb3f8e665e07420b8ca16205d084
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/linkedlists/LinkedList.sol
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+/**
+ * @title Maintains a doubly linked list keyed by bytes32.
+ * @dev Following the `next` pointers will lead you to the head, rather than the tail.
+ */
+library LinkedList {
+ struct Element {
+ bytes32 previousKey;
+ bytes32 nextKey;
+ bool exists;
+ }
+
+ struct List {
+ bytes32 head;
+ bytes32 tail;
+ uint256 numElements;
+ mapping(bytes32 => Element) elements;
+ }
+
+ /**
+ * @notice Inserts an element into a doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ * @param previousKey The key of the element that comes before the element to insert.
+ * @param nextKey The key of the element that comes after the element to insert.
+ */
+ function insert(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal {
+ require(key != bytes32(0), "Key must be defined");
+ require(!contains(list, key), "Can't insert an existing element");
+ require(previousKey != key && nextKey != key, "Key cannot be the same as previousKey or nextKey");
+
+ Element storage element = list.elements[key];
+ element.exists = true;
+
+ if (list.numElements == 0) {
+ list.tail = key;
+ list.head = key;
+ } else {
+ require(previousKey != bytes32(0) || nextKey != bytes32(0), "Either previousKey or nextKey must be defined");
+
+ element.previousKey = previousKey;
+ element.nextKey = nextKey;
+
+ if (previousKey != bytes32(0)) {
+ require(contains(list, previousKey), "If previousKey is defined, it must exist in the list");
+ Element storage previousElement = list.elements[previousKey];
+ require(previousElement.nextKey == nextKey, "previousKey must be adjacent to nextKey");
+ previousElement.nextKey = key;
+ } else {
+ list.tail = key;
+ }
+
+ if (nextKey != bytes32(0)) {
+ require(contains(list, nextKey), "If nextKey is defined, it must exist in the list");
+ Element storage nextElement = list.elements[nextKey];
+ require(nextElement.previousKey == previousKey, "previousKey must be adjacent to nextKey");
+ nextElement.previousKey = key;
+ } else {
+ list.head = key;
+ }
+ }
+
+ list.numElements = list.numElements + 1;
+ }
+
+ /**
+ * @notice Inserts an element at the tail of the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ */
+ function push(List storage list, bytes32 key) internal {
+ insert(list, key, bytes32(0), list.tail);
+ }
+
+ /**
+ * @notice Removes an element from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to remove.
+ */
+ function remove(List storage list, bytes32 key) internal {
+ Element storage element = list.elements[key];
+ require(key != bytes32(0) && contains(list, key), "key not in list");
+ if (element.previousKey != bytes32(0)) {
+ Element storage previousElement = list.elements[element.previousKey];
+ previousElement.nextKey = element.nextKey;
+ } else {
+ list.tail = element.nextKey;
+ }
+
+ if (element.nextKey != bytes32(0)) {
+ Element storage nextElement = list.elements[element.nextKey];
+ nextElement.previousKey = element.previousKey;
+ } else {
+ list.head = element.previousKey;
+ }
+
+ delete list.elements[key];
+ list.numElements = list.numElements - 1;
+ }
+
+ /**
+ * @notice Updates an element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @param previousKey The key of the element that comes before the updated element.
+ * @param nextKey The key of the element that comes after the updated element.
+ */
+ function update(List storage list, bytes32 key, bytes32 previousKey, bytes32 nextKey) internal {
+ require(key != bytes32(0) && key != previousKey && key != nextKey && contains(list, key), "key on in list");
+ remove(list, key);
+ insert(list, key, previousKey, nextKey);
+ }
+
+ /**
+ * @notice Returns whether or not a particular key is present in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function contains(List storage list, bytes32 key) internal view returns (bool) {
+ return list.elements[key].exists;
+ }
+
+ /**
+ * @notice Returns Element based on key.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function get(List storage list, bytes32 key) internal view returns (Element memory) {
+ return list.elements[key];
+ }
+
+ /**
+ * @notice Returns the keys of the N elements at the head of the list.
+ * @param list A storage pointer to the underlying list.
+ * @param n The number of elements to return.
+ * @return The keys of the N elements at the head of the list.
+ * @dev Reverts if n is greater than the number of elements in the list.
+ */
+ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) {
+ require(n <= list.numElements, "not enough elements");
+ bytes32[] memory keys = new bytes32[](n);
+ bytes32 key = list.head;
+ for (uint256 i = 0; i < n; i = i + 1) {
+ keys[i] = key;
+ key = list.elements[key].previousKey;
+ }
+ return keys;
+ }
+
+ /**
+ * @notice Gets all element keys from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return All element keys from head to tail.
+ */
+ function getKeys(List storage list) internal view returns (bytes32[] memory) {
+ return headN(list, list.numElements);
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedList.sol CELO/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedList.sol
new file mode 100644
index 0000000000000000000000000000000000000000..9703cf565523deace3374d6a334ecfdc7c0589eb
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedList.sol
@@ -0,0 +1,218 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "./LinkedList.sol";
+
+/**
+ * @title Maintains a sorted list of unsigned ints keyed by bytes32.
+ */
+library SortedLinkedList {
+ using LinkedList for LinkedList.List;
+
+ struct List {
+ LinkedList.List list;
+ mapping(bytes32 => uint256) values;
+ }
+
+ /**
+ * @notice Inserts an element into a doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ * @param value The element value.
+ * @param lesserKey The key of the element less than the element to insert.
+ * @param greaterKey The key of the element greater than the element to insert.
+ */
+ function insert(List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey) internal {
+ require(key != bytes32(0) && key != lesserKey && key != greaterKey && !contains(list, key), "invalid key");
+ require(
+ (lesserKey != bytes32(0) || greaterKey != bytes32(0)) || list.list.numElements == 0,
+ "greater and lesser key zero"
+ );
+ require(contains(list, lesserKey) || lesserKey == bytes32(0), "invalid lesser key");
+ require(contains(list, greaterKey) || greaterKey == bytes32(0), "invalid greater key");
+ (lesserKey, greaterKey) = getLesserAndGreater(list, value, lesserKey, greaterKey);
+ list.list.insert(key, lesserKey, greaterKey);
+ list.values[key] = value;
+ }
+
+ /**
+ * @notice Removes an element from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to remove.
+ */
+ function remove(List storage list, bytes32 key) internal {
+ list.list.remove(key);
+ list.values[key] = 0;
+ }
+
+ /**
+ * @notice Updates an element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @param value The element value.
+ * @param lesserKey The key of the element will be just left of `key` after the update.
+ * @param greaterKey The key of the element will be just right of `key` after the update.
+ * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
+ */
+ function update(List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey) internal {
+ remove(list, key);
+ insert(list, key, value, lesserKey, greaterKey);
+ }
+
+ /**
+ * @notice Inserts an element at the tail of the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ */
+ function push(List storage list, bytes32 key) internal {
+ insert(list, key, 0, bytes32(0), list.list.tail);
+ }
+
+ /**
+ * @notice Removes N elements from the head of the list and returns their keys.
+ * @param list A storage pointer to the underlying list.
+ * @param n The number of elements to pop.
+ * @return The keys of the popped elements.
+ */
+ function popN(List storage list, uint256 n) internal returns (bytes32[] memory) {
+ require(n <= list.list.numElements, "not enough elements");
+ bytes32[] memory keys = new bytes32[](n);
+ for (uint256 i = 0; i < n; i = i + 1) {
+ bytes32 key = list.list.head;
+ keys[i] = key;
+ remove(list, key);
+ }
+ return keys;
+ }
+
+ /**
+ * @notice Returns whether or not a particular key is present in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function contains(List storage list, bytes32 key) internal view returns (bool) {
+ return list.list.contains(key);
+ }
+
+ /**
+ * @notice Returns Element based on key.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function get(List storage list, bytes32 key) internal view returns (LinkedList.Element memory) {
+ return list.list.get(key);
+ }
+
+ /**
+ * @notice Returns the value for a particular key in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return The element value.
+ */
+ function getValue(List storage list, bytes32 key) internal view returns (uint256) {
+ return list.values[key];
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return Array of all keys in the list.
+ * @return Values corresponding to keys, which will be ordered largest to smallest.
+ */
+ function getElements(List storage list) internal view returns (bytes32[] memory, uint256[] memory) {
+ bytes32[] memory keys = getKeys(list);
+ uint256[] memory values = new uint256[](keys.length);
+ for (uint256 i = 0; i < keys.length; i = i + 1) {
+ values[i] = list.values[keys[i]];
+ }
+ return (keys, values);
+ }
+
+ /**
+ * @notice Gets all element keys from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return All element keys from head to tail.
+ */
+ function getKeys(List storage list) internal view returns (bytes32[] memory) {
+ return list.list.getKeys();
+ }
+
+ /**
+ * @notice Returns first N greatest elements of the list.
+ * @param list A storage pointer to the underlying list.
+ * @param n The number of elements to return.
+ * @return The keys of the first n elements.
+ * @dev Reverts if n is greater than the number of elements in the list.
+ */
+ function headN(List storage list, uint256 n) internal view returns (bytes32[] memory) {
+ return list.list.headN(n);
+ }
+
+ /**
+ * @notice Returns the keys of the elements greaterKey than and less than the provided value.
+ * @param list A storage pointer to the underlying list.
+ * @param value The element value.
+ * @param lesserKey The key of the element which could be just left of the new value.
+ * @param greaterKey The key of the element which could be just right of the new value.
+ * @return The correct lesserKey keys.
+ * @return The correct greaterKey keys.
+ */
+ function getLesserAndGreater(
+ List storage list,
+ uint256 value,
+ bytes32 lesserKey,
+ bytes32 greaterKey
+ )
+ private
+ view
+ returns (bytes32, bytes32)
+ {
+ // Check for one of the following conditions and fail if none are met:
+ // 1. The value is less than the current lowest value
+ // 2. The value is greater than the current greatest value
+ // 3. The value is just greater than the value for `lesserKey`
+ // 4. The value is just less than the value for `greaterKey`
+ if (lesserKey == bytes32(0) && isValueBetween(list, value, lesserKey, list.list.tail)) {
+ return (lesserKey, list.list.tail);
+ } else if (greaterKey == bytes32(0) && isValueBetween(list, value, list.list.head, greaterKey)) {
+ return (list.list.head, greaterKey);
+ } else if (
+ lesserKey != bytes32(0) && isValueBetween(list, value, lesserKey, list.list.elements[lesserKey].nextKey)
+ ) {
+ return (lesserKey, list.list.elements[lesserKey].nextKey);
+ } else if (
+ greaterKey != bytes32(0)
+ && isValueBetween(list, value, list.list.elements[greaterKey].previousKey, greaterKey)
+ ) {
+ return (list.list.elements[greaterKey].previousKey, greaterKey);
+ }
+
+ require(false, "get lesser and greater failure");
+ return (0, 0);
+ }
+
+ /**
+ * @notice Returns whether or not a given element is between two other elements.
+ * @param list A storage pointer to the underlying list.
+ * @param value The element value.
+ * @param lesserKey The key of the element whose value should be lesserKey.
+ * @param greaterKey The key of the element whose value should be greaterKey.
+ * @return True if the given element is between the two other elements.
+ */
+ function isValueBetween(
+ List storage list,
+ uint256 value,
+ bytes32 lesserKey,
+ bytes32 greaterKey
+ )
+ private
+ view
+ returns (bool)
+ {
+ bool isLesser = lesserKey == bytes32(0) || list.values[lesserKey] <= value;
+ bool isGreater = greaterKey == bytes32(0) || list.values[greaterKey] >= value;
+ return isLesser && isGreater;
+ }
+}
(new)
+253
-0
diff --git OP/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedListWithMedian.sol CELO/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedListWithMedian.sol
new file mode 100644
index 0000000000000000000000000000000000000000..458ef554220772c97273526478a794885fa6ac45
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/common/linkedlists/SortedLinkedListWithMedian.sol
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import "./LinkedList.sol";
+import "./SortedLinkedList.sol";
+
+/**
+ * @title Maintains a sorted list of unsigned ints keyed by bytes32.
+ */
+library SortedLinkedListWithMedian {
+ using SortedLinkedList for SortedLinkedList.List;
+
+ enum MedianAction {
+ None,
+ Lesser,
+ Greater
+ }
+
+ enum MedianRelation {
+ Undefined,
+ Lesser,
+ Greater,
+ Equal
+ }
+
+ struct List {
+ SortedLinkedList.List list;
+ bytes32 median;
+ mapping(bytes32 => MedianRelation) relation;
+ }
+
+ /**
+ * @notice Inserts an element into a doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ * @param value The element value.
+ * @param lesserKey The key of the element less than the element to insert.
+ * @param greaterKey The key of the element greater than the element to insert.
+ */
+ function insert(List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey) internal {
+ list.list.insert(key, value, lesserKey, greaterKey);
+ LinkedList.Element storage element = list.list.list.elements[key];
+
+ MedianAction action = MedianAction.None;
+ if (list.list.list.numElements == 1) {
+ list.median = key;
+ list.relation[key] = MedianRelation.Equal;
+ } else if (list.list.list.numElements % 2 == 1) {
+ // When we have an odd number of elements, and the element that we inserted is less than
+ // the previous median, we need to slide the median down one element, since we had previously
+ // selected the greater of the two middle elements.
+ if (element.previousKey == bytes32(0) || list.relation[element.previousKey] == MedianRelation.Lesser) {
+ action = MedianAction.Lesser;
+ list.relation[key] = MedianRelation.Lesser;
+ } else {
+ list.relation[key] = MedianRelation.Greater;
+ }
+ } else {
+ // When we have an even number of elements, and the element that we inserted is greater than
+ // the previous median, we need to slide the median up one element, since we always select
+ // the greater of the two middle elements.
+ if (element.nextKey == bytes32(0) || list.relation[element.nextKey] == MedianRelation.Greater) {
+ action = MedianAction.Greater;
+ list.relation[key] = MedianRelation.Greater;
+ } else {
+ list.relation[key] = MedianRelation.Lesser;
+ }
+ }
+ updateMedian(list, action);
+ }
+
+ /**
+ * @notice Removes an element from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to remove.
+ */
+ function remove(List storage list, bytes32 key) internal {
+ MedianAction action = MedianAction.None;
+ if (list.list.list.numElements == 0) {
+ list.median = bytes32(0);
+ } else if (list.list.list.numElements % 2 == 0) {
+ // When we have an even number of elements, we always choose the higher of the two medians.
+ // Thus, if the element we're removing is greaterKey than or equal to the median we need to
+ // slide the median left by one.
+ if (list.relation[key] == MedianRelation.Greater || list.relation[key] == MedianRelation.Equal) {
+ action = MedianAction.Lesser;
+ }
+ } else {
+ // When we don't have an even number of elements, we just choose the median value.
+ // Thus, if the element we're removing is less than or equal to the median, we need to slide
+ // median right by one.
+ if (list.relation[key] == MedianRelation.Lesser || list.relation[key] == MedianRelation.Equal) {
+ action = MedianAction.Greater;
+ }
+ }
+ updateMedian(list, action);
+
+ list.list.remove(key);
+ }
+
+ /**
+ * @notice Updates an element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @param value The element value.
+ * @param lesserKey The key of the element will be just left of `key` after the update.
+ * @param greaterKey The key of the element will be just right of `key` after the update.
+ * @dev Note that only one of "lesserKey" or "greaterKey" needs to be correct to reduce friction.
+ */
+ function update(List storage list, bytes32 key, uint256 value, bytes32 lesserKey, bytes32 greaterKey) internal {
+ remove(list, key);
+ insert(list, key, value, lesserKey, greaterKey);
+ }
+
+ /**
+ * @notice Inserts an element at the tail of the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The key of the element to insert.
+ */
+ function push(List storage list, bytes32 key) internal {
+ insert(list, key, 0, bytes32(0), list.list.list.tail);
+ }
+
+ /**
+ * @notice Removes N elements from the head of the list and returns their keys.
+ * @param list A storage pointer to the underlying list.
+ * @param n The number of elements to pop.
+ * @return The keys of the popped elements.
+ */
+ function popN(List storage list, uint256 n) internal returns (bytes32[] memory) {
+ require(n <= list.list.list.numElements, "not enough elements");
+ bytes32[] memory keys = new bytes32[](n);
+ for (uint256 i = 0; i < n; i++) {
+ bytes32 key = list.list.list.head;
+ keys[i] = key;
+ remove(list, key);
+ }
+ return keys;
+ }
+
+ /**
+ * @notice Returns whether or not a particular key is present in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return Whether or not the key is in the sorted list.
+ */
+ function contains(List storage list, bytes32 key) internal view returns (bool) {
+ return list.list.contains(key);
+ }
+
+ /**
+ * @notice Returns the value for a particular key in the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @param key The element key.
+ * @return The element value.
+ */
+ function getValue(List storage list, bytes32 key) internal view returns (uint256) {
+ return list.list.values[key];
+ }
+
+ /**
+ * @notice Returns the median value of the sorted list.
+ * @param list A storage pointer to the underlying list.
+ * @return The median value.
+ */
+ function getMedianValue(List storage list) internal view returns (uint256) {
+ return getValue(list, list.median);
+ }
+
+ /**
+ * @notice Returns the key of the first element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the first element in the list.
+ */
+ function getHead(List storage list) internal view returns (bytes32) {
+ return list.list.list.head;
+ }
+
+ /**
+ * @notice Returns the key of the median element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the median element in the list.
+ */
+ function getMedian(List storage list) internal view returns (bytes32) {
+ return list.median;
+ }
+
+ /**
+ * @notice Returns the key of the last element in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The key of the last element in the list.
+ */
+ function getTail(List storage list) internal view returns (bytes32) {
+ return list.list.list.tail;
+ }
+
+ /**
+ * @notice Returns the number of elements in the list.
+ * @param list A storage pointer to the underlying list.
+ * @return The number of elements in the list.
+ */
+ function getNumElements(List storage list) internal view returns (uint256) {
+ return list.list.list.numElements;
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return Array of all keys in the list.
+ * @return Values corresponding to keys, which will be ordered largest to smallest.
+ * @return Array of relations to median of corresponding list elements.
+ */
+ function getElements(List storage list)
+ internal
+ view
+ returns (bytes32[] memory, uint256[] memory, MedianRelation[] memory)
+ {
+ bytes32[] memory keys = getKeys(list);
+ uint256[] memory values = new uint256[](keys.length);
+ MedianRelation[] memory relations = new MedianRelation[](keys.length);
+ for (uint256 i = 0; i < keys.length; i++) {
+ values[i] = list.list.values[keys[i]];
+ relations[i] = list.relation[keys[i]];
+ }
+ return (keys, values, relations);
+ }
+
+ /**
+ * @notice Gets all element keys from the doubly linked list.
+ * @param list A storage pointer to the underlying list.
+ * @return All element keys from head to tail.
+ */
+ function getKeys(List storage list) internal view returns (bytes32[] memory) {
+ return list.list.getKeys();
+ }
+
+ /**
+ * @notice Moves the median pointer right or left of its current value.
+ * @param list A storage pointer to the underlying list.
+ * @param action Which direction to move the median pointer.
+ */
+ function updateMedian(List storage list, MedianAction action) private {
+ LinkedList.Element storage previousMedian = list.list.list.elements[list.median];
+ if (action == MedianAction.Lesser) {
+ list.relation[list.median] = MedianRelation.Greater;
+ list.median = previousMedian.previousKey;
+ } else if (action == MedianAction.Greater) {
+ list.relation[list.median] = MedianRelation.Lesser;
+ list.median = previousMedian.nextKey;
+ }
+ list.relation[list.median] = MedianRelation.Equal;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/governance/interfaces/IElection.sol CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IElection.sol
new file mode 100644
index 0000000000000000000000000000000000000000..f099ce364a2705987e0b242c07fbc1871371077b
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IElection.sol
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IElection {
+ function electValidatorSigners() external view returns (address[] memory);
+ function electNValidatorSigners(uint256, uint256) external view returns (address[] memory);
+ function vote(address, uint256, address, address) external returns (bool);
+ function activate(address) external returns (bool);
+ function revokeActive(address, uint256, address, address, uint256) external returns (bool);
+ function revokeAllActive(address, address, address, uint256) external returns (bool);
+ function revokePending(address, uint256, address, address, uint256) external returns (bool);
+ function markGroupIneligible(address) external;
+ function markGroupEligible(address, address, address) external;
+ function allowedToVoteOverMaxNumberOfGroups(address) external returns (bool);
+ function forceDecrementVotes(
+ address,
+ uint256,
+ address[] calldata,
+ address[] calldata,
+ uint256[] calldata
+ )
+ external
+ returns (uint256);
+ function setAllowedToVoteOverMaxNumberOfGroups(bool flag) external;
+
+ // view functions
+ function getElectableValidators() external view returns (uint256, uint256);
+ function getElectabilityThreshold() external view returns (uint256);
+ function getNumVotesReceivable(address) external view returns (uint256);
+ function getTotalVotes() external view returns (uint256);
+ function getActiveVotes() external view returns (uint256);
+ function getTotalVotesByAccount(address) external view returns (uint256);
+ function getPendingVotesForGroupByAccount(address, address) external view returns (uint256);
+ function getActiveVotesForGroupByAccount(address, address) external view returns (uint256);
+ function getTotalVotesForGroupByAccount(address, address) external view returns (uint256);
+ function getActiveVoteUnitsForGroupByAccount(address, address) external view returns (uint256);
+ function getTotalVotesForGroup(address) external view returns (uint256);
+ function getActiveVotesForGroup(address) external view returns (uint256);
+ function getPendingVotesForGroup(address) external view returns (uint256);
+ function getGroupEligibility(address) external view returns (bool);
+ function getGroupEpochRewards(address, uint256, uint256[] calldata) external view returns (uint256);
+ function getGroupsVotedForByAccount(address) external view returns (address[] memory);
+ function getEligibleValidatorGroups() external view returns (address[] memory);
+ function getTotalVotesForEligibleValidatorGroups() external view returns (address[] memory, uint256[] memory);
+ function getCurrentValidatorSigners() external view returns (address[] memory);
+ function canReceiveVotes(address, uint256) external view returns (bool);
+ function hasActivatablePendingVotes(address, address) external view returns (bool);
+ function validatorSignerAddressFromCurrentSet(uint256 index) external view returns (address);
+ function numberValidatorsInCurrentSet() external view returns (uint256);
+
+ // only owner
+ function setElectableValidators(uint256, uint256) external returns (bool);
+ function setMaxNumGroupsVotedFor(uint256) external returns (bool);
+ function setElectabilityThreshold(uint256) external returns (bool);
+
+ // only VM
+ function distributeEpochRewards(address, uint256, address, address) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/governance/interfaces/IGovernance.sol CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IGovernance.sol
new file mode 100644
index 0000000000000000000000000000000000000000..883844ea8f219feaaa747a6fd61f33424c6828a8
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IGovernance.sol
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IGovernance {
+ function votePartially(
+ uint256 proposalId,
+ uint256 index,
+ uint256 yesVotes,
+ uint256 noVotes,
+ uint256 abstainVotes
+ )
+ external
+ returns (bool);
+
+ function isVoting(address) external view returns (bool);
+ function getAmountOfGoldUsedForVoting(address account) external view returns (uint256);
+
+ function getProposal(uint256 proposalId)
+ external
+ view
+ returns (address, uint256, uint256, uint256, string memory, uint256, bool);
+
+ function getReferendumStageDuration() external view returns (uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/governance/interfaces/ILockedGold.sol CELO/packages/contracts-bedrock/src/celo/governance/interfaces/ILockedGold.sol
new file mode 100644
index 0000000000000000000000000000000000000000..38002d58914c70665df042ea9e3a3051d2c53091
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/governance/interfaces/ILockedGold.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface ILockedGold {
+ function lock() external payable;
+ function incrementNonvotingAccountBalance(address, uint256) external;
+ function decrementNonvotingAccountBalance(address, uint256) external;
+ function getAccountTotalLockedGold(address) external view returns (uint256);
+ function getTotalLockedGold() external view returns (uint256);
+ function getPendingWithdrawals(address) external view returns (uint256[] memory, uint256[] memory);
+ function getPendingWithdrawal(address account, uint256 index) external view returns (uint256, uint256);
+ function getTotalPendingWithdrawals(address) external view returns (uint256);
+ function unlock(uint256) external;
+ function relock(uint256, uint256) external;
+ function withdraw(uint256) external;
+ function slash(
+ address account,
+ uint256 penalty,
+ address reporter,
+ uint256 reward,
+ address[] calldata lessers,
+ address[] calldata greaters,
+ uint256[] calldata indices
+ )
+ external;
+ function isSlasher(address) external view returns (bool);
+ function unlockingPeriod() external view returns (uint256);
+ function getAccountNonvotingLockedGold(address account) external view returns (uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/governance/interfaces/IReleaseGold.sol CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IReleaseGold.sol
new file mode 100644
index 0000000000000000000000000000000000000000..e211ce7399e37478a43b3b5e0335339e5c253265
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IReleaseGold.sol
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IReleaseGold {
+ function transfer(address, uint256) external;
+ function unlockGold(uint256) external;
+ function withdrawLockedGold(uint256) external;
+ function authorizeVoteSigner(address payable, uint8, bytes32, bytes32) external;
+ function authorizeValidatorSigner(address payable, uint8, bytes32, bytes32) external;
+ function authorizeValidatorSignerWithPublicKey(address payable, uint8, bytes32, bytes32, bytes calldata) external;
+ function authorizeValidatorSignerWithKeys(
+ address payable,
+ uint8,
+ bytes32,
+ bytes32,
+ bytes calldata,
+ bytes calldata,
+ bytes calldata
+ )
+ external;
+ function authorizeAttestationSigner(address payable, uint8, bytes32, bytes32) external;
+ function revokeActive(address, uint256, address, address, uint256) external;
+ function revokePending(address, uint256, address, address, uint256) external;
+
+ // view functions
+ function getTotalBalance() external view returns (uint256);
+ function getRemainingTotalBalance() external view returns (uint256);
+ function getRemainingUnlockedBalance() external view returns (uint256);
+ function getRemainingLockedBalance() external view returns (uint256);
+ function getCurrentReleasedTotalAmount() external view returns (uint256);
+ function isRevoked() external view returns (bool);
+
+ // only beneficiary
+ function setCanExpire(bool) external;
+ function withdraw(uint256) external;
+ function lockGold(uint256) external;
+ function relockGold(uint256, uint256) external;
+ function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;
+ function createAccount() external;
+ function setAccountName(string calldata) external;
+ function setAccountWalletAddress(address, uint8, bytes32, bytes32) external;
+ function setAccountDataEncryptionKey(bytes calldata) external;
+ function setAccountMetadataURL(string calldata) external;
+
+ // only owner
+ function setBeneficiary(address payable) external;
+
+ // only release owner
+ function setLiquidityProvision() external;
+ function setMaxDistribution(uint256) external;
+ function refundAndFinalize() external;
+ function revoke() external;
+ function expire() external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/governance/interfaces/IValidators.sol CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IValidators.sol
new file mode 100644
index 0000000000000000000000000000000000000000..8a10e91fc8129cfb736057443bbec7c63170921e
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/governance/interfaces/IValidators.sol
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IValidators {
+ function registerValidator(bytes calldata, bytes calldata, bytes calldata) external returns (bool);
+ function deregisterValidator(uint256) external returns (bool);
+ function affiliate(address) external returns (bool);
+ function deaffiliate() external returns (bool);
+ function updateBlsPublicKey(bytes calldata, bytes calldata) external returns (bool);
+ function registerValidatorGroup(uint256) external returns (bool);
+ function deregisterValidatorGroup(uint256) external returns (bool);
+ function addMember(address) external returns (bool);
+ function addFirstMember(address, address, address) external returns (bool);
+ function removeMember(address) external returns (bool);
+ function reorderMember(address, address, address) external returns (bool);
+ function updateCommission() external;
+ function setNextCommissionUpdate(uint256) external;
+ function resetSlashingMultiplier() external;
+
+ // only owner
+ function setCommissionUpdateDelay(uint256) external;
+ function setMaxGroupSize(uint256) external returns (bool);
+ function setMembershipHistoryLength(uint256) external returns (bool);
+ function setValidatorScoreParameters(uint256, uint256) external returns (bool);
+ function setGroupLockedGoldRequirements(uint256, uint256) external returns (bool);
+ function setValidatorLockedGoldRequirements(uint256, uint256) external returns (bool);
+ function setSlashingMultiplierResetPeriod(uint256) external;
+
+ // view functions
+ function getMaxGroupSize() external view returns (uint256);
+ function getCommissionUpdateDelay() external view returns (uint256);
+ function getValidatorScoreParameters() external view returns (uint256, uint256);
+ function getMembershipHistory(address)
+ external
+ view
+ returns (uint256[] memory, address[] memory, uint256, uint256);
+ function calculateEpochScore(uint256) external view returns (uint256);
+ function calculateGroupEpochScore(uint256[] calldata) external view returns (uint256);
+ function getAccountLockedGoldRequirement(address) external view returns (uint256);
+ function meetsAccountLockedGoldRequirements(address) external view returns (bool);
+ function getValidatorBlsPublicKeyFromSigner(address) external view returns (bytes memory);
+ function getValidator(address account)
+ external
+ view
+ returns (bytes memory, bytes memory, address, uint256, address);
+ function getValidatorGroup(address)
+ external
+ view
+ returns (address[] memory, uint256, uint256, uint256, uint256[] memory, uint256, uint256);
+ function getGroupNumMembers(address) external view returns (uint256);
+ function getTopGroupValidators(address, uint256) external view returns (address[] memory);
+ function getGroupsNumMembers(address[] calldata accounts) external view returns (uint256[] memory);
+ function getNumRegisteredValidators() external view returns (uint256);
+ function groupMembershipInEpoch(address, uint256, uint256) external view returns (address);
+
+ // only registered contract
+ function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);
+ function updatePublicKeys(
+ address,
+ address,
+ bytes calldata,
+ bytes calldata,
+ bytes calldata
+ )
+ external
+ returns (bool);
+ function getValidatorLockedGoldRequirements() external view returns (uint256, uint256);
+ function getGroupLockedGoldRequirements() external view returns (uint256, uint256);
+ function getRegisteredValidators() external view returns (address[] memory);
+ function getRegisteredValidatorSigners() external view returns (address[] memory);
+ function getRegisteredValidatorGroups() external view returns (address[] memory);
+ function isValidatorGroup(address) external view returns (bool);
+ function isValidator(address) external view returns (bool);
+ function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);
+ function getMembershipInLastEpoch(address) external view returns (address);
+ function getMembershipInLastEpochFromSigner(address) external view returns (address);
+
+ // only VM
+ function updateValidatorScoreFromSigner(address, uint256) external;
+ function distributeEpochPaymentsFromSigner(address, uint256) external returns (uint256);
+
+ // only slasher
+ function forceDeaffiliateIfValidator(address) external;
+ function halveSlashingMultiplier(address) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/identity/interfaces/IAttestations.sol CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IAttestations.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5c1a1d7a8f484e1cedc6336b39144ceea0941c97
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IAttestations.sol
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IAttestations {
+ function revoke(bytes32, uint256) external;
+ function withdraw(address) external;
+
+ // view functions
+ function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address);
+ function getAttestationIssuers(bytes32, address) external view returns (address[] memory);
+ function getAttestationStats(bytes32, address) external view returns (uint32, uint32);
+ function batchGetAttestationStats(bytes32[] calldata)
+ external
+ view
+ returns (uint256[] memory, address[] memory, uint64[] memory, uint64[] memory);
+ function getAttestationState(bytes32, address, address) external view returns (uint8, uint32, address);
+ function getCompletableAttestations(
+ bytes32,
+ address
+ )
+ external
+ view
+ returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory);
+ function getAttestationRequestFee(address) external view returns (uint256);
+ function getMaxAttestations() external view returns (uint256);
+ function validateAttestationCode(bytes32, address, uint8, bytes32, bytes32) external view returns (address);
+ function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory);
+ function requireNAttestationsRequested(bytes32, address, uint32) external view;
+
+ // only owner
+ function setAttestationRequestFee(address, uint256) external;
+ function setAttestationExpiryBlocks(uint256) external;
+ function setSelectIssuersWaitBlocks(uint256) external;
+ function setMaxAttestations(uint256) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/identity/interfaces/IEscrow.sol CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IEscrow.sol
new file mode 100644
index 0000000000000000000000000000000000000000..87c145a4a1bb9bf3aa469bb8ec5ca6e92073525f
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IEscrow.sol
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+interface IEscrow {
+ function transfer(
+ bytes32 identifier,
+ address token,
+ uint256 value,
+ uint256 expirySeconds,
+ address paymentId,
+ uint256 minAttestations
+ )
+ external
+ returns (bool);
+ function transferWithTrustedIssuers(
+ bytes32 identifier,
+ address token,
+ uint256 value,
+ uint256 expirySeconds,
+ address paymentId,
+ uint256 minAttestations,
+ address[] calldata trustedIssuers
+ )
+ external
+ returns (bool);
+ function withdraw(address paymentID, uint8 v, bytes32 r, bytes32 s) external returns (bool);
+ function revoke(address paymentID) external returns (bool);
+
+ // view functions
+ function getReceivedPaymentIds(bytes32 identifier) external view returns (address[] memory);
+ function getSentPaymentIds(address sender) external view returns (address[] memory);
+ function getTrustedIssuersPerPayment(address paymentId) external view returns (address[] memory);
+ function getDefaultTrustedIssuers() external view returns (address[] memory);
+ function MAX_TRUSTED_ISSUERS_PER_PAYMENT() external view returns (uint256);
+
+ // onlyOwner functions
+ function addDefaultTrustedIssuer(address trustedIssuer) external;
+ function removeDefaultTrustedIssuer(address trustedIssuer, uint256 index) external;
+}
(new)
+62
-0
diff --git OP/packages/contracts-bedrock/src/celo/identity/interfaces/IFederatedAttestations.sol CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IFederatedAttestations.sol
new file mode 100644
index 0000000000000000000000000000000000000000..c0586eb9e44dc7a10fdd0e86de09a7753c6e4974
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IFederatedAttestations.sol
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+interface IFederatedAttestations {
+ function registerAttestationAsIssuer(bytes32 identifier, address account, uint64 issuedOn) external;
+ function registerAttestation(
+ bytes32 identifier,
+ address issuer,
+ address account,
+ address signer,
+ uint64 issuedOn,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ )
+ external;
+ function revokeAttestation(bytes32 identifier, address issuer, address account) external;
+ function batchRevokeAttestations(
+ address issuer,
+ bytes32[] calldata identifiers,
+ address[] calldata accounts
+ )
+ external;
+
+ // view functions
+ function lookupAttestations(
+ bytes32 identifier,
+ address[] calldata trustedIssuers
+ )
+ external
+ view
+ returns (uint256[] memory, address[] memory, address[] memory, uint64[] memory, uint64[] memory);
+ function lookupIdentifiers(
+ address account,
+ address[] calldata trustedIssuers
+ )
+ external
+ view
+ returns (uint256[] memory, bytes32[] memory);
+ function validateAttestationSig(
+ bytes32 identifier,
+ address issuer,
+ address account,
+ address signer,
+ uint64 issuedOn,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ )
+ external
+ view;
+ function getUniqueAttestationHash(
+ bytes32 identifier,
+ address issuer,
+ address account,
+ address signer,
+ uint64 issuedOn
+ )
+ external
+ pure
+ returns (bytes32);
+}
diff --git OP/packages/contracts-bedrock/src/celo/identity/interfaces/IOdisPayments.sol CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IOdisPayments.sol
new file mode 100644
index 0000000000000000000000000000000000000000..ca188432c0dda414dfa563d857cccc600947de9e
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IOdisPayments.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+interface IOdisPayments {
+ function payInCUSD(address account, uint256 value) external;
+ function totalPaidCUSD(address) external view returns (uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/identity/interfaces/IRandom.sol CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IRandom.sol
new file mode 100644
index 0000000000000000000000000000000000000000..65cf3082d685cd4a5a9a2e38d8254e85de1bb2e5
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/identity/interfaces/IRandom.sol
@@ -0,0 +1,9 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IRandom {
+ function revealAndCommit(bytes32, bytes32, address) external;
+ function randomnessBlockRetentionWindow() external view returns (uint256);
+ function random() external view returns (bytes32);
+ function getBlockRandomness(uint256) external view returns (bytes32);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IAccounts.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IAccounts.sol
new file mode 100644
index 0000000000000000000000000000000000000000..734dcddeb941d89c467af92a24ba0a488df4ab57
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IAccounts.sol
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IAccounts {
+ function isAccount(address) external view returns (bool);
+ function voteSignerToAccount(address) external view returns (address);
+ function validatorSignerToAccount(address) external view returns (address);
+ function attestationSignerToAccount(address) external view returns (address);
+ function signerToAccount(address) external view returns (address);
+ function getAttestationSigner(address) external view returns (address);
+ function getValidatorSigner(address) external view returns (address);
+ function getVoteSigner(address) external view returns (address);
+ function hasAuthorizedVoteSigner(address) external view returns (bool);
+ function hasAuthorizedValidatorSigner(address) external view returns (bool);
+ function hasAuthorizedAttestationSigner(address) external view returns (bool);
+
+ function setAccountDataEncryptionKey(bytes calldata) external;
+ function setMetadataURL(string calldata) external;
+ function setName(string calldata) external;
+ function setWalletAddress(address, uint8, bytes32, bytes32) external;
+ function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;
+
+ function getDataEncryptionKey(address) external view returns (bytes memory);
+ function getWalletAddress(address) external view returns (address);
+ function getMetadataURL(address) external view returns (string memory);
+ function batchGetMetadataURL(address[] calldata) external view returns (uint256[] memory, bytes memory);
+ function getName(address) external view returns (string memory);
+
+ function authorizeVoteSigner(address, uint8, bytes32, bytes32) external;
+ function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external;
+ function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata) external;
+ function authorizeValidatorSignerWithKeys(
+ address,
+ uint8,
+ bytes32,
+ bytes32,
+ bytes calldata,
+ bytes calldata,
+ bytes calldata
+ )
+ external;
+ function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external;
+ function createAccount() external returns (bool);
+
+ function setPaymentDelegation(address, uint256) external;
+ function getPaymentDelegation(address) external view returns (address, uint256);
+ function isSigner(address, address, bytes32) external view returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/ICeloRegistry.sol CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloRegistry.sol
new file mode 100644
index 0000000000000000000000000000000000000000..95e586da3954ffc48f18c7e781161990abab7936
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloRegistry.sol
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface ICeloRegistry {
+ function setAddressFor(string calldata, address) external;
+ function getAddressForOrDie(bytes32) external view returns (address);
+ function getAddressFor(bytes32) external view returns (address);
+ function getAddressForStringOrDie(string calldata identifier) external view returns (address);
+ function getAddressForString(string calldata identifier) external view returns (address);
+ function isOneOf(bytes32[] calldata, address) external view returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/ICeloToken.sol CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloToken.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5bf2033f31726110e6504078561108cfee40a42d
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloToken.sol
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+/**
+ * @title This interface describes the non- ERC20 shared interface for all Celo Tokens, and
+ * in the absence of interface inheritance is intended as a companion to IERC20.sol.
+ */
+interface ICeloToken {
+ function transferWithComment(address, uint256, string calldata) external returns (bool);
+ function name() external view returns (string memory);
+ function symbol() external view returns (string memory);
+ function decimals() external view returns (uint8);
+ function burn(uint256 value) external returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/ICeloVersionedContract.sol CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloVersionedContract.sol
new file mode 100644
index 0000000000000000000000000000000000000000..37b1538c2a121b4dd73b5762db9ba4a97364581c
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/ICeloVersionedContract.sol
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface ICeloVersionedContract {
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IFeeCurrencyDirectory.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IFeeCurrencyDirectory.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5c6ab9051ccf28eebd9f8482ae22b9e9df8e939f
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IFeeCurrencyDirectory.sol
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.0;
+
+interface IFeeCurrencyDirectory {
+ struct CurrencyConfig {
+ address oracle;
+ uint256 intrinsicGas;
+ }
+
+ /**
+ * @notice Returns the list of all currency addresses.
+ * @return An array of addresses.
+ */
+ function getCurrencies() external view returns (address[] memory);
+ /**
+ * @notice Returns the configuration for a currency.
+ * @param token The address of the token.
+ * @return Currency configuration of the token.
+ */
+ function getCurrencyConfig(address token) external view returns (CurrencyConfig memory);
+
+ /**
+ * @notice Retrieves exchange rate between token and CELO.
+ * @param token The token address whose price is to be fetched.
+ * @return numerator The exchange rate numerator.
+ * @return denominator The exchange rate denominator.
+ */
+ function getExchangeRate(address token) external view returns (uint256 numerator, uint256 denominator);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IFreezer.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IFreezer.sol
new file mode 100644
index 0000000000000000000000000000000000000000..a629b3325a5ba883298aa61d85f260573fe042a8
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IFreezer.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IFreezer {
+ function isFrozen(address) external view returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWallet.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWallet.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5c7f392814b615b6b35ec6de7e4a044708fec8df
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWallet.sol
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IMetaTransactionWallet {
+ function setEip712DomainSeparator() external;
+ function executeMetaTransaction(
+ address,
+ uint256,
+ bytes calldata,
+ uint8,
+ bytes32,
+ bytes32
+ )
+ external
+ returns (bytes memory);
+ function executeTransaction(address, uint256, bytes calldata) external returns (bytes memory);
+ function executeTransactions(
+ address[] calldata,
+ uint256[] calldata,
+ bytes calldata,
+ uint256[] calldata
+ )
+ external
+ returns (bytes memory, uint256[] memory);
+
+ // view functions
+ function getMetaTransactionDigest(address, uint256, bytes calldata, uint256) external view returns (bytes32);
+ function getMetaTransactionSigner(
+ address,
+ uint256,
+ bytes calldata,
+ uint256,
+ uint8,
+ bytes32,
+ bytes32
+ )
+ external
+ view
+ returns (address);
+
+ //only owner
+ function setSigner(address) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWalletDeployer.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWalletDeployer.sol
new file mode 100644
index 0000000000000000000000000000000000000000..5828bee3c7467f9386974465a6a3fee00c3ef65f
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IMetaTransactionWalletDeployer.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IMetaTransactionWalletDeployer {
+ function deploy(address, address, bytes calldata) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IOracle.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IOracle.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b3ae66a92756c915ede5a6c5b1f57387b2edc254
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IOracle.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.5.13 <0.9.0;
+
+/// Possibly not final version
+interface IOracle {
+ function getExchangeRate(address token) external view returns (uint256 numerator, uint256 denominator);
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IStableToken.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IStableToken.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b13febff81fc8c95da5bc8567fdbcc64938c9d19
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IStableToken.sol
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity >=0.5.17 <9.0.0;
+
+interface IStableTokenV2 {
+ function totalSupply() external view returns (uint256);
+
+ function balanceOf(address account) external view returns (uint256);
+
+ function transfer(address recipient, uint256 amount) external returns (bool);
+
+ function allowance(address owner, address spender) external view returns (uint256);
+
+ function approve(address spender, uint256 amount) external returns (bool);
+
+ function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
+
+ function mint(address, uint256) external returns (bool);
+
+ function burn(uint256) external returns (bool);
+
+ function permit(
+ address owner,
+ address spender,
+ uint256 value,
+ uint256 deadline,
+ uint8 v,
+ bytes32 r,
+ bytes32 s
+ )
+ external;
+
+ /**
+ * @notice Transfer token for a specified address
+ * @param to The address to transfer to.
+ * @param value The amount to be transferred.
+ * @param comment The transfer comment.
+ * @return True if the transaction succeeds.
+ */
+ function transferWithComment(address to, uint256 value, string calldata comment) external returns (bool);
+
+ /**
+ * @notice Initializes a StableTokenV2.
+ * It keeps the same signature as the original initialize() function
+ * in legacy/StableToken.sol
+ * @param _name The name of the stable token (English)
+ * @param _symbol A short symbol identifying the token (e.g. "cUSD")
+ * @param initialBalanceAddresses Array of addresses with an initial balance.
+ * @param initialBalanceValues Array of balance values corresponding to initialBalanceAddresses.
+ * deprecated-param exchangeIdentifier String identifier of exchange in registry (for specific fiat pairs)
+ */
+ function initialize(
+ string calldata _name,
+ string calldata _symbol,
+ address[] calldata initialBalanceAddresses,
+ uint256[] calldata initialBalanceValues
+ )
+ external;
+
+ /**
+ * @notice Initializes a StableTokenV2 contract
+ * when upgrading from legacy/StableToken.sol.
+ * It sets the addresses that were previously read from the Registry.
+ * It runs the ERC20PermitUpgradeable initializer.
+ * @dev This function is only callable once.
+ * @param _broker The address of the Broker contract.
+ * @param _validators The address of the Validators contract.
+ * @param _exchange The address of the Exchange contract.
+ */
+ function initializeV2(address _broker, address _validators, address _exchange) external;
+
+ /**
+ * @notice Gets the address of the Broker contract.
+ */
+ function broker() external returns (address);
+
+ /**
+ * @notice Gets the address of the Validators contract.
+ */
+ function validators() external returns (address);
+
+ /**
+ * @notice Gets the address of the Exchange contract.
+ */
+ function exchange() external returns (address);
+
+ function debitGasFees(address from, uint256 value) external;
+
+ function creditGasFees(
+ address from,
+ address feeRecipient,
+ address gatewayFeeRecipient,
+ address communityFund,
+ uint256 refund,
+ uint256 tipTxFee,
+ uint256 gatewayFee,
+ uint256 baseTxFee
+ )
+ external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/interfaces/IStableTokenMento.sol CELO/packages/contracts-bedrock/src/celo/interfaces/IStableTokenMento.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b309071d9f0ad88f27ece5e2648d4fa51465b741
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/interfaces/IStableTokenMento.sol
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+/**
+ * @title This interface describes the functions specific to Celo Stable Tokens, and in the
+ * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol.
+ */
+interface IStableTokenMento {
+ function mint(address, uint256) external returns (bool);
+
+ function burn(uint256) external returns (bool);
+
+ function setInflationParameters(uint256, uint256) external;
+
+ function valueToUnits(uint256) external view returns (uint256);
+
+ function unitsToValue(uint256) external view returns (uint256);
+
+ function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);
+
+ // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported.
+ function balanceOf(address) external view returns (uint256);
+
+ function getExchangeRegistryId() external view returns (bytes32);
+
+ function approve(address spender, uint256 value) external returns (bool);
+}
diff --git OP/packages/contracts-bedrock/src/celo/mento/interfaces/IExchange.sol CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IExchange.sol
new file mode 100644
index 0000000000000000000000000000000000000000..4e15e8a8750d45e28c6fc9eb7e483bf39591fa0b
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IExchange.sol
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IExchange {
+ function buy(uint256, uint256, bool) external returns (uint256);
+
+ function sell(uint256, uint256, bool) external returns (uint256);
+
+ function exchange(uint256, uint256, bool) external returns (uint256);
+
+ function setUpdateFrequency(uint256) external;
+
+ function getBuyTokenAmount(uint256, bool) external view returns (uint256);
+
+ function getSellTokenAmount(uint256, bool) external view returns (uint256);
+
+ function getBuyAndSellBuckets(bool) external view returns (uint256, uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/mento/interfaces/IReserve.sol CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IReserve.sol
new file mode 100644
index 0000000000000000000000000000000000000000..14f77c10549a1247f645191e241cd61a23145af5
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IReserve.sol
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IReserve {
+ function setTobinTaxStalenessThreshold(uint256) external;
+
+ function addToken(address) external returns (bool);
+
+ function removeToken(address, uint256) external returns (bool);
+
+ function transferGold(address payable, uint256) external returns (bool);
+
+ function transferExchangeGold(address payable, uint256) external returns (bool);
+
+ function getReserveGoldBalance() external view returns (uint256);
+
+ function getUnfrozenReserveGoldBalance() external view returns (uint256);
+
+ function getOrComputeTobinTax() external returns (uint256, uint256);
+
+ function getTokens() external view returns (address[] memory);
+
+ function getReserveRatio() external view returns (uint256);
+
+ function addExchangeSpender(address) external;
+
+ function removeExchangeSpender(address, uint256) external;
+
+ function addSpender(address) external;
+
+ function removeSpender(address) external;
+}
diff --git OP/packages/contracts-bedrock/src/celo/mento/interfaces/IStableToken.sol CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IStableToken.sol
new file mode 100644
index 0000000000000000000000000000000000000000..c0b681dfb8aee25aa686d5484adea6f3f6f79179
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/mento/interfaces/IStableToken.sol
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+/**
+ * @title This interface describes the functions specific to Celo Stable Tokens, and in the
+ * absence of interface inheritance is intended as a companion to IERC20.sol and ICeloToken.sol.
+ */
+interface IStableToken {
+ function mint(address, uint256) external returns (bool);
+
+ function burn(uint256) external returns (bool);
+
+ function setInflationParameters(uint256, uint256) external;
+
+ function valueToUnits(uint256) external view returns (uint256);
+
+ function unitsToValue(uint256) external view returns (uint256);
+
+ function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);
+
+ // NOTE: duplicated with IERC20.sol, remove once interface inheritance is supported.
+ function balanceOf(address) external view returns (uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/stability/SortedOracles.sol CELO/packages/contracts-bedrock/src/celo/stability/SortedOracles.sol
new file mode 100644
index 0000000000000000000000000000000000000000..d2209dac5d2c8de4df0d0a1eb0ae0ec3f0e4422b
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/stability/SortedOracles.sol
@@ -0,0 +1,466 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+pragma solidity ^0.8.15;
+
+import "../../../lib/openzeppelin-contracts/contracts/access/Ownable.sol";
+import "../../../lib/openzeppelin-contracts/contracts/utils/math/SafeMath.sol";
+
+import "./interfaces/ISortedOracles.sol";
+import "../common/interfaces/ICeloVersionedContract.sol";
+import "./interfaces/IBreakerBox.sol";
+
+import "../common/FixidityLib.sol";
+import "../common/Initializable.sol";
+import "../common/linkedlists/AddressSortedLinkedListWithMedian.sol";
+import "../common/linkedlists/SortedLinkedListWithMedian.sol";
+import "./interfaces/IOracle.sol";
+
+/**
+ * @title SortedOracles
+ *
+ * @notice This contract stores a collection of exchange rates with CELO
+ * expressed in units of other assets. The most recent exchange rates
+ * are gathered off-chain by oracles, who then use the `report` function to
+ * submit the rates to this contract. Before submitting a rate report, an
+ * oracle's address must be added to the `isOracle` mapping for a specific
+ * rateFeedId, with the flag set to true. While submitting a report requires
+ * an address to be added to the mapping, no additional permissions are needed
+ * to read the reports, the calculated median rate, or the list of oracles.
+ *
+ * @dev A unique rateFeedId identifies each exchange rate. In the initial implementation
+ * of this contract, the rateFeedId was set as the address of the stable
+ * asset contract that used the rate. However, this implementation has since
+ * been updated, and the rateFeedId block.timestamp also refers to an address derived from the
+ * concatenation other asset symbols. This change enables the contract to store multiple exchange rates for a
+ * single token. As a result of this change, there may be instances
+ * where the term "token" is used in the contract code. These useages of the term
+ * "token" are actually referring to the rateFeedId.
+ *
+ */
+contract SortedOracles is ISortedOracles, IOracle, ICeloVersionedContract, Ownable, Initializable {
+ using SafeMath for uint256;
+ using AddressSortedLinkedListWithMedian for SortedLinkedListWithMedian.List;
+ using FixidityLib for FixidityLib.Fraction;
+
+ struct EquivalentToken {
+ address token;
+ }
+
+ uint256 private constant FIXED1_UINT = 1e24;
+
+ // Maps a rateFeedID to a sorted list of report values.
+ mapping(address => SortedLinkedListWithMedian.List) private rates;
+ // Maps a rateFeedID to a sorted list of report timestamps.
+ mapping(address => SortedLinkedListWithMedian.List) private timestamps;
+ mapping(address => mapping(address => bool)) public isOracle;
+ mapping(address => address[]) public oracles;
+
+ // `reportExpirySeconds` is the fallback value used to determine reporting
+ // frequency. Initially it was the _only_ value but we later introduced
+ // the per token mapping in `tokenReportExpirySeconds`. If a token
+ // doesn't have a value in the mapping (i.e. it's 0), the fallback is used.
+ // See: #getTokenReportExpirySeconds
+ uint256 public reportExpirySeconds;
+ // Maps a rateFeedId to its report expiry time in seconds.
+ mapping(address => uint256) public tokenReportExpirySeconds;
+
+ IBreakerBox public breakerBox;
+ // Maps a token address to its equivalent token address.
+ // Original token will return the median value same as the value of equivalent token.
+ mapping(address => EquivalentToken) public equivalentTokens;
+
+ event OracleAdded(address indexed token, address indexed oracleAddress);
+ event OracleRemoved(address indexed token, address indexed oracleAddress);
+ event OracleReported(address indexed token, address indexed oracle, uint256 timestamp, uint256 value);
+ event OracleReportRemoved(address indexed token, address indexed oracle);
+ event MedianUpdated(address indexed token, uint256 value);
+ event ReportExpirySet(uint256 reportExpiry);
+ event TokenReportExpirySet(address token, uint256 reportExpiry);
+ event BreakerBoxUpdated(address indexed newBreakerBox);
+ event EquivalentTokenSet(address indexed token, address indexed equivalentToken);
+
+ modifier onlyOracle(address token) {
+ require(isOracle[token][msg.sender], "sender was not an oracle for token addr");
+ _;
+ }
+
+ /**
+ * @notice Sets initialized == true on implementation contracts
+ * @param test Set to true to skip implementation initialization
+ */
+ constructor(bool test) Initializable(test) { }
+
+ /**
+ * @notice Used in place of the constructor to allow the contract to be upgradable via proxy.
+ * @param _reportExpirySeconds The number of seconds before a report is considered expired.
+ */
+ function initialize(uint256 _reportExpirySeconds) external initializer {
+ _transferOwnership(msg.sender);
+ setReportExpiry(_reportExpirySeconds);
+ }
+
+ /**
+ * @notice Sets the report expiry parameter for a rateFeedId.
+ * @param _token The token for which the report expiry is being set.
+ * @param _reportExpirySeconds The number of seconds before a report is considered expired.
+ */
+ function setTokenReportExpiry(address _token, uint256 _reportExpirySeconds) external onlyOwner {
+ require(_reportExpirySeconds > 0, "report expiry seconds must be > 0");
+ require(_reportExpirySeconds != tokenReportExpirySeconds[_token], "token reportExpirySeconds hasn't changed");
+ tokenReportExpirySeconds[_token] = _reportExpirySeconds;
+ emit TokenReportExpirySet(_token, _reportExpirySeconds);
+ }
+
+ /**
+ * @notice Adds a new Oracle for a specified rate feed.
+ * @param token The token for which the specified oracle is to be added.
+ * @param oracleAddress The address of the oracle.
+ */
+ function addOracle(address token, address oracleAddress) external onlyOwner {
+ // solhint-disable-next-line reason-string
+ require(
+ token != address(0) && oracleAddress != address(0) && !isOracle[token][oracleAddress],
+ "token addr was null or oracle addr was null or oracle addr is already an oracle for token addr"
+ );
+ isOracle[token][oracleAddress] = true;
+ oracles[token].push(oracleAddress);
+ emit OracleAdded(token, oracleAddress);
+ }
+
+ /**
+ * @notice Removes an Oracle from a specified rate feed.
+ * @param token The token from which the specified oracle is to be removed.
+ * @param oracleAddress The address of the oracle.
+ * @param index The index of `oracleAddress` in the list of oracles.
+ */
+ function removeOracle(address token, address oracleAddress, uint256 index) external onlyOwner {
+ // solhint-disable-next-line reason-string
+ require(
+ token != address(0) && oracleAddress != address(0) && oracles[token].length > index
+ && oracles[token][index] == oracleAddress,
+ "token addr null or oracle addr null or index of token oracle not mapped to oracle addr"
+ );
+ isOracle[token][oracleAddress] = false;
+ oracles[token][index] = oracles[token][oracles[token].length.sub(1)];
+ oracles[token].pop();
+ if (reportExists(token, oracleAddress)) {
+ removeReport(token, oracleAddress);
+ }
+ emit OracleRemoved(token, oracleAddress);
+ }
+
+ /**
+ * @notice Removes a report that is expired.
+ * @param token The token for which the expired report is to be removed.
+ * @param n The number of expired reports to remove, at most (deterministic upper gas bound).
+ */
+ function removeExpiredReports(address token, uint256 n) external {
+ require(
+ token != address(0) && n < timestamps[token].getNumElements(),
+ "token addr null or trying to remove too many reports"
+ );
+ for (uint256 i = 0; i < n; i = i.add(1)) {
+ (bool isExpired, address oldestAddress) = isOldestReportExpired(token);
+ if (isExpired) {
+ removeReport(token, oldestAddress);
+ } else {
+ break;
+ }
+ }
+ }
+
+ /**
+ * @notice Sets the equivalent token for a token.
+ * @param token The address of the token.
+ * @param equivalentToken The address of the equivalent token.
+ */
+ function setEquivalentToken(address token, address equivalentToken) external onlyOwner {
+ require(token != address(0), "token address cannot be 0");
+ require(equivalentToken != address(0), "equivalentToken address cannot be 0");
+ equivalentTokens[token] = EquivalentToken(equivalentToken);
+ emit EquivalentTokenSet(token, equivalentToken);
+ }
+
+ /**
+ * @notice Sets the equivalent token for a token.
+ * @param token The address of the token.
+ */
+ function deleteEquivalentToken(address token) external onlyOwner {
+ require(token != address(0), "token address cannot be 0");
+ delete equivalentTokens[token];
+ emit EquivalentTokenSet(token, address(0));
+ }
+
+ /**
+ * @notice Updates an oracle value and the median.
+ * @param token The token for which the rate is being reported.
+ * @param value The number of stable asset that equate to one unit of collateral asset, for the
+ * specified rateFeedId, expressed as a fixidity value.
+ * @param lesserKey The element which should be just left of the new oracle value.
+ * @param greaterKey The element which should be just right of the new oracle value.
+ * @dev Note that only one of `lesserKey` or `greaterKey` needs to be correct to reduce friction.
+ */
+ function report(address token, uint256 value, address lesserKey, address greaterKey) external onlyOracle(token) {
+ uint256 originalMedian = rates[token].getMedianValue();
+ if (rates[token].contains(msg.sender)) {
+ rates[token].update(msg.sender, value, lesserKey, greaterKey);
+
+ // Rather than update the timestamp, we remove it and re-add it at the
+ // head of the list later. The reason for this is that we need to handle
+ // a few different cases:
+ // 1. This oracle is the only one to report so far. lesserKey = address(0)
+ // 2. Other oracles have reported since this one's last report. lesserKey = getHead()
+ // 3. Other oracles have reported, but the most recent is this one.
+ // lesserKey = key immediately after getHead()
+ //
+ // However, if we just remove this timestamp, timestamps[token].getHead()
+ // does the right thing in all cases.
+ timestamps[token].remove(msg.sender);
+ } else {
+ rates[token].insert(msg.sender, value, lesserKey, greaterKey);
+ }
+ timestamps[token].insert(
+ msg.sender,
+ // solhint-disable-next-line not-rely-on-time
+ block.timestamp,
+ timestamps[token].getHead(),
+ address(0)
+ );
+ emit OracleReported(token, msg.sender, block.timestamp, value);
+ uint256 newMedian = rates[token].getMedianValue();
+ if (newMedian != originalMedian) {
+ emit MedianUpdated(token, newMedian);
+ }
+
+ if (address(breakerBox) != address(0)) {
+ breakerBox.checkAndSetBreakers(token);
+ }
+ }
+
+ /**
+ * @notice Gets the equivalent token for a token.
+ * @param token The address of the token.
+ * @return The address of the equivalent token.
+ */
+ function getEquivalentToken(address token) external view returns (address) {
+ return (equivalentTokens[token].token);
+ }
+
+ /**
+ * @notice Returns the median timestamp.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the median timestamp is being retrieved.
+ * @return uint256 The median report timestamp for the specified rateFeedId.
+ */
+ function medianTimestamp(address token) external view returns (uint256) {
+ return timestamps[token].getMedianValue();
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the timestamps are being retrieved.
+ * @return keys Keys of nn unpacked list of elements from largest to smallest.
+ * @return values Values of an unpacked list of elements from largest to smallest.
+ * @return relations Relations of an unpacked list of elements from largest to smallest.
+ */
+ function getTimestamps(address token)
+ external
+ view
+ returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
+ {
+ return timestamps[token].getElements();
+ }
+
+ /**
+ * @notice Returns the list of oracles for a speficied rateFeedId.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the oracles are being retrieved.
+ * @return address[] A list of oracles for the given rateFeedId.
+ */
+ function getOracles(address token) external view returns (address[] memory) {
+ return oracles[token];
+ }
+
+ /**
+ * @notice Gets all elements from the doubly linked list.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the rates are being retrieved.
+ * @return keys Keys of an unpacked list of elements from largest to smallest.
+ * @return values Values of an unpacked list of elements from largest to smallest.
+ * @return relations Relations of an unpacked list of elements from largest to smallest.
+ */
+ function getRates(address token)
+ external
+ view
+ returns (address[] memory, uint256[] memory, SortedLinkedListWithMedian.MedianRelation[] memory)
+ {
+ return rates[token].getElements();
+ }
+
+ /**
+ * @notice Returns the exchange rate for a specified token.
+ * @param token The token for which the exchange rate is being retrieved.
+ * @return numerator uint256 The exchange rate for the specified token.
+ * @return denominator uint256 The denominator for the exchange rate.
+ */
+ function getExchangeRate(address token) external view returns (uint256 numerator, uint256 denominator) {
+ (numerator, denominator) = medianRate(token);
+ }
+
+ /**
+ * @notice Returns the storage, major, minor, and patch version of the contract.
+ * @return Storage version of the contract.
+ * @return Major version of the contract.
+ * @return Minor version of the contract.
+ * @return Patch version of the contract.
+ */
+ function getVersionNumber() external pure returns (uint256, uint256, uint256, uint256) {
+ return (1, 1, 4, 0);
+ }
+
+ /**
+ * @notice Sets the report expiry parameter.
+ * @param _reportExpirySeconds The number of seconds before a report is considered expired.
+ */
+ function setReportExpiry(uint256 _reportExpirySeconds) public onlyOwner {
+ require(_reportExpirySeconds > 0, "report expiry seconds must be > 0");
+ require(_reportExpirySeconds != reportExpirySeconds, "reportExpirySeconds hasn't changed");
+ reportExpirySeconds = _reportExpirySeconds;
+ emit ReportExpirySet(_reportExpirySeconds);
+ }
+
+ /**
+ * @notice Sets the address of the BreakerBox.
+ * @param newBreakerBox The new BreakerBox address.
+ */
+ function setBreakerBox(IBreakerBox newBreakerBox) public onlyOwner {
+ require(address(newBreakerBox) != address(0), "BreakerBox address must be set");
+ breakerBox = newBreakerBox;
+ emit BreakerBoxUpdated(address(newBreakerBox));
+ }
+
+ /**
+ * @notice Returns the median of the currently stored rates for a specified rateFeedId.
+ * @dev Please note that this function respects the equivalentToken mapping, and so may
+ * return the median identified as an equivalent to the supplied rateFeedId.
+ * @param token The token for which the median value is being retrieved.
+ * @return uint256 The median exchange rate for rateFeedId (fixidity).
+ * @return uint256 denominator
+ */
+ function medianRate(address token) public view returns (uint256, uint256) {
+ EquivalentToken storage equivalentToken = equivalentTokens[token];
+ if (equivalentToken.token != address(0)) {
+ (uint256 equivalentMedianRate, uint256 denominator) =
+ medianRateWithoutEquivalentMapping(equivalentToken.token);
+ return (equivalentMedianRate, denominator);
+ }
+
+ return medianRateWithoutEquivalentMapping(token);
+ }
+
+ /**
+ * @notice Returns the number of rates that are currently stored for a specifed rateFeedId.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the number of rates is being retrieved.
+ * @return uint256 The number of reported oracle rates stored for the given rateFeedId.
+ */
+ function numRates(address token) public view returns (uint256) {
+ return rates[token].getNumElements();
+ }
+
+ /**
+ * @notice Check if last report is expired.
+ * @param token The token for which the expired report is to be checked.
+ * @return bool A bool indicating if the last report is expired.
+ * @return address Oracle address of the last report.
+ */
+ function isOldestReportExpired(address token) public view returns (bool, address) {
+ // solhint-disable-next-line reason-string
+ require(token != address(0));
+ address oldest = timestamps[token].getTail();
+ uint256 timestamp = timestamps[token].getValue(oldest);
+ // solhint-disable-next-line not-rely-on-time
+ if (block.timestamp.sub(timestamp) >= getTokenReportExpirySeconds(token)) {
+ return (true, oldest);
+ }
+ return (false, oldest);
+ }
+
+ /**
+ * @notice Returns the median of the currently stored rates for a specified rateFeedId.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * @param token The token for which the median value is being retrieved.
+ * @return uint256 The median exchange rate for rateFeedId (fixidity).
+ * @return uint256 denominator
+ */
+ function medianRateWithoutEquivalentMapping(address token) public view returns (uint256, uint256) {
+ return (rates[token].getMedianValue(), numRates(token) == 0 ? 0 : FIXED1_UINT);
+ }
+
+ /**
+ * @notice Returns the number of timestamps.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the number of timestamps is being retrieved.
+ * @return uint256 The number of oracle report timestamps for the specified rateFeedId.
+ */
+ function numTimestamps(address token) public view returns (uint256) {
+ return timestamps[token].getNumElements();
+ }
+
+ /**
+ * @notice Returns the expiry for specified rateFeedId if it exists, if not the default is returned.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the report expiry is being retrieved.
+ * @return The report expiry in seconds.
+ */
+ function getTokenReportExpirySeconds(address token) public view returns (uint256) {
+ if (tokenReportExpirySeconds[token] == 0) {
+ return reportExpirySeconds;
+ }
+
+ return tokenReportExpirySeconds[token];
+ }
+
+ /**
+ * @notice Checks if a report exists for a specified rateFeedId from a given oracle.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the report should be checked.
+ * @param oracle The oracle whose report should be checked.
+ * @return bool True if a report exists, false otherwise.
+ */
+ function reportExists(address token, address oracle) internal view returns (bool) {
+ return rates[token].contains(oracle) && timestamps[token].contains(oracle);
+ }
+
+ /**
+ * @notice Removes an oracle value and updates the median.
+ * @dev Does not take the equivalentTokens mapping into account.
+ * For that, the underlying token should be queried.
+ * @param token The token for which the oracle report should be removed.
+ * @param oracle The oracle whose value should be removed.
+ * @dev This can be used to delete elements for oracles that have been removed.
+ * However, a > 1 elements reports list should always be maintained
+ */
+ function removeReport(address token, address oracle) private {
+ if (numTimestamps(token) == 1 && reportExists(token, oracle)) return;
+ uint256 originalMedian = rates[token].getMedianValue();
+ rates[token].remove(oracle);
+ timestamps[token].remove(oracle);
+ emit OracleReportRemoved(token, oracle);
+ uint256 newMedian = rates[token].getMedianValue();
+ if (newMedian != originalMedian) {
+ emit MedianUpdated(token, newMedian);
+ if (address(breakerBox) != address(0)) {
+ breakerBox.checkAndSetBreakers(token);
+ }
+ }
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/stability/interfaces/IBreakerBox.sol CELO/packages/contracts-bedrock/src/celo/stability/interfaces/IBreakerBox.sol
new file mode 100644
index 0000000000000000000000000000000000000000..26430da7a3bea5db65b04502a7057a0606b44d7d
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/stability/interfaces/IBreakerBox.sol
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.5.13 <0.9.0;
+
+/**
+ * @title Breaker Box Interface
+ * @notice Defines the basic interface for the Breaker Box
+ */
+interface IBreakerBox {
+ /**
+ * @dev Used to keep track of the status of a breaker for a specific rate feed.
+ *
+ * - TradingMode: Represents the trading mode the breaker is in for a rate feed.
+ * This uses a bitmask approach, meaning each bit represents a
+ * different trading mode. The final trading mode of the rate feed
+ * is obtained by applying a logical OR operation to the TradingMode
+ * of all breakers associated with that rate feed. This allows multiple
+ * breakers to contribute to the final trading mode simultaneously.
+ * Possible values:
+ * 0: bidirectional trading.
+ * 1: inflow only.
+ * 2: outflow only.
+ * 3: trading halted.
+ *
+ * - LastUpdatedTime: Records the last time the breaker status was updated. This is
+ * used to manage cooldown periods before the breaker can be reset.
+ *
+ * - Enabled: Indicates whether the breaker is enabled for the associated rate feed.
+ */
+ struct BreakerStatus {
+ uint8 tradingMode;
+ uint64 lastUpdatedTime;
+ bool enabled;
+ }
+
+ /**
+ * @notice Emitted when a new breaker is added to the breaker box.
+ * @param breaker The address of the breaker.
+ */
+ event BreakerAdded(address indexed breaker);
+
+ /**
+ * @notice Emitted when a breaker is removed from the breaker box.
+ * @param breaker The address of the breaker.
+ */
+ event BreakerRemoved(address indexed breaker);
+
+ /**
+ * @notice Emitted when a breaker is tripped by a rate feed.
+ * @param breaker The address of the breaker.
+ * @param rateFeedID The address of the rate feed.
+ */
+ event BreakerTripped(address indexed breaker, address indexed rateFeedID);
+
+ /**
+ * @notice Emitted when a new rate feed is added to the breaker box.
+ * @param rateFeedID The address of the rate feed.
+ */
+ event RateFeedAdded(address indexed rateFeedID);
+
+ /**
+ * @notice Emitted when dependencies for a rate feed are set.
+ * @param rateFeedID The address of the rate feed.
+ * @param dependencies The addresses of the dependendent rate feeds.
+ */
+ event RateFeedDependenciesSet(address indexed rateFeedID, address[] indexed dependencies);
+
+ /**
+ * @notice Emitted when a rate feed is removed from the breaker box.
+ * @param rateFeedID The address of the rate feed.
+ */
+ event RateFeedRemoved(address indexed rateFeedID);
+
+ /**
+ * @notice Emitted when the trading mode for a rate feed is updated
+ * @param rateFeedID The address of the rate feed.
+ * @param tradingMode The new trading mode.
+ */
+ event TradingModeUpdated(address indexed rateFeedID, uint256 tradingMode);
+
+ /**
+ * @notice Emitted after a reset attempt is successful.
+ * @param rateFeedID The address of the rate feed.
+ * @param breaker The address of the breaker.
+ */
+ event ResetSuccessful(address indexed rateFeedID, address indexed breaker);
+
+ /**
+ * @notice Emitted after a reset attempt fails when the
+ * rate feed fails the breakers reset criteria.
+ * @param rateFeedID The address of the rate feed.
+ * @param breaker The address of the breaker.
+ */
+ event ResetAttemptCriteriaFail(address indexed rateFeedID, address indexed breaker);
+
+ /**
+ * @notice Emitted after a reset attempt fails when cooldown time has not elapsed.
+ * @param rateFeedID The address of the rate feed.
+ * @param breaker The address of the breaker.
+ */
+ event ResetAttemptNotCool(address indexed rateFeedID, address indexed breaker);
+
+ /**
+ * @notice Emitted when the sortedOracles address is updated.
+ * @param newSortedOracles The address of the new sortedOracles.
+ */
+ event SortedOraclesUpdated(address indexed newSortedOracles);
+
+ /**
+ * @notice Emitted when the breaker is enabled or disabled for a rate feed.
+ * @param breaker The address of the breaker.
+ * @param rateFeedID The address of the rate feed.
+ * @param status Indicating the status.
+ */
+ event BreakerStatusUpdated(address breaker, address rateFeedID, bool status);
+
+ /**
+ * @notice Checks breakers for the rateFeedID and sets correct trading mode
+ * if any breakers are tripped or need to be reset.
+ * @param rateFeedID The address of the rate feed to run checks for.
+ */
+ function checkAndSetBreakers(address rateFeedID) external;
+
+ /**
+ * @notice Retrives an array of all breaker addresses.
+ */
+ function getBreakers() external view returns (address[] memory);
+
+ /**
+ * @notice Checks if a breaker with the specified address has been added to the breaker box.
+ * @param breaker The address of the breaker to check;
+ * @return A bool indicating whether or not the breaker has been added.
+ */
+ function isBreaker(address breaker) external view returns (bool);
+
+ /**
+ * @notice Gets the trading mode for the specified rateFeedID.
+ * @param rateFeedID The address of the rate feed to retrieve the trading mode for.
+ */
+ function getRateFeedTradingMode(address rateFeedID) external view returns (uint8 tradingMode);
+}
diff --git OP/packages/contracts-bedrock/src/celo/stability/interfaces/IOracle.sol CELO/packages/contracts-bedrock/src/celo/stability/interfaces/IOracle.sol
new file mode 100644
index 0000000000000000000000000000000000000000..b3ae66a92756c915ede5a6c5b1f57387b2edc254
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/stability/interfaces/IOracle.sol
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: MIT
+pragma solidity >=0.5.13 <0.9.0;
+
+/// Possibly not final version
+interface IOracle {
+ function getExchangeRate(address token) external view returns (uint256 numerator, uint256 denominator);
+}
diff --git OP/packages/contracts-bedrock/src/celo/stability/interfaces/ISortedOracles.sol CELO/packages/contracts-bedrock/src/celo/stability/interfaces/ISortedOracles.sol
new file mode 100644
index 0000000000000000000000000000000000000000..ecea4210cd40e4fb48a7a101b74625ff9746edcc
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/stability/interfaces/ISortedOracles.sol
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+interface ISortedOracles {
+ function addOracle(address, address) external;
+ function removeOracle(address, address, uint256) external;
+ function report(address, uint256, address, address) external;
+ function removeExpiredReports(address, uint256) external;
+ function isOldestReportExpired(address token) external view returns (bool, address);
+ function numRates(address) external view returns (uint256);
+ function medianRate(address) external view returns (uint256, uint256);
+ function numTimestamps(address) external view returns (uint256);
+ function medianTimestamp(address) external view returns (uint256);
+}
diff --git OP/packages/contracts-bedrock/src/celo/testing/FeeCurrency.sol CELO/packages/contracts-bedrock/src/celo/testing/FeeCurrency.sol
new file mode 100644
index 0000000000000000000000000000000000000000..fd00f42c01bbb45a455790ec9e7cd3d181742319
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/testing/FeeCurrency.sol
@@ -0,0 +1,420 @@
+// SPDX-License-Identifier: MIT
+// Modified from OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)
+
+pragma solidity ^0.8.0;
+
+import "../../../lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
+import "../../../lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
+import "../../../lib/openzeppelin-contracts/contracts/utils/Context.sol";
+
+import "../CalledByVm.sol";
+
+/**
+ * @dev Implementation of the {IERC20} interface + Celo debit/creditGasFees.
+ *
+ * This implementation is agnostic to the way tokens are created. This means
+ * that a supply mechanism has to be added in a derived contract using {_mint}.
+ * For a generic mechanism see {ERC20PresetMinterPauser}.
+ *
+ * TIP: For a detailed writeup see our guide
+ * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
+ * to implement supply mechanisms].
+ *
+ * We have followed general OpenZeppelin Contracts guidelines: functions revert
+ * instead returning `false` on failure. This behavior is nonetheless
+ * conventional and does not conflict with the expectations of ERC20
+ * applications.
+ *
+ * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
+ * This allows applications to reconstruct the allowance for all accounts just
+ * by listening to said events. Other implementations of the EIP may not emit
+ * these events, as it isn't required by the specification.
+ *
+ * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
+ * functions have been added to mitigate the well-known issues around setting
+ * allowances. See {IERC20-approve}.
+ */
+contract FeeCurrency is Context, IERC20, IERC20Metadata, CalledByVm {
+ mapping(address => uint256) private _balances;
+
+ mapping(address => mapping(address => uint256)) private _allowances;
+
+ uint256 private _totalSupply;
+
+ string private _name;
+ string private _symbol;
+
+ /**
+ * @dev Sets the values for {name} and {symbol}.
+ *
+ * The default value of {decimals} is 18. To select a different value for
+ * {decimals} you should overload it.
+ *
+ * All two of these values are immutable: they can only be set once during
+ * construction.
+ */
+ constructor(string memory name_, string memory symbol_) {
+ _name = name_;
+ _symbol = symbol_;
+ }
+
+ /**
+ * @dev Returns the name of the token.
+ */
+ function name() public view virtual override returns (string memory) {
+ return _name;
+ }
+
+ /**
+ * @dev Returns the symbol of the token, usually a shorter version of the
+ * name.
+ */
+ function symbol() public view virtual override returns (string memory) {
+ return _symbol;
+ }
+
+ /**
+ * @dev Returns the number of decimals used to get its user representation.
+ * For example, if `decimals` equals `2`, a balance of `505` tokens should
+ * be displayed to a user as `5.05` (`505 / 10 ** 2`).
+ *
+ * Tokens usually opt for a value of 18, imitating the relationship between
+ * Ether and Wei. This is the value {ERC20} uses, unless this function is
+ * overridden;
+ *
+ * NOTE: This information is only used for _display_ purposes: it in
+ * no way affects any of the arithmetic of the contract, including
+ * {IERC20-balanceOf} and {IERC20-transfer}.
+ */
+ function decimals() public view virtual override returns (uint8) {
+ return 18;
+ }
+
+ /**
+ * @dev See {IERC20-totalSupply}.
+ */
+ function totalSupply() public view virtual override returns (uint256) {
+ return _totalSupply;
+ }
+
+ /**
+ * @dev See {IERC20-balanceOf}.
+ */
+ function balanceOf(address account) public view virtual override returns (uint256) {
+ return _balances[account];
+ }
+
+ /**
+ * @dev See {IERC20-transfer}.
+ *
+ * Requirements:
+ *
+ * - `to` cannot be the zero address.
+ * - the caller must have a balance of at least `amount`.
+ */
+ function transfer(address to, uint256 amount) public virtual override returns (bool) {
+ address owner = _msgSender();
+ _transfer(owner, to, amount);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-allowance}.
+ */
+ function allowance(address owner, address spender) public view virtual override returns (uint256) {
+ return _allowances[owner][spender];
+ }
+
+ /**
+ * @dev See {IERC20-approve}.
+ *
+ * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
+ * `transferFrom`. This is semantically equivalent to an infinite approval.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ */
+ function approve(address spender, uint256 amount) public virtual override returns (bool) {
+ address owner = _msgSender();
+ _approve(owner, spender, amount);
+ return true;
+ }
+
+ /**
+ * @dev See {IERC20-transferFrom}.
+ *
+ * Emits an {Approval} event indicating the updated allowance. This is not
+ * required by the EIP. See the note at the beginning of {ERC20}.
+ *
+ * NOTE: Does not update the allowance if the current allowance
+ * is the maximum `uint256`.
+ *
+ * Requirements:
+ *
+ * - `from` and `to` cannot be the zero address.
+ * - `from` must have a balance of at least `amount`.
+ * - the caller must have allowance for ``from``'s tokens of at least
+ * `amount`.
+ */
+ function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
+ address spender = _msgSender();
+ _spendAllowance(from, spender, amount);
+ _transfer(from, to, amount);
+ return true;
+ }
+
+ /**
+ * @dev Atomically increases the allowance granted to `spender` by the caller.
+ *
+ * This is an alternative to {approve} that can be used as a mitigation for
+ * problems described in {IERC20-approve}.
+ *
+ * Emits an {Approval} event indicating the updated allowance.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ */
+ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
+ address owner = _msgSender();
+ _approve(owner, spender, allowance(owner, spender) + addedValue);
+ return true;
+ }
+
+ /**
+ * @dev Atomically decreases the allowance granted to `spender` by the caller.
+ *
+ * This is an alternative to {approve} that can be used as a mitigation for
+ * problems described in {IERC20-approve}.
+ *
+ * Emits an {Approval} event indicating the updated allowance.
+ *
+ * Requirements:
+ *
+ * - `spender` cannot be the zero address.
+ * - `spender` must have allowance for the caller of at least
+ * `subtractedValue`.
+ */
+ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
+ address owner = _msgSender();
+ uint256 currentAllowance = allowance(owner, spender);
+ require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
+ unchecked {
+ _approve(owner, spender, currentAllowance - subtractedValue);
+ }
+
+ return true;
+ }
+
+ /**
+ * @dev Moves `amount` of tokens from `from` to `to`.
+ *
+ * This internal function is equivalent to {transfer}, and can be used to
+ * e.g. implement automatic token fees, slashing mechanisms, etc.
+ *
+ * Emits a {Transfer} event.
+ *
+ * Requirements:
+ *
+ * - `from` cannot be the zero address.
+ * - `to` cannot be the zero address.
+ * - `from` must have a balance of at least `amount`.
+ */
+ function _transfer(address from, address to, uint256 amount) internal virtual {
+ require(from != address(0), "ERC20: transfer from the zero address");
+ require(to != address(0), "ERC20: transfer to the zero address");
+
+ _beforeTokenTransfer(from, to, amount);
+
+ uint256 fromBalance = _balances[from];
+ require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
+ unchecked {
+ _balances[from] = fromBalance - amount;
+ }
+ _balances[to] += amount;
+
+ emit Transfer(from, to, amount);
+
+ _afterTokenTransfer(from, to, amount);
+ }
+
+ /**
+ * @dev Creates `amount` tokens and assigns them to `account`, increasing
+ * the total supply.
+ *
+ * Emits a {Transfer} event with `from` set to the zero address.
+ *
+ * Requirements:
+ *
+ * - `account` cannot be the zero address.
+ */
+ function _mint(address account, uint256 amount) internal virtual {
+ require(account != address(0), "ERC20: mint to the zero address");
+
+ _beforeTokenTransfer(address(0), account, amount);
+
+ _totalSupply += amount;
+ _balances[account] += amount;
+ emit Transfer(address(0), account, amount);
+
+ _afterTokenTransfer(address(0), account, amount);
+ }
+
+ /**
+ * @dev Destroys `amount` tokens from `account`, reducing the
+ * total supply.
+ *
+ * Emits a {Transfer} event with `to` set to the zero address.
+ *
+ * Requirements:
+ *
+ * - `account` cannot be the zero address.
+ * - `account` must have at least `amount` tokens.
+ */
+ function _burn(address account, uint256 amount) internal virtual {
+ require(account != address(0), "ERC20: burn from the zero address");
+
+ _beforeTokenTransfer(account, address(0), amount);
+
+ uint256 accountBalance = _balances[account];
+ require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
+ unchecked {
+ _balances[account] = accountBalance - amount;
+ }
+ _totalSupply -= amount;
+
+ emit Transfer(account, address(0), amount);
+
+ _afterTokenTransfer(account, address(0), amount);
+ }
+
+ /**
+ * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
+ *
+ * This internal function is equivalent to `approve`, and can be used to
+ * e.g. set automatic allowances for certain subsystems, etc.
+ *
+ * Emits an {Approval} event.
+ *
+ * Requirements:
+ *
+ * - `owner` cannot be the zero address.
+ * - `spender` cannot be the zero address.
+ */
+ function _approve(address owner, address spender, uint256 amount) internal virtual {
+ require(owner != address(0), "ERC20: approve from the zero address");
+ require(spender != address(0), "ERC20: approve to the zero address");
+
+ _allowances[owner][spender] = amount;
+ emit Approval(owner, spender, amount);
+ }
+
+ /**
+ * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
+ *
+ * Does not update the allowance amount in case of infinite allowance.
+ * Revert if not enough allowance is available.
+ *
+ * Might emit an {Approval} event.
+ */
+ function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
+ uint256 currentAllowance = allowance(owner, spender);
+ if (currentAllowance != type(uint256).max) {
+ require(currentAllowance >= amount, "ERC20: insufficient allowance");
+ unchecked {
+ _approve(owner, spender, currentAllowance - amount);
+ }
+ }
+ }
+
+ /**
+ * @dev Hook that is called before any transfer of tokens. This includes
+ * minting and burning.
+ *
+ * Calling conditions:
+ *
+ * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+ * will be transferred to `to`.
+ * - when `from` is zero, `amount` tokens will be minted for `to`.
+ * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
+ * - `from` and `to` are never both zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
+
+ /**
+ * @dev Hook that is called after any transfer of tokens. This includes
+ * minting and burning.
+ *
+ * Calling conditions:
+ *
+ * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
+ * has been transferred to `to`.
+ * - when `from` is zero, `amount` tokens have been minted for `to`.
+ * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
+ * - `from` and `to` are never both zero.
+ *
+ * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
+ */
+ function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual { }
+
+ /**
+ * @notice Reserve balance for making payments for gas in this StableToken currency.
+ * @param from The account to reserve balance from
+ * @param value The amount of balance to reserve
+ * @dev Note that this function is called by the protocol when paying for tx fees in this
+ * currency. After the tx is executed, gas is refunded to the sender and credited to the
+ * various tx fee recipients via a call to `creditGasFees`. Note too that the events emitted
+ * by `creditGasFees` reflect the *net* gas fee payments for the transaction.
+ */
+ function debitGasFees(address from, uint256 value) external onlyVm {
+ _balances[from] -= value;
+ _totalSupply -= value;
+ }
+
+ /**
+ * @notice Alternative function to credit balance after making payments
+ * for gas in this StableToken currency.
+ * @param from The account to debit balance from
+ * @param feeRecipient Coinbase address
+ * legacy param gatewayFeeRecipient Gateway address (UNUSED!)
+ * @param communityFund Community fund address
+ * @param tipTxFee Coinbase fee
+ * @param baseTxFee Community fund fee
+ * legacy param gatewayFee Gateway fee (UNUSED!)
+ * @dev Note that this function is called by the protocol when paying for tx fees in this
+ * currency. Before the tx is executed, gas is debited from the sender via a call to
+ * `debitGasFees`. Note too that the events emitted by `creditGasFees` reflect the *net* gas fee
+ * payments for the transaction.
+ */
+ function creditGasFees(
+ address from,
+ address feeRecipient,
+ address, // gatewayFeeRecipient
+ address communityFund,
+ uint256 refund,
+ uint256 tipTxFee,
+ uint256, // gatewayFee
+ uint256 baseTxFee
+ )
+ external
+ onlyVm
+ {
+ _balances[from] += refund;
+
+ refund += _creditGas(from, communityFund, baseTxFee);
+ refund += _creditGas(from, feeRecipient, tipTxFee);
+ _totalSupply += refund;
+ }
+
+ function _creditGas(address from, address to, uint256 value) internal returns (uint256) {
+ if (to == address(0)) {
+ return 0;
+ }
+ _balances[to] += value;
+ emit Transfer(from, to, value);
+ return value;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/testing/MockSortedOracles.sol CELO/packages/contracts-bedrock/src/celo/testing/MockSortedOracles.sol
new file mode 100644
index 0000000000000000000000000000000000000000..d51fa2a7c56c47dc97af8fd34c1db22b8832e7ec
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/testing/MockSortedOracles.sol
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.15;
+
+import { IOracle } from "../interfaces/IOracle.sol";
+
+/**
+ * @title A mock SortedOracles for testing.
+ */
+contract MockSortedOracles is IOracle {
+ uint256 public constant DENOMINATOR = 1000000000000000000000000;
+ mapping(address => uint256) public numerators;
+ mapping(address => uint256) public medianTimestamp;
+ mapping(address => uint256) public numRates;
+ mapping(address => bool) public expired;
+
+ function setMedianRate(address token, uint256 numerator) external returns (bool) {
+ numerators[token] = numerator;
+ return true;
+ }
+
+ function setMedianTimestamp(address token, uint256 timestamp) external {
+ medianTimestamp[token] = timestamp;
+ }
+
+ function setMedianTimestampToNow(address token) external {
+ // solhint-disable-next-line not-rely-on-time
+ medianTimestamp[token] = uint128(block.timestamp);
+ }
+
+ function setNumRates(address token, uint256 rate) external {
+ numRates[token] = rate; // This change may break something, TODO
+ }
+
+ function getExchangeRate(address token) external view returns (uint256 numerator, uint256 denominator) {
+ return medianRate(token);
+ }
+
+ function medianRate(address token) public view returns (uint256, uint256) {
+ if (numerators[token] > 0) {
+ return (numerators[token], DENOMINATOR);
+ }
+ return (0, 0);
+ }
+
+ function isOldestReportExpired(address token) public view returns (bool, address) {
+ return (expired[token], token);
+ }
+
+ function setOldestReportExpired(address token) public {
+ expired[token] = true;
+ }
+}
diff --git OP/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2FactoryMin.sol CELO/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2FactoryMin.sol
new file mode 100644
index 0000000000000000000000000000000000000000..14c6495920a1ff49978917c124c7a7fd82d7c6b6
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2FactoryMin.sol
@@ -0,0 +1,6 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IUniswapV2FactoryMin {
+ function getPair(address tokenA, address tokenB) external view returns (address pair);
+}
diff --git OP/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2RouterMin.sol CELO/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2RouterMin.sol
new file mode 100644
index 0000000000000000000000000000000000000000..f1755edb137d00b91696baa96ac6d44ae601ca28
--- /dev/null
+++ CELO/packages/contracts-bedrock/src/celo/uniswap/interfaces/IUniswapV2RouterMin.sol
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: LGPL-3.0-only
+pragma solidity ^0.8.15;
+
+interface IUniswapV2RouterMin {
+ function factory() external pure returns (address);
+ function swapExactTokensForTokens(
+ uint256 amountIn,
+ uint256 amountOutMin,
+ address[] calldata path,
+ address to,
+ uint256 deadline
+ )
+ external
+ returns (uint256[] memory amounts);
+ function getAmountsOut(
+ uint256 amountIn,
+ address[] calldata path
+ )
+ external
+ view
+ returns (uint256[] memory amounts);
+}
Ignored changes
+703
-484
diff --git OP/.circleci/config.yml CELO/.circleci/config.yml
index 0dffb662b1168e32ccfae0e1433b22bfe91e21af..2addad58881ba14cf387ab1b057eea6727533741 100644
--- OP/.circleci/config.yml
+++ CELO/.circleci/config.yml
@@ -44,51 +44,8 @@ default: false
orbs:
go: circleci/go@1.8.0
- gcp-cli: circleci/gcp-cli@3.0.1
- slack: circleci/slack@4.10.1
shellcheck: circleci/shellcheck@3.2.0
commands:
- gcp-oidc-authenticate:
- description: "Authenticate with GCP using a CircleCI OIDC token."
- parameters:
- project_id:
- type: env_var_name
- default: GCP_PROJECT_ID
- workload_identity_pool_id:
- type: env_var_name
- default: GCP_WIP_ID
- workload_identity_pool_provider_id:
- type: env_var_name
- default: GCP_WIP_PROVIDER_ID
- service_account_email:
- type: env_var_name
- default: GCP_SERVICE_ACCOUNT_EMAIL
- gcp_cred_config_file_path:
- type: string
- default: /home/circleci/gcp_cred_config.json
- oidc_token_file_path:
- type: string
- default: /home/circleci/oidc_token.json
- steps:
- - run:
- name: "Create OIDC credential configuration"
- command: |
- # Store OIDC token in temp file
- echo $CIRCLE_OIDC_TOKEN > << parameters.oidc_token_file_path >>
- # Create a credential configuration for the generated OIDC ID Token
- gcloud iam workload-identity-pools create-cred-config \
- "projects/${<< parameters.project_id >>}/locations/global/workloadIdentityPools/${<< parameters.workload_identity_pool_id >>}/providers/${<< parameters.workload_identity_pool_provider_id >>}"\
- --output-file="<< parameters.gcp_cred_config_file_path >>" \
- --service-account="${<< parameters.service_account_email >>}" \
- --credential-source-file=<< parameters.oidc_token_file_path >>
- - run:
- name: "Authenticate with GCP using OIDC"
- command: |
- # Configure gcloud to leverage the generated credential configuration
- gcloud auth login --brief --cred-file "<< parameters.gcp_cred_config_file_path >>"
- # Configure ADC
- echo "export GOOGLE_APPLICATION_CREDENTIALS='<< parameters.gcp_cred_config_file_path >>'" | tee -a "$BASH_ENV"
-
check-changed:
description: "Conditionally halts a step if certain modules change"
parameters:
@@ -126,12 +83,8 @@ mentions:
type: string
default: ""
steps:
- - slack/notify:
- channel: << parameters.channel >>
- event: fail
- template: basic_fail_1
- branch_pattern: develop
- mentions: "<< parameters.mentions >>"
+ - run:
+ command: "true" # No notifications setup up for celo-org fork
run-contracts-check:
parameters:
@@ -275,6 +228,12 @@ command: |
USE_MT_CANNON="true" make devnet-allocs
cp -r .devnet/ .devnet-mt-cannon/
- run:
+ name: Generate Celo allocs
+ command: DEVNET_L2OO="true" DEVNET_CELO="true" make devnet-allocs
+ - run:
+ name: Copy Celo allocs to .devnet-celo
+ command: cp -r .devnet/ .devnet-celo/
+ - run:
name: Generate default allocs
command: make devnet-allocs
- save_cache:
@@ -300,6 +259,12 @@ - ".devnet-l2oo"
- ".devnet-altda"
- ".devnet-altda-generic"
- ".devnet-mt-cannon"
+ - ".devnet-celo/addresses.json"
+ - ".devnet-celo/allocs-l1.json"
+ - ".devnet-celo/allocs-l2-delta.json"
+ - ".devnet-celo/allocs-l2-ecotone.json"
+ - ".devnet-celo/allocs-l2-fjord.json"
+ - ".devnet-celo/addresses.json"
- notify-failures-on-develop
docker-build:
@@ -351,20 +316,6 @@ - attach_workspace:
at: /tmp/docker_images
- run:
command: mkdir -p /tmp/docker_images
- - when:
- condition:
- or:
- - "<<parameters.publish>>"
- - "<<parameters.release>>"
- steps:
- - gcp-cli/install
- - when:
- condition:
- or:
- - "<<parameters.publish>>"
- - "<<parameters.release>>"
- steps:
- - gcp-oidc-authenticate
- run:
name: Build
command: |
@@ -442,10 +393,6 @@ <<parameters.docker_name>>
no_output_timeout: 45m
- when:
- condition: "<<parameters.publish>>"
- steps:
- - notify-failures-on-develop
- - when:
condition: "<<parameters.save_image_tag>>"
steps:
- run:
@@ -457,87 +404,7 @@ - persist_to_workspace:
root: /tmp/docker_images
paths: # only write the one file, to avoid concurrent workspace-file additions
- "<<parameters.docker_name>>.tar"
- - when:
- condition: "<<parameters.release>>"
- steps:
- - run:
- name: Tag
- command: |
- ./ops/scripts/ci-docker-tag-op-stack-release.sh <<parameters.registry>>/<<parameters.repo>> $CIRCLE_TAG $CIRCLE_SHA1
- - when:
- condition:
- or:
- - and:
- - "<<parameters.publish>>"
- - "<<parameters.release>>"
- - and:
- - "<<parameters.publish>>"
- - equal: [develop, << pipeline.git.branch >>]
- steps:
- - gcp-oidc-authenticate:
- service_account_email: GCP_SERVICE_ATTESTOR_ACCOUNT_EMAIL
- - run:
- name: Sign
- command: |
- VER=$(jq -r .binary_signer < versions.json)
- wget -O - "https://github.com/ethereum-optimism/binary_signer/archive/refs/tags/v${VER}.tar.gz" | tar xz
- cd "binary_signer-${VER}/signer"
- IMAGE_PATH="<<parameters.registry>>/<<parameters.repo>>/<<parameters.docker_name>>:<<pipeline.git.revision>>"
- echo $IMAGE_PATH
- pip3 install -r requirements.txt
-
- python3 ./sign_image.py --command="sign"\
- --attestor-project-name="$ATTESTOR_PROJECT_NAME"\
- --attestor-name="$ATTESTOR_NAME"\
- --image-path="$IMAGE_PATH"\
- --signer-logging-level="INFO"\
- --attestor-key-id="//cloudkms.googleapis.com/v1/projects/$ATTESTOR_PROJECT_NAME/locations/global/keyRings/$ATTESTOR_NAME-key-ring/cryptoKeys/$ATTESTOR_NAME-key/cryptoKeyVersions/1"
-
- # Verify newly published images (built on AMD machine) will run on ARM
- check-cross-platform:
- docker:
- - image: cimg/base:current
- resource_class: arm.medium
- parameters:
- registry:
- description: Docker registry
- type: string
- default: "us-docker.pkg.dev"
- repo:
- description: Docker repo
- type: string
- default: "oplabs-tools-artifacts/images"
- op_component:
- description: "Name of op-stack component (e.g. op-node)"
- type: string
- default: ""
- docker_tag:
- description: "Tag of docker image"
- type: string
- default: "<<pipeline.git.revision>>"
- steps:
- - setup_remote_docker
- - run:
- name: "Verify Image Platform"
- command: |
- image_name="<<parameters.registry>>/<<parameters.repo>>/<<parameters.op_component>>:<<parameters.docker_tag>>"
- echo "Retrieving Docker image manifest: $image_name"
- MANIFEST=$(docker manifest inspect $image_name)
-
- echo "Verifying 'linux/arm64' is supported..."
- SUPPORTED_PLATFORM=$(echo "$MANIFEST" | jq -r '.manifests[] | select(.platform.architecture == "arm64" and .platform.os == "linux")')
- echo $SUPPORT_PLATFORM
- if [ -z "$SUPPORTED_PLATFORM" ]; then
- echo "Platform 'linux/arm64' not supported by this image"
- exit 1
- fi
- - run:
- name: "Pull and run docker image"
- command: |
- image_name="<<parameters.registry>>/<<parameters.repo>>/<<parameters.op_component>>:<<parameters.docker_tag>>"
- docker pull $image_name || exit 1
- docker run $image_name <<parameters.op_component>> --version || exit 1
contracts-bedrock-coverage:
docker:
@@ -1170,6 +1037,16 @@ name: Set DEVNET_ALTDA = true
command: echo 'export DEVNET_ALTDA=true' >> $BASH_ENV
- when:
condition:
+ equal: ['celo', <<parameters.variant>>]
+ steps:
+ - run:
+ name: Set DEVNET_CELO = true
+ command: echo 'export DEVNET_CELO=true' >> $BASH_ENV
+ - run:
+ name: Set DEVNET_L2OO = true
+ command: echo 'export DEVNET_L2OO=true' >> $BASH_ENV
+ - when:
+ condition:
equal: ['altda-generic', <<parameters.variant>>]
steps:
- run:
@@ -1251,9 +1128,35 @@ # Specify like this to avoid a forced rebuild of the contracts + devnet L1
PYTHONPATH=./bedrock-devnet python3 ./bedrock-devnet/main.py --monorepo-dir=.
echo "Waiting for 10 seconds to give the devnet time to settle in..."
sleep 10
- - run:
- name: Test the stack
- command: make devnet-test
+ - when:
+ condition:
+ not:
+ equal: ['celo', <<parameters.variant>>]
+ steps:
+ - run:
+ name: Test the stack
+ command: make devnet-test
+ - when:
+ condition:
+ equal: ['celo', <<parameters.variant>>]
+ steps:
+ - restore_cache:
+ key: v1-celo-deps-{{ checksum "op-e2e/celo/package-lock.json" }}
+ # install dependencies
+ - run:
+ working_directory: op-e2e/celo
+ name: install dependencies
+ command: npm install
+ # save any changes to the cache
+ - save_cache:
+ key: v1-celo-deps-{{ checksum "op-e2e/celo/package-lock.json" }}
+ paths:
+ - op-e2e/celo/node_modules
+ - run:
+ working_directory: op-e2e/celo
+ name: Run Celo e2e tests
+ command: |
+ SPAWN_DEVNET=false ./run_all_tests.sh
- run:
name: Dump op-node logs
command: |
@@ -1406,40 +1309,6 @@ resource_class: medium
steps:
- run: echo Done
- fpp-verify:
- docker:
- - image: cimg/go:1.21
- steps:
- - checkout
- - run:
- name: verify-sepolia
- command: |
- make verify-sepolia
- working_directory: op-program
- - notify-failures-on-develop:
- mentions: "@proofs-squad"
-
- op-program-compat:
- docker:
- - image: <<pipeline.parameters.ci_builder_image>>
- steps:
- - checkout
- - restore_cache:
- name: Restore Go modules cache
- key: gomod-{{ checksum "go.sum" }}
- - restore_cache:
- key: golang-build-cache-op-program-compat-{{ checksum "go.sum" }}
- - run:
- name: compat-sepolia
- command: |
- make verify-compat
- working_directory: op-program
- - save_cache:
- name: Save Go build cache
- key: golang-build-cache-op-program-compat-{{ checksum "go.sum" }}
- paths:
- - "/root/.cache/go-build"
-
check-generated-mocks-op-node:
docker:
- image: <<pipeline.parameters.ci_builder_image>>
@@ -1645,9 +1514,6 @@ parallelism: 4
requires:
- contracts-bedrock-build
- cannon-prestate
- - op-program-compat:
- requires:
- - op-program-tests
- bedrock-go-tests:
requires:
- go-mod-download
@@ -1666,45 +1532,64 @@ - op-challenger-tests
- op-dispute-mon-tests
- op-conductor-tests
- op-program-tests
- - op-program-compat
- op-service-tests
- op-supervisor-tests
- op-e2e-HTTP-tests
- op-e2e-fault-proof-tests
- op-e2e-action-tests
- op-e2e-action-tests-altda
- # Not needed for the devnet but we want to make sure they build successfully
- - cannon-docker-build
- - op-dispute-mon-docker-build
- - op-program-docker-build
- - op-supervisor-docker-build
- - proofs-tools-docker-build
- docker-build:
- name: <<matrix.docker_name>>-docker-build
+ name: op-node-docker-build
+ docker_name: op-node
docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
- save_image_tag: <<pipeline.git.revision>>
- matrix:
- parameters:
- docker_name:
- - op-node
- - op-batcher
- - op-program
- - op-proposer
- - op-challenger
- - proofs-tools
- - op-dispute-mon
- - op-conductor
- - da-server
- - op-supervisor
- - op-deployer
- - cannon
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-batcher-docker-build
+ docker_name: op-batcher
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-program-docker-build
+ docker_name: op-program
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ # op-program is not part of the devnet, we don't save it.
+ - docker-build:
+ name: op-proposer-docker-build
+ docker_name: op-proposer
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-challenger-docker-build
+ docker_name: op-challenger
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-dispute-mon-docker-build
+ docker_name: op-dispute-mon
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-conductor-docker-build
+ docker_name: op-conductor
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ # op-conductor is not part of the devnet, we don't save it.
+ - docker-build:
+ name: da-server-docker-build
+ docker_name: da-server
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ save_image_tag: <<pipeline.git.revision>> # for devnet later
+ - docker-build:
+ name: op-supervisor-docker-build
+ docker_name: op-supervisor
+ docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
+ # op-supervisor is not (yet) part of the devnet, we don't save it
- cannon-prestate:
requires:
- go-mod-download
- devnet:
matrix:
parameters:
- variant: ["default", "altda", "altda-generic"]
+ variant: ["celo",]
requires:
- contracts-bedrock-build
- op-batcher-docker-build
@@ -1718,275 +1603,10 @@ - check-generated-mocks-op-service
- cannon-go-lint-and-test:
requires:
- contracts-bedrock-build
- skip_slow_tests: true
- notify: true
- cannon-build-test-vectors
- - todo-issues:
- name: todo-issues-check
- check_closed: false
- shellcheck/check:
name: shell-check
# We don't need the `exclude` key as the orb detects the `.shellcheckrc`
dir: .
ignore-dirs:
./packages/contracts-bedrock/lib
-
- release:
- when:
- not:
- equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]
- jobs:
- # Wait for approval on the release
- - hold:
- type: approval
- filters:
- tags:
- only: /^(da-server|ci-builder(-rust)?|proofs-tools|cannon|ufm-[a-z0-9\-]*|op-[a-z0-9\-]*)\/v.*/
- branches:
- ignore: /.*/
- # Standard (medium) cross-platform docker images go here
- - docker-build:
- matrix:
- parameters:
- docker_name:
- - op-node
- - op-batcher
- - op-proposer
- - op-challenger
- - op-dispute-mon
- - op-conductor
- - da-server
- - op-ufm
- - op-supervisor
- - op-deployer
- - cannon
- name: <<matrix.docker_name>>-docker-release
- docker_tags: <<pipeline.git.revision>>
- platforms: "linux/amd64,linux/arm64"
- publish: true
- release: true
- filters:
- tags:
- only: /^<<matrix.docker_name>>\/v.*/
- branches:
- ignore: /.*/
- context:
- - oplabs-gcr-release
- requires:
- - hold
- # Checks for cross-platform images go here
- - check-cross-platform:
- matrix:
- parameters:
- op_component:
- - op-node
- - op-batcher
- - op-proposer
- - op-challenger
- - op-dispute-mon
- - op-conductor
- - da-server
- - op-ufm
- - op-supervisor
- - op-deployer
- - cannon
- name: <<matrix.op_component>>-cross-platform
- requires:
- - op-node-docker-release
- - op-batcher-docker-release
- - op-proposer-docker-release
- - op-challenger-docker-release
- - op-dispute-mon-docker-release
- - op-conductor-docker-release
- - da-server-docker-release
- - op-ufm-docker-release
- - op-supervisor-docker-release
- - op-deployer-docker-release
- - cannon-docker-release
- # Standard (xlarge) AMD-only docker images go here
- - docker-build:
- matrix:
- parameters:
- docker_name:
- - ci-builder
- - ci-builder-rust
- - proofs-tools
- name: <<matrix.docker_name>>-docker-release
- resource_class: xlarge
- docker_tags: <<pipeline.git.revision>>
- publish: true
- release: true
- filters:
- tags:
- only: /^<<matrix.docker_name>>\/v.*/
- branches:
- ignore: /.*/
- context:
- - oplabs-gcr-release
- requires:
- - hold
-
- scheduled-todo-issues:
- when:
- equal: [ build_four_hours, <<pipeline.schedule.name>> ]
- jobs:
- - todo-issues:
- name: todo-issue-checks
- context:
- - slack
-
- scheduled-fpp:
- when:
- equal: [ build_four_hours, <<pipeline.schedule.name>> ]
- jobs:
- - fpp-verify:
- context:
- - slack
- - oplabs-fpp-nodes
-
- develop-publish-contract-artifacts:
- when:
- or:
- - equal: [ "develop", <<pipeline.git.branch>> ]
- - equal: [ true, <<pipeline.parameters.publish_contract_artifacts_dispatch>> ]
- jobs:
- - publish-contract-artifacts
-
- develop-fault-proofs:
- when:
- and:
- - or:
- - equal: [ "develop", <<pipeline.git.branch>> ]
- - equal: [ true, <<pipeline.parameters.fault_proofs_dispatch>> ]
- - not:
- equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]
- jobs:
- - go-mod-download
- - cannon-prestate:
- requires:
- - go-mod-download
- - contracts-bedrock-build:
- skip_pattern: test
- context:
- - slack
- - go-e2e-test:
- name: op-e2e-cannon-tests<< matrix.variant >>
- matrix:
- parameters:
- variant: ["", "-mt-cannon"]
- module: op-e2e
- target: test-cannon
- parallelism: 4
- notify: true
- mentions: "@proofs-squad"
- requires:
- - contracts-bedrock-build
- - cannon-prestate
- context:
- - slack
-
- develop-kontrol-tests:
- when:
- and:
- - or:
- - equal: [ "develop", <<pipeline.git.branch>> ]
- - equal: [ true, <<pipeline.parameters.kontrol_dispatch>> ]
- - not:
- equal: [ scheduled_pipeline, << pipeline.trigger_source >> ]
- jobs:
- - kontrol-tests:
- context:
- - slack
- - runtimeverification
-
- scheduled-cannon-full-tests:
- when:
- or:
- - equal: [ build_four_hours, <<pipeline.schedule.name>> ]
- - equal: [ true, << pipeline.parameters.cannon_full_test_dispatch >> ]
- jobs:
- - contracts-bedrock-build:
- skip_pattern: test
- - cannon-go-lint-and-test:
- requires:
- - contracts-bedrock-build
- context:
- - slack
-
- scheduled-docker-publish:
- when:
- or:
- - equal: [ build_hourly, <<pipeline.schedule.name>> ]
- # Trigger on manual triggers if explicitly requested
- - equal: [ true, << pipeline.parameters.docker_publish_dispatch >> ]
- jobs:
- - docker-build:
- matrix:
- parameters:
- docker_name:
- - op-node
- - op-batcher
- - op-program
- - op-proposer
- - op-challenger
- - op-dispute-mon
- - op-conductor
- - op-supervisor
- - cannon
- name: <<matrix.docker_name>>-docker-publish
- docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
- platforms: "linux/amd64,linux/arm64"
- publish: true
- context:
- - oplabs-gcr
- - slack
- - check-cross-platform:
- matrix:
- parameters:
- op_component:
- - op-node
- - op-batcher
- - op-program
- - op-proposer
- - op-challenger
- - op-dispute-mon
- - op-conductor
- - op-supervisor
- - cannon
- name: <<matrix.op_component>>-cross-platform
- requires:
- - <<matrix.op_component>>-docker-publish
- - docker-build:
- name: contracts-bedrock-docker-publish
- docker_name: contracts-bedrock
- docker_tags: <<pipeline.git.revision>>,<<pipeline.git.branch>>
- resource_class: xlarge
- publish: true
- context:
- - oplabs-gcr
- - slack
-
- scheduled-preimage-reproducibility:
- when:
- or:
- - equal: [build_daily, <<pipeline.schedule.name>> ]
- # Trigger on manual triggers if explicitly requested
- - equal: [ true, << pipeline.parameters.reproducibility_dispatch >> ]
- jobs:
- - preimage-reproducibility:
- matrix:
- parameters:
- version:
- - "0.1.0"
- - "0.2.0"
- - "0.3.0"
- - "1.0.0"
- - "1.1.0"
- - "1.2.0"
- - "1.3.0-rc.1"
- - "1.3.0-rc.2"
- - "1.3.0-rc.3"
- - "1.3.1-rc.1"
- - "1.3.1-rc.2"
- context:
- slack
diff --git OP/.github/dependabot.yml CELO/.github/dependabot.yml
index e2c739a570d569656a412cf955ec8d54757abaeb..ce096cfc17fcb9a16132e9d30ba879bf07b29d69 100644
--- OP/.github/dependabot.yml
+++ CELO/.github/dependabot.yml
@@ -7,7 +7,7 @@ interval: "daily"
day: "tuesday"
time: "14:30"
timezone: "America/New_York"
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 0
commit-message:
prefix: "dependabot(docker): "
labels:
@@ -20,7 +20,7 @@ interval: "weekly"
day: "tuesday"
time: "14:30"
timezone: "America/New_York"
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 0
commit-message:
prefix: "dependabot(actions): "
labels:
@@ -33,7 +33,7 @@ interval: "weekly"
day: "tuesday"
time: "14:30"
timezone: "America/New_York"
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 0
versioning-strategy: "auto"
commit-message:
prefix: "dependabot(npm): "
@@ -47,7 +47,7 @@ interval: "daily"
day: "tuesday"
time: "14:30"
timezone: "America/New_York"
- open-pull-requests-limit: 10
+ open-pull-requests-limit: 0
commit-message:
prefix: "dependabot(gomod): "
labels:
diff --git OP/.github/workflows/contracts-celo.yaml CELO/.github/workflows/contracts-celo.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4db01c9406a1dafee59b318a9b26a8b1e99b86e6
--- /dev/null
+++ CELO/.github/workflows/contracts-celo.yaml
@@ -0,0 +1,99 @@
+name: Alfajores-Holesky Deploy Celo4 L1 Contracts
+on:
+ workflow_dispatch:
+ inputs:
+ deploy_contracts:
+ required: false
+ type: boolean
+ default: true
+ contracts_tag:
+ required: false
+ type: string
+ default: 'celo4'
+ deployment_context:
+ required: false
+ type: string
+ default: 'test-celo4'
+ l2_chain_id:
+ required: false
+ default: '42069'
+
+jobs:
+ deploy-contracts:
+ runs-on: ubuntu-latest
+ permissions: # Must change the job token permissions to use Akeyless JWT auth
+ id-token: write
+ contents: read
+ if: ${{ ! startsWith(github.triggering_actor, 'akeyless') }}
+ env:
+ DEPLOY_CONTRACTS: ${{ github.event_name == 'push' && 'true' || inputs.deploy_contracts }}
+ CONTRACTS_TAG: ${{ github.event_name == 'push' && 'op-contracts/v1.3.0' || inputs.contracts_tag }}
+ DEPLOYMENT_CONTEXT: ${{ github.event_name == 'push' && 'test' || inputs.deployment_context }}
+ L2_CHAIN_ID: ${{ github.event_name == 'push' && '42069' || inputs.l2_chain_id }}
+ L1_CHAIN_ID: '17000' # Holesky
+ L1_RPC_URL: 'https://ethereum-holesky-rpc.publicnode.com'
+ GS_ADMIN_ADDRESS: '0xb2397dF29AFB4B4661559436180019bEb7912985'
+ GS_BATCHER_ADDRESS: '0x7fDBe8F4D22ab511340667d7Ce5675568d09eBB4'
+ GS_PROPOSER_ADDRESS: '0xdCf30236Fa0aBE2ca0BEc2eE0a2F40b16A144DB3'
+ GS_SEQUENCER_ADDRESS: '0x3e2Df8efB6fA1d6E6021572a99BB67BA9ab2C59D'
+ steps:
+
+ - name: "Get GitHub Token from Akeyless"
+ id: get_auth_token
+ uses:
+ docker://us-west1-docker.pkg.dev/devopsre/akeyless-public/akeyless-action:latest
+ with:
+ api-url: https://api.gateway.akeyless.celo-networks-dev.org
+ access-id: p-kf9vjzruht6l
+ dynamic-secrets: '{"/dynamic-secrets/keys/github/optimism/contents=write,pull_requests=write":"PAT"}'
+
+ # "/static-secrets/devops-circle/alfajores/op-testnet-alfajores/HOLESKY_QUICKNODE_URL":"L1_RPC_URL",
+ - name: Akeyless get secrets
+ uses: docker://us-west1-docker.pkg.dev/devopsre/akeyless-public/akeyless-action:latest
+ with:
+ api-url: https://api.gateway.akeyless.celo-networks-dev.org
+ access-id: p-kf9vjzruht6l
+ static-secrets: '{
+ "/static-secrets/devops-circle/alfajores/op-testnet-alfajores/GS_ADMIN_PRIVATE_KEY":"GS_ADMIN_PRIVATE_KEY"
+ }'
+
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ token: ${{ env.PAT }}
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: Setup
+ uses: ./.github/actions/setup
+
+ - name: Generate config JSON
+ run: |
+ cd packages/contracts-bedrock
+ ./scripts/getting-started/config-vars-celo.sh
+
+ - name: Deploy L1 contracts
+ if: ${{ env.DEPLOY_CONTRACTS != 'false' }}
+ run: |
+ export IMPL_SALT=$(openssl rand -hex 32)
+ cd packages/contracts-bedrock
+ echo "Broadcasting ..."
+ forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --broadcast --rpc-url $L1_RPC_URL --legacy
+
+ - name: Generate genesis files
+ run: |
+ mkdir -p l2-config-files/$DEPLOYMENT_CONTEXT
+ cd op-node
+ go run cmd/main.go genesis l2 \
+ --deploy-config ../packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json \
+ --l1-deployments ../packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT/.deploy \
+ --outfile.l2 ../l2-config-files/$DEPLOYMENT_CONTEXT/genesis-$(date +%s).json \
+ --outfile.rollup ../l2-config-files/$DEPLOYMENT_CONTEXT/rollup-$(date +%s).json \
+ --l1-rpc $L1_RPC_URL
+
+ - name: "Commit genesis files"
+ uses: stefanzweifel/git-auto-commit-action@v5
+ with:
+ commit_message: '[Automatic] - Commit genesis files'
+ branch: alvarof2/contracts
+ file_pattern: 'l2-config-files packages/contracts-bedrock/**'
diff --git OP/.github/workflows/contracts-op-stack.yaml CELO/.github/workflows/contracts-op-stack.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..7c7efb2409c08e44cbf6955d4e8b9fe07398bdef
--- /dev/null
+++ CELO/.github/workflows/contracts-op-stack.yaml
@@ -0,0 +1,117 @@
+name: Alfajores-Holesky Deploy OP-Stack L1 Contracts
+on:
+ workflow_dispatch:
+ inputs:
+ deploy_contracts:
+ required: false
+ type: boolean
+ default: true
+ contracts_tag:
+ required: false
+ type: string
+ default: 'op-contracts/v1.3.0'
+ deployment_context:
+ required: false
+ type: string
+ default: 'test-alvaro'
+ l2_chain_id:
+ required: false
+ default: '42069'
+
+jobs:
+ deploy-contracts:
+ runs-on: ubuntu-latest
+ permissions: # Must change the job token permissions to use Akeyless JWT auth
+ id-token: write
+ contents: read
+ if: ${{ ! startsWith(github.triggering_actor, 'akeyless') }}
+ env:
+ DEPLOY_CONTRACTS: ${{ github.event_name == 'push' && 'true' || inputs.deploy_contracts }}
+ CONTRACTS_TAG: ${{ github.event_name == 'push' && 'op-contracts/v1.3.0' || inputs.contracts_tag }}
+ DEPLOYMENT_CONTEXT: ${{ github.event_name == 'push' && 'test' || inputs.deployment_context }}
+ L2_CHAIN_ID: ${{ github.event_name == 'push' && '42069' || inputs.l2_chain_id }}
+ L1_CHAIN_ID: '17000' # Holesky
+ L1_RPC_URL: 'https://ethereum-holesky-rpc.publicnode.com'
+ GS_ADMIN_ADDRESS: '0xb2397dF29AFB4B4661559436180019bEb7912985'
+ GS_BATCHER_ADDRESS: '0x7fDBe8F4D22ab511340667d7Ce5675568d09eBB4'
+ GS_PROPOSER_ADDRESS: '0xdCf30236Fa0aBE2ca0BEc2eE0a2F40b16A144DB3'
+ GS_SEQUENCER_ADDRESS: '0x3e2Df8efB6fA1d6E6021572a99BB67BA9ab2C59D'
+ steps:
+
+ - name: "Get GitHub Token from Akeyless"
+ id: get_auth_token
+ uses:
+ docker://us-west1-docker.pkg.dev/devopsre/akeyless-public/akeyless-action:latest
+ with:
+ api-url: https://api.gateway.akeyless.celo-networks-dev.org
+ access-id: p-kf9vjzruht6l
+ dynamic-secrets: '{"/dynamic-secrets/keys/github/optimism/contents=write,pull_requests=write":"PAT"}'
+
+ # "/static-secrets/devops-circle/alfajores/op-testnet-alfajores/HOLESKY_QUICKNODE_URL":"L1_RPC_URL",
+ - name: Akeyless get secrets
+ uses: docker://us-west1-docker.pkg.dev/devopsre/akeyless-public/akeyless-action:latest
+ with:
+ api-url: https://api.gateway.akeyless.celo-networks-dev.org
+ access-id: p-kf9vjzruht6l
+ static-secrets: '{
+ "/static-secrets/devops-circle/alfajores/op-testnet-alfajores/GS_ADMIN_PRIVATE_KEY":"GS_ADMIN_PRIVATE_KEY"
+ }'
+
+ - name: "Checkout"
+ uses: actions/checkout@v4
+ with:
+ token: ${{ env.PAT }}
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: "Checkout OP Repo"
+ uses: actions/checkout@v4
+ with:
+ repository: 'ethereum-optimism/optimism'
+ ref: '${{ env.CONTRACTS_TAG }}'
+ path: ethereum-optimism
+ submodules: recursive
+ fetch-depth: 0
+
+ - name: Setup
+ uses: ./.github/actions/setup
+
+ - name: Generate config JSON
+ run: |
+ cd packages/contracts-bedrock
+ ./scripts/getting-started/config-vars-op-stack.sh
+ cp deploy-config/$DEPLOYMENT_CONTEXT.json /home/runner/work/optimism/optimism/ethereum-optimism/packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json
+
+ - name: Deploy L1 contracts
+ if: ${{ env.DEPLOY_CONTRACTS != 'false' }}
+ run: |
+ export IMPL_SALT=$(openssl rand -hex 32)
+ cd ethereum-optimism/packages/contracts-bedrock
+ echo "Broadcasting ..."
+ forge script scripts/Deploy.s.sol:Deploy --private-key $GS_ADMIN_PRIVATE_KEY --broadcast --rpc-url $L1_RPC_URL --legacy
+ mkdir -p /home/runner/work/optimism/optimism/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT
+ cp deployments/$DEPLOYMENT_CONTEXT/.deploy /home/runner/work/optimism/optimism/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT/.deploy
+
+ - name: Copy old .deploy file if contracts not deployed
+ if: ${{ env.DEPLOY_CONTRACTS == 'false' }}
+ run: |
+ mkdir -p ethereum-optimism/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT
+ cp packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT/.deploy ethereum-optimism/packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT/.deploy
+
+ - name: Generate genesis files
+ run: |
+ mkdir -p l2-config-files/$DEPLOYMENT_CONTEXT
+ cd ethereum-optimism/op-node
+ go run cmd/main.go genesis l2 \
+ --deploy-config ../packages/contracts-bedrock/deploy-config/$DEPLOYMENT_CONTEXT.json \
+ --l1-deployments ../packages/contracts-bedrock/deployments/$DEPLOYMENT_CONTEXT/.deploy \
+ --outfile.l2 ../../l2-config-files/$DEPLOYMENT_CONTEXT/genesis-$(date +%s).json \
+ --outfile.rollup ../../l2-config-files/$DEPLOYMENT_CONTEXT/rollup-$(date +%s).json \
+ --l1-rpc $L1_RPC_URL
+
+ - name: "Commit genesis files"
+ uses: stefanzweifel/git-auto-commit-action@v5
+ with:
+ commit_message: '[Automatic] - Commit genesis files'
+ branch: alvarof2/contracts
+ file_pattern: 'l2-config-files packages/contracts-bedrock/**'
diff --git OP/.github/workflows/docker-build-scan.yaml CELO/.github/workflows/docker-build-scan.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..989b8127e40ad008b03ea38e74c07dd3eb2e81d5
--- /dev/null
+++ CELO/.github/workflows/docker-build-scan.yaml
@@ -0,0 +1,105 @@
+name: Docker Build Scan
+on:
+ pull_request:
+ branches:
+ - 'master'
+ - 'celo*'
+ push:
+ branches:
+ - 'master'
+ - 'celo*'
+ workflow_dispatch:
+
+jobs:
+ detect-files-changed:
+ runs-on: ubuntu-latest
+ outputs:
+ files-changed: ${{ steps.detect-files-changed.outputs.all_changed_files }}
+ steps:
+ - uses: actions/checkout@v4
+ - name: Detect files changed
+ id: detect-files-changed
+ uses: tj-actions/changed-files@v44
+ with:
+ separator: ','
+
+ build-cel2-migration-tool:
+ runs-on: ubuntu-latest
+ env:
+ GIT_COMMIT: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
+ needs: detect-files-changed
+ if: |
+ contains(needs.detect-files-changed.outputs.files-changed, 'go.sum') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-chain-ops/cmd/celo-migrate') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-chain-ops/Dockerfile') ||
+ contains(needs.detect-files-changed.outputs.files-changed, '.github/workflows/docker-build-scan.yaml') ||
+ github.event_name == 'workflow_dispatch' ||
+ true
+ permissions:
+ contents: read
+ id-token: write
+ security-events: write
+ steps:
+ - uses: actions/checkout@v4
+ - name: Login at GCP Artifact Registry
+ uses: celo-org/reusable-workflows/.github/actions/auth-gcp-artifact-registry@v2.0
+ with:
+ workload-id-provider: 'projects/1094498259535/locations/global/workloadIdentityPools/gh-optimism/providers/github-by-repos'
+ service-account: 'celo-optimism-gh@devopsre.iam.gserviceaccount.com'
+ docker-gcp-registries: us-west1-docker.pkg.dev
+ - name: Build and push container
+ uses: celo-org/reusable-workflows/.github/actions/build-container@v2.0
+ with:
+ platforms: linux/amd64
+ registry: us-west1-docker.pkg.dev/devopsre/dev-images/cel2-migration-tool
+ tags: ${{ env.GIT_COMMIT }}
+ context: ./
+ dockerfile: ./op-chain-ops/Dockerfile
+ push: true
+ trivy: false
+
+ # Build op-node op-batcher op-proposer using docker-bake
+ build-op-stack:
+ runs-on: ubuntu-latest
+ needs: detect-files-changed
+ if: |
+ contains(needs.detect-files-changed.outputs.files-changed, 'go.sum') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'ops/docker') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-node/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-batcher/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-conductor/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-challenger/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-dispute-mon/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-proposer/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, 'op-service/') ||
+ contains(needs.detect-files-changed.outputs.files-changed, '.github/workflows/docker-build-scan.yaml') ||
+ github.event_name == 'workflow_dispatch' ||
+ true
+ permissions:
+ contents: read
+ id-token: write
+ security-events: write
+ env:
+ GIT_COMMIT: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
+ GIT_DATE: ${{ github.event.head_commit.timestamp }}
+ IMAGE_TAGS: ${{ (github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/celo')) && 'latest,' || '') }}${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
+ REGISTRY: us-west1-docker.pkg.dev
+ REPOSITORY: blockchaintestsglobaltestnet/dev-images
+ steps:
+ - uses: actions/checkout@v4
+ - name: Login at GCP Artifact Registry
+ uses: celo-org/reusable-workflows/.github/actions/auth-gcp-artifact-registry@v2.0
+ with:
+ workload-id-provider: 'projects/1094498259535/locations/global/workloadIdentityPools/gh-optimism/providers/github-by-repos'
+ service-account: 'celo-optimism-gh@devopsre.iam.gserviceaccount.com'
+ docker-gcp-registries: us-west1-docker.pkg.dev
+ # We need a custom steps as it's using docker bake
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v3
+ - name: Build and push
+ uses: docker/bake-action@v5
+ with:
+ push: true
+ source: .
+ files: docker-bake.hcl
+ targets: op-node,op-batcher,op-proposer,op-conductor,op-challenger,op-dispute-mon
diff --git OP/.github/workflows/docker-op-ufm-build-push.yaml CELO/.github/workflows/docker-op-ufm-build-push.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e4a0ab33b1033742801b286de8003032909575ef
--- /dev/null
+++ CELO/.github/workflows/docker-op-ufm-build-push.yaml
@@ -0,0 +1,41 @@
+---
+name: Build op-ufm container and push to cLabs registry
+on:
+ push:
+ branches:
+ - cel4
+ paths:
+ # Run if any of the following files are changed
+ - 'op-ufm/**'
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ['self-hosted', 'org', '8-cpu']
+ permissions: # Required for workload identity auth and push the trivy results to GitHub
+ contents: read
+ id-token: write
+ security-events: write
+ steps:
+
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Authenticate to Google Cloud
+ uses: celo-org/reusable-workflows/.github/actions/auth-gcp-artifact-registry@main
+ with:
+ workload-id-provider: projects/1094498259535/locations/global/workloadIdentityPools/gh-optimism/providers/github-by-repos
+ service-account: celo-optimism-gh@devopsre.iam.gserviceaccount.com
+ access-token-lifetime: "60m"
+ docker-gcp-registries: us-west1-docker.pkg.dev
+
+ - name: Build, push and scan the container
+ uses: celo-org/reusable-workflows/.github/actions/build-container@main
+ with:
+ platforms: linux/amd64
+ registry: us-west1-docker.pkg.dev/devopsre/dev-images/op-ufm
+ tags: test
+ context: .
+ dockerfile: op-ufm/Dockerfile
+ push: true
+ trivy: false
diff --git OP/.github/workflows/pages.yml CELO/.github/workflows/pages.yml
new file mode 100644
index 0000000000000000000000000000000000000000..075443e414da22ad05c49612372337de379b4f9b
--- /dev/null
+++ CELO/.github/workflows/pages.yml
@@ -0,0 +1,36 @@
+name: Build and publish forkdiff github-pages
+permissions:
+ contents: write
+on:
+ push:
+ branches:
+ - celo[0-9]+
+
+ workflow_dispatch:
+
+jobs:
+ deploy:
+ concurrency: ci-${{ github.ref }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # make sure to fetch the old commit we diff against
+
+ - name: Build forkdiff
+ uses: "docker://protolambda/forkdiff:0.1.0"
+ with:
+ args: -repo=/github/workspace -fork=/github/workspace/fork.yaml -out=/github/workspace/index.html
+
+ - name: Build pages
+ run: |
+ mkdir -p tmp/pages
+ mv index.html tmp/pages/index.html
+ touch tmp/pages/.nojekyll
+
+ - name: Deploy
+ uses: JamesIves/github-pages-deploy-action@v4
+ with:
+ folder: tmp/pages
+ clean: true
diff --git OP/.github/workflows/update-geth.yaml CELO/.github/workflows/update-geth.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..f2717223c82b60d1021df2298a195772447af90c
--- /dev/null
+++ CELO/.github/workflows/update-geth.yaml
@@ -0,0 +1,60 @@
+name: "Update celo-org/op-geth"
+on:
+ schedule:
+ - cron: "00 8 * * Mon"
+ workflow_dispatch:
+
+env:
+ OP_GETH_BASE_BRANCH: "celo10"
+
+jobs:
+ job_id:
+ # Add "id-token" with the intended permissions.
+ permissions:
+ contents: write
+ pull-requests: write
+ id-token: "write"
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Login at GCP Artifact Registry
+ uses: celo-org/reusable-workflows/.github/actions/auth-gcp-artifact-registry@v2.0
+ with:
+ workload-id-provider: "projects/1094498259535/locations/global/workloadIdentityPools/gh-optimism-ro/providers/github-by-repos"
+ service-account: "celo-optimism-gh-ro@devopsre.iam.gserviceaccount.com"
+ docker-gcp-registries: us-west1-docker.pkg.dev
+ access-token-lifetime: "2m"
+ - name: "Set up Cloud SDK"
+ uses: "google-github-actions/setup-gcloud@v2"
+ with:
+ version: ">= 363.0.0"
+ - name: Run the update-geth script
+ id: geth-update-script
+ run: |
+ GETH_COMMIT=$(bash ./ops/celo/update-geth.sh "$OP_GETH_BASE_BRANCH")
+ echo "GETH_COMMIT=${GETH_COMMIT}" >> $GITHUB_OUTPUT
+ - name: Create pull request
+ uses: peter-evans/create-pull-request@v7
+ env:
+ TITLE: "[Automatic] - Update op-geth dependencies"
+ MESSAGE: |
+ Update the go package dependency and the devnet
+ docker container reference of the `l2` service
+ to the latest commit (`${{ steps.geth-update-script.outputs.GETH_COMMIT }}`)
+ in the `${{ env.OP_GETH_BASE_BRANCH }}` ref.
+ with:
+ add-paths: |
+ go.mod
+ go.sum
+ ops-bedrock/*.Dockerfile
+ commit-message: |
+ ${{ env.TITLE }}
+
+ ${{ env.MESSAGE }}
+ signoff: false
+ branch: update/op-geth
+ base: "${{ env.OP_GETH_BASE_BRANCH }}"
+ delete-branch: true
+ title: "${{ env.TITLE }}"
+ body: "${{ env.MESSAGE }}"
+ draft: false
diff --git OP/fork.yaml CELO/fork.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5c5414ce63188f3063942beb5a94091455442f01
--- /dev/null
+++ CELO/fork.yaml
@@ -0,0 +1,141 @@
+title: "CELO <> OP optimism forkdiff"
+footer: |
+ Fork-diff overview of changes made in [Celo's `optimism`](https://github.com/celo-org/optimism),
+ a fork of [Optimism's `optimism`](https://github.com/ethereum-optimism/optimism).
+
+base:
+ name: OP
+ url: https://github.com/celo-org/optimism
+ ref: refs/remotes/origin/celo10-upstream
+fork:
+ name: CELO
+ url: https://github.com/celo-org/optimism
+ ref: HEAD
+def:
+ title: "Celo's optimism"
+ description: |
+ This is an overview of the changes in [Celo's `optimism` implementation](https://github.com/celo-org/optimism),
+ a fork of [Optimism's `optimism`](https://github.com/ethereum-optimism/optimism).
+
+ Changes are currently separated by sub-package or component. Check out the [README](https://github.com/celo-org/optimism/blob/develop/README.md)
+ for more details about each of these components and packages.
+
+ sub:
+ - title: "packages/*"
+ description: ""
+ sub:
+ - title: "common-ts"
+ description: ""
+ globs:
+ - "packages/common-ts/*"
+ - title: "contracts-bedrock"
+ description: ""
+ globs:
+ - "packages/contracts-bedrock/*"
+ - "packages/contracts-bedrock/*/*"
+ - "packages/contracts-bedrock/*/*/*"
+ - title: "core-utils"
+ description: ""
+ globs:
+ - "packages/core-utils/*"
+ - title: "chain-mon"
+ description: ""
+ globs:
+ - "packages/chain-mon/*"
+ - title: "sdk"
+ description: ""
+ globs:
+ - "packages/sdk/*"
+ - title: "op-bindings"
+ description: ""
+ globs:
+ - "op-bindings/*"
+ - "op-bindings/*/*"
+ - title: "op-batcher"
+ description: ""
+ globs:
+ - "op-batcher/*"
+ - title: "op-bootnode"
+ description: ""
+ globs:
+ - "op-bootnode/*"
+ - title: "op-chain-ops"
+ description: ""
+ globs:
+ - "op-chain-ops/*"
+ - "op-chain-ops/*/*"
+ - "op-chain-ops/*/*/*"
+ - title: "op-challenger"
+ description: ""
+ globs:
+ - "op-challenger/*"
+ - "op-challenger/*/*"
+ - "op-challenger/*/*/*"
+ - title: "op-e2e"
+ description: ""
+ globs:
+ - "op-e2e/*"
+ - "op-e2e/*/*"
+ - "op-e2e/*/*/*"
+ - "op-e2e/*/*/*/*"
+
+ - title: "op-exporter"
+ description: ""
+ globs:
+ - "op-exporter/*"
+ - title: "op-node"
+ description: ""
+ globs:
+ - "op-node/*"
+ - "op-node/*/*"
+ - "op-node/*/*/*"
+ - title: "op-program"
+ description: ""
+ globs:
+ - "op-program/*"
+ - title: "op-proposer"
+ description: ""
+ globs:
+ - "op-proposer/*"
+ - title: "op-service"
+ description: ""
+ globs:
+ - "op-service/*"
+ - title: "op-signer"
+ description: ""
+ globs:
+ - "op-signer/*"
+ - title: "op-wheel"
+ description: ""
+ globs:
+ - "op-wheel/*"
+ - title: "ops-bedrock"
+ description: ""
+ globs:
+ - "ops-bedrock/*"
+ - title: "proxyd"
+ description: ""
+ globs:
+ - "proxyd/*"
+ - title: "specs"
+ description: ""
+ globs:
+ - "specs/*"
+ - title: "indexer"
+ description: ""
+ globs:
+ - "indexer/*"
+ - "indexer/*/*"
+ - "indexer/*/*/*"
+
+# ignored globally, does not count towards line count
+ignore:
+ - ".circleci/*"
+ - "*.sum"
+ - "go.mod"
+ - "fork.yaml"
+ - ".github/workflows/*"
+ - ".changeset/*"
+ - ".github/*"
+ - "CONTRIBUTING.md"
+ - "pnpm-lock.yaml"
diff --git OP/go.mod CELO/go.mod
index 4681c720ba8ca75833f282b7354f9c8c27128c44..cdb76bc37c19985566ede9396edd975ee3f68347 100644
--- OP/go.mod
+++ CELO/go.mod
@@ -257,7 +257,7 @@ lukechampine.com/blake3 v1.3.0 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
)
-replace github.com/ethereum/go-ethereum v1.14.8 => github.com/ethereum-optimism/op-geth v1.101408.0-rc.4.0.20240827042333-110c433a2469
+replace github.com/ethereum/go-ethereum => github.com/celo-org/op-geth v1.101408.1-0.20241211135814-0162ce9d0298
// replace github.com/ethereum/go-ethereum => ../op-geth
diff --git OP/go.sum CELO/go.sum
index a92b17d143eb73a1cf13e351fdebbb0daca78764..e0a4c89501f671f761dc5e93b35623d27578bed4 100644
--- OP/go.sum
+++ CELO/go.sum
@@ -81,6 +81,8 @@ github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/celo-org/op-geth v1.101408.1-0.20241211135814-0162ce9d0298 h1:tv3rg2aT8xQJoL0e2hMyLG+s/a+y4GucB0Ir/TitqaQ=
+github.com/celo-org/op-geth v1.101408.1-0.20241211135814-0162ce9d0298/go.mod h1:Mk8AhvlqFbjI9oW2ymThSSoqc6kiEH0/tCmHGMEu6ac=
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -183,8 +185,6 @@ github.com/elastic/gosigar v0.14.3 h1:xwkKwPia+hSfg9GqrCUKYdId102m9qTJIIr7egmK/uo=
github.com/elastic/gosigar v0.14.3/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3 h1:RWHKLhCrQThMfch+QJ1Z8veEq5ZO3DfIhZ7xgRP9WTc=
github.com/ethereum-optimism/go-ethereum-hdwallet v0.1.3/go.mod h1:QziizLAiF0KqyLdNJYD7O5cpDlaFMNZzlxYNcWsJUxs=
-github.com/ethereum-optimism/op-geth v1.101408.0-rc.4.0.20240827042333-110c433a2469 h1:sGqlBjx0+z/ExU6VNo5OHSXS/5nc6BfkEQJvSdVbWp0=
-github.com/ethereum-optimism/op-geth v1.101408.0-rc.4.0.20240827042333-110c433a2469/go.mod h1:Mk8AhvlqFbjI9oW2ymThSSoqc6kiEH0/tCmHGMEu6ac=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac h1:hCIrLuOPV3FJfMDvXeOhCC3uQNvFoMIIlkT2mN2cfeg=
github.com/ethereum-optimism/superchain-registry/superchain v0.0.0-20240910145426-b3905c89e8ac/go.mod h1:XaVXL9jg8BcyOeugECgIUGa9Y3DjYJj71RHmb5qon6M=
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=