Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 30 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Poke | 22946031 | 231 days ago | IN | 0 ETH | 0.00035549 | ||||
| Poke | 22944235 | 231 days ago | IN | 0 ETH | 0.00035245 | ||||
| Poke | 22942446 | 232 days ago | IN | 0 ETH | 0.00021202 | ||||
| Poke | 22940652 | 232 days ago | IN | 0 ETH | 0.00054487 | ||||
| Poke | 22938852 | 232 days ago | IN | 0 ETH | 0.00029594 | ||||
| Poke | 22937052 | 232 days ago | IN | 0 ETH | 0.00007843 | ||||
| Poke | 22935256 | 233 days ago | IN | 0 ETH | 0.00013295 | ||||
| Poke | 22933462 | 233 days ago | IN | 0 ETH | 0.0014392 | ||||
| Poke | 22931667 | 233 days ago | IN | 0 ETH | 0.00026371 | ||||
| Poke | 22929867 | 233 days ago | IN | 0 ETH | 0.00005717 | ||||
| Poke | 22928075 | 234 days ago | IN | 0 ETH | 0.00010415 | ||||
| Rely | 22737182 | 260 days ago | IN | 0 ETH | 0.00002953 | ||||
| Deny | 22737165 | 260 days ago | IN | 0 ETH | 0.00001031 | ||||
| Rely | 22737104 | 260 days ago | IN | 0 ETH | 0.00003553 | ||||
| Deny | 22737099 | 260 days ago | IN | 0 ETH | 0.00001086 | ||||
| Rely | 22737093 | 260 days ago | IN | 0 ETH | 0.00001005 | ||||
| Rely | 22737092 | 260 days ago | IN | 0 ETH | 0.00001091 | ||||
| Set Bar Schnorr | 22737089 | 260 days ago | IN | 0 ETH | 0.00001076 | ||||
| Set Bar ECDSA | 22737087 | 260 days ago | IN | 0 ETH | 0.00001075 | ||||
| Set Bar ECDSA | 22737008 | 260 days ago | IN | 0 ETH | 0.00001316 | ||||
| Set Bar Schnorr | 22737007 | 260 days ago | IN | 0 ETH | 0.00001176 | ||||
| Rely | 22737002 | 260 days ago | IN | 0 ETH | 0.00002871 | ||||
| Rely | 22737000 | 260 days ago | IN | 0 ETH | 0.00002908 | ||||
| Kiss | 22736872 | 260 days ago | IN | 0 ETH | 0.00001957 | ||||
| Rely | 22736852 | 260 days ago | IN | 0 ETH | 0.0000266 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x60c06040 | 22732401 | 261 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ChronicleVAO_Superstate_USTB_Consumer_1
Compiler Version
v0.8.28+commit.7893614a
Optimization Enabled:
Yes with 10000 runs
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.28;
import {Toll} from "chronicle-std/toll/Toll.sol";
import {UScribe} from "uscribe/UScribe.sol";
import {IChronicleVAO_Superstate_USTB_Reader as IReader} from "./IReader.sol";
import {TollWithImmutableRouter} from "./TollWithImmutableRouter.sol";
// The poke struct is the single struct that is being poked.
struct PokeData {
uint48 age;
uint128 val;
}
/**
* @title ChronicleVAO_Superstate_USTB_Consumer_1
* @custom:version 1.2.0
*
* @author Chronicle Labs, Inc
* @custom:security-contact security@chroniclelabs.org
*/
contract ChronicleVAO_Superstate_USTB_Consumer_1 is
UScribe,
TollWithImmutableRouter,
IReader
{
/// @notice Thrown if attempted to poke a stale message.
error StaleMessage();
/// @notice Thrown if attempted to poke a future message.
error FutureMessage();
/// @notice Emitted when a poke is received.
/// @param caller The caller's address.
/// @param val The value poked.
/// @param age The age of the value poked.
event Poked(address indexed caller, uint128 val, uint48 age);
//--------------------------------------------------------------------------
// Storage
/// @dev The last received poke data (note that age is the block timestamp
/// when the poke data was received).
///
/// @dev Note that any data signed beforehand is deemed stale and not
/// accepted.
PokeData internal _pokeData;
//--------------------------------------------------------------------------
// Constructor
constructor(address initialAuthed, address router)
UScribe(initialAuthed, "VAO::Superstate_USTB")
TollWithImmutableRouter(router)
{}
/// @dev Defines authorization for IToll's authenticated functions.
function toll_auth() internal override(TollWithImmutableRouter) auth {}
//--------------------------------------------------------------------------
// Poke Functionality
/// @dev Function to handle state update.
///
/// This function is being called by the upstream uScribe
/// implementation iff the poke's signature verification succeeded.
///
/// Therefore, this function MUST only verify the payload contains
/// correctly encoded, non-stale and non-future data before committing a state update.
///
/// @dev Reverts if:
/// - Decoding payload to expected format fails
///
/// @dev Returns error if:
/// - Payload is stale
/// - Payload is signed at a future date to block timestamp
///
/// @dev The payload is expected to be encoded using the PokeData struct
/// containing the fields:
///
/// - age: uint48
/// - val: uint128
///
/// @dev The age stored after a poke is equal to the current block time,
/// not the age sent in the poke.
function _poke(bytes calldata payload)
internal
override(UScribe)
returns (bytes4)
{
PokeData memory pokeData = abi.decode(payload, (PokeData));
// Fail if payload stale.
if (pokeData.age <= _pokeData.age) {
return StaleMessage.selector;
}
// Fail if payload from the future.
if (pokeData.age > block.timestamp) {
return FutureMessage.selector;
}
// Store the poke data.
_pokeData = PokeData({val: pokeData.val, age: uint48(block.timestamp)});
emit Poked(msg.sender, pokeData.val, pokeData.age);
return _NO_ERR;
}
//--------------------------------------------------------------------------
// IReader Functionality
//
// Note that read functions differ from Scribe with regards to `val = 0` not
// being a failure code. Read function only revert/fail if `age = 0`,
// implying no valid poke occured yet.
//
// Side effect of this is that the read functions cannot be disabled.
//// @inheritdoc IVAOReader
function read() public view toll returns (uint val) {
bool ok;
(ok, val,) = _tryReadWithAge();
require(ok);
}
//// @inheritdoc IVAOReader
function tryRead() public view toll returns (bool ok, uint val) {
(ok, val,) = _tryReadWithAge();
// assert(ok || val == 0);
}
//// @inheritdoc IVAOReader
function readWithAge() public view toll returns (uint val, uint age) {
bool ok;
(ok, val, age) = _tryReadWithAge();
require(ok);
}
//// @inheritdoc IVAOReader
function tryReadWithAge()
public
view
toll
returns (bool ok, uint val, uint age)
{
(ok, val, age) = _tryReadWithAge();
}
function _tryReadWithAge()
internal
view
returns (bool ok, uint val, uint age)
{
PokeData memory pokeData = _pokeData;
val = pokeData.val;
age = pokeData.age;
ok = age != 0;
// assert(ok || val == 0);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
import {IToll} from "./IToll.sol";
/**
* @title Toll Module
*
* @notice "Toll paid, we kiss - but dissension looms, maybe diss?"
*
* @dev The `Toll` contract module provides a basic access control mechanism,
* where a set of addresses are granted access to protected functions.
* These addresses are said the be _tolled_.
*
* Initially, no address is tolled. Through the `kiss(address)` and
* `diss(address)` functions, auth'ed callers are able to toll/de-toll
* addresses. Authentication for these functions is defined via the
* downstream implemented `toll_auth()` function.
*
* This module is used through inheritance. It will make available the
* modifier `toll`, which can be applied to functions to restrict their
* use to only tolled callers.
*/
abstract contract Toll is IToll {
/// @dev Mapping storing whether address is tolled.
/// @custom:invariant Image of mapping is {0, 1}.
/// ∀x ∊ Address: _buds[x] ∊ {0, 1}
/// @custom:invariant Only functions `kiss` and `diss` may mutate the mapping's state.
/// ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
/// → (msg.sig == "kiss" ∨ msg.sig == "diss")
/// @custom:invariant Mapping's state may only be mutated by authenticated caller.
/// ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
/// → toll_auth()
mapping(address => uint) private _buds;
/// @dev List of addresses possibly being tolled.
/// @dev May contain duplicates.
/// @dev May contain addresses not being tolled anymore.
/// @custom:invariant Every address being tolled once is element of the list.
/// ∀x ∊ Address: tolled(x) → x ∊ _budsTouched
address[] private _budsTouched;
/// @dev Ensures caller is tolled.
modifier toll() {
assembly ("memory-safe") {
// Compute slot of _buds[msg.sender].
mstore(0x00, caller())
mstore(0x20, _buds.slot)
let slot := keccak256(0x00, 0x40)
// Revert if caller not tolled.
let isTolled := sload(slot)
if iszero(isTolled) {
// Store selector of `NotTolled(address)`.
mstore(0x00, 0xd957b595)
// Store msg.sender.
mstore(0x20, caller())
// Revert with (offset, size).
revert(0x1c, 0x24)
}
}
_;
}
/// @dev Reverts if caller not allowed to access protected function.
/// @dev Must be implemented in downstream contract.
function toll_auth() internal virtual;
/// @inheritdoc IToll
function kiss(address who) external {
toll_auth();
if (_buds[who] == 1) return;
_buds[who] = 1;
_budsTouched.push(who);
emit TollGranted(msg.sender, who);
}
/// @inheritdoc IToll
function diss(address who) external {
toll_auth();
if (_buds[who] == 0) return;
_buds[who] = 0;
emit TollRenounced(msg.sender, who);
}
/// @inheritdoc IToll
function tolled(address who) public view returns (bool) {
return _buds[who] == 1;
}
/// @inheritdoc IToll
/// @custom:invariant Only contains tolled addresses.
/// ∀x ∊ tolled(): _tolled[x]
/// @custom:invariant Contains all tolled addresses.
/// ∀x ∊ Address: _tolled[x] == 1 → x ∊ tolled()
function tolled() public view returns (address[] memory) {
// Initiate array with upper limit length.
address[] memory budsList = new address[](_budsTouched.length);
// Iterate through all possible tolled addresses.
uint ctr;
for (uint i; i < budsList.length; i++) {
// Add address only if still tolled.
if (_buds[_budsTouched[i]] == 1) {
budsList[ctr++] = _budsTouched[i];
}
}
// Set length of array to number of tolled addresses actually included.
assembly ("memory-safe") {
mstore(budsList, ctr)
}
return budsList;
}
/// @inheritdoc IToll
function bud(address who) public view returns (uint) {
return _buds[who];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;
import {Auth} from "chronicle-std/auth/Auth.sol";
import {IUScribe} from "./IUScribe.sol";
import {UPokeData, SchnorrData, ECDSAData} from "./Types.sol";
import {LibSchnorr} from "./libs/LibSchnorr.sol";
import {LibSecp256k1} from "./libs/LibSecp256k1.sol";
/**
* @title UScribe
* @custom:version 1.2.0
*
* @notice A universal Oracle
*
* @author Chronicle Labs, Inc
* @custom:security-contact security@chroniclelabs.org
*/
abstract contract UScribe is IUScribe, Auth {
using LibSchnorr for LibSecp256k1.Point;
using LibSecp256k1 for LibSecp256k1.Point;
using LibSecp256k1 for LibSecp256k1.JacobianPoint;
//--------------------------------------------------------------------------
// Constants and Immutables
bytes4 internal constant _NO_ERR = bytes4(0);
bytes32 public immutable wat;
// Note that strings cannot be marked as immutable.
// @custom:invariant Is immutable.
string private _name;
//--------------------------------------------------------------------------
// Storage
struct SchnorrStorage {
LibSecp256k1.Point[256] pubKeys;
uint8 bar;
}
SchnorrStorage private __schnorrStorage;
struct ECDSAStorage {
address[256] validators;
uint8 bar;
}
ECDSAStorage private __ecdsaStorage;
//--------------------------------------------------------------------------
// Constructor
constructor(address initialAuthed, string memory name_)
Auth(initialAuthed)
{
require(bytes(name_).length != 0);
_name = name_;
wat = keccak256(bytes(name_));
// Note to not have bars of zero.
__schnorrStorage.bar = type(uint8).max;
__ecdsaStorage.bar = type(uint8).max;
}
/// @inheritdoc IUScribe
function name() external view returns (string memory) {
return _name;
}
//--------------------------------------------------------------------------
// Consumer Implemented Functionality
/// @dev Function implemented in downstream consumer contract to handle
/// application specific state update.
///
/// @dev The implementation MUST deserialize the payload and perform
/// necessary sanity checks.
///
/// It SHOULD NOT revert but instead return the error types' selector
/// whenever possible. This allows uScribe to wrap the application
/// specific error into a `PokeError_ConsumerRejectedPayload()` error.
///
/// To indicate a successful poke, the function MUST return the
/// `_NO_ERR = bytes4(0)` constant.
///
/// @dev Note that this function is vulnerable to replay attacks.
///
/// Consumers MUST implement application specific logic to prevent
/// replayability issues. uScribe only verifies that the respective
/// validators attested to the payload at some point in time, ie
/// uScribe performs a stateless signature verification.
///
/// Note that this requires the payload to contain sufficient data for
/// the consumer logic to protect against replayability issues.
///
/// Protections against replayability issues MAY be including a nonce
/// in the payload or only accepting payloads with strictly
/// monotonically increasing timestamps.
///
/// To protect against cross-chain replayability issues the payload
/// MAY be expected to include the chain's id.
///
/// @param payload The verified payload blob.
/// @return bytes4 `_NO_ERR` if poke successful, application's error type
/// selector otherwise.
function _poke(bytes calldata payload) internal virtual returns (bytes4);
//--------------------------------------------------------------------------
// Poke Functionality
/// @inheritdoc IUScribe
function poke(UPokeData calldata uPokeData, SchnorrData calldata schnorr)
external
{
bytes4 err;
bytes32 message;
// Construct Schnorr Chronicle Signed Message of uPokeData.
message = constructChronicleSignedMessage({
scheme: bytes32("SCHNORR"),
uPokeData: uPokeData
});
// Verify Schnorr signature.
err = __verifySchnorrSignature(message, schnorr);
if (err != _NO_ERR) {
revert PokeError_VerificationFailed(err);
}
// Poke's security verified.
emit UPoked(msg.sender, uPokeData.proofURI);
// Forward payload to consumer.
err = _poke(uPokeData.payload);
if (err != _NO_ERR) {
revert PokeError_ConsumerRejectedPayload(err);
}
}
/// @inheritdoc IUScribe
function poke(UPokeData calldata uPokeData, ECDSAData[] calldata ecdsas)
external
{
bytes4 err;
bytes32 message;
// Construct ECDSA Chronicle Signed Message of uPokeData.
message = constructChronicleSignedMessage({
scheme: bytes32("ECDSA"),
uPokeData: uPokeData
});
// Verify ECDSA signatures.
err = __verifyECDSASignatures(message, ecdsas);
if (err != _NO_ERR) {
revert PokeError_VerificationFailed(err);
}
// Poke's security verified.
emit UPoked(msg.sender, uPokeData.proofURI);
// Forward payload to consumer.
err = _poke(uPokeData.payload);
if (err != _NO_ERR) {
revert PokeError_ConsumerRejectedPayload(err);
}
}
//--------------------------------------------------------------------------
// Chronicle Signed Message Functionality
/// @inheritdoc IUScribe
function constructChronicleSignedMessage(
bytes32 scheme,
UPokeData calldata uPokeData
) public view returns (bytes32) {
return keccak256(
abi.encodePacked(
"\x19Chronicle Signed Message:\n32",
keccak256(
abi.encodePacked(
scheme,
wat,
keccak256(abi.encodePacked(uPokeData.payload)),
keccak256(abi.encodePacked(uPokeData.proofURI))
)
)
)
);
}
//--------------------------------------------------------------------------
// Signature Verification Functionality
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Runtime is O(__schnorrStorage.bar).
function __verifySchnorrSignature(
bytes32 message,
SchnorrData calldata schnorr
) private view returns (bytes4) {
// Let pubKey be the currently processed validator's public key.
LibSecp256k1.Point memory pubKey;
// Let id be the currently processed validator's id.
uint8 id;
// Let aggPubKey be the sum of processed validator public keys.
// Note that Jacobian coordinates are used.
LibSecp256k1.JacobianPoint memory aggPubKey;
// Let bloom be a bloom filter to guarantee signer uniqueness.
uint bloom;
// Fail if number of validators unequal to bar.
//
// Note that requiring equality constrains the verification's runtime
// from Ω(bar) to Θ(bar).
uint bar = __schnorrStorage.bar;
if (schnorr.validatorIds.length != bar) {
return VerificationError_BarNotReached.selector;
}
// Initiate validator variables.
id = uint8(schnorr.validatorIds[0]);
pubKey = __schnorrStorage.pubKeys[id];
if (pubKey.isZeroPoint()) {
return VerificationError_ValidatorInvalid.selector;
}
// Initiate bloom filter and aggPubKey.
bloom = 1 << id;
aggPubKey = pubKey.toJacobian();
// Aggregation loop.
for (uint i = 1; i < bar; i++) {
// Update validator variables.
id = uint8(schnorr.validatorIds[i]);
pubKey = __schnorrStorage.pubKeys[id];
if (pubKey.isZeroPoint()) {
return VerificationError_ValidatorInvalid.selector;
}
// Fail if double signing attempted.
if (bloom & (1 << id) != 0) {
return VerificationError_DoubleSigningAttempted.selector;
}
// Update bloom filter.
bloom |= 1 << id;
// Add pubKey to aggPubKey.
aggPubKey.addAffinePoint(pubKey);
}
// Perform signature verification.
bool ok = aggPubKey.toAffine().verifySignature(
message, schnorr.signature, schnorr.commitment
);
if (!ok) {
return VerificationError_SignatureInvalid.selector;
}
return _NO_ERR;
}
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Runtime is O(__ecdsaStorage.bar).
function __verifyECDSASignatures(
bytes32 message,
ECDSAData[] calldata ecdsas
) private view returns (bytes4) {
// Let ecdsa be the currently processed ECDSA signature.
ECDSAData memory ecdsa;
// Let signer be the currently processed ECDSA signature's signer.
address signer;
// Let id the the currently processed ECDSA signature's signer id.
uint id;
// Let bloom be a bloom filter to guarantee signer uniqueness.
uint bloom;
// Fail if number of validators unequal to bar.
//
// Note that requiring equality constrains the verification's runtime
// from Ω(bar) to Θ(bar).
uint bar = __ecdsaStorage.bar;
if (ecdsas.length != bar) {
return VerificationError_BarNotReached.selector;
}
for (uint i; i < bar; i++) {
// Update ECDSA variables.
ecdsa = ecdsas[i];
signer = ecrecover(message, ecdsa.v, ecdsa.r, ecdsa.s);
id = uint160(signer) >> 152;
// Fail if signature invalid or signer not a validator.
// forgefmt: disable-next-item
if (signer == address(0) || __ecdsaStorage.validators[id] != signer) {
return VerificationError_SignatureInvalid.selector;
}
// Fail if double signing attempted.
if (bloom & (1 << id) != 0) {
return VerificationError_DoubleSigningAttempted.selector;
}
// Update bloom filter.
bloom |= 1 << id;
}
return _NO_ERR;
}
//--------------------------------------------------------------------------
// Auth'ed Functionality
//----------------------------------
// SchnorrStorage
/// @inheritdoc IUScribe
function liftSchnorr(LibSecp256k1.Point[] calldata pubKeys) external auth {
for (uint i; i < pubKeys.length; i++) {
LibSecp256k1.Point memory pubKey = pubKeys[i];
require(!pubKey.isZeroPoint());
// assert(pubKey.toAddress() != address(0));
address validator = pubKey.toAddress();
uint id = uint160(validator) >> 152;
LibSecp256k1.Point memory sPubKey = __schnorrStorage.pubKeys[id];
if (sPubKey.isZeroPoint()) {
__schnorrStorage.pubKeys[id] = pubKey;
emit ValidatorLiftedSchnorr(msg.sender, validator);
} else {
require(validator == sPubKey.toAddress());
}
}
}
/// @inheritdoc IUScribe
function dropSchnorr(uint8[] calldata ids) external auth {
for (uint i; i < ids.length; i++) {
uint8 id = ids[i];
LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];
if (!pubKey.isZeroPoint()) {
delete __schnorrStorage.pubKeys[id];
emit ValidatorDroppedSchnorr(msg.sender, pubKey.toAddress());
}
}
}
/// @inheritdoc IUScribe
function setBarSchnorr(uint8 bar) external auth {
require(bar != 0);
if (__schnorrStorage.bar != bar) {
emit BarUpdatedSchnorr(msg.sender, __schnorrStorage.bar, bar);
__schnorrStorage.bar = bar;
}
}
//----------------------------------
// ECDSAStorage
/// @inheritdoc IUScribe
function liftECDSA(address[] calldata validators) external auth {
for (uint i; i < validators.length; i++) {
address validator = validators[i];
require(validator != address(0));
uint id = uint160(validator) >> 152;
if (__ecdsaStorage.validators[id] == address(0)) {
__ecdsaStorage.validators[id] = validator;
emit ValidatorLiftedECDSA(msg.sender, validator);
} else {
require(__ecdsaStorage.validators[id] == validator);
}
}
}
/// @inheritdoc IUScribe
function dropECDSA(uint8[] calldata ids) external auth {
for (uint i; i < ids.length; i++) {
uint8 id = ids[i];
address validator = __ecdsaStorage.validators[id];
if (validator != address(0)) {
// assert(uint160(validator) >> 152 == id);
delete __ecdsaStorage.validators[id];
emit ValidatorDroppedECDSA(msg.sender, validator);
}
}
}
/// @inheritdoc IUScribe
function setBarECDSA(uint8 bar) external auth {
require(bar != 0);
if (__ecdsaStorage.bar != bar) {
emit BarUpdatedECDSA(msg.sender, __ecdsaStorage.bar, bar);
__ecdsaStorage.bar = bar;
}
}
//--------------------------------------------------------------------------
// Public View Functions
//----------------------------------
// SchnorrStorage
/// @inheritdoc IUScribe
function validatorsSchnorr(address who) external view returns (bool) {
uint id = uint160(who) >> 152;
LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];
return !pubKey.isZeroPoint() && pubKey.toAddress() == who;
}
/// @inheritdoc IUScribe
function validatorsSchnorr(uint8 id)
external
view
returns (bool, address)
{
LibSecp256k1.Point memory pubKey = __schnorrStorage.pubKeys[id];
return !pubKey.isZeroPoint()
? (true, pubKey.toAddress())
: (false, address(0));
}
/// @inheritdoc IUScribe
function validatorsSchnorr() external view returns (address[] memory) {
address[] memory validators = new address[](256);
LibSecp256k1.Point memory pubKey;
uint ctr;
for (uint i; i < 256; i++) {
pubKey = __schnorrStorage.pubKeys[i];
if (!pubKey.isZeroPoint()) {
validators[ctr++] = pubKey.toAddress();
}
}
assembly ("memory-safe") {
mstore(validators, ctr)
}
return validators;
}
/// @inheritdoc IUScribe
function barSchnorr() external view returns (uint8) {
return __schnorrStorage.bar;
}
//----------------------------------
// ECDSAStorage
/// @inheritdoc IUScribe
function validatorsECDSA(address who) external view returns (bool) {
uint id = uint160(who) >> 152;
return who != address(0) && __ecdsaStorage.validators[id] == who;
}
/// @inheritdoc IUScribe
function validatorsECDSA(uint id) external view returns (bool, address) {
address validator = __ecdsaStorage.validators[id];
return validator != address(0) ? (true, validator) : (false, address(0));
}
/// @inheritdoc IUScribe
function validatorsECDSA() external view returns (address[] memory) {
address[] memory validators = new address[](256);
address validator;
uint ctr;
for (uint i; i < 256; i++) {
validator = __ecdsaStorage.validators[i];
if (validator != address(0)) {
validators[ctr++] = validator;
}
}
assembly ("memory-safe") {
mstore(validators, ctr)
}
return validators;
}
/// @inheritdoc IUScribe
function barECDSA() external view returns (uint8) {
return __ecdsaStorage.bar;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
interface IChronicleVAO_Superstate_USTB_Reader {
/// @notice Returns the oracle's current value.
/// @dev Reverts if:
/// - Not yet poked
/// @return val The oracle's current value.
function read() external view returns (uint val);
/// @notice Returns the oracle's current value.
/// @return ok True if previously poked, false otherwise.
/// @return val The oracle's current value if it exists, zero otherwise.
function tryRead() external view returns (bool ok, uint val);
/// @notice Returns the oracle's current value and its age.
/// @dev Reverts if:
/// - Not yet poked
/// @return val The oracle's current value.
/// @return age The value's age.
function readWithAge() external view returns (uint val, uint age);
/// @notice Returns the oracle's current value and its age.
/// @return ok True if previously poked, false otherwise.
/// @return val The oracle's current value if it exists, zero otherwise.
/// @return age The value's age if value exists, zero otherwise.
function tryReadWithAge()
external
view
returns (bool ok, uint val, uint age);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;
import {IToll} from "chronicle-std/toll/IToll.sol";
/**
* @title TollWithImmutableRouter
*
* @notice "Toll paid, we kiss - but dissension looms, maybe diss?"
*
* @dev The `TollWithImmutableRouter` contract module provides a basic access
* control mechanism, where a set of addresses are granted access to
* protected functions.
* These addresses are said the be _tolled_.
*
* Note that this module differs from chronicle-std/Toll in that a router
* address given at construction is immutably tolled.
*
* This path reduces gas costs for customers connecting to the router
* instead of directly reading from the uscribe consumer.
*
* Initially, only the router is tolled. Through the `kiss(address)` and
* `diss(address)` functions, auth'ed callers are able to toll/de-toll
* addresses. Authentication for these functions is defined via the
* downstream implemented `toll_auth()` function.
*
* This module is used through inheritance. It will make available the
* modifier `toll`, which can be applied to functions to restrict their
* use to only tolled callers.
*/
abstract contract TollWithImmutableRouter is IToll {
/// @dev Address of the immutably tolled router.
address private immutable _router;
/// @dev Mapping storing whether address is tolled.
/// @custom:invariant Image of mapping is {0, 1}.
/// ∀x ∊ Address: _buds[x] ∊ {0, 1}
/// @custom:invariant Only functions `kiss`, `diss` or constructor may
/// mutate the mapping's state.
/// ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
/// → (msg.sig == "kiss" ∨ msg.sig == "diss" ∨ msg.sig == "")
/// @custom:invariant Mapping's state may only be mutated by authenticated
/// caller or during construction.
/// ∀x ∊ Address: preTx(_buds[x]) != postTx(_buds[x])
/// → (toll_auth() ∨ msg.sig == "")
mapping(address => uint) private _buds;
/// @dev List of addresses possibly being tolled.
/// @dev May contain duplicates.
/// @dev May contain addresses not being tolled anymore.
/// @custom:invariant Every address being tolled once is element of the list.
/// ∀x ∊ Address: tolled(x) → x ∊ _budsTouched
address[] private _budsTouched;
constructor(address router) {
_router = router;
_buds[router] = 1;
_budsTouched.push(router);
emit TollGranted(msg.sender, router);
}
/// @dev Ensures caller is tolled.
modifier toll() {
if (msg.sender != _router) {
assembly ("memory-safe") {
// Compute slot of _buds[msg.sender].
mstore(0x00, caller())
mstore(0x20, _buds.slot)
let slot := keccak256(0x00, 0x40)
// Revert if caller not tolled.
let isTolled := sload(slot)
if iszero(isTolled) {
// Store selector of `NotTolled(address)`.
mstore(0x00, 0xd957b595)
// Store msg.sender.
mstore(0x20, caller())
// Revert with (offset, size).
revert(0x1c, 0x24)
}
}
}
_;
}
/// @dev Reverts if caller not allowed to access protected function.
/// @dev Must be implemented in downstream contract.
function toll_auth() internal virtual;
/// @inheritdoc IToll
function kiss(address who) external {
toll_auth();
if (_buds[who] == 1) return;
_buds[who] = 1;
_budsTouched.push(who);
emit TollGranted(msg.sender, who);
}
/// @inheritdoc IToll
function diss(address who) external {
toll_auth();
require(who != _router, "TollWithImmutableRouter: cannot diss router");
if (_buds[who] == 0) return;
_buds[who] = 0;
emit TollRenounced(msg.sender, who);
}
/// @inheritdoc IToll
function tolled(address who) public view returns (bool) {
return _buds[who] == 1;
}
/// @inheritdoc IToll
/// @custom:invariant Only contains tolled addresses.
/// ∀x ∊ tolled(): _buds[x] == 1
/// @custom:invariant Contains all tolled addresses.
/// ∀x ∊ Address: _buds[x] == 1 → x ∊ tolled()
function tolled() public view returns (address[] memory) {
// Initiate array with upper limit length.
address[] memory budsList = new address[](_budsTouched.length);
// Iterate through all possible tolled addresses.
uint ctr;
for (uint i; i < budsList.length; i++) {
// Add address only if still tolled.
if (_buds[_budsTouched[i]] == 1) {
budsList[ctr++] = _budsTouched[i];
}
}
// Set length of array to number of tolled addresses actually included.
assembly ("memory-safe") {
mstore(budsList, ctr)
}
return budsList;
}
/// @inheritdoc IToll
function bud(address who) public view returns (uint) {
return _buds[who];
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IToll {
/// @notice Thrown by protected function if caller not tolled.
/// @param caller The caller's address.
error NotTolled(address caller);
/// @notice Emitted when toll granted to address.
/// @param caller The caller's address.
/// @param who The address toll got granted to.
event TollGranted(address indexed caller, address indexed who);
/// @notice Emitted when toll renounced from address.
/// @param caller The caller's address.
/// @param who The address toll got renounced from.
event TollRenounced(address indexed caller, address indexed who);
/// @notice Grants address `who` toll.
/// @dev Only callable by auth'ed address.
/// @param who The address to grant toll.
function kiss(address who) external;
/// @notice Renounces address `who`'s toll.
/// @dev Only callable by auth'ed address.
/// @param who The address to renounce toll.
function diss(address who) external;
/// @notice Returns whether address `who` is tolled.
/// @param who The address to check.
/// @return True if `who` is tolled, false otherwise.
function tolled(address who) external view returns (bool);
/// @notice Returns full list of addresses tolled.
/// @dev May contain duplicates.
/// @return List of addresses tolled.
function tolled() external view returns (address[] memory);
/// @notice Returns whether address `who` is tolled.
/// @custom:deprecated Use `tolled(address)(bool)` instead.
/// @param who The address to check.
/// @return 1 if `who` is tolled, 0 otherwise.
function bud(address who) external view returns (uint);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
import {IAuth} from "./IAuth.sol";
/**
* @title Auth Module
*
* @dev The `Auth` contract module provides a basic access control mechanism,
* where a set of addresses are granted access to protected functions.
* These addresses are said to be _auth'ed_.
*
* Initially, the address given as constructor argument is the only address
* auth'ed. Through the `rely(address)` and `deny(address)` functions,
* auth'ed callers are able to grant/renounce auth to/from addresses.
*
* This module is used through inheritance. It will make available the
* modifier `auth`, which can be applied to functions to restrict their
* use to only auth'ed callers.
*/
abstract contract Auth is IAuth {
/// @dev Mapping storing whether address is auth'ed.
/// @custom:invariant Image of mapping is {0, 1}.
/// ∀x ∊ Address: _wards[x] ∊ {0, 1}
/// @custom:invariant Only address given as constructor argument is authenticated after deployment.
/// deploy(initialAuthed) → (∀x ∊ Address: _wards[x] == 1 → x == initialAuthed)
/// @custom:invariant Only functions `rely` and `deny` may mutate the mapping's state.
/// ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x])
/// → (msg.sig == "rely" ∨ msg.sig == "deny")
/// @custom:invariant Mapping's state may only be mutated by authenticated caller.
/// ∀x ∊ Address: preTx(_wards[x]) != postTx(_wards[x]) → _wards[msg.sender] = 1
mapping(address => uint) private _wards;
/// @dev List of addresses possibly being auth'ed.
/// @dev May contain duplicates.
/// @dev May contain addresses not being auth'ed anymore.
/// @custom:invariant Every address being auth'ed once is element of the list.
/// ∀x ∊ Address: authed(x) -> x ∊ _wardsTouched
address[] private _wardsTouched;
/// @dev Ensures caller is auth'ed.
modifier auth() {
assembly ("memory-safe") {
// Compute slot of _wards[msg.sender].
mstore(0x00, caller())
mstore(0x20, _wards.slot)
let slot := keccak256(0x00, 0x40)
// Revert if caller not auth'ed.
let isAuthed := sload(slot)
if iszero(isAuthed) {
// Store selector of `NotAuthorized(address)`.
mstore(0x00, 0x4a0bfec1)
// Store msg.sender.
mstore(0x20, caller())
// Revert with (offset, size).
revert(0x1c, 0x24)
}
}
_;
}
constructor(address initialAuthed) {
_wards[initialAuthed] = 1;
_wardsTouched.push(initialAuthed);
// Note to use address(0) as caller to indicate address was auth'ed
// during deployment.
emit AuthGranted(address(0), initialAuthed);
}
/// @inheritdoc IAuth
function rely(address who) external auth {
if (_wards[who] == 1) return;
_wards[who] = 1;
_wardsTouched.push(who);
emit AuthGranted(msg.sender, who);
}
/// @inheritdoc IAuth
function deny(address who) external auth {
if (_wards[who] == 0) return;
_wards[who] = 0;
emit AuthRenounced(msg.sender, who);
}
/// @inheritdoc IAuth
function authed(address who) public view returns (bool) {
return _wards[who] == 1;
}
/// @inheritdoc IAuth
/// @custom:invariant Only contains auth'ed addresses.
/// ∀x ∊ authed(): _wards[x] == 1
/// @custom:invariant Contains all auth'ed addresses.
/// ∀x ∊ Address: _wards[x] == 1 → x ∊ authed()
function authed() public view returns (address[] memory) {
// Initiate array with upper limit length.
address[] memory wardsList = new address[](_wardsTouched.length);
// Iterate through all possible auth'ed addresses.
uint ctr;
for (uint i; i < wardsList.length; i++) {
// Add address only if still auth'ed.
if (_wards[_wardsTouched[i]] == 1) {
wardsList[ctr++] = _wardsTouched[i];
}
}
// Set length of array to number of auth'ed addresses actually included.
assembly ("memory-safe") {
mstore(wardsList, ctr)
}
return wardsList;
}
/// @inheritdoc IAuth
function wards(address who) public view returns (uint) {
return _wards[who];
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {UPokeData, SchnorrData, ECDSAData} from "./Types.sol";
import {LibSecp256k1} from "./libs/LibSecp256k1.sol";
interface IUScribe {
//--------------------------------------------------------------------------
// Errors
/// @notice Thrown if poke verification failed.
/// @param err The verification error.
error PokeError_VerificationFailed(bytes4 err);
/// @notice Thrown if poke rejected by consumer.
/// @param err The consumer error.
error PokeError_ConsumerRejectedPayload(bytes4 err);
//----------------------------------
// Verification Errors
/// @notice Verification error thrown via `PokeError_VerificationFailed` if
/// poke did not reach bar threshold.
error VerificationError_BarNotReached();
/// @notice Verification error thrown via `PokeError_VerificationFailed` if
/// poke attempted double signing.
error VerificationError_DoubleSigningAttempted();
/// @notice Verification error thrown via `PokeError_VerificationFailed` if
/// poke included invalid validator.
error VerificationError_ValidatorInvalid();
/// @notice Verification error thrown via `PokeError_VerificationFailed` if
/// poke included invalid signature.
error VerificationError_SignatureInvalid();
//--------------------------------------------------------------------------
// Events
/// @notice Emitted when oracle was successfully poked.
/// @param caller The caller's address.
/// @param proofURI Optional URI to validity proof.
event UPoked(address indexed caller, string proofURI);
/// @notice Emitted when new validator lifted for Schnorr verification.
/// @param caller The caller's address.
/// @param validator The validator address lifted.
event ValidatorLiftedSchnorr(
address indexed caller, address indexed validator
);
/// @notice Emitted when validator dropped from Schnorr verification.
/// @param caller The caller's address.
/// @param validator The validator address dropped.
event ValidatorDroppedSchnorr(
address indexed caller, address indexed validator
);
/// @notice Emitted when bar for Schnorr verification updated.
/// @param caller The caller's address.
/// @param oldBar The old bar's value.
/// @param newBar The new bar's value.
event BarUpdatedSchnorr(address indexed caller, uint8 oldBar, uint8 newBar);
/// @notice Emitted when new validator lifted for ECDSA verification.
/// @param caller The caller's address.
/// @param validator The validator address lifted.
event ValidatorLiftedECDSA(
address indexed caller, address indexed validator
);
/// @notice Emitted when validator dropped from ECDSA verification.
/// @param caller The caller's address.
/// @param validator The validator address dropped.
event ValidatorDroppedECDSA(
address indexed caller, address indexed validator
);
/// @notice Emitted when bar for ECDSA verification updated.
/// @param caller The caller's address.
/// @param oldBar The old bar's value.
/// @param newBar The new bar's value.
event BarUpdatedECDSA(address indexed caller, uint8 oldBar, uint8 newBar);
//--------------------------------------------------------------------------
// Poke Functionality
/// @notice Pokes the oracle using Schnorr verification.
/// @param uPokeData The UPokeData being poked.
/// @param schnorrData The SchnorrData proving the `uPokeData`'s integrity.
function poke(
UPokeData calldata uPokeData,
SchnorrData calldata schnorrData
) external;
/// @notice Pokes the oracle using ECDSA verification.
/// @param uPokeData The UPokeData being poked.
/// @param ecdsaDatas The list of ECDSAData proving the `uPokeData`'s
/// integrity.
function poke(UPokeData calldata uPokeData, ECDSAData[] calldata ecdsaDatas)
external;
/// @notice Construct a Chronicle Signed Message.
/// @param scheme The scheme to construct the message for.
/// @param uPokeData The UPokeData to inlcude in the message.
function constructChronicleSignedMessage(
bytes32 scheme,
UPokeData calldata uPokeData
) external view returns (bytes32);
//--------------------------------------------------------------------------
// Auth'ed Functionality
/// @notice Lifts list of public keys `pubKeys` for Schnorr verification.
/// @dev Only callable by auth'ed address.
/// @param pubKeys The list of public keys to lift.
function liftSchnorr(LibSecp256k1.Point[] calldata pubKeys) external;
/// @notice Drops list of validator ids `ids` from Schnorr verification.
/// @dev Only callable by auth'ed address.
/// @param ids The list of validator ids to drop.
function dropSchnorr(uint8[] calldata ids) external;
/// @notice Updates the bar security parameter for Schnorr verification.
/// @dev Only callable by auth'ed address.
/// @param bar The value to update bar to.
function setBarSchnorr(uint8 bar) external;
/// @notice Lifts list of addresses `validators` for ECDSA verification.
/// @dev Only callable by auth'ed address.
/// @param validators The list of addresses to lift.
function liftECDSA(address[] calldata validators) external;
/// @notice Drops list of validator ids `ids` from ECDSA verification.
/// @dev Only callable by auth'ed address.
/// @param ids The list of validator ids to drop.
function dropECDSA(uint8[] calldata ids) external;
/// @notice Updates the bar security parameter for ECDSA verification.
/// @dev Only callable by auth'ed address.
/// @param bar The value to update bar to.
function setBarECDSA(uint8 bar) external;
//--------------------------------------------------------------------------
// Public View Functions
/// @notice Returns the oracle's identifier.
/// @dev The wat is derived from `name()`:
///
/// ```solidity
/// assert(wat() = keccak256(bytes(name())));
/// ```
/// @return bytes32 The oracle's identifier.
function wat() external view returns (bytes32);
/// @notice Returns the oracle's name.
/// @return string The oracle's name.
function name() external view returns (string memory);
/// @notice Returns whether address `who` is a validator for Schnorr
/// verification.
/// @param who The address to check.
/// @return bool True if `who` is a validator for Schnorr verification,
/// false otherwise.
function validatorsSchnorr(address who) external view returns (bool);
/// @notice Returns whether validator id `id` is a validator for Schnorr
/// verification and, if so, the validator's address.
/// @param id The validator id to check.
/// @return bool True if `who` is a validator for Schnorr verification,
/// false otherwise.
/// @return address Address of the validator if `id` is a validator for
/// Schnorr verification, zero address otherwise.
function validatorsSchnorr(uint8 id)
external
view
returns (bool, address);
/// @notice Returns the lift of validator addresses for Schnorr
/// verification.
/// @return address[] The lift of validator addresses for Schnorr
/// verification.
function validatorsSchnorr() external view returns (address[] memory);
/// @notice Returns the bar security parameter for Schnorr verification.
/// @return uint8 The bar security parameter for Schnorr verification.
function barSchnorr() external view returns (uint8);
/// @notice Returns whether address `who` is a validator for ECDSA
/// verification.
/// @param who The address to check.
/// @return bool True if `who` is a validator for ECDSA verification, false
/// otherwise.
function validatorsECDSA(address who) external view returns (bool);
/// @notice Returns whether validator id `id` is a validator for ECDSA
/// verification and, if so, the validator's address.
/// @param id The validator id to check.
/// @return bool True if `who` is a validator for ECDSA verification,
/// false otherwise.
/// @return address Address of the validator if `id` is a validator for
/// ECDSA verification, zero address otherwise.
function validatorsECDSA(uint id) external view returns (bool, address);
/// @notice Returns the lift of validator addresses for ECDSA verification.
/// @return address[] The lift of validator addresses for ECDSA
/// verification.
function validatorsECDSA() external view returns (address[] memory);
/// @notice Returns the bar security parameter for ECDSA verification.
/// @return uint8 The bar security parameter for ECDSA verification.
function barECDSA() external view returns (uint8);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
struct UPokeData {
bytes payload;
string proofURI;
}
struct SchnorrData {
bytes32 signature;
address commitment;
bytes validatorIds;
}
struct ECDSAData {
uint8 v;
bytes32 r;
bytes32 s;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
import {LibSecp256k1} from "./LibSecp256k1.sol";
///////////////////////////////////////////////////////////////////////////////
//
// Library copied from Scribe@v2.0.1
//
// Reference: https://github.com/chronicleprotocol/scribe/blob/7d2106a265a8d82f259b506c4c8fec42002546ef/src/libs/LibSchnorr.sol
//
///////////////////////////////////////////////////////////////////////////////
/**
* @title LibSchnorr
*
* @notice Custom-purpose library for Schnorr signature verification on the
* secp256k1 curve
*/
library LibSchnorr {
using LibSecp256k1 for LibSecp256k1.Point;
/// @dev Returns whether `signature` and `commitment` sign via `pubKey`
/// message `message`.
///
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Uses constant amount of gas.
function verifySignature(
LibSecp256k1.Point memory pubKey,
bytes32 message,
bytes32 signature,
address commitment
) internal pure returns (bool) {
// Return false if signature or commitment is zero.
if (signature == 0 || commitment == address(0)) {
return false;
}
// Note to enforce pubKey is valid secp256k1 point.
//
// While the Scribe contract ensures to only verify signatures for valid
// public keys, this check is enabled as an additional defense
// mechanism.
if (!pubKey.isOnCurve()) {
return false;
}
// Note to enforce signature is less than Q to prevent signature
// malleability.
//
// While the Scribe contract only accepts messages with strictly
// monotonically increasing timestamps, circumventing replay attack
// vectors and therefore also signature malleability issues at a higher
// level, this check is enabled as an additional defense mechanism.
if (uint(signature) >= LibSecp256k1.Q()) {
return false;
}
// Construct challenge = H(Pₓ ‖ Pₚ ‖ m ‖ Rₑ) mod Q
uint challenge = uint(
keccak256(
abi.encodePacked(
pubKey.x, uint8(pubKey.yParity()), message, commitment
)
)
) % LibSecp256k1.Q();
// Compute msgHash = -sig * Pₓ (mod Q)
// = Q - (sig * Pₓ) (mod Q)
//
// Unchecked because the only protected operation performed is the
// subtraction from Q where the subtrahend is the result of a (mod Q)
// computation, i.e. the subtrahend is guaranteed to be less than Q.
uint msgHash;
unchecked {
msgHash = LibSecp256k1.Q()
- mulmod(uint(signature), pubKey.x, LibSecp256k1.Q());
}
// Compute v = Pₚ + 27
//
// Unchecked because pubKey.yParity() ∊ {0, 1} which cannot overflow
// by adding 27.
uint v;
unchecked {
v = pubKey.yParity() + 27;
}
// Set r = Pₓ
uint r = pubKey.x;
// Compute s = Q - (e * Pₓ) (mod Q)
//
// Unchecked because the only protected operation performed is the
// subtraction from Q where the subtrahend is the result of a (mod Q)
// computation, i.e. the subtrahend is guaranteed to be less than Q.
uint s;
unchecked {
s = LibSecp256k1.Q() - mulmod(challenge, pubKey.x, LibSecp256k1.Q());
}
// Compute ([s]G - [e]P)ₑ via ecrecover.
address recovered =
ecrecover(bytes32(msgHash), uint8(v), bytes32(r), bytes32(s));
// Verification succeeds iff ([s]G - [e]P)ₑ = Rₑ.
//
// Note that commitment is guaranteed to not be zero.
return commitment == recovered;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
///////////////////////////////////////////////////////////////////////////////
//
// Library copied from Scribe@v2.0.1
//
// Reference: https://github.com/chronicleprotocol/scribe/blob/7d2106a265a8d82f259b506c4c8fec42002546ef/src/libs/LibSecp256k1.sol
//
///////////////////////////////////////////////////////////////////////////////
/**
* @title LibSecp256k1
*
* @notice Library for secp256k1 elliptic curve computations
*
* @dev This library was developed to efficiently compute aggregated public
* keys for Schnorr signatures based on secp256k1, i.e. it is _not_ a
* general purpose elliptic curve library!
*
* References to the Ethereum Yellow Paper are based on the following
* version: "BERLIN VERSION beacfbd – 2022-10-24".
*/
library LibSecp256k1 {
using LibSecp256k1 for LibSecp256k1.Point;
using LibSecp256k1 for LibSecp256k1.JacobianPoint;
uint private constant ADDRESS_MASK =
0x000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
// -- Secp256k1 Constants --
//
// Taken from https://www.secg.org/sec2-v2.pdf.
// See section 2.4.1 "Recommended Parameters secp256k1".
uint private constant _A = 0;
uint private constant _B = 7;
uint private constant _P =
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
/// @dev Returns the order of the group.
function Q() internal pure returns (uint) {
return
0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
}
/// @dev Returns the generator G.
/// Note that the generator is also called base point.
function G() internal pure returns (Point memory) {
return Point({
x: 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,
y: 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
});
}
/// @dev Returns the zero point.
function ZERO_POINT() internal pure returns (Point memory) {
return Point({x: 0, y: 0});
}
// -- (Affine) Point --
/// @dev Point encapsulates a secp256k1 point in Affine coordinates.
struct Point {
uint x;
uint y;
}
/// @dev Returns the Ethereum address of `self`.
///
/// @dev An Ethereum address is defined as the rightmost 160 bits of the
/// keccak256 hash of the concatenation of the hex-encoded x and y
/// coordinates of the corresponding ECDSA public key.
/// See "Appendix F: Signing Transactions" §134 in the Yellow Paper.
function toAddress(Point memory self) internal pure returns (address) {
address addr;
// Functionally equivalent Solidity code:
// addr = address(uint160(uint(keccak256(abi.encode(self.x, self.y)))));
assembly ("memory-safe") {
addr := and(keccak256(self, 0x40), ADDRESS_MASK)
}
return addr;
}
/// @dev Returns Affine point `self` in Jacobian coordinates.
function toJacobian(Point memory self)
internal
pure
returns (JacobianPoint memory)
{
return JacobianPoint({x: self.x, y: self.y, z: 1});
}
/// @dev Returns whether `self` is the zero point.
function isZeroPoint(Point memory self) internal pure returns (bool) {
return (self.x | self.y) == 0;
}
/// @dev Returns whether `self` is a point on the curve.
///
/// @dev The secp256k1 curve is specified as y² ≡ x³ + ax + b (mod P)
/// where:
/// a = 0
/// b = 7
function isOnCurve(Point memory self) internal pure returns (bool) {
uint left = mulmod(self.y, self.y, _P);
// Note that adding a * x can be waived as ∀x: a * x = 0.
uint right =
addmod(mulmod(self.x, mulmod(self.x, self.x, _P), _P), _B, _P);
return left == right;
}
/// @dev Returns the parity of `self`'s y coordinate.
///
/// @dev The value 0 represents an even y value and 1 represents an odd y
/// value.
/// See "Appendix F: Signing Transactions" in the Yellow Paper.
function yParity(Point memory self) internal pure returns (uint) {
return self.y & 1;
}
// -- Jacobian Point --
/// @dev JacobianPoint encapsulates a secp256k1 point in Jacobian
/// coordinates.
struct JacobianPoint {
uint x;
uint y;
uint z;
}
/// @dev Returns Jacobian point `self` in Affine coordinates.
///
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Does not run into an infinite loop.
function toAffine(JacobianPoint memory self)
internal
pure
returns (Point memory)
{
Point memory result;
// Compute z⁻¹, i.e. the modular inverse of self.z.
uint zInv = _invMod(self.z);
// Compute (z⁻¹)² (mod P)
uint zInv_2 = mulmod(zInv, zInv, _P);
// Compute self.x * (z⁻¹)² (mod P), i.e. the x coordinate of given
// Jacobian point in Affine representation.
result.x = mulmod(self.x, zInv_2, _P);
// Compute self.y * (z⁻¹)³ (mod P), i.e. the y coordinate of given
// Jacobian point in Affine representation.
result.y = mulmod(self.y, mulmod(zInv, zInv_2, _P), _P);
return result;
}
/// @dev Adds Affine point `p` to Jacobian point `self`.
///
/// It is the caller's responsibility to ensure given points are on the
/// curve!
///
/// Computation based on: https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#addition-madd-2007-bl.
///
/// Note that the formula assumes z2 = 1, which always holds if z2's
/// point is given in Affine coordinates.
///
/// Note that eventhough the function is marked as pure, to be
/// understood as only being dependent on the input arguments, it
/// nevertheless has side effects by writing the result into the
/// `self` memory variable.
///
/// @custom:invariant Only mutates `self` memory variable.
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Uses constant amount of gas.
function addAffinePoint(JacobianPoint memory self, Point memory p)
internal
pure
{
// Addition formula:
// x = r² - j - (2 * v) (mod P)
// y = (r * (v - x)) - (2 * y1 * j) (mod P)
// z = (z1 + h)² - z1² - h² (mod P)
//
// where:
// r = 2 * (s - y1) (mod P)
// j = h * i (mod P)
// v = x1 * i (mod P)
// h = u - x1 (mod P)
// s = y2 * z1³ (mod P) Called s2 in reference
// i = 4 * h² (mod P)
// u = x2 * z1² (mod P) Called u2 in reference
//
// and:
// x1 = self.x
// y1 = self.y
// z1 = self.z
// x2 = p.x
// y2 = p.y
//
// Note that in order to save memory allocations the result is stored
// in the self variable, i.e. the following holds true after the
// functions execution:
// x = self.x
// y = self.y
// z = self.z
// Cache self's coordinates on stack.
uint x1 = self.x;
uint y1 = self.y;
uint z1 = self.z;
// Compute z1_2 = z1² (mod P)
// = z1 * z1 (mod P)
uint z1_2 = mulmod(z1, z1, _P);
// Compute h = u - x1 (mod P)
// = u + (P - x1) (mod P)
// = x2 * z1² + (P - x1) (mod P)
//
// Unchecked because the only protected operation performed is P - x1
// where x1 is guaranteed by the caller to be an x coordinate belonging
// to a point on the curve, i.e. being less than P.
uint h;
unchecked {
h = addmod(mulmod(p.x, z1_2, _P), _P - x1, _P);
}
// Compute h_2 = h² (mod P)
// = h * h (mod P)
uint h_2 = mulmod(h, h, _P);
// Compute i = 4 * h² (mod P)
uint i = mulmod(4, h_2, _P);
// Compute z = (z1 + h)² - z1² - h² (mod P)
// = (z1 + h)² - z1² + (P - h²) (mod P)
// = (z1 + h)² + (P - z1²) + (P - h²) (mod P)
// ╰───────╯ ╰───────╯ ╰──────╯
// left mid right
//
// Unchecked because the only protected operations performed are
// subtractions from P where the subtrahend is the result of a (mod P)
// computation, i.e. the subtrahend being guaranteed to be less than P.
unchecked {
uint left = mulmod(addmod(z1, h, _P), addmod(z1, h, _P), _P);
uint mid = _P - z1_2;
uint right = _P - h_2;
self.z = addmod(left, addmod(mid, right, _P), _P);
}
// Compute v = x1 * i (mod P)
uint v = mulmod(x1, i, _P);
// Compute j = h * i (mod P)
uint j = mulmod(h, i, _P);
// Compute r = 2 * (s - y1) (mod P)
// = 2 * (s + (P - y1)) (mod P)
// = 2 * ((y2 * z1³) + (P - y1)) (mod P)
// = 2 * ((y2 * z1² * z1) + (P - y1)) (mod P)
//
// Unchecked because the only protected operation performed is P - y1
// where y1 is guaranteed by the caller to be an y coordinate belonging
// to a point on the curve, i.e. being less than P.
uint r;
unchecked {
r = mulmod(
2,
addmod(mulmod(p.y, mulmod(z1_2, z1, _P), _P), _P - y1, _P),
_P
);
}
// Compute x = r² - j - (2 * v) (mod P)
// = r² - j + (P - (2 * v)) (mod P)
// = r² + (P - j) + (P - (2 * v)) (mod P)
// ╰─────╯ ╰───────────╯
// mid right
//
// Unchecked because the only protected operations performed are
// subtractions from P where the subtrahend is the result of a (mod P)
// computation, i.e. the subtrahend being guaranteed to be less than P.
unchecked {
uint r_2 = mulmod(r, r, _P);
uint mid = _P - j;
uint right = _P - mulmod(2, v, _P);
self.x = addmod(r_2, addmod(mid, right, _P), _P);
}
// Compute y = (r * (v - x)) - (2 * y1 * j) (mod P)
// = (r * (v - x)) + (P - (2 * y1 * j)) (mod P)
// = (r * (v + (P - x))) + (P - (2 * y1 * j)) (mod P)
// ╰─────────────────╯ ╰────────────────╯
// left right
//
// Unchecked because the only protected operations performed are
// subtractions from P where the subtrahend is the result of a (mod P)
// computation, i.e. the subtrahend being guaranteed to be less than P.
unchecked {
uint left = mulmod(r, addmod(v, _P - self.x, _P), _P);
uint right = _P - mulmod(2, mulmod(y1, j, _P), _P);
self.y = addmod(left, right, _P);
}
}
// -- Private Helpers --
/// @dev Returns the modular inverse of `x` for modulo `_P`.
///
/// It is the caller's responsibility to ensure `x` is less than `_P`!
///
/// The modular inverse of `x` is x⁻¹ such that x * x⁻¹ ≡ 1 (mod P).
///
/// @dev Modified from Jordi Baylina's [ecsol](https://github.com/jbaylina/ecsol/blob/c2256afad126b7500e6f879a9369b100e47d435d/ec.sol#L51-L67).
///
/// @custom:invariant Reverts iff out of gas.
/// @custom:invariant Does not run into an infinite loop.
function _invMod(uint x) private pure returns (uint) {
uint t;
uint q;
uint newT = 1;
uint r = _P;
assembly ("memory-safe") {
// Implemented in assembly to circumvent division-by-zero
// and over-/underflow protection.
//
// Functionally equivalent Solidity code:
// while (x != 0) {
// q = r / x;
// (t, newT) = (newT, addmod(t, (_P - mulmod(q, newT, _P)), _P));
// (r, x) = (x, r - (q * x));
// }
//
// For the division r / x, x is guaranteed to not be zero via the
// loop condition.
//
// The subtraction of form P - mulmod(_, _, P) is guaranteed to not
// underflow due to the subtrahend being a (mod P) result,
// i.e. the subtrahend being guaranteed to be less than P.
//
// The subterm q * x is guaranteed to not overflow because
// q * x ≤ r due to q = ⎣r / x⎦.
//
// The term r - (q * x) is guaranteed to not underflow because
// q * x ≤ r and therefore r - (q * x) ≥ 0.
for {} x {} {
q := div(r, x)
let tmp := t
t := newT
newT := addmod(tmp, sub(_P, mulmod(q, newT, _P)), _P)
tmp := r
r := x
x := sub(tmp, mul(q, x))
}
}
return t;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.16;
interface IAuth {
/// @notice Thrown by protected function if caller not auth'ed.
/// @param caller The caller's address.
error NotAuthorized(address caller);
/// @notice Emitted when auth granted to address.
/// @param caller The caller's address.
/// @param who The address auth got granted to.
event AuthGranted(address indexed caller, address indexed who);
/// @notice Emitted when auth renounced from address.
/// @param caller The caller's address.
/// @param who The address auth got renounced from.
event AuthRenounced(address indexed caller, address indexed who);
/// @notice Grants address `who` auth.
/// @dev Only callable by auth'ed address.
/// @param who The address to grant auth.
function rely(address who) external;
/// @notice Renounces address `who`'s auth.
/// @dev Only callable by auth'ed address.
/// @param who The address to renounce auth.
function deny(address who) external;
/// @notice Returns whether address `who` is auth'ed.
/// @param who The address to check.
/// @return True if `who` is auth'ed, false otherwise.
function authed(address who) external view returns (bool);
/// @notice Returns full list of addresses granted auth.
/// @dev May contain duplicates.
/// @return List of addresses granted auth.
function authed() external view returns (address[] memory);
/// @notice Returns whether address `who` is auth'ed.
/// @custom:deprecated Use `authed(address)(bool)` instead.
/// @param who The address to check.
/// @return 1 if `who` is auth'ed, 0 otherwise.
function wards(address who) external view returns (uint);
}{
"remappings": [
"ds-test/=lib/chronicle-std/lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"chronicle-std/=lib/chronicle-std/src/",
"greenhouse/=lib/greenhouse/src/",
"uscribe/=lib/uscribe/src/",
"test-uscribe/=lib/uscribe/test/",
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"@script/chronicle-std/=lib/greenhouse/lib/chronicle-std/script/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 10000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "cancun",
"viaIR": true,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"initialAuthed","type":"address"},{"internalType":"address","name":"router","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"FutureMessage","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotAuthorized","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"NotTolled","type":"error"},{"inputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"PokeError_ConsumerRejectedPayload","type":"error"},{"inputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"PokeError_VerificationFailed","type":"error"},{"inputs":[],"name":"StaleMessage","type":"error"},{"inputs":[],"name":"VerificationError_BarNotReached","type":"error"},{"inputs":[],"name":"VerificationError_DoubleSigningAttempted","type":"error"},{"inputs":[],"name":"VerificationError_SignatureInvalid","type":"error"},{"inputs":[],"name":"VerificationError_ValidatorInvalid","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"AuthGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"AuthRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint8","name":"oldBar","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"newBar","type":"uint8"}],"name":"BarUpdatedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint8","name":"oldBar","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"newBar","type":"uint8"}],"name":"BarUpdatedSchnorr","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"uint128","name":"val","type":"uint128"},{"indexed":false,"internalType":"uint48","name":"age","type":"uint48"}],"name":"Poked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"TollGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"who","type":"address"}],"name":"TollRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"string","name":"proofURI","type":"string"}],"name":"UPoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDroppedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorDroppedSchnorr","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorLiftedECDSA","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"caller","type":"address"},{"indexed":true,"internalType":"address","name":"validator","type":"address"}],"name":"ValidatorLiftedSchnorr","type":"event"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"authed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authed","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"barECDSA","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"barSchnorr","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"bud","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"scheme","type":"bytes32"},{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"}],"name":"constructChronicleSignedMessage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"deny","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"diss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ids","type":"uint8[]"}],"name":"dropECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ids","type":"uint8[]"}],"name":"dropSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"kiss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"validators","type":"address[]"}],"name":"liftECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"x","type":"uint256"},{"internalType":"uint256","name":"y","type":"uint256"}],"internalType":"struct LibSecp256k1.Point[]","name":"pubKeys","type":"tuple[]"}],"name":"liftSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"},{"components":[{"internalType":"bytes32","name":"signature","type":"bytes32"},{"internalType":"address","name":"commitment","type":"address"},{"internalType":"bytes","name":"validatorIds","type":"bytes"}],"internalType":"struct SchnorrData","name":"schnorr","type":"tuple"}],"name":"poke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"string","name":"proofURI","type":"string"}],"internalType":"struct UPokeData","name":"uPokeData","type":"tuple"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct ECDSAData[]","name":"ecdsas","type":"tuple[]"}],"name":"poke","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"read","outputs":[{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"readWithAge","outputs":[{"internalType":"uint256","name":"val","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"rely","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"bar","type":"uint8"}],"name":"setBarECDSA","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"bar","type":"uint8"}],"name":"setBarSchnorr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"tolled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tolled","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tryRead","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"uint256","name":"val","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tryReadWithAge","outputs":[{"internalType":"bool","name":"ok","type":"bool"},{"internalType":"uint256","name":"val","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"validatorsECDSA","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsECDSA","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"validatorsECDSA","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"validatorsSchnorr","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"validatorsSchnorr","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"id","type":"uint8"}],"name":"validatorsSchnorr","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"who","type":"address"}],"name":"wards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wat","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60c0604052346103aa57604051601f612b4b38819003918201601f19168301916001600160401b038311848410176102a65780849260409485528339810103126103aa576100586020610051836103ae565b92016103ae565b604080519192919081016001600160401b038111828210176102a6576040526014815260208101917f56414f3a3a537570657273746174655f55535442000000000000000000000000835260018060a01b0316805f525f602052600160405f2055600154680100000000000000008110156102a65760018101806001558110156102925760015f9081527fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf69190910180546001600160a01b031916831790557fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f8180a3805180156103aa576001600160401b0381116102a657600254600181811c911680156103a0575b602082101461038c57601f8111610329575b50806020601f82116001146102c5575f916102ba575b508160011b915f199060031b1c1916176002555b51902060805260ff80196102035416176102035560ff8019610304541617610304558060a05260018060a01b0316805f52610305602052600160405f205561030654680100000000000000008110156102a657600181018061030655811015610292576103065f5260205f20018160018060a01b031982541617905560405190337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a35f80a361278890816103c3823960805181818161033901528181610ba00152818161100a01526114b2015260a05181818161064601528181610f4601528181611145015281816115650152611b2c0152f35b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b90508201515f61018a565b60025f9081528181209250601f198416905b818110610311575090836001949392106102f9575b5050811b0160025561019e565b8401515f1960f88460031b161c191690555f806102ec565b919260206001819286890151815501940192016102d7565b60025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace601f830160051c81019160208410610382575b601f0160051c01905b8181106103775750610174565b5f815560010161036a565b9091508190610361565b634e487b7160e01b5f52602260045260245ffd5b90607f1690610162565b5f80fd5b51906001600160a01b03821682036103aa5756fe6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146116bb575080630e947235146116125780630fce3415146115c857806310b07b711461153e578063140432091461139c57806318969a2d146112b5578063224242ca1461121457806338e3e013146111ac578063393e5ede1461111e5780633bee58f9146110d257806344baa5fd1461102d5780634ca2992314610ff35780634fce7a2a14610faa57806357de26a414610f1f5780635b2f752514610efe5780635ffcbba714610e1b578063635d4acd14610d8857806365c4ce7a14610d4e57806365fae35e14610d035780638575738614610a675780638cf6a8f1146109e55780639954b0dc146109275780639c52a7f1146108dc578063a7260f9f146107b5578063bf353dbb1461076e578063cb8370a3146106af578063ceed3ef21461061f578063e32da6e81461049d578063e891c0951461047c578063ef4097cc146103c2578063f0b76dd714610288578063f29c29c41461024c5763fc8717c314610187575f80fd5b34610248576020600319360112610248576101a061180c565b61010081101561021b576101b99060011b600301611ad0565b80516020820151171561021357604073ffffffffffffffffffffffffffffffffffffffff91201660015b60408051911515825273ffffffffffffffffffffffffffffffffffffffff909216602082015290819081015b0390f35b505f806101e3565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80fd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff811681036102485761028690611d58565b005b346102485760406003193601126102485760243567ffffffffffffffff8111610248578060040190604060031982360301126102485761030160209260246102d08280611924565b6102f68760405183819483830196873781015f838201520301601f198101835282611901565b519020930190611924565b6103278460405183819483830196873781015f838201520301601f198101835282611901565b519020604051908382019260043584527f00000000000000000000000000000000000000000000000000000000000000006040840152606083015260808201526080815261037660a082611901565b519020604051828101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d81526103b7605d82611901565b519020604051908152f35b34610248576020600319360112610248576103db61180c565b335f525f60205260405f20541561046b5760ff8116908115610248576103045460ff811683810361040857005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917ff1f337dab208fa554bd26f24051a905078905ccd741043ca59e486a3b9e03f4c91a2161761030455005b634a0bfec15f52336020526024601cfd5b34610248575f60031936011261024857602060ff6102035416604051908152f35b346102485760206003193601126102485760043567ffffffffffffffff811161024857366023820112156102485780600401359067ffffffffffffffff8211610248573660248360061b8301011161024857335f525f60205260405f20541561046b575f5b82811015610286578060061b82019060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8336030112610248576040519161054a8361189c565b604460248201359182855201356020840191818352171561024857604083209073ffffffffffffffffffffffffffffffffffffffff82169161010060ff8260981c16101561021b5760971c6101fe1690600382016105a781611ad0565b958651602088015117155f146105f257519055516004919091015560019250337f189ea7fe6fa9a5be238df17366f57d37c1943a76871a92123a439f66bc4893355f80a35b01610502565b505050509091604073ffffffffffffffffffffffffffffffffffffffff91201603610248576001906105ec565b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016330361068c575b6060610677611dfa565b90604051921515835260208301526040820152f35b335f5261030560205260405f205461066d5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff81168082036102485761010060ff8360981c16101561021b5761072d7401fffffffffffffffffffffffffffffffffffffffe6101fe6d01fffffffffffffffffffffffffe60209560971c161616600301611ad0565b90815183830151171515918261074a575b50506040519015158152f35b6040902073ffffffffffffffffffffffffffffffffffffffff16149050828061073e565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f525f602052602060405f2054604051908152f35b346102485760206003193601126102485760043567ffffffffffffffff8111610248576107e690369060040161181c565b90335f525f60205260405f20541561046b575f5b82811061080357005b61081661081182858561199c565b611d37565b9073ffffffffffffffffffffffffffffffffffffffff82169182156102485760ff9060981c1691610100831015928361021b57610204019273ffffffffffffffffffffffffffffffffffffffff84541680155f146108ca575061021b5782817fffffffffffffffffffffffff00000000000000000000000000000000000000006001955416179055337fafb0e3c5f69ca0548e193d035ea46175485ad76d40ebac3f49531a414447047f5f80a35b016107fa565b919293505003610248576001906108c4565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116810361024857335f525f60205260405f20541561046b5761028690611cdc565b34610248575f60031936011261024857610943610306546119d2565b5f905f5b81518110156109d2578073ffffffffffffffffffffffffffffffffffffffff610971600193611a1b565b90549060031b1c165f526103056020528160405f205414610993575b01610947565b73ffffffffffffffffffffffffffffffffffffffff6109b182611a1b565b90549060031b1c166109cc6109c586611a4a565b9585611aa4565b5261098d565b5061020f9181526040519182918261184d565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116908181036102485760981c60ff16908015159081610a36575b6020826040519015158152f35b905061010082101561021b5773ffffffffffffffffffffffffffffffffffffffff6020926102040154161482610a29565b346102485760406003193601126102485760043567ffffffffffffffff8111610248578060040190604060031982360301126102485760243567ffffffffffffffff811161024857366023820112156102485780600401359067ffffffffffffffff8211610248573660246060840283010111610248577fffffffff0000000000000000000000000000000000000000000000000000000091610c2a91602480610b118880611924565b610b38602060405183819483830196873781015f838201520301601f198101835282611901565b519020960195610b488789611924565b610b6f602060405183819483830196873781015f838201520301601f198101835282611901565b5190206040519060208201927f454344534100000000000000000000000000000000000000000000000000000084527f000000000000000000000000000000000000000000000000000000000000000060408401526060830152608082015260808152610bdd60a082611901565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152610c1f605d82611901565b519020910190612387565b1680610cd8577fffffffff00000000000000000000000000000000000000000000000000000000610ca5610c9f85610c967f16f91548bee0e0722f10b5b21a55dae299cd9024229347fd3063ffe2eee8ea34610c868884611924565b6040513394909283929083611975565b0390a280611924565b90612213565b1680610cad57005b7fda45eb1c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fc61f8ee6000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116810361024857335f525f60205260405f20541561046b5761028690611c22565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff811681036102485761028690611aee565b34610248575f60031936011261024857604051601f19612020610dab8184611901565b6101008352013660208301375f5f5b610100811015610e0a5760019073ffffffffffffffffffffffffffffffffffffffff8161020401541680610df0575b5001610dba565b610e03610dfc85611a4a565b9486611aa4565b5284610de9565b8183526040518061020f858261184d565b346102485760206003193601126102485760043567ffffffffffffffff811161024857610e4c90369060040161181c565b90335f525f60205260405f20541561046b575f5b828110610e6957005b610e7c610e7782858561199c565b6119ac565b9061010082101561021b57600191821b80600301610e9981611ad0565b8051602082015117610eaf575b50505001610e60565b5f600473ffffffffffffffffffffffffffffffffffffffff94826040955501552016337f52ce30f1a5a6d183f1c399b08dbbebaa6bcd0e2a3f6da47ff3b6984b863d28de5f80a3848080610ea6565b34610248575f60031936011261024857602060ff6103045416604051908152f35b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303610f87575b610f75611dfa565b50901561024857602090604051908152f35b335f5261030560205260405f2054610f6d5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f52610305602052602060405f2054604051908152f35b34610248575f6003193601126102485760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b34610248575f60031936011261024857604051601f196120206110508184611901565b6101008352013660208301376040516110688161189c565b5f81525f6020820152505f905f5b6101008110156109d25760019061109181831b600301611ad0565b80516020820151176110a5575b5001611076565b604073ffffffffffffffffffffffffffffffffffffffff9120166110cb6109c586611a4a565b528461109e565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f526103056020526020600160405f205414604051908152f35b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000163303611189575b611174611dfa565b91156102485760409182519182526020820152f35b335f5261030560205260405f205461116c5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043561010081101561021b57610204015473ffffffffffffffffffffffffffffffffffffffff16801561021357604080516001815273ffffffffffffffffffffffffffffffffffffffff92909216602083015290f35b34610248575f6003193601126102485761122f6001546119d2565b5f905f5b81518110156109d2578073ffffffffffffffffffffffffffffffffffffffff61125d600193611a03565b90549060031b1c165f525f6020528160405f20541461127d575b01611233565b73ffffffffffffffffffffffffffffffffffffffff61129b82611a03565b90549060031b1c166112af6109c586611a4a565b52611277565b346102485760206003193601126102485760043567ffffffffffffffff8111610248576112e690369060040161181c565b90335f525f60205260405f20541561046b575f5b82811061130357005b611311610e7782858561199c565b9061010082101561021b576001916102040173ffffffffffffffffffffffffffffffffffffffff815416908161134a575b5050016112fa565b7fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055337f7d553b93bbf05f357fad190f996038832a2de9be7a99c6647f6b047cf3284fc95f80a38480611342565b346102485760406003193601126102485760043567ffffffffffffffff8111610248578060040190604060031982360301126102485760243567ffffffffffffffff8111610248576060600319823603011261024857610c2a7fffffffff000000000000000000000000000000000000000000000000000000009160246114238680611924565b61144a602060405183819483830196873781015f838201520301601f198101835282611901565b51902094019361145a8587611924565b611481602060405183819483830196873781015f838201520301601f198101835282611901565b5190206040519060208201927f5343484e4f52520000000000000000000000000000000000000000000000000084527f0000000000000000000000000000000000000000000000000000000000000000604084015260608301526080820152608081526114ef60a082611901565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152611531605d82611901565b5190209060040190611e59565b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001633036115a5575b6040611596611dfa565b50825191151582526020820152f35b335f5261030560205260405f205461158c5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f525f6020526020600160405f205414604051908152f35b346102485760206003193601126102485761162b61180c565b335f525f60205260405f20541561046b5760ff8116908115610248576102035460ff811683810361165857005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917f6725eac4d9463d79b15ccb65e620936de0a75d44795151a2fc5a6f62f1dc376c91a2161761020355005b34610248575f600319360112610248575f90600254918260011c60018416938415611802575b6020821085146117d557818452602084019490811561179c575060011461173e575b5090611713816040930382611901565b601f19601f8351948593602085525180918160208701528686015e5f85828601015201168101030190f35b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061178257509091508101602001611713611703565b91926001816020925483858801015201910190929161176a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016855250151560051b82016020019050611713611703565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906116e1565b6004359060ff8216820361024857565b9181601f840112156102485782359167ffffffffffffffff8311610248576020808501948460051b01011161024857565b60206040818301928281528451809452019201905f5b8181106118705750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611863565b6040810190811067ffffffffffffffff8211176118b857604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176118b857604052565b90601f601f19910116810190811067ffffffffffffffff8211176118b857604052565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610248570180359067ffffffffffffffff82116102485760200191813603831361024857565b90601f83604094601f199360208652816020870152868601375f8582860101520116010190565b919081101561021b5760051b0190565b3560ff811681036102485790565b67ffffffffffffffff81116118b85760051b60200190565b906119dc826119ba565b6119e96040519182611901565b828152601f196119f982946119ba565b0190602036910137565b60015481101561021b5760015f5260205f2001905f90565b6103065481101561021b576103065f5260205f2001905f90565b805482101561021b575f5260205f2001905f90565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611a775760010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b805182101561021b5760209160051b010190565b60405190611ac58261189c565b5f6020838281520152565b90604051611add8161189c565b602060018294805484520154910152565b335f525f60205260405f20541561046b5773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000168114611b9e57805f5261030560205260405f205415611b9b57805f526103056020525f6040812055337fdadd1471db1ea2f303654fb1bdcc010e5a664214ab41934c0f752aabca88a4915f80a3565b50565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f546f6c6c57697468496d6d757461626c65526f757465723a2063616e6e6f742060448201527f6469737320726f757465720000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff811690815f525f602052600160405f205414611cd857815f525f602052600160405f205560015490680100000000000000008210156118b857611c85826001611cb194016001556001611a35565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b337fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f5f80a3565b5050565b73ffffffffffffffffffffffffffffffffffffffff16805f525f60205260405f205415611b9b57805f525f6020525f6040812055337f58466e5837b54e559819c9ba8a5d7c77c97c985d1aabf4bdc5f41069fa5d65a05f80a3565b3573ffffffffffffffffffffffffffffffffffffffff811681036102485790565b335f525f60205260405f20541561046b5773ffffffffffffffffffffffffffffffffffffffff811690815f52610305602052600160405f205414611cd857815f52610305602052600160405f20556103065490680100000000000000008210156118b857611c85826001611dd3940161030655610306611a35565b337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a35f80a3565b604051611e068161189c565b602061030754916fffffffffffffffffffffffffffffffff65ffffffffffff84169384835260301c1691829101529080151592565b60405190611e48826118e5565b5f6040838281528260208201520152565b9190611e63611ab8565b50611e6c611e3b565b5060ff6102035416604082019381611e848685611924565b9050036121eb57611e958584611924565b1561021b57358060f81c9061010082101561021b576101fe80611ebf9260f71c1616600301611ad0565b928351916020850192835117156121c0576001909791971b93611ee0611e3b565b505191519660405192611ef2846118e5565b8352602083019788526040830194600186526001925f935b838110612023575050505050611f1e611ab8565b5060405192611f2c8461189c565b5f84525f602085015251955f96600190807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f915b611fe657505050957ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8092611fb99798828085800980935109875251920990096020830152611fb160208401611d37565b92359161253d565b15611fc2575f90565b7fcbc4755f0000000000000000000000000000000000000000000000000000000090565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183949b930492818c8509820390089290918202900380611f60565b61202d828a611924565b82101561021b57810135908160f81c9161010083101561021b576101fe8061205c9260f71c1616600301611ad0565b9384519260208601938451171561218f576001901b9081811661215e57179387518d51978b5190612131576001947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f83818f818f978f9982809b818b8180809e819a82809a818085819609809c510990820390089d8e91838b818080878009928184600409998a988d0893820390820308918009089052099b099b519282039409900908600209948180808660020981038382030881888009088098525f9e09600209820394820390089009088c5201611f0a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b507fe7908552000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e5639000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e56390000000000000000000000000000000000000000000000000000000096505050505050565b507f19877c600000000000000000000000000000000000000000000000000000000093505050565b908160409181010312610248576040519061222d8261189c565b803565ffffffffffff81169182820361024857602091845201356fffffffffffffffffffffffffffffffff811691828203610248576020840190828252610307549065ffffffffffff821681111561235d5742106123345765ffffffffffff937fffffffffffffffffffff0000000000000000000000000000000000000000000075ffffffffffffffffffffffffffffffff0000000000006fffffffffffffffffffffffffffffffff958742169360206040516122e98161189c565b868152015260301b169216171761030755511691511660405191825260208201527f9f8b8154174dc4a9ed8bbe5a985ecf6d8b2db481a1c64a02c8d94ae7929e0ba660403392a25f90565b50505050507f5507d1ac0000000000000000000000000000000000000000000000000000000090565b5050505050507f4ef874670000000000000000000000000000000000000000000000000000000090565b61238f611e3b565b505f9160ff610304541693848103612514575f935b8585106123b5575050505050505f90565b8185101561021b57606085028301606081360312610248576040516123d9816118e5565b81359160ff83168084036102485761242e836020955f9552604086850135948588840152013590816040820152506040519384938b859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612509575f5160ff73ffffffffffffffffffffffffffffffffffffffff82169160981c169080159081156124d9575b506124ae576001901b80821661248357600191179401936123a4565b505050505050507fe79085520000000000000000000000000000000000000000000000000000000090565b505050505050507fcbc4755f0000000000000000000000000000000000000000000000000000000090565b905061010082101561021b5773ffffffffffffffffffffffffffffffffffffffff8261020401541614155f612467565b6040513d5f823e3d90fd5b50505050507f19877c600000000000000000000000000000000000000000000000000000000090565b909180158015612734575b61272c57602082019081517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8060078187518181800990090891800903612723577ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141811015612723576126f683601b60017ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141806020995f9951908951907f0100000000000000000000000000000000000000000000000000000000000000604051928e840194855260f81b16604083015260418201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008d60601b16606182015260558152612658607582611901565b5190200695845190097ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414103955116019051809460ff7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641416040519788970991865290921660ff16602085015260408401527ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410360608301526080820190565b838052039060015afa156125095773ffffffffffffffffffffffffffffffffffffffff805f511691161490565b50505050505f90565b505050505f90565b5073ffffffffffffffffffffffffffffffffffffffff84161561254856fea26469706673582212207274edf763fbf257186cd3efc51a4a943890b9382d23ffbbe1fc72e40ad8b46864736f6c634300081c003300000000000000000000000074258a92611e029b748f79c50024dd851339db15000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61
Deployed Bytecode
0x6080806040526004361015610012575f80fd5b5f3560e01c90816306fdde03146116bb575080630e947235146116125780630fce3415146115c857806310b07b711461153e578063140432091461139c57806318969a2d146112b5578063224242ca1461121457806338e3e013146111ac578063393e5ede1461111e5780633bee58f9146110d257806344baa5fd1461102d5780634ca2992314610ff35780634fce7a2a14610faa57806357de26a414610f1f5780635b2f752514610efe5780635ffcbba714610e1b578063635d4acd14610d8857806365c4ce7a14610d4e57806365fae35e14610d035780638575738614610a675780638cf6a8f1146109e55780639954b0dc146109275780639c52a7f1146108dc578063a7260f9f146107b5578063bf353dbb1461076e578063cb8370a3146106af578063ceed3ef21461061f578063e32da6e81461049d578063e891c0951461047c578063ef4097cc146103c2578063f0b76dd714610288578063f29c29c41461024c5763fc8717c314610187575f80fd5b34610248576020600319360112610248576101a061180c565b61010081101561021b576101b99060011b600301611ad0565b80516020820151171561021357604073ffffffffffffffffffffffffffffffffffffffff91201660015b60408051911515825273ffffffffffffffffffffffffffffffffffffffff909216602082015290819081015b0390f35b505f806101e3565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52603260045260245ffd5b5f80fd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff811681036102485761028690611d58565b005b346102485760406003193601126102485760243567ffffffffffffffff8111610248578060040190604060031982360301126102485761030160209260246102d08280611924565b6102f68760405183819483830196873781015f838201520301601f198101835282611901565b519020930190611924565b6103278460405183819483830196873781015f838201520301601f198101835282611901565b519020604051908382019260043584527fe4ee0a2eb1d0299212172dfca37468f842440be7d40e2589e57b6f0689b1373c6040840152606083015260808201526080815261037660a082611901565b519020604051828101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d81526103b7605d82611901565b519020604051908152f35b34610248576020600319360112610248576103db61180c565b335f525f60205260405f20541561046b5760ff8116908115610248576103045460ff811683810361040857005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917ff1f337dab208fa554bd26f24051a905078905ccd741043ca59e486a3b9e03f4c91a2161761030455005b634a0bfec15f52336020526024601cfd5b34610248575f60031936011261024857602060ff6102035416604051908152f35b346102485760206003193601126102485760043567ffffffffffffffff811161024857366023820112156102485780600401359067ffffffffffffffff8211610248573660248360061b8301011161024857335f525f60205260405f20541561046b575f5b82811015610286578060061b82019060407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc8336030112610248576040519161054a8361189c565b604460248201359182855201356020840191818352171561024857604083209073ffffffffffffffffffffffffffffffffffffffff82169161010060ff8260981c16101561021b5760971c6101fe1690600382016105a781611ad0565b958651602088015117155f146105f257519055516004919091015560019250337f189ea7fe6fa9a5be238df17366f57d37c1943a76871a92123a439f66bc4893355f80a35b01610502565b505050509091604073ffffffffffffffffffffffffffffffffffffffff91201603610248576001906105ec565b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db6116330361068c575b6060610677611dfa565b90604051921515835260208301526040820152f35b335f5261030560205260405f205461066d5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff81168082036102485761010060ff8360981c16101561021b5761072d7401fffffffffffffffffffffffffffffffffffffffe6101fe6d01fffffffffffffffffffffffffe60209560971c161616600301611ad0565b90815183830151171515918261074a575b50506040519015158152f35b6040902073ffffffffffffffffffffffffffffffffffffffff16149050828061073e565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f525f602052602060405f2054604051908152f35b346102485760206003193601126102485760043567ffffffffffffffff8111610248576107e690369060040161181c565b90335f525f60205260405f20541561046b575f5b82811061080357005b61081661081182858561199c565b611d37565b9073ffffffffffffffffffffffffffffffffffffffff82169182156102485760ff9060981c1691610100831015928361021b57610204019273ffffffffffffffffffffffffffffffffffffffff84541680155f146108ca575061021b5782817fffffffffffffffffffffffff00000000000000000000000000000000000000006001955416179055337fafb0e3c5f69ca0548e193d035ea46175485ad76d40ebac3f49531a414447047f5f80a35b016107fa565b919293505003610248576001906108c4565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116810361024857335f525f60205260405f20541561046b5761028690611cdc565b34610248575f60031936011261024857610943610306546119d2565b5f905f5b81518110156109d2578073ffffffffffffffffffffffffffffffffffffffff610971600193611a1b565b90549060031b1c165f526103056020528160405f205414610993575b01610947565b73ffffffffffffffffffffffffffffffffffffffff6109b182611a1b565b90549060031b1c166109cc6109c586611a4a565b9585611aa4565b5261098d565b5061020f9181526040519182918261184d565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116908181036102485760981c60ff16908015159081610a36575b6020826040519015158152f35b905061010082101561021b5773ffffffffffffffffffffffffffffffffffffffff6020926102040154161482610a29565b346102485760406003193601126102485760043567ffffffffffffffff8111610248578060040190604060031982360301126102485760243567ffffffffffffffff811161024857366023820112156102485780600401359067ffffffffffffffff8211610248573660246060840283010111610248577fffffffff0000000000000000000000000000000000000000000000000000000091610c2a91602480610b118880611924565b610b38602060405183819483830196873781015f838201520301601f198101835282611901565b519020960195610b488789611924565b610b6f602060405183819483830196873781015f838201520301601f198101835282611901565b5190206040519060208201927f454344534100000000000000000000000000000000000000000000000000000084527fe4ee0a2eb1d0299212172dfca37468f842440be7d40e2589e57b6f0689b1373c60408401526060830152608082015260808152610bdd60a082611901565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152610c1f605d82611901565b519020910190612387565b1680610cd8577fffffffff00000000000000000000000000000000000000000000000000000000610ca5610c9f85610c967f16f91548bee0e0722f10b5b21a55dae299cd9024229347fd3063ffe2eee8ea34610c868884611924565b6040513394909283929083611975565b0390a280611924565b90612213565b1680610cad57005b7fda45eb1c000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b7fc61f8ee6000000000000000000000000000000000000000000000000000000005f5260045260245ffd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116810361024857335f525f60205260405f20541561046b5761028690611c22565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff811681036102485761028690611aee565b34610248575f60031936011261024857604051601f19612020610dab8184611901565b6101008352013660208301375f5f5b610100811015610e0a5760019073ffffffffffffffffffffffffffffffffffffffff8161020401541680610df0575b5001610dba565b610e03610dfc85611a4a565b9486611aa4565b5284610de9565b8183526040518061020f858261184d565b346102485760206003193601126102485760043567ffffffffffffffff811161024857610e4c90369060040161181c565b90335f525f60205260405f20541561046b575f5b828110610e6957005b610e7c610e7782858561199c565b6119ac565b9061010082101561021b57600191821b80600301610e9981611ad0565b8051602082015117610eaf575b50505001610e60565b5f600473ffffffffffffffffffffffffffffffffffffffff94826040955501552016337f52ce30f1a5a6d183f1c399b08dbbebaa6bcd0e2a3f6da47ff3b6984b863d28de5f80a3848080610ea6565b34610248575f60031936011261024857602060ff6103045416604051908152f35b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61163303610f87575b610f75611dfa565b50901561024857602090604051908152f35b335f5261030560205260405f2054610f6d5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f52610305602052602060405f2054604051908152f35b34610248575f6003193601126102485760206040517fe4ee0a2eb1d0299212172dfca37468f842440be7d40e2589e57b6f0689b1373c8152f35b34610248575f60031936011261024857604051601f196120206110508184611901565b6101008352013660208301376040516110688161189c565b5f81525f6020820152505f905f5b6101008110156109d25760019061109181831b600301611ad0565b80516020820151176110a5575b5001611076565b604073ffffffffffffffffffffffffffffffffffffffff9120166110cb6109c586611a4a565b528461109e565b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f526103056020526020600160405f205414604051908152f35b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61163303611189575b611174611dfa565b91156102485760409182519182526020820152f35b335f5261030560205260405f205461116c5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043561010081101561021b57610204015473ffffffffffffffffffffffffffffffffffffffff16801561021357604080516001815273ffffffffffffffffffffffffffffffffffffffff92909216602083015290f35b34610248575f6003193601126102485761122f6001546119d2565b5f905f5b81518110156109d2578073ffffffffffffffffffffffffffffffffffffffff61125d600193611a03565b90549060031b1c165f525f6020528160405f20541461127d575b01611233565b73ffffffffffffffffffffffffffffffffffffffff61129b82611a03565b90549060031b1c166112af6109c586611a4a565b52611277565b346102485760206003193601126102485760043567ffffffffffffffff8111610248576112e690369060040161181c565b90335f525f60205260405f20541561046b575f5b82811061130357005b611311610e7782858561199c565b9061010082101561021b576001916102040173ffffffffffffffffffffffffffffffffffffffff815416908161134a575b5050016112fa565b7fffffffffffffffffffffffff00000000000000000000000000000000000000008154169055337f7d553b93bbf05f357fad190f996038832a2de9be7a99c6647f6b047cf3284fc95f80a38480611342565b346102485760406003193601126102485760043567ffffffffffffffff8111610248578060040190604060031982360301126102485760243567ffffffffffffffff8111610248576060600319823603011261024857610c2a7fffffffff000000000000000000000000000000000000000000000000000000009160246114238680611924565b61144a602060405183819483830196873781015f838201520301601f198101835282611901565b51902094019361145a8587611924565b611481602060405183819483830196873781015f838201520301601f198101835282611901565b5190206040519060208201927f5343484e4f52520000000000000000000000000000000000000000000000000084527fe4ee0a2eb1d0299212172dfca37468f842440be7d40e2589e57b6f0689b1373c604084015260608301526080820152608081526114ef60a082611901565b51902060405160208101917f194368726f6e69636c65205369676e6564204d6573736167653a0a33320000008352603d820152603d8152611531605d82611901565b5190209060040190611e59565b34610248575f6003193601126102485773ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db611633036115a5575b6040611596611dfa565b50825191151582526020820152f35b335f5261030560205260405f205461158c5763d957b5955f52336020526024601cfd5b346102485760206003193601126102485760043573ffffffffffffffffffffffffffffffffffffffff8116809103610248575f525f6020526020600160405f205414604051908152f35b346102485760206003193601126102485761162b61180c565b335f525f60205260405f20541561046b5760ff8116908115610248576102035460ff811683810361165857005b6040805160ff92831681529390911660208401527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff009233917f6725eac4d9463d79b15ccb65e620936de0a75d44795151a2fc5a6f62f1dc376c91a2161761020355005b34610248575f600319360112610248575f90600254918260011c60018416938415611802575b6020821085146117d557818452602084019490811561179c575060011461173e575b5090611713816040930382611901565b601f19601f8351948593602085525180918160208701528686015e5f85828601015201168101030190f35b91905060025f527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace915f905b80821061178257509091508101602001611713611703565b91926001816020925483858801015201910190929161176a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016855250151560051b82016020019050611713611703565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52602260045260245ffd5b90607f16906116e1565b6004359060ff8216820361024857565b9181601f840112156102485782359167ffffffffffffffff8311610248576020808501948460051b01011161024857565b60206040818301928281528451809452019201905f5b8181106118705750505090565b825173ffffffffffffffffffffffffffffffffffffffff16845260209384019390920191600101611863565b6040810190811067ffffffffffffffff8211176118b857604052565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b6060810190811067ffffffffffffffff8211176118b857604052565b90601f601f19910116810190811067ffffffffffffffff8211176118b857604052565b9035907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe181360301821215610248570180359067ffffffffffffffff82116102485760200191813603831361024857565b90601f83604094601f199360208652816020870152868601375f8582860101520116010190565b919081101561021b5760051b0190565b3560ff811681036102485790565b67ffffffffffffffff81116118b85760051b60200190565b906119dc826119ba565b6119e96040519182611901565b828152601f196119f982946119ba565b0190602036910137565b60015481101561021b5760015f5260205f2001905f90565b6103065481101561021b576103065f5260205f2001905f90565b805482101561021b575f5260205f2001905f90565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114611a775760010190565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b805182101561021b5760209160051b010190565b60405190611ac58261189c565b5f6020838281520152565b90604051611add8161189c565b602060018294805484520154910152565b335f525f60205260405f20541561046b5773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61168114611b9e57805f5261030560205260405f205415611b9b57805f526103056020525f6040812055337fdadd1471db1ea2f303654fb1bdcc010e5a664214ab41934c0f752aabca88a4915f80a3565b50565b60846040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f546f6c6c57697468496d6d757461626c65526f757465723a2063616e6e6f742060448201527f6469737320726f757465720000000000000000000000000000000000000000006064820152fd5b73ffffffffffffffffffffffffffffffffffffffff811690815f525f602052600160405f205414611cd857815f525f602052600160405f205560015490680100000000000000008210156118b857611c85826001611cb194016001556001611a35565b90919073ffffffffffffffffffffffffffffffffffffffff8084549260031b9316831b921b1916179055565b337fe31c10b0adbedd0c6e5d024286c6eeead7761e65a67608dcf0b67604c0da7e2f5f80a3565b5050565b73ffffffffffffffffffffffffffffffffffffffff16805f525f60205260405f205415611b9b57805f525f6020525f6040812055337f58466e5837b54e559819c9ba8a5d7c77c97c985d1aabf4bdc5f41069fa5d65a05f80a3565b3573ffffffffffffffffffffffffffffffffffffffff811681036102485790565b335f525f60205260405f20541561046b5773ffffffffffffffffffffffffffffffffffffffff811690815f52610305602052600160405f205414611cd857815f52610305602052600160405f20556103065490680100000000000000008210156118b857611c85826001611dd3940161030655610306611a35565b337f75d30ca40c7bcd48e685894b82b864808b9cb566090efc53444a2e61742f18a35f80a3565b604051611e068161189c565b602061030754916fffffffffffffffffffffffffffffffff65ffffffffffff84169384835260301c1691829101529080151592565b60405190611e48826118e5565b5f6040838281528260208201520152565b9190611e63611ab8565b50611e6c611e3b565b5060ff6102035416604082019381611e848685611924565b9050036121eb57611e958584611924565b1561021b57358060f81c9061010082101561021b576101fe80611ebf9260f71c1616600301611ad0565b928351916020850192835117156121c0576001909791971b93611ee0611e3b565b505191519660405192611ef2846118e5565b8352602083019788526040830194600186526001925f935b838110612023575050505050611f1e611ab8565b5060405192611f2c8461189c565b5f84525f602085015251955f96600190807ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f915b611fe657505050957ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8092611fb99798828085800980935109875251920990096020830152611fb160208401611d37565b92359161253d565b15611fc2575f90565b7fcbc4755f0000000000000000000000000000000000000000000000000000000090565b7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8183949b930492818c8509820390089290918202900380611f60565b61202d828a611924565b82101561021b57810135908160f81c9161010083101561021b576101fe8061205c9260f71c1616600301611ad0565b9384519260208601938451171561218f576001901b9081811661215e57179387518d51978b5190612131576001947ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f83818f818f978f9982809b818b8180809e819a82809a818085819609809c510990820390089d8e91838b818080878009928184600409998a988d0893820390820308918009089052099b099b519282039409900908600209948180808660020981038382030881888009088098525f9e09600209820394820390089009088c5201611f0a565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52601260045260245ffd5b507fe7908552000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e5639000000000000000000000000000000000000000000000000000000009c505050505050505050505050565b507f552e56390000000000000000000000000000000000000000000000000000000096505050505050565b507f19877c600000000000000000000000000000000000000000000000000000000093505050565b908160409181010312610248576040519061222d8261189c565b803565ffffffffffff81169182820361024857602091845201356fffffffffffffffffffffffffffffffff811691828203610248576020840190828252610307549065ffffffffffff821681111561235d5742106123345765ffffffffffff937fffffffffffffffffffff0000000000000000000000000000000000000000000075ffffffffffffffffffffffffffffffff0000000000006fffffffffffffffffffffffffffffffff958742169360206040516122e98161189c565b868152015260301b169216171761030755511691511660405191825260208201527f9f8b8154174dc4a9ed8bbe5a985ecf6d8b2db481a1c64a02c8d94ae7929e0ba660403392a25f90565b50505050507f5507d1ac0000000000000000000000000000000000000000000000000000000090565b5050505050507f4ef874670000000000000000000000000000000000000000000000000000000090565b61238f611e3b565b505f9160ff610304541693848103612514575f935b8585106123b5575050505050505f90565b8185101561021b57606085028301606081360312610248576040516123d9816118e5565b81359160ff83168084036102485761242e836020955f9552604086850135948588840152013590816040820152506040519384938b859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa15612509575f5160ff73ffffffffffffffffffffffffffffffffffffffff82169160981c169080159081156124d9575b506124ae576001901b80821661248357600191179401936123a4565b505050505050507fe79085520000000000000000000000000000000000000000000000000000000090565b505050505050507fcbc4755f0000000000000000000000000000000000000000000000000000000090565b905061010082101561021b5773ffffffffffffffffffffffffffffffffffffffff8261020401541614155f612467565b6040513d5f823e3d90fd5b50505050507f19877c600000000000000000000000000000000000000000000000000000000090565b909180158015612734575b61272c57602082019081517ffffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f8060078187518181800990090891800903612723577ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141811015612723576126f683601b60017ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141806020995f9951908951907f0100000000000000000000000000000000000000000000000000000000000000604051928e840194855260f81b16604083015260418201527fffffffffffffffffffffffffffffffffffffffff0000000000000000000000008d60601b16606182015260558152612658607582611901565b5190200695845190097ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd036414103955116019051809460ff7ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641416040519788970991865290921660ff16602085015260408401527ffffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd03641410360608301526080820190565b838052039060015afa156125095773ffffffffffffffffffffffffffffffffffffffff805f511691161490565b50505050505f90565b505050505f90565b5073ffffffffffffffffffffffffffffffffffffffff84161561254856fea26469706673582212207274edf763fbf257186cd3efc51a4a943890b9382d23ffbbe1fc72e40ad8b46864736f6c634300081c0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000074258a92611e029b748f79c50024dd851339db15000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61
-----Decoded View---------------
Arg [0] : initialAuthed (address): 0x74258A92611e029b748F79c50024DD851339dB15
Arg [1] : router (address): 0xD40d9E595Bdf98731FBF70da31217C7D7654Db61
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 00000000000000000000000074258a92611e029b748f79c50024dd851339db15
Arg [1] : 000000000000000000000000d40d9e595bdf98731fbf70da31217c7d7654db61
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.