Address Contract Verified
Address
0x59888ea06a54bdC7d495c24513ed5b7A58ed7804
Balance
0 ETH
Nonce
1
Code Size
7389 bytes
Creator
0x61D4daFf...7B1a at tx 0x3652311f...84d87b
Indexed Transactions
0 (1 on-chain, 0.8% indexed)
Contract Bytecode
7389 bytes
0x608060405234801561001057600080fd5b50600436106100415760003560e01c80632418833f1461015d5780632b7ac3f314610178578063c4d66de8146101c3575b6004361161007b576040517f0f601ef500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600061008a366004818461173b565b8080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201829052509394506100cc92508491506101d89050565b6000546040517f1e5de2ab00000000000000000000000000000000000000000000000000000000815291925062010000900473ffffffffffffffffffffffffffffffffffffffff1690631e5de2ab906101299084906004016119bd565b60006040518083038186803b15801561014157600080fd5b505afa158015610155573d6000803e3d6000fd5b505050505050005b610165600481565b6040519081526020015b60405180910390f35b60005461019e9062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161016f565b6101d66101d1366004611b92565b6102ab565b005b6101e061159c565b600061021b6102168460408051808201825260008082526020918201528151808301909252825182529182019181019190915290565b610480565b50905061023b604051806040016040528060008152602001600081525090565b61024482610528565b9250905061025181610572565b835261025c82610528565b92509050610269816105f1565b602084015261027782610528565b925090506102848161067f565b604084015261029282610528565b50905061029e8161078e565b6060840152509092915050565b600054610100900460ff16158080156102cb5750600054600160ff909116105b806102e55750303b1580156102e5575060005460ff166001145b610376576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a656400000000000000000000000000000000000060648201526084015b60405180910390fd5b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600117905580156103d457600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b600080547fffffffffffffffffffff0000000000000000000000000000000000000000ffff166201000073ffffffffffffffffffffffffffffffffffffffff851602179055801561047c57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b5050565b60008061048c83610921565b6104f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6104ff836020015161095a565b836020015161050e9190611bf7565b8351602085015191935061052191611bf7565b9050915091565b6040805180820190915260008082526020820152600080610548846109dc565b60408051808201909152818152602081018690529350905061056a8185611bf7565b915050915091565b6040805180820190915260008082526020820152600061059183610480565b5090506105b1604051806040016040528060008152602001600081525090565b6105ba82610528565b925090506105c781610a83565b83526105d282610528565b5090506105de81610c0d565b63ffffffff166020840152509092915050565b6105f96115e0565b600061060483610480565b509050610624604051806040016040528060008152602001600081525090565b61062d82610528565b9250905061063a81610c1e565b835261064582610528565b9250905061065281610c0d565b63ffffffff16602084015261066682610528565b5090506106728161078e565b6040840152509092915050565b610687611607565b600061069283610480565b5090506106b2604051806040016040528060008152602001600081525090565b6106bb82610528565b925090506106c881610c95565b83526106d382610528565b925090506106e081610e2a565b60208401526106ee82610528565b925090506106fb81610e2a565b604084015261070982610528565b9250905061071681610f20565b606084015261072482610528565b925090506107318161103c565b608084015261073f82610528565b9250905061074c81610c95565b60a084015261075a82610528565b9250905061076781610c95565b60c084015261077582610528565b509050610781816110b5565b60e0840152509092915050565b80516060906107f9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f524c505265616465723a206974656d20686173206e6f20646174610000000000604482015260640161036d565b602082015182518151600090811a60808110600181146108a35760b88210600181146108985760c083106001811461086c5760f8841060018114610861577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a85019550610866565b600195505b50610892565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a840194505b5061089d565b600193505b506108a8565b600092505b506108b590508183611c0f565b915060008267ffffffffffffffff8111156108d2576108d2611c26565b6040519080825280601f01601f1916602001820160405280156108fc576020820181803683370190505b509050602081016109176109108487611bf7565b8286611232565b5095945050505050565b805160009061093257506000919050565b6020820151805160001a9060c0821015610950575060009392505050565b5060019392505050565b8051600090811a60808110156109735750600092915050565b60b881108061098e575060c0811080159061098e575060f881105b1561099c5750600192915050565b60c08110156109d0576109b1600160b8611c55565b6109be9060ff1682611c0f565b6109c9906001611bf7565b9392505050565b6109b1600160f8611c55565b80516000908190811a60808110156109f75760019150610a7c565b60b8811015610a1d57610a0b608082611c0f565b610a16906001611bf7565b9150610a7c565b60c0811015610a495760b781036001850194508451816020036008021c60018201810193505050610a7c565b60f8811015610a5d57610a0b60c082611c0f565b60f781036001850194508451816020036008021c600182018101935050505b5092915050565b8051600090610aee576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f524c505265616465723a206974656d20686173206e6f20646174610000000000604482015260640161036d565b602082015182518151600090811a906080821060018114610b995760b8831060018114610b8e5760c0841060018114610b625760f8851060018114610b57577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a86019450610b5c565b600194505b50610b88565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a850193505b50610b93565b600192505b50610b9e565b600091505b509283019290910390506020811115610bed576308c379a06000526020600452601a6024527f524c505265616465723a2062797465733332206f766572666c6f77000000000060445260646000fd5b815192506020811015610c065782816020036008021c92505b5050919050565b6000610c18826112c1565b92915050565b610c2661166d565b6000610c3183610480565b509050610c51604051806040016040528060008152602001600081525090565b610c5a82610528565b92509050610c6781611459565b8352610c7282610528565b92509050610c7f8161078e565b6020840152610c8d82610528565b509050610672815b6060610ca082610921565b610d06576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6000610d15836020015161095a565b8360200151610d249190611bf7565b9050600083600001518460200151610d3c9190611bf7565b90506000825b82811015610d5f57610d53816109dc565b60019092019101610d42565b8167ffffffffffffffff811115610d7857610d78611c26565b604051908082528060200260200182016040528015610da1578160200160208202803683370190505b50945083905060005b82811015610e20576000610dbd836109dc565b90506000610dca8461095a565b84810151909150818303906020821015610de857602082900360031b1c5b808a8681518110610dfb57610dfb611c78565b63ffffffff909216602092830291909101909101525050509190910190600101610daa565b5050505050919050565b6060600080610e3884610480565b90925090506000825b82811015610e5e57610e52816109dc565b60019092019101610e41565b8167ffffffffffffffff811115610e7757610e77611c26565b604051908082528060200260200182016040528015610ebc57816020015b6040805180820190915260008082526020820152815260200190600190039081610e955790505b50945060005b82811015610e20576000610ed5866109dc565b6040805180820190915281815260208101889052909150610ef58161103c565b888481518110610f0757610f07611c78565b6020908102919091010152509490940193600101610ec2565b610f28611694565b6000610f3383610480565b509050610f53604051806040016040528060008152602001600081525090565b610f5c82610528565b925090506000610f6b82610480565b509050610f8b604051806040016040528060008152602001600081525090565b610f9482610528565b92509050610fa1816112c1565b855152610fad82610528565b509050610fb9816112c1565b85516020015250610fcb905082610528565b5090506000610fd982610480565b509050610ff9604051806040016040528060008152602001600081525090565b61100282610528565b9250905061100f816112c1565b60208601515261101e82610528565b50905061102a816112c1565b60208681015101525092949350505050565b6040805180820190915260008082526020820152600061105b83610480565b50905061107b604051806040016040528060008152602001600081525090565b61108482610528565b92509050611091816112c1565b835261109c82610528565b5090506110a8816112c1565b6020840152509092915050565b60606110c082610921565b611126576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f524c505265616465723a206974656d206973206e6f742061206c697374000000604482015260640161036d565b6000611135836020015161095a565b83602001516111449190611bf7565b905060008360000151846020015161115c9190611bf7565b90506000825b8281101561117f57611173816109dc565b60019092019101611162565b8167ffffffffffffffff81111561119857611198611c26565b6040519080825280602002602001820160405280156111cb57816020015b60608152602001906001900390816111b65790505b50945083905060005b82811015610e205760006111e7836109dc565b604080518082019091528181526020810185905290915061120781610c95565b88848151811061121957611219611c78565b60209081029190910101525091909101906001016111d4565b8061123c57505050565b5b6020811061127a5782518252602092830192909101907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00161123d565b80156112bc5782518251600160208490036008021b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01801990921691161782525b505050565b8051600090158015906112d657508151602110155b61133c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f524c505265616465723a20696e76616c69642075696e74323536000000000000604482015260640161036d565b602082015182518151600090811a8160808210600181146113e75760b88310600181146113dc5760c08410600181146113b05760f88510600181146113a5577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a860194506113aa565b600194505b506113d6565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a850193505b506113e1565b600192505b506113ec565b600091505b50938401939092039150602082111561143b576308c379a06000526020600452601b6024527f524c505265616465723a2075696e74323536206f766572666c6f77000000000060445260646000fd5b50815160208210156114515760086020839003021c5b949350505050565b6114616116b9565b600061146c83610480565b50905061148c604051806040016040528060008152602001600081525090565b61149582610528565b925090506114a281610c0d565b61ffff1683526114b182610528565b925090506114be8161078e565b60208401526114cc82610528565b925090506114d9816114f3565b60408401526114e782610528565b50905061029e81610a83565b6114fb6116e6565b600061150683610480565b509050611526604051806040016040528060008152602001600081525090565b61152f82610528565b9250905061153c8161103c565b835261154782610528565b9250905061155481610f20565b602084015261156282610528565b9250905061156f81610f20565b604084015261157d82610528565b50905061158981610c0d565b63ffffffff166060840152509092915050565b6040805160c0810190915260006080820181815260a08301919091528152602081016115c66115e0565b81526020016115d3611607565b8152602001606081525090565b60405180606001604052806115f361166d565b815260006020820152606060409091015290565b604051806101000160405280606081526020016060815260200160608152602001611630611694565b8152602001611652604051806040016040528060008152602001600081525090565b81526020016060815260200160608152602001606081525090565b60405180606001604052806116806116b9565b815260200160608152602001606081525090565b60405180604001604052806116a761171d565b81526020016116b461171d565b905290565b6040805160808101825260008152606060208201529081016116d96116e6565b8152600060209091015290565b6040805160c0810190915260006080820181815260a0830191909152815260208101611710611694565b81526020016116d9611694565b60405180604001604052806002906020820280368337509192915050565b6000808585111561174b57600080fd5b8386111561175857600080fd5b5050820193919092039150565b6000815180845260005b8181101561178b5760208185018101518683018201520161176f565b8181111561179d576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b8060005b60028110156117f35781518452602093840193909101906001016117d4565b50505050565b6118048282516117d0565b60208101516112bc60408401826117d0565b600081518084526020808501945080840160005b8381101561184c57815163ffffffff168752958201959082019060010161182a565b509495945050505050565b600081518084526020808501945080840160005b8381101561184c5761188887835180518252602090810151910152565b604096909601959082019060010161186b565b600081518084526020808501808196508360051b8101915082860160005b858110156118e35782840389526118d1848351611816565b988501989350908401906001016118b9565b5091979650505050505050565b6000610180825181855261190682860182611816565b915050602083015184820360208601526119208282611857565b9150506040830151848203604086015261193a8282611857565b915050606083015161194f60608601826117f9565b506080830151805160e08601526020015161010085015260a083015184820361012086015261197e8282611816565b91505060c08301518482036101408601526119998282611816565b91505060e08301518482036101608601526119b4828261189b565b95945050505050565b600060208083528351805182850152818101519050604063ffffffff80831682870152838701519250606060a08188015283518160c08901528051826101208a015261ffff8151166101808a0152868101516101c0806101a08c0152611a276103408c0183611765565b915086830151611a44828d01825180518252602090810151910152565b898101519150611a586102008d01836117f9565b878101519150611a6c6102808d01836117f9565b8501519095166103008b0152908301516103208a0152818701518982037ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee09081016101408c015290945090611ac18186611765565b928601518a84039092016101608b015250909250611adf8382611816565b9585015163ffffffff811660e08a0152959250611af99050565b8284015194507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4087830301610100880152611b348286611765565b94508288015193507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0925082878603016080880152611b7385856118f0565b94508088015193505050808584030160a0860152506119b48282611765565b600060208284031215611ba457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff811681146109c957600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60008219821115611c0a57611c0a611bc8565b500190565b600082821015611c2157611c21611bc8565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060ff821660ff841680821015611c6f57611c6f611bc8565b90039392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fdfea264697066735822122075d2b7165e0b15a21e6a02b722890210414488714ef1b78f0a35d137d074851064736f6c634300080c0033
Verified Source Code Full Match
Compiler: v0.8.12+commit.f00d7308
EVM: london
Optimization: Yes (1000000 runs)
Initializable.sol 138 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)
pragma solidity ^0.8.2;
import "../../utils/AddressUpgradeable.sol";
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
* @custom:oz-retyped-from bool
*/
uint8 private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint8 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.
*/
modifier initializer() {
bool isTopLevelCall = !_initializing;
require(
(isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
"Initializable: contract is already initialized"
);
_initialized = 1;
if (isTopLevelCall) {
_initializing = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original
* initialization step. This is essential to configure modules that are added through upgrades and that require
* initialization.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*/
modifier reinitializer(uint8 version) {
require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
_initialized = version;
_initializing = true;
_;
_initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
require(_initializing, "Initializable: contract is not initializing");
_;
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*/
function _disableInitializers() internal virtual {
require(!_initializing, "Initializable: contract is initializing");
if (_initialized < type(uint8).max) {
_initialized = type(uint8).max;
emit Initialized(type(uint8).max);
}
}
}
AddressUpgradeable.sol 195 lines
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library AddressUpgradeable {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
BN254.sol 350 lines
// SPDX-License-Identifier: MIT
// several functions are taken or adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol (MIT license):
// Copyright 2017 Christian Reitwiessner
// 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.
// The remainder of the code in this library is written by LayrLabs Inc. and is also under an MIT license
pragma solidity ^0.8.12;
/**
* @title Library for operations on the BN254 elliptic curve.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @notice Contains BN254 parameters, common operations (addition, scalar mul, pairing), and BLS signature functionality.
*/
library BN254 {
// modulus for the underlying field F_p of the elliptic curve
uint256 internal constant FP_MODULUS =
21888242871839275222246405745257275088696311157297823662689037894645226208583;
// modulus for the underlying field F_r of the elliptic curve
uint256 internal constant FR_MODULUS =
21888242871839275222246405745257275088548364400416034343698204186575808495617;
struct G1Point {
uint256 X;
uint256 Y;
}
// Encoding of field elements is: X[1] * i + X[0]
struct G2Point {
uint256[2] X;
uint256[2] Y;
}
function generatorG1() internal pure returns (G1Point memory) {
return G1Point(1, 2);
}
// generator of group G2
/// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
uint256 internal constant G2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 internal constant G2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 internal constant G2y1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 internal constant G2y0 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
/// @notice returns the G2 generator
/// @dev mind the ordering of the 1s and 0s!
/// this is because of the (unknown to us) convention used in the bn254 pairing precompile contract
/// "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)."
/// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding
function generatorG2() internal pure returns (G2Point memory) {
return G2Point([G2x1, G2x0], [G2y1, G2y0]);
}
// negation of the generator of group G2
/// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1).
uint256 internal constant nG2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 internal constant nG2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 internal constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052;
uint256 internal constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653;
function negGeneratorG2() internal pure returns (G2Point memory) {
return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]);
}
bytes32 internal constant powersOfTauMerkleRoot =
0x22c998e49752bbb1918ba87d6d59dd0e83620a311ba91dd4b2cc84990b31b56f;
/**
* @param p Some point in G1.
* @return The negation of `p`, i.e. p.plus(p.negate()) should be zero.
*/
function negate(G1Point memory p) internal pure returns (G1Point memory) {
// The prime q in the base field F_q for G1
if (p.X == 0 && p.Y == 0) {
return G1Point(0, 0);
} else {
return G1Point(p.X, FP_MODULUS - (p.Y % FP_MODULUS));
}
}
/**
* @return r the sum of two points of G1
*/
function plus(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
uint256[4] memory input;
input[0] = p1.X;
input[1] = p1.Y;
input[2] = p2.X;
input[3] = p2.Y;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
require(success, "ec-add-failed");
}
/**
* @notice an optimized ecMul implementation that takes O(log_2(s)) ecAdds
* @param p the point to multiply
* @param s the scalar to multiply by
* @dev this function is only safe to use if the scalar is 9 bits or less
*/
function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) {
require(s < 2**9, "scalar-too-large");
// if s is 1 return p
if(s == 1) {
return p;
}
// the accumulated product to return
BN254.G1Point memory acc = BN254.G1Point(0, 0);
// the 2^n*p to add to the accumulated product in each iteration
BN254.G1Point memory p2n = p;
// value of most significant bit
uint16 m = 1;
// index of most significant bit
uint8 i = 0;
//loop until we reach the most significant bit
while(s >= m){
unchecked {
// if the current bit is 1, add the 2^n*p to the accumulated product
if ((s >> i) & 1 == 1) {
acc = plus(acc, p2n);
}
// double the 2^n*p for the next iteration
p2n = plus(p2n, p2n);
// increment the index and double the value of the most significant bit
m <<= 1;
++i;
}
}
// return the accumulated product
return acc;
}
/**
* @return r the product of a point on G1 and a scalar, i.e.
* p == p.scalar_mul(1) and p.plus(p) == p.scalar_mul(2) for all
* points p.
*/
function scalar_mul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
uint256[3] memory input;
input[0] = p.X;
input[1] = p.Y;
input[2] = s;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
require(success, "ec-mul-failed");
}
/**
* @return The result of computing the pairing check
* e(p1[0], p2[0]) * .... * e(p1[n], p2[n]) == 1
* For example,
* pairing([P1(), P1().negate()], [P2(), P2()]) should return true.
*/
function pairing(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2
) internal view returns (bool) {
G1Point[2] memory p1 = [a1, b1];
G2Point[2] memory p2 = [a2, b2];
uint256[12] memory input;
for (uint256 i = 0; i < 2; i++) {
uint256 j = i * 6;
input[j + 0] = p1[i].X;
input[j + 1] = p1[i].Y;
input[j + 2] = p2[i].X[0];
input[j + 3] = p2[i].X[1];
input[j + 4] = p2[i].Y[0];
input[j + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(sub(gas(), 2000), 8, input, mul(12, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
require(success, "pairing-opcode-failed");
return out[0] != 0;
}
/**
* @notice This function is functionally the same as pairing(), however it specifies a gas limit
* the user can set, as a precompile may use the entire gas budget if it reverts.
*/
function safePairing(
G1Point memory a1,
G2Point memory a2,
G1Point memory b1,
G2Point memory b2,
uint256 pairingGas
) internal view returns (bool, bool) {
G1Point[2] memory p1 = [a1, b1];
G2Point[2] memory p2 = [a2, b2];
uint256[12] memory input;
for (uint256 i = 0; i < 2; i++) {
uint256 j = i * 6;
input[j + 0] = p1[i].X;
input[j + 1] = p1[i].Y;
input[j + 2] = p2[i].X[0];
input[j + 3] = p2[i].X[1];
input[j + 4] = p2[i].Y[0];
input[j + 5] = p2[i].Y[1];
}
uint256[1] memory out;
bool success;
// solium-disable-next-line security/no-inline-assembly
assembly {
success := staticcall(pairingGas, 8, input, mul(12, 0x20), out, 0x20)
}
//Out is the output of the pairing precompile, either 0 or 1 based on whether the two pairings are equal.
//Success is true if the precompile actually goes through (aka all inputs are valid)
return (success, out[0] != 0);
}
/// @return hashedG1 the keccak256 hash of the G1 Point
/// @dev used for BLS signatures
function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) {
assembly {
mstore(0, mload(pk))
mstore(0x20, mload(add(0x20, pk)))
hashedG1 := keccak256(0, 0x40)
}
}
/// @return the keccak256 hash of the G2 Point
/// @dev used for BLS signatures
function hashG2Point(
BN254.G2Point memory pk
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1]));
}
/**
* @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol
*/
function hashToG1(bytes32 _x) internal view returns (G1Point memory) {
uint256 beta = 0;
uint256 y = 0;
uint256 x = uint256(_x) % FP_MODULUS;
while (true) {
(beta, y) = findYFromX(x);
// y^2 == beta
if( beta == mulmod(y, y, FP_MODULUS) ) {
return G1Point(x, y);
}
x = addmod(x, 1, FP_MODULUS);
}
return G1Point(0, 0);
}
/**
* Given X, find Y
*
* where y = sqrt(x^3 + b)
*
* Returns: (x^3 + b), y
*/
function findYFromX(uint256 x) internal view returns (uint256, uint256) {
// beta = (x^3 + b) % p
uint256 beta = addmod(mulmod(mulmod(x, x, FP_MODULUS), x, FP_MODULUS), 3, FP_MODULUS);
// y^2 = x^3 + b
// this acts like: y = sqrt(beta) = beta^((p+1) / 4)
uint256 y = expMod(beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS);
return (beta, y);
}
function expMod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval) {
bool success;
uint256[1] memory output;
uint[6] memory input;
input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32))
input[1] = 0x20; // expLen = new(big.Int).SetBytes(getData(input, 32, 32))
input[2] = 0x20; // modLen = new(big.Int).SetBytes(getData(input, 64, 32))
input[3] = _base;
input[4] = _exponent;
input[5] = _modulus;
assembly {
success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20)
// Use "invalid" to make gas estimation work
switch success
case 0 {
invalid()
}
}
require(success, "BN254.expMod: call failure");
return output[0];
}
}
EigenDATypesV1.sol 79 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";
library EigenDATypesV1 {
struct VersionedBlobParams {
uint32 maxNumOperators;
uint32 numChunks;
uint8 codingRate;
}
struct SecurityThresholds {
uint8 confirmationThreshold;
uint8 adversaryThreshold;
}
struct QuorumBlobParam {
uint8 quorumNumber;
uint8 adversaryThresholdPercentage;
uint8 confirmationThresholdPercentage;
uint32 chunkLength;
}
struct BlobHeader {
BN254.G1Point commitment;
uint32 dataLength;
QuorumBlobParam[] quorumBlobParams;
}
struct ReducedBatchHeader {
bytes32 blobHeadersRoot;
uint32 referenceBlockNumber;
}
struct BatchHeader {
bytes32 blobHeadersRoot;
bytes quorumNumbers;
bytes signedStakeForQuorums;
uint32 referenceBlockNumber;
}
struct BatchMetadata {
BatchHeader batchHeader;
bytes32 signatoryRecordHash;
uint32 confirmationBlockNumber;
}
struct BlobVerificationProof {
uint32 batchId;
uint32 blobIndex;
BatchMetadata batchMetadata;
bytes inclusionProof;
bytes quorumIndices;
}
struct NonSignerStakesAndSignature {
uint32[] nonSignerQuorumBitmapIndices;
BN254.G1Point[] nonSignerPubkeys;
BN254.G1Point[] quorumApks;
BN254.G2Point apkG2;
BN254.G1Point sigma;
uint32[] quorumApkIndices;
uint32[] totalStakeIndices;
uint32[][] nonSignerStakeIndices;
}
struct QuorumStakeTotals {
uint96[] signedStakeForQuorum;
uint96[] totalStakeForQuorum;
}
struct CheckSignaturesIndices {
uint32[] nonSignerQuorumBitmapIndices;
uint32[] quorumApkIndices;
uint32[] totalStakeIndices;
uint32[][] nonSignerStakeIndices;
}
}
EigenDATypesV2.sol 59 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";
library EigenDATypesV2 {
struct RelayInfo {
address relayAddress;
string relayURL;
}
struct DisperserInfo {
address disperserAddress;
}
struct BlobInclusionInfo {
BlobCertificate blobCertificate;
uint32 blobIndex;
bytes inclusionProof;
}
struct BlobCertificate {
BlobHeaderV2 blobHeader;
bytes signature;
uint32[] relayKeys;
}
struct BlobHeaderV2 {
uint16 version;
bytes quorumNumbers;
BlobCommitment commitment;
bytes32 paymentHeaderHash;
}
struct BlobCommitment {
BN254.G1Point commitment;
BN254.G2Point lengthCommitment;
BN254.G2Point lengthProof;
uint32 length;
}
struct SignedBatch {
BatchHeaderV2 batchHeader;
Attestation attestation;
}
struct BatchHeaderV2 {
bytes32 batchRoot;
uint32 referenceBlockNumber;
}
struct Attestation {
BN254.G1Point[] nonSignerPubkeys;
BN254.G1Point[] quorumApks;
BN254.G1Point sigma;
BN254.G2Point apkG2;
uint32[] quorumNumbers;
}
}
BunnyInbox.sol 350 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {IEigenDACertVerifierBase} from "src/integrations/cert/interfaces/IEigenDACertVerifierBase.sol";
import {EigenDACertTypes as CT} from "src/integrations/cert/EigenDACertTypes.sol";
import {EigenDATypesV1 as DATypesV1} from "src/core/libraries/v1/EigenDATypesV1.sol";
import {EigenDATypesV2 as DATypesV2} from "src/core/libraries/v2/EigenDATypesV2.sol";
import {BN254} from "lib/eigenlayer-middleware/src/libraries/BN254.sol";
import {RLPReader} from "src/integrations/cert/libraries/RLPReader.sol";
/// @title BunnyInbox
/// @notice Implementation contract for RLP DA cert decoding, deployed behind a TransparentUpgradeableProxy
/// @dev Uses storage variable instead of immutable for verifier to support proxy pattern.
/// Accepts raw DA cert calldata via fallback() in format: 4-byte prefix + RLP-encoded EigenDACertV3
/// Prefix format: [0x01 op_version][0x01 generic_mode][0x00 da_layer][0x02 cert_version]
contract BunnyInbox is Initializable {
using RLPReader for bytes;
using RLPReader for RLPReader.RLPItem;
/// @notice The underlying cert verifier that will validate the decoded certificate
IEigenDACertVerifierBase public verifier;
/// @notice Length of the prefix to strip from raw calldata
uint256 public constant PREFIX_LENGTH = 4;
error InvalidRawCertLength();
error RLPDecodingFailed();
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}
/// @notice Initializes the contract with the verifier address
/// @param _verifier Address of the EigenDACertVerifier contract
function initialize(IEigenDACertVerifierBase _verifier) external initializer {
verifier = _verifier;
}
/// @notice Fallback function that verifies raw DA certificate from msg.data
/// @dev Processes msg.data directly: 4-byte prefix + RLP-encoded EigenDACertV3
/// Reverts if the certificate is invalid
fallback() external {
if (msg.data.length <= PREFIX_LENGTH) {
revert InvalidRawCertLength();
}
// Strip the 4-byte prefix
bytes memory rlpCert = msg.data[PREFIX_LENGTH:];
// Decode the RLP data into EigenDACertV3 struct
CT.EigenDACertV3 memory cert = _rlpDecodeCert(rlpCert);
// Call the verifier with struct directly (reverts on invalid cert)
verifier.checkDACertReverts(cert);
}
/// @notice Decodes RLP-encoded data into an EigenDACertV3 struct
/// @param rlpData RLP-encoded certificate data
/// @return cert The decoded EigenDACertV3 struct
function _rlpDecodeCert(bytes memory rlpData) internal pure returns (CT.EigenDACertV3 memory cert) {
// Top-level is a list of 4 items:
// [batchHeader, blobInclusionInfo, nonSignerStakesAndSignature, signedQuorumNumbers]
(uint256 currPtr, ) = _listHead(rlpData.toRlpItem());
RLPReader.RLPItem memory item;
(item, currPtr) = _nextItem(currPtr);
cert.batchHeader = _decodeBatchHeaderV2(item);
(item, currPtr) = _nextItem(currPtr);
cert.blobInclusionInfo = _decodeBlobInclusionInfo(item);
(item, currPtr) = _nextItem(currPtr);
cert.nonSignerStakesAndSignature = _decodeNonSignerStakesAndSignature(item);
(item, ) = _nextItem(currPtr);
cert.signedQuorumNumbers = item.toBytes();
}
/// @notice Decodes BatchHeaderV2 from RLP
function _decodeBatchHeaderV2(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV2.BatchHeaderV2 memory header)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
header.batchRoot = field.toBytes32();
(field, ) = _nextItem(currPtr);
header.referenceBlockNumber = field.toUint32();
}
/// @notice Decodes BlobInclusionInfo from RLP
function _decodeBlobInclusionInfo(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV2.BlobInclusionInfo memory info)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
info.blobCertificate = _decodeBlobCertificate(field);
(field, currPtr) = _nextItem(currPtr);
info.blobIndex = field.toUint32();
(field, ) = _nextItem(currPtr);
info.inclusionProof = field.toBytes();
}
/// @notice Decodes BlobCertificate from RLP
function _decodeBlobCertificate(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV2.BlobCertificate memory cert)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
cert.blobHeader = _decodeBlobHeaderV2(field);
(field, currPtr) = _nextItem(currPtr);
cert.signature = field.toBytes();
(field, ) = _nextItem(currPtr);
cert.relayKeys = _decodeUint32Array(field);
}
/// @notice Decodes BlobHeaderV2 from RLP
function _decodeBlobHeaderV2(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV2.BlobHeaderV2 memory header)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
header.version = field.toUint16();
(field, currPtr) = _nextItem(currPtr);
header.quorumNumbers = field.toBytes();
(field, currPtr) = _nextItem(currPtr);
header.commitment = _decodeBlobCommitment(field);
(field, ) = _nextItem(currPtr);
header.paymentHeaderHash = field.toBytes32();
}
/// @notice Decodes BlobCommitment from RLP
function _decodeBlobCommitment(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV2.BlobCommitment memory commitment)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
commitment.commitment = _decodeG1Point(field);
(field, currPtr) = _nextItem(currPtr);
commitment.lengthCommitment = _decodeG2Point(field);
(field, currPtr) = _nextItem(currPtr);
commitment.lengthProof = _decodeG2Point(field);
(field, ) = _nextItem(currPtr);
commitment.length = field.toUint32();
}
/// @notice Decodes NonSignerStakesAndSignature from RLP
function _decodeNonSignerStakesAndSignature(RLPReader.RLPItem memory item)
internal
pure
returns (DATypesV1.NonSignerStakesAndSignature memory sig)
{
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
sig.nonSignerQuorumBitmapIndices = _decodeUint32Array(field);
(field, currPtr) = _nextItem(currPtr);
sig.nonSignerPubkeys = _decodeG1PointArray(field);
(field, currPtr) = _nextItem(currPtr);
sig.quorumApks = _decodeG1PointArray(field);
(field, currPtr) = _nextItem(currPtr);
sig.apkG2 = _decodeG2Point(field);
(field, currPtr) = _nextItem(currPtr);
sig.sigma = _decodeG1Point(field);
(field, currPtr) = _nextItem(currPtr);
sig.quorumApkIndices = _decodeUint32Array(field);
(field, currPtr) = _nextItem(currPtr);
sig.totalStakeIndices = _decodeUint32Array(field);
(field, ) = _nextItem(currPtr);
sig.nonSignerStakeIndices = _decodeUint32ArrayArray(field);
}
/// @notice Decodes a G1Point from RLP (2-element list: X, Y)
function _decodeG1Point(RLPReader.RLPItem memory item) internal pure returns (BN254.G1Point memory point) {
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
point.X = field.toUint256();
(field, ) = _nextItem(currPtr);
point.Y = field.toUint256();
}
/// @notice Decodes a G2Point from RLP (2-element list: X[2], Y[2])
function _decodeG2Point(RLPReader.RLPItem memory item) internal pure returns (BN254.G2Point memory point) {
(uint256 currPtr, ) = _listHead(item);
RLPReader.RLPItem memory field;
(field, currPtr) = _nextItem(currPtr);
// X is a 2-element list
{
(uint256 xPtr, ) = _listHead(field);
RLPReader.RLPItem memory xField;
(xField, xPtr) = _nextItem(xPtr);
point.X[0] = xField.toUint256();
(xField, ) = _nextItem(xPtr);
point.X[1] = xField.toUint256();
}
(field, ) = _nextItem(currPtr);
// Y is a 2-element list
{
(uint256 yPtr, ) = _listHead(field);
RLPReader.RLPItem memory yField;
(yField, yPtr) = _nextItem(yPtr);
point.Y[0] = yField.toUint256();
(yField, ) = _nextItem(yPtr);
point.Y[1] = yField.toUint256();
}
}
/// @notice Decodes an array of G1Points from RLP
function _decodeG1PointArray(RLPReader.RLPItem memory item)
internal
pure
returns (BN254.G1Point[] memory points)
{
(uint256 currPtr, uint256 endPtr) = _listHead(item);
// Count items
uint256 count = 0;
uint256 scanPtr = currPtr;
unchecked {
while (scanPtr < endPtr) {
scanPtr = scanPtr + RLPReader._itemLength(scanPtr);
++count;
}
}
points = new BN254.G1Point[](count);
unchecked {
for (uint256 i = 0; i < count; ++i) {
uint256 itemLen = RLPReader._itemLength(currPtr);
RLPReader.RLPItem memory pointItem = RLPReader.RLPItem(itemLen, currPtr);
points[i] = _decodeG1Point(pointItem);
currPtr = currPtr + itemLen;
}
}
}
function _listHead(RLPReader.RLPItem memory item) private pure returns (uint256 currPtr, uint256 endPtr) {
require(item.isList(), "RLPReader: item is not a list");
currPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
endPtr = item.memPtr + item.len;
}
function _nextItem(uint256 currPtr)
private
pure
returns (RLPReader.RLPItem memory item, uint256 nextPtr)
{
uint256 itemLen = RLPReader._itemLength(currPtr);
item = RLPReader.RLPItem(itemLen, currPtr);
nextPtr = currPtr + itemLen;
}
/// @notice Decodes an array of uint32 from RLP
function _decodeUint32Array(RLPReader.RLPItem memory item) internal pure returns (uint32[] memory arr) {
require(item.isList(), "RLPReader: item is not a list");
uint256 memPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
// Count items
uint256 count = 0;
uint256 currPtr = memPtr;
unchecked {
while (currPtr < endPtr) {
currPtr = currPtr + RLPReader._itemLength(currPtr);
++count;
}
}
// Allocate final array (no intermediate RLPItem[])
arr = new uint32[](count);
// Decode directly to uint32[]
currPtr = memPtr;
unchecked {
for (uint256 i = 0; i < count; ++i) {
uint256 itemLen = RLPReader._itemLength(currPtr);
uint256 offset = RLPReader._payloadOffset(currPtr);
uint256 dataLen = itemLen - offset;
uint256 value;
assembly {
value := mload(add(currPtr, offset))
if lt(dataLen, 32) {
value := shr(shl(3, sub(32, dataLen)), value)
}
}
arr[i] = uint32(value);
currPtr = currPtr + itemLen;
}
}
}
/// @notice Decodes a 2D array of uint32 from RLP
function _decodeUint32ArrayArray(RLPReader.RLPItem memory item) internal pure returns (uint32[][] memory arr) {
require(item.isList(), "RLPReader: item is not a list");
uint256 memPtr = item.memPtr + RLPReader._payloadOffset(item.memPtr);
uint256 endPtr = item.memPtr + item.len;
// Count outer array items
uint256 count = 0;
uint256 currPtr = memPtr;
unchecked {
while (currPtr < endPtr) {
currPtr = currPtr + RLPReader._itemLength(currPtr);
++count;
}
}
// Allocate outer array
arr = new uint32[][](count);
// Decode each inner array directly
currPtr = memPtr;
unchecked {
for (uint256 i = 0; i < count; ++i) {
uint256 itemLen = RLPReader._itemLength(currPtr);
// Create RLPItem for the inner array and decode it
RLPReader.RLPItem memory innerItem = RLPReader.RLPItem(itemLen, currPtr);
arr[i] = _decodeUint32Array(innerItem);
currPtr = currPtr + itemLen;
}
}
}
}
EigenDACertTypes.sol 17 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {EigenDATypesV1 as DATypesV1} from "src/core/libraries/v1/EigenDATypesV1.sol";
import {EigenDATypesV2 as DATypesV2} from "src/core/libraries/v2/EigenDATypesV2.sol";
/// @title EigenDACertTypes
/// @notice This library defines the types for each EigenDA certificate version.
/// @dev It is required that RBN be located in positions 32:64 (padded) in the ABI encoded certificate.
library EigenDACertTypes {
struct EigenDACertV3 {
DATypesV2.BatchHeaderV2 batchHeader;
DATypesV2.BlobInclusionInfo blobInclusionInfo;
DATypesV1.NonSignerStakesAndSignature nonSignerStakesAndSignature;
bytes signedQuorumNumbers;
}
}
IEigenDACertVerifierBase.sol 19 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
import {EigenDACertTypes as CT} from "src/integrations/cert/EigenDACertTypes.sol";
interface IEigenDACertVerifierBase {
/// @notice Check a DA cert's validity
/// @param abiEncodedCert The ABI encoded certificate. Any cert verifier should decode this ABI encoding based on the certificate version.
/// @return status An enum value. Success is always mapped to 1, and other values are errors specific to each CertVerifier.
/// @dev This function should never revert on invalid certs, and should instead return an error status code.
/// This is because cert invalidity needs to be proven to the rollup's derivation pipeline that the cert can be discarded.
/// We use Risc0's Steel library for this purpose, which doesn't support reverts: https://github.com/risc0/risc0-ethereum/issues/438
function checkDACert(bytes calldata abiEncodedCert) external view returns (uint8 status);
/// @notice Check a DA cert's validity, reverting on failure
/// @param daCert The EigenDA certificate
/// @dev This function will revert if the certificate is invalid.
function checkDACertReverts(CT.EigenDACertV3 calldata daCert) external view;
}
RLPReader.sol 341 lines
// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns * https://github.com/hamdiallam/Solidity-RLP */ pragma solidity ^0.8.9; library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint256 len; uint256 memPtr; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint256 memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item), "RLPReader: item is not a list"); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; // Single-pass list decoding: count items and cache their positions/lengths uint256 itemCount = 0; uint256 currPtr = memPtr; // First, count items (unavoidable to allocate array) unchecked { while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); ++itemCount; } } // Allocate result array RLPItem[] memory result = new RLPItem[](itemCount); // Second pass: populate array (but we already have the structure) currPtr = memPtr; unchecked { for (uint256 i = 0; i < itemCount; ++i) { uint256 itemLen = _itemLength(currPtr); result[i] = RLPItem(itemLen, currPtr); currPtr = currPtr + itemLen; } } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint256 memPtr) internal pure returns (uint256) { uint256 itemLen; uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { itemLen = 1; } else if (byte0 < STRING_LONG_START) { itemLen = byte0 - STRING_SHORT_START + 1; } else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ // Use bit shift instead of exp: shr(bits, x) = x >> bits = x / 2^bits let dataLen := shr(mul(8, sub(32, byteLen)), mload(memPtr)) itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) // Use bit shift instead of exp: shr(bits, x) = x >> bits = x / 2^bits let dataLen := shr(mul(8, sub(32, byteLen)), mload(memPtr)) itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint256 memPtr) internal pure returns (uint256) { uint256 byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) { return 0; } else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) { return 1; } else if (byte0 < LIST_SHORT_START) { // being explicit return byte0 - (STRING_LONG_START - 1) + 1; } else { return byte0 - (LIST_LONG_START - 1) + 1; } } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint256 src, uint256 dest, uint256 len) private pure { if (len == 0) return; // copy as many word sizes as possible unchecked { for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word // Use bit shift instead of exp: 256 ** x = 2 ** (8 * x) = 1 << (8 * x) uint256 mask; assembly { mask := sub(shl(mul(8, sub(WORD_SIZE, len)), 1), 1) let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } /* * Additional helper functions for EigenDA cert decoding */ /// @notice Convert RLPItem to bytes function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0, "RLPReader: item has no data"); uint256 memPtr = item.memPtr; uint256 len = item.len; uint256 offset; assembly { let byte0 := byte(0, mload(memPtr)) // Inline _payloadOffset calculation switch lt(byte0, 0x80) case 1 { offset := 0 } default { switch lt(byte0, 0xb8) case 1 { offset := 1 } default { switch lt(byte0, 0xc0) case 1 { offset := add(sub(byte0, 0xb7), 1) } default { switch lt(byte0, 0xf8) case 1 { offset := 1 } default { offset := add(sub(byte0, 0xf7), 1) } } } } } len = len - offset; bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(result, 0x20) } copy(memPtr + offset, destPtr, len); return result; } /// @notice Convert RLPItem to bytes32 function toBytes32(RLPItem memory item) internal pure returns (bytes32 result) { require(item.len > 0, "RLPReader: item has no data"); uint256 memPtr = item.memPtr; uint256 len = item.len; assembly { let byte0 := byte(0, mload(memPtr)) let offset := 0 // Inline _payloadOffset calculation switch lt(byte0, 0x80) case 1 { offset := 0 } default { switch lt(byte0, 0xb8) case 1 { offset := 1 } default { switch lt(byte0, 0xc0) case 1 { offset := add(sub(byte0, 0xb7), 1) } default { switch lt(byte0, 0xf8) case 1 { offset := 1 } default { offset := add(sub(byte0, 0xf7), 1) } } } } memPtr := add(memPtr, offset) len := sub(len, offset) // Validate length if gt(len, 32) { mstore(0x00, 0x08c379a0) // Error selector for "Error(string)" mstore(0x04, 0x20) mstore(0x24, 26) // Length of error message mstore(0x44, "RLPReader: bytes32 overflow") revert(0x00, 0x64) } result := mload(memPtr) // Right-align if less than 32 bytes if lt(len, 32) { result := shr(mul(8, sub(32, len)), result) } } } /// @notice Convert RLPItem to uint256 function toUint256(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33, "RLPReader: invalid uint256"); uint256 memPtr = item.memPtr; uint256 len = item.len; uint256 result; assembly { let byte0 := byte(0, mload(memPtr)) let offset := 0 // Inline _payloadOffset calculation switch lt(byte0, 0x80) case 1 { offset := 0 } default { switch lt(byte0, 0xb8) case 1 { offset := 1 } default { switch lt(byte0, 0xc0) case 1 { offset := add(sub(byte0, 0xb7), 1) } default { switch lt(byte0, 0xf8) case 1 { offset := 1 } default { offset := add(sub(byte0, 0xf7), 1) } } } } memPtr := add(memPtr, offset) len := sub(len, offset) // Validate length if gt(len, 32) { mstore(0x00, 0x08c379a0) // Error selector for "Error(string)" mstore(0x04, 0x20) mstore(0x24, 27) // Length of error message mstore(0x44, "RLPReader: uint256 overflow") revert(0x00, 0x64) } result := mload(memPtr) // Right-align the value using bit shift if lt(len, 32) { result := shr(mul(8, sub(32, len)), result) } } return result; } /// @notice Convert RLPItem to uint32 function toUint32(RLPItem memory item) internal pure returns (uint32) { return uint32(toUint256(item)); } /// @notice Convert RLPItem to uint16 function toUint16(RLPItem memory item) internal pure returns (uint16) { return uint16(toUint256(item)); } }
Read Contract
PREFIX_LENGTH 0x2418833f → uint256
verifier 0x2b7ac3f3 → address
Write Contract 1 functions
These functions modify contract state and require a wallet transaction to execute.
initialize 0xc4d66de8
address _verifier
Recent Transactions
This address has 1 on-chain transactions, but only 0.8% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →