Source Code
Overview
HYPE Balance
HYPE Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 27274836 | 40 hrs ago | Contract Creation | 0 HYPE |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
SP1Verifier
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {ISP1Verifier, ISP1VerifierWithHash} from "../ISP1Verifier.sol";
import {Verifier} from "./Groth16Verifier.sol";
/// @title SP1 Verifier
/// @author Succinct Labs
/// @notice This contracts implements a solidity verifier for SP1.
contract SP1Verifier is Verifier, ISP1VerifierWithHash {
/// @notice Thrown when the verifier selector from this proof does not match the one in this
/// verifier. This indicates that this proof was sent to the wrong verifier.
/// @param received The verifier selector from the first 4 bytes of the proof.
/// @param expected The verifier selector from the first 4 bytes of the VERIFIER_HASH().
error WrongVerifierSelector(bytes4 received, bytes4 expected);
/// @notice Thrown when the exit code is invalid.
error InvalidExitCode();
/// @notice Thrown when the proof is invalid.
error InvalidProof();
/// @notice Thrown when the vkRoot is invalid.
error InvalidVkRoot();
/// @notice The version of the circuit.
function VERSION() external pure returns (string memory) {
return "v6.0.0";
}
/// @inheritdoc ISP1VerifierWithHash
function VERIFIER_HASH() public pure returns (bytes32) {
return 0x0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec896;
}
/// @notice The recursion vk root.
function VK_ROOT() public pure returns (bytes32) {
return 0x008cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e8670;
}
/// @notice Hashes the public values to a field elements inside Bn254.
/// @param publicValues The public values.
function hashPublicValues(bytes calldata publicValues) public pure returns (bytes32) {
return sha256(publicValues) & bytes32(uint256((1 << 253) - 1));
}
/// @notice Verifies a proof with given public values and vkey.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view {
bytes4 receivedSelector = bytes4(proofBytes[:4]);
bytes4 expectedSelector = bytes4(VERIFIER_HASH());
if (receivedSelector != expectedSelector) {
revert WrongVerifierSelector(receivedSelector, expectedSelector);
}
uint256 expectedVkRoot = uint256(VK_ROOT());
bytes32 publicValuesDigest = hashPublicValues(publicValues);
(uint256 exitCode, uint256 vkRoot, uint256 nonce, uint256[8] memory proof) =
abi.decode(proofBytes[4:], (uint256, uint256, uint256, uint256[8]));
if (exitCode != 0) {
revert InvalidExitCode();
}
if (vkRoot != expectedVkRoot) {
revert InvalidVkRoot();
}
uint256[5] memory inputs;
inputs[0] = uint256(programVKey);
inputs[1] = uint256(publicValuesDigest);
inputs[2] = exitCode;
inputs[3] = vkRoot;
inputs[4] = nonce;
this.verifyProof(proof, inputs);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title SP1 Verifier Interface
/// @author Succinct Labs
/// @notice This contract is the interface for the SP1 Verifier.
interface ISP1Verifier {
/// @notice Verifies a proof with given public values and vkey.
/// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of
/// target verifier's VERIFIER_HASH.
/// @param programVKey The verification key for the RISC-V program.
/// @param publicValues The public values encoded as bytes.
/// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes.
function verifyProof(
bytes32 programVKey,
bytes calldata publicValues,
bytes calldata proofBytes
) external view;
}
interface ISP1VerifierWithHash is ISP1Verifier {
/// @notice Returns the hash of the verifier.
function VERIFIER_HASH() external pure returns (bytes32);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/// @title Groth16 verifier template.
/// @author Remco Bloemen
/// @notice Supports verifying Groth16 proofs. Proofs can be in uncompressed
/// (256 bytes) and compressed (128 bytes) format. A view function is provided
/// to compress proofs.
/// @notice See <https://2π.com/23/bn254-compression> for further explanation.
contract Verifier {
/// Some of the provided public input values are larger than the field modulus.
/// @dev Public input elements are not automatically reduced, as this is can be
/// a dangerous source of bugs.
error PublicInputNotInField();
/// The proof is invalid.
/// @dev This can mean that provided Groth16 proof points are not on their
/// curves, that pairing equation fails, or that the proof is not for the
/// provided public input.
error ProofInvalid();
// Addresses of precompiles
uint256 constant PRECOMPILE_MODEXP = 0x05;
uint256 constant PRECOMPILE_ADD = 0x06;
uint256 constant PRECOMPILE_MUL = 0x07;
uint256 constant PRECOMPILE_VERIFY = 0x08;
// Base field Fp order P and scalar field Fr order R.
// For BN254 these are computed as follows:
// t = 4965661367192848881
// P = 36⋅t⁴ + 36⋅t³ + 24⋅t² + 6⋅t + 1
// R = 36⋅t⁴ + 36⋅t³ + 18⋅t² + 6⋅t + 1
uint256 constant P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47;
uint256 constant R = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001;
// Extension field Fp2 = Fp[i] / (i² + 1)
// Note: This is the complex extension field of Fp with i² = -1.
// Values in Fp2 are represented as a pair of Fp elements (a₀, a₁) as a₀ + a₁⋅i.
// Note: The order of Fp2 elements is *opposite* that of the pairing contract, which
// expects Fp2 elements in order (a₁, a₀). This is also the order in which
// Fp2 elements are encoded in the public interface as this became convention.
// Constants in Fp
uint256 constant FRACTION_1_2_FP = 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea4;
uint256 constant FRACTION_27_82_FP = 0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5;
uint256 constant FRACTION_3_82_FP = 0x2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e775;
// Exponents for inversions and square roots mod P
uint256 constant EXP_INVERSE_FP = 0x30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD45; // P - 2
uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4;
// Groth16 alpha point in G1
uint256 constant ALPHA_X = 18193098175943527192735001101109759089299489218029277024981049303509728390714;
uint256 constant ALPHA_Y = 13002098922164504856448878431298858958287263223238113532689647401549143136802;
// Groth16 beta point in G2 in powers of i
uint256 constant BETA_NEG_X_0 = 21435991793309354620208998839048833929408421035752814055468203505370113177907;
uint256 constant BETA_NEG_X_1 = 1153299178682776078763875679774322676284574659382610527726005807059970948421;
uint256 constant BETA_NEG_Y_0 = 14549477341221195645936627541635804922258425228606259869736025448350578736808;
uint256 constant BETA_NEG_Y_1 = 11642222268846896781195289459924484986164757595949162399971767305523112060547;
// Groth16 gamma point in G2 in powers of i
uint256 constant GAMMA_NEG_X_0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant GAMMA_NEG_X_1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant GAMMA_NEG_Y_0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653;
uint256 constant GAMMA_NEG_Y_1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052;
// Groth16 delta point in G2 in powers of i
uint256 constant DELTA_NEG_X_0 = 1307090331524814175704090408842692723818436064448889851578512306950732772855;
uint256 constant DELTA_NEG_X_1 = 137383337791766739140246086388506671891847942071016045052220104013730448401;
uint256 constant DELTA_NEG_Y_0 = 18176516653581763163575152843878714966832153444275466192493637065851642016199;
uint256 constant DELTA_NEG_Y_1 = 19219057324336367439257853584115458794082407148591815287600779150919241441914;
// Constant and public input points
uint256 constant CONSTANT_X = 19076354653072111336552532082014805057498873518518516761323068695350252381540;
uint256 constant CONSTANT_Y = 14722222875656460695102157554156335986355296183699164072914272094029232004506;
uint256 constant PUB_0_X = 15205650220572466259118892361475480343661712697966864528540178421362309949892;
uint256 constant PUB_0_Y = 16870076904710557229902069154949962941355047114880780961340865439247323228457;
uint256 constant PUB_1_X = 16983718256613983916793425440640784309466930024922866755993885618825596154582;
uint256 constant PUB_1_Y = 5082937731183538291488801097598857949092616162025607059421755002399927346065;
uint256 constant PUB_2_X = 4193949434218093934236927708380304233355510984741594680448881554654604634659;
uint256 constant PUB_2_Y = 13994205507046466708587811774761710548204773721153594492816404543789273541310;
uint256 constant PUB_3_X = 18564681243992670607326349759968448650720046559677745125178440392100920501084;
uint256 constant PUB_3_Y = 9302975514291303895397487318903174778917665548854240519153237070996190682800;
uint256 constant PUB_4_X = 15504625725316527736371459206321170330760263395535109031414282104301490600214;
uint256 constant PUB_4_Y = 17721188253172389160253049897039822757501960974163688317614931747181126144820;
/// Negation in Fp.
/// @notice Returns a number x such that a + x = 0 in Fp.
/// @notice The input does not need to be reduced.
/// @param a the base
/// @return x the result
function negate(uint256 a) internal pure returns (uint256 x) {
unchecked {
x = (P - (a % P)) % P; // Modulo is cheaper than branching
}
}
/// Exponentiation in Fp.
/// @notice Returns a number x such that a ^ e = x in Fp.
/// @notice The input does not need to be reduced.
/// @param a the base
/// @param e the exponent
/// @return x the result
function exp(uint256 a, uint256 e) internal view returns (uint256 x) {
bool success;
assembly ("memory-safe") {
let f := mload(0x40)
mstore(f, 0x20)
mstore(add(f, 0x20), 0x20)
mstore(add(f, 0x40), 0x20)
mstore(add(f, 0x60), a)
mstore(add(f, 0x80), e)
mstore(add(f, 0xa0), P)
success := staticcall(gas(), PRECOMPILE_MODEXP, f, 0xc0, f, 0x20)
x := mload(f)
}
if (!success) {
// Exponentiation failed.
// Should not happen.
revert ProofInvalid();
}
}
/// Invertsion in Fp.
/// @notice Returns a number x such that a * x = 1 in Fp.
/// @notice The input does not need to be reduced.
/// @notice Reverts with ProofInvalid() if the inverse does not exist
/// @param a the input
/// @return x the solution
function invert_Fp(uint256 a) internal view returns (uint256 x) {
x = exp(a, EXP_INVERSE_FP);
if (mulmod(a, x, P) != 1) {
// Inverse does not exist.
// Can only happen during G2 point decompression.
revert ProofInvalid();
}
}
/// Square root in Fp.
/// @notice Returns a number x such that x * x = a in Fp.
/// @notice Will revert with InvalidProof() if the input is not a square
/// or not reduced.
/// @param a the square
/// @return x the solution
function sqrt_Fp(uint256 a) internal view returns (uint256 x) {
x = exp(a, EXP_SQRT_FP);
if (mulmod(x, x, P) != a) {
// Square root does not exist or a is not reduced.
// Happens when G1 point is not on curve.
revert ProofInvalid();
}
}
/// Square test in Fp.
/// @notice Returns whether a number x exists such that x * x = a in Fp.
/// @notice Will revert with InvalidProof() if the input is not a square
/// or not reduced.
/// @param a the square
/// @return x the solution
function isSquare_Fp(uint256 a) internal view returns (bool) {
uint256 x = exp(a, EXP_SQRT_FP);
return mulmod(x, x, P) == a;
}
/// Square root in Fp2.
/// @notice Fp2 is the complex extension Fp[i]/(i^2 + 1). The input is
/// a0 + a1 ⋅ i and the result is x0 + x1 ⋅ i.
/// @notice Will revert with InvalidProof() if
/// * the input is not a square,
/// * the hint is incorrect, or
/// * the input coefficients are not reduced.
/// @param a0 The real part of the input.
/// @param a1 The imaginary part of the input.
/// @param hint A hint which of two possible signs to pick in the equation.
/// @return x0 The real part of the square root.
/// @return x1 The imaginary part of the square root.
function sqrt_Fp2(uint256 a0, uint256 a1, bool hint) internal view returns (uint256 x0, uint256 x1) {
// If this square root reverts there is no solution in Fp2.
uint256 d = sqrt_Fp(addmod(mulmod(a0, a0, P), mulmod(a1, a1, P), P));
if (hint) {
d = negate(d);
}
// If this square root reverts there is no solution in Fp2.
x0 = sqrt_Fp(mulmod(addmod(a0, d, P), FRACTION_1_2_FP, P));
x1 = mulmod(a1, invert_Fp(mulmod(x0, 2, P)), P);
// Check result to make sure we found a root.
// Note: this also fails if a0 or a1 is not reduced.
if (a0 != addmod(mulmod(x0, x0, P), negate(mulmod(x1, x1, P)), P)
|| a1 != mulmod(2, mulmod(x0, x1, P), P)) {
revert ProofInvalid();
}
}
/// Compress a G1 point.
/// @notice Reverts with InvalidProof if the coordinates are not reduced
/// or if the point is not on the curve.
/// @notice The point at infinity is encoded as (0,0) and compressed to 0.
/// @param x The X coordinate in Fp.
/// @param y The Y coordinate in Fp.
/// @return c The compresed point (x with one signal bit).
function compress_g1(uint256 x, uint256 y) internal view returns (uint256 c) {
if (x >= P || y >= P) {
// G1 point not in field.
revert ProofInvalid();
}
if (x == 0 && y == 0) {
// Point at infinity
return 0;
}
// Note: sqrt_Fp reverts if there is no solution, i.e. the x coordinate is invalid.
uint256 y_pos = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P));
if (y == y_pos) {
return (x << 1) | 0;
} else if (y == negate(y_pos)) {
return (x << 1) | 1;
} else {
// G1 point not on curve.
revert ProofInvalid();
}
}
/// Decompress a G1 point.
/// @notice Reverts with InvalidProof if the input does not represent a valid point.
/// @notice The point at infinity is encoded as (0,0) and compressed to 0.
/// @param c The compresed point (x with one signal bit).
/// @return x The X coordinate in Fp.
/// @return y The Y coordinate in Fp.
function decompress_g1(uint256 c) internal view returns (uint256 x, uint256 y) {
// Note that X = 0 is not on the curve since 0³ + 3 = 3 is not a square.
// so we can use it to represent the point at infinity.
if (c == 0) {
// Point at infinity as encoded in EIP196 and EIP197.
return (0, 0);
}
bool negate_point = c & 1 == 1;
x = c >> 1;
if (x >= P) {
// G1 x coordinate not in field.
revert ProofInvalid();
}
// Note: (x³ + 3) is irreducible in Fp, so it can not be zero and therefore
// y can not be zero.
// Note: sqrt_Fp reverts if there is no solution, i.e. the point is not on the curve.
y = sqrt_Fp(addmod(mulmod(mulmod(x, x, P), x, P), 3, P));
if (negate_point) {
y = negate(y);
}
}
/// Compress a G2 point.
/// @notice Reverts with InvalidProof if the coefficients are not reduced
/// or if the point is not on the curve.
/// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1)
/// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i).
/// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0).
/// @param x0 The real part of the X coordinate.
/// @param x1 The imaginary poart of the X coordinate.
/// @param y0 The real part of the Y coordinate.
/// @param y1 The imaginary part of the Y coordinate.
/// @return c0 The first half of the compresed point (x0 with two signal bits).
/// @return c1 The second half of the compressed point (x1 unmodified).
function compress_g2(uint256 x0, uint256 x1, uint256 y0, uint256 y1)
internal view returns (uint256 c0, uint256 c1) {
if (x0 >= P || x1 >= P || y0 >= P || y1 >= P) {
// G2 point not in field.
revert ProofInvalid();
}
if ((x0 | x1 | y0 | y1) == 0) {
// Point at infinity
return (0, 0);
}
// Compute y^2
// Note: shadowing variables and scoping to avoid stack-to-deep.
uint256 y0_pos;
uint256 y1_pos;
{
uint256 n3ab = mulmod(mulmod(x0, x1, P), P-3, P);
uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P);
uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P);
y0_pos = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P);
y1_pos = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P));
}
// Determine hint bit
// If this sqrt fails the x coordinate is not on the curve.
bool hint;
{
uint256 d = sqrt_Fp(addmod(mulmod(y0_pos, y0_pos, P), mulmod(y1_pos, y1_pos, P), P));
hint = !isSquare_Fp(mulmod(addmod(y0_pos, d, P), FRACTION_1_2_FP, P));
}
// Recover y
(y0_pos, y1_pos) = sqrt_Fp2(y0_pos, y1_pos, hint);
if (y0 == y0_pos && y1 == y1_pos) {
c0 = (x0 << 2) | (hint ? 2 : 0) | 0;
c1 = x1;
} else if (y0 == negate(y0_pos) && y1 == negate(y1_pos)) {
c0 = (x0 << 2) | (hint ? 2 : 0) | 1;
c1 = x1;
} else {
// G1 point not on curve.
revert ProofInvalid();
}
}
/// Decompress a G2 point.
/// @notice Reverts with InvalidProof if the input does not represent a valid point.
/// @notice The G2 curve is defined over the complex extension Fp[i]/(i^2 + 1)
/// with coordinates (x0 + x1 ⋅ i, y0 + y1 ⋅ i).
/// @notice The point at infinity is encoded as (0,0,0,0) and compressed to (0,0).
/// @param c0 The first half of the compresed point (x0 with two signal bits).
/// @param c1 The second half of the compressed point (x1 unmodified).
/// @return x0 The real part of the X coordinate.
/// @return x1 The imaginary poart of the X coordinate.
/// @return y0 The real part of the Y coordinate.
/// @return y1 The imaginary part of the Y coordinate.
function decompress_g2(uint256 c0, uint256 c1)
internal view returns (uint256 x0, uint256 x1, uint256 y0, uint256 y1) {
// Note that X = (0, 0) is not on the curve since 0³ + 3/(9 + i) is not a square.
// so we can use it to represent the point at infinity.
if (c0 == 0 && c1 == 0) {
// Point at infinity as encoded in EIP197.
return (0, 0, 0, 0);
}
bool negate_point = c0 & 1 == 1;
bool hint = c0 & 2 == 2;
x0 = c0 >> 2;
x1 = c1;
if (x0 >= P || x1 >= P) {
// G2 x0 or x1 coefficient not in field.
revert ProofInvalid();
}
uint256 n3ab = mulmod(mulmod(x0, x1, P), P-3, P);
uint256 a_3 = mulmod(mulmod(x0, x0, P), x0, P);
uint256 b_3 = mulmod(mulmod(x1, x1, P), x1, P);
y0 = addmod(FRACTION_27_82_FP, addmod(a_3, mulmod(n3ab, x1, P), P), P);
y1 = negate(addmod(FRACTION_3_82_FP, addmod(b_3, mulmod(n3ab, x0, P), P), P));
// Note: sqrt_Fp2 reverts if there is no solution, i.e. the point is not on the curve.
// Note: (X³ + 3/(9 + i)) is irreducible in Fp2, so y can not be zero.
// But y0 or y1 may still independently be zero.
(y0, y1) = sqrt_Fp2(y0, y1, hint);
if (negate_point) {
y0 = negate(y0);
y1 = negate(y1);
}
}
/// Compute the public input linear combination.
/// @notice Reverts with PublicInputNotInField if the input is not in the field.
/// @notice Computes the multi-scalar-multiplication of the public input
/// elements and the verification key including the constant term.
/// @param input The public inputs. These are elements of the scalar field Fr.
/// @return x The X coordinate of the resulting G1 point.
/// @return y The Y coordinate of the resulting G1 point.
function publicInputMSM(uint256[5] calldata input)
internal view returns (uint256 x, uint256 y) {
// Note: The ECMUL precompile does not reject unreduced values, so we check this.
// Note: Unrolling this loop does not cost much extra in code-size, the bulk of the
// code-size is in the PUB_ constants.
// ECMUL has input (x, y, scalar) and output (x', y').
// ECADD has input (x1, y1, x2, y2) and output (x', y').
// We reduce commitments(if any) with constants as the first point argument to ECADD.
// We call them such that ecmul output is already in the second point
// argument to ECADD so we can have a tight loop.
bool success = true;
assembly ("memory-safe") {
let f := mload(0x40)
let g := add(f, 0x40)
let s
mstore(f, CONSTANT_X)
mstore(add(f, 0x20), CONSTANT_Y)
mstore(g, PUB_0_X)
mstore(add(g, 0x20), PUB_0_Y)
s := calldataload(input)
mstore(add(g, 0x40), s)
success := and(success, lt(s, R))
success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40))
success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40))
mstore(g, PUB_1_X)
mstore(add(g, 0x20), PUB_1_Y)
s := calldataload(add(input, 32))
mstore(add(g, 0x40), s)
success := and(success, lt(s, R))
success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40))
success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40))
mstore(g, PUB_2_X)
mstore(add(g, 0x20), PUB_2_Y)
s := calldataload(add(input, 64))
mstore(add(g, 0x40), s)
success := and(success, lt(s, R))
success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40))
success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40))
mstore(g, PUB_3_X)
mstore(add(g, 0x20), PUB_3_Y)
s := calldataload(add(input, 96))
mstore(add(g, 0x40), s)
success := and(success, lt(s, R))
success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40))
success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40))
mstore(g, PUB_4_X)
mstore(add(g, 0x20), PUB_4_Y)
s := calldataload(add(input, 128))
mstore(add(g, 0x40), s)
success := and(success, lt(s, R))
success := and(success, staticcall(gas(), PRECOMPILE_MUL, g, 0x60, g, 0x40))
success := and(success, staticcall(gas(), PRECOMPILE_ADD, f, 0x80, f, 0x40))
x := mload(f)
y := mload(add(f, 0x20))
}
if (!success) {
// Either Public input not in field, or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
revert PublicInputNotInField();
}
}
/// Compress a proof.
/// @notice Will revert with InvalidProof if the curve points are invalid,
/// but does not verify the proof itself.
/// @param proof The uncompressed Groth16 proof. Elements are in the same order as for
/// verifyProof. I.e. Groth16 points (A, B, C) encoded as in EIP-197.
/// @return compressed The compressed proof. Elements are in the same order as for
/// verifyCompressedProof. I.e. points (A, B, C) in compressed format.
function compressProof(uint256[8] calldata proof)
public view returns (uint256[4] memory compressed) {
compressed[0] = compress_g1(proof[0], proof[1]);
(compressed[2], compressed[1]) = compress_g2(proof[3], proof[2], proof[5], proof[4]);
compressed[3] = compress_g1(proof[6], proof[7]);
}
/// Verify a Groth16 proof with compressed points.
/// @notice Reverts with InvalidProof if the proof is invalid or
/// with PublicInputNotInField the public input is not reduced.
/// @notice There is no return value. If the function does not revert, the
/// proof was successfully verified.
/// @param compressedProof the points (A, B, C) in compressed format
/// matching the output of compressProof.
/// @param input the public input field elements in the scalar field Fr.
/// Elements must be reduced.
function verifyCompressedProof(
uint256[4] calldata compressedProof,
uint256[5] calldata input
) public view {
uint256[24] memory pairings;
{
(uint256 Ax, uint256 Ay) = decompress_g1(compressedProof[0]);
(uint256 Bx0, uint256 Bx1, uint256 By0, uint256 By1) = decompress_g2(compressedProof[2], compressedProof[1]);
(uint256 Cx, uint256 Cy) = decompress_g1(compressedProof[3]);
(uint256 Lx, uint256 Ly) = publicInputMSM(input);
// Verify the pairing
// Note: The precompile expects the F2 coefficients in big-endian order.
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
// e(A, B)
pairings[ 0] = Ax;
pairings[ 1] = Ay;
pairings[ 2] = Bx1;
pairings[ 3] = Bx0;
pairings[ 4] = By1;
pairings[ 5] = By0;
// e(C, -δ)
pairings[ 6] = Cx;
pairings[ 7] = Cy;
pairings[ 8] = DELTA_NEG_X_1;
pairings[ 9] = DELTA_NEG_X_0;
pairings[10] = DELTA_NEG_Y_1;
pairings[11] = DELTA_NEG_Y_0;
// e(α, -β)
pairings[12] = ALPHA_X;
pairings[13] = ALPHA_Y;
pairings[14] = BETA_NEG_X_1;
pairings[15] = BETA_NEG_X_0;
pairings[16] = BETA_NEG_Y_1;
pairings[17] = BETA_NEG_Y_0;
// e(L_pub, -γ)
pairings[18] = Lx;
pairings[19] = Ly;
pairings[20] = GAMMA_NEG_X_1;
pairings[21] = GAMMA_NEG_X_0;
pairings[22] = GAMMA_NEG_Y_1;
pairings[23] = GAMMA_NEG_Y_0;
// Check pairing equation.
bool success;
uint256[1] memory output;
assembly ("memory-safe") {
success := staticcall(gas(), PRECOMPILE_VERIFY, pairings, 0x300, output, 0x20)
}
if (!success || output[0] != 1) {
// Either proof or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
revert ProofInvalid();
}
}
}
/// Verify an uncompressed Groth16 proof.
/// @notice Reverts with InvalidProof if the proof is invalid or
/// with PublicInputNotInField the public input is not reduced.
/// @notice There is no return value. If the function does not revert, the
/// proof was successfully verified.
/// @param proof the points (A, B, C) in EIP-197 format matching the output
/// of compressProof.
/// @param input the public input field elements in the scalar field Fr.
/// Elements must be reduced.
function verifyProof(
uint256[8] calldata proof,
uint256[5] calldata input
) public view {
(uint256 x, uint256 y) = publicInputMSM(input);
// Note: The precompile expects the F2 coefficients in big-endian order.
// Note: The pairing precompile rejects unreduced values, so we won't check that here.
bool success;
assembly ("memory-safe") {
let f := mload(0x40) // Free memory pointer.
// Copy points (A, B, C) to memory. They are already in correct encoding.
// This is pairing e(A, B) and G1 of e(C, -δ).
calldatacopy(f, proof, 0x100)
// Complete e(C, -δ) and write e(α, -β), e(L_pub, -γ) to memory.
// OPT: This could be better done using a single codecopy, but
// Solidity (unlike standalone Yul) doesn't provide a way to
// to do this.
mstore(add(f, 0x100), DELTA_NEG_X_1)
mstore(add(f, 0x120), DELTA_NEG_X_0)
mstore(add(f, 0x140), DELTA_NEG_Y_1)
mstore(add(f, 0x160), DELTA_NEG_Y_0)
mstore(add(f, 0x180), ALPHA_X)
mstore(add(f, 0x1a0), ALPHA_Y)
mstore(add(f, 0x1c0), BETA_NEG_X_1)
mstore(add(f, 0x1e0), BETA_NEG_X_0)
mstore(add(f, 0x200), BETA_NEG_Y_1)
mstore(add(f, 0x220), BETA_NEG_Y_0)
mstore(add(f, 0x240), x)
mstore(add(f, 0x260), y)
mstore(add(f, 0x280), GAMMA_NEG_X_1)
mstore(add(f, 0x2a0), GAMMA_NEG_X_0)
mstore(add(f, 0x2c0), GAMMA_NEG_Y_1)
mstore(add(f, 0x2e0), GAMMA_NEG_Y_0)
// Check pairing equation.
success := staticcall(gas(), PRECOMPILE_VERIFY, f, 0x300, f, 0x20)
// Also check returned value (both are either 1 or 0).
success := and(success, mload(f))
}
if (!success) {
// Either proof or verification key invalid.
// We assume the contract is correctly generated, so the verification key is valid.
revert ProofInvalid();
}
}
}{
"remappings": [
"@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
"ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "shanghai",
"viaIR": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"name":"InvalidExitCode","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidVkRoot","type":"error"},{"inputs":[],"name":"ProofInvalid","type":"error"},{"inputs":[],"name":"PublicInputNotInField","type":"error"},{"inputs":[{"internalType":"bytes4","name":"received","type":"bytes4"},{"internalType":"bytes4","name":"expected","type":"bytes4"}],"name":"WrongVerifierSelector","type":"error"},{"inputs":[],"name":"VERIFIER_HASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"VK_ROOT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"}],"name":"compressProof","outputs":[{"internalType":"uint256[4]","name":"compressed","type":"uint256[4]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"publicValues","type":"bytes"}],"name":"hashPublicValues","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256[4]","name":"compressedProof","type":"uint256[4]"},{"internalType":"uint256[5]","name":"input","type":"uint256[5]"}],"name":"verifyCompressedProof","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[8]","name":"proof","type":"uint256[8]"},{"internalType":"uint256[5]","name":"input","type":"uint256[5]"}],"name":"verifyProof","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"programVKey","type":"bytes32"},{"internalType":"bytes","name":"publicValues","type":"bytes"},{"internalType":"bytes","name":"proofBytes","type":"bytes"}],"name":"verifyProof","outputs":[],"stateMutability":"view","type":"function"}]Contract Creation Code
608060405234801561000f575f80fd5b50611a548061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610085575f3560e01c80636b61d8e7116100585780636b61d8e7146101065780637cad4e1314610119578063a67086041461013e578063ffa1ad7414610151575f80fd5b80632a07d99a146100895780632a5104361461009e57806341493c60146100d357806344f63692146100e6575b5f80fd5b61009c610097366004611620565b610179565b005b7f0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec8965b6040519081526020015b60405180910390f35b61009c6100e136600461169a565b6103f6565b6100f96100f436600461170e565b610593565b6040516100ca9190611730565b6100c0610114366004611760565b6105f0565b7e8cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e86706100c0565b61009c61014c36600461179f565b610655565b6040805180820182526006815265076362e302e360d41b602082015290516100ca91906117d8565b5f806101848361096e565b915091505f6040516101008682377e4dc1973723ec3d0b4070ff5252997c42a13bde5927768bf8a427b13a7a84116101008201527f02e3c972f8d24e54fa806283471852a829579d53987c874db351f2da2d0bf5f76101208201527f2a7d99d860e085078e65c4fc54e89eb8c2a5590a57b09d19b4c4e119168e227a6101408201527f282f8b39b2044e8d391402421e461391815bb265f3e87e5a38cb54a1e73b71c76101608201527f2838edbc8aee47ec511c2837d538a49ffd752370e06ed44e109b4c0f35be6e3a6101808201527f1cbeed5cf07bc7baa706137b59f34086467c2ebc770205fd1038c2c70d5ada226101a08201527f028cbe84124fba3ad76d33e6ca441f570726da5692cae5335a52209a15b9fd456101c08201527f2f6457660eeb88acf2baf1e7aefc0958da27058879cc77ba162d2df754aaf9336101e08201527f19bd43a87907704ce03cb365e44c3375453e8d24ab626dcc7081b28d60f626836102008201527f202ab65c6ef68868df1a07b213125fd12b1c480090563941d2e74243dffd7ea861022082015283610240820152826102608201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08201526020816103008360085afa9051169050806103ef57604051631ff3747d60e21b815260040160405180910390fd5b5050505050565b5f6104046004828486611823565b61040d9161184a565b90507f0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec896630e78f4db60e01b6001600160e01b03198316146104795760405163988066a160e01b81526001600160e01b031980841660048301528216602482015260440160405180910390fd5b7e8cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e86705f6104a488886105f0565b90505f8080806104b7896004818d611823565b8101906104c4919061188e565b9350935093509350835f146104ec57604051631fcf917760e01b815260040160405180910390fd5b85831461050c57604051631ab15d8b60e31b815260040160405180910390fd5b610514611586565b8d8152602081018690526040808201869052606082018590526080820184905251631503eccd60e11b81523090632a07d99a906105579085908590600401611929565b5f6040518083038186803b15801561056d575f80fd5b505afa15801561057f573d5f803e3d5ffd5b505050505050505050505050505050505050565b61059b6115a4565b6105ae82358360015b6020020135610c90565b81526105cc6060830135604084013560a08501356080860135610d7c565b602083015260408201526105e660c08301358360076105a4565b6060820152919050565b5f6001600160fd1b035f1b6002848460405161060d929190611985565b602060405180830381855afa158015610628573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061064b9190611994565b1690505b92915050565b61065d6115c2565b5f8061066f85825b6020020135611055565b90925090505f80808061068a60408a013560208b01356110f3565b929650909450925090505f806106a18b6003610665565b915091505f806106b08c61096e565b8b8d5260208d018b905260408d0189905260608d018a905260808d0187905260a08d0188905260c08d0186905260e08d018590527e4dc1973723ec3d0b4070ff5252997c42a13bde5927768bf8a427b13a7a84116101008e01527f02e3c972f8d24e54fa806283471852a829579d53987c874db351f2da2d0bf5f76101208e01527f2a7d99d860e085078e65c4fc54e89eb8c2a5590a57b09d19b4c4e119168e227a6101408e01527f282f8b39b2044e8d391402421e461391815bb265f3e87e5a38cb54a1e73b71c76101608e01527f2838edbc8aee47ec511c2837d538a49ffd752370e06ed44e109b4c0f35be6e3a6101808e01527f1cbeed5cf07bc7baa706137b59f34086467c2ebc770205fd1038c2c70d5ada226101a08e01527f028cbe84124fba3ad76d33e6ca441f570726da5692cae5335a52209a15b9fd456101c08e01527f2f6457660eeb88acf2baf1e7aefc0958da27058879cc77ba162d2df754aaf9336101e08e01527f19bd43a87907704ce03cb365e44c3375453e8d24ab626dcc7081b28d60f626836102008e01527f202ab65c6ef68868df1a07b213125fd12b1c480090563941d2e74243dffd7ea86102208e01526102408d018290526102608d018190527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808e01527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08e01527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08e01527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08e015290925090505f6109236115e1565b6020816103008f60085afa915081158061093f57508051600114155b1561095d57604051631ff3747d60e21b815260040160405180910390fd5b505050505050505050505050505050565b5f805f60019050604051604081015f7f2a2cd5881e62ead81dc6997cfff997745379facd38c972e0825deedb0e4fa56483527f208c7b9c6bf876a51b3d62d0a5bdc0d7188e7342dea7d32ddb9635e291e8dd9a60208401527f219e17d13bc5f5ae36d78093cd6d112374a69844b7d058a7a0a62493f1c369c482527f254c200a2cdb5bc5e4e262780b4c70a988c4317fb11ac5fd5491f10692d1e9296020830152863590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f258c71a2309359a248879ba915796e5e2e655acebace0ae7ef8fda2d40d2b2d682527f0b3cd73ef5ee90c6808893b3e4f81d8da3438cb5d2b601045825b2ab3990a3916020830152602087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f0945b0f65ee8acfce0b22bab7a27663bfaf8eed78d511a96a54b50f307cd2a2382527f1ef0708b683e9cbfeb8800001f06f9c80950d60869ebfc6b5cc58bd2bbfd6abe6020830152604087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f290b3cba8ec4c97f171261b17b9c90e101b65934db12f4a299d4d5b939e9235c82527f14914c2bf919019e575b0bd613363aa160d700bd929bcbc14de06a05e3a25eb06020830152606087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa7f22474ea30b64abc35269a0c55be5972965bf920e937c3d1927da5e89e60cf91683527f272dd64ca95c75938da75797ef702ec5112808c36914020a4b1822fff576d3346020840152608088013560408085018290525f805160206119ff83398151915290911091909516169390508160608160075afa831692505060408160808360065afa81516020909201519194509092501680610c8a5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5f5f805160206119df83398151915283101580610cba57505f805160206119df8339815191528210155b15610cd857604051631ff3747d60e21b815260040160405180910390fd5b82158015610ce4575081155b15610cf057505f61064f565b5f610d2b5f805160206119df83398151915260035f805160206119df833981519152875f805160206119df833981519152898a0909086112c7565b9050808303610d40575050600182901b61064f565b610d4981611329565b8303610d5c575050600182811b1761064f565b604051631ff3747d60e21b815260040160405180910390fd5b5092915050565b5f805f805160206119df83398151915286101580610da757505f805160206119df8339815191528510155b80610dbf57505f805160206119df8339815191528410155b80610dd757505f805160206119df8339815191528310155b15610df557604051631ff3747d60e21b815260040160405180910390fd5b828486881717175f03610e0c57505f90508061104c565b5f80805f805160206119df833981519152610e3560035f805160206119df8339815191526119bf565b5f805160206119df8339815191528a8c090990505f5f805160206119df8339815191528a5f805160206119df8339815191528c8d090990505f5f805160206119df8339815191528a5f805160206119df8339815191528c8d090990505f805160206119df833981519152805f805160206119df8339815191528c860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5089450610f235f805160206119df833981519152805f805160206119df8339815191528e870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e77508611329565b93505050505f80610f705f805160206119df83398151915280610f4857610f486119ab565b5f805160206119df8339815191528586095f805160206119df833981519152878809086112c7565b9050610fbb5f805160206119df8339815191527f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea45f805160206119df83398151915284880809611341565b15915050610fca838383611389565b90935091508683148015610fdd57508186145b156110055780610fed575f610ff0565b60025b60ff1660028a901b175f179450879350611048565b61100e83611329565b87148015611023575061102082611329565b86145b15610d5c5780611033575f611036565b60025b60ff1660028a901b1760011794508793505b5050505b94509492505050565b5f80825f0361106857505f928392509050565b600183811c9250808416145f805160206119df83398151915283106110a057604051631ff3747d60e21b815260040160405180910390fd5b6110da5f805160206119df83398151915260035f805160206119df833981519152865f805160206119df83398151915288890909086112c7565b91508015610c8a576110eb82611329565b915050915091565b5f80808085158015611103575084155b1561111857505f9250829150819050806112be565b600286811c945085935060018088161490808816145f805160206119df8339815191528610158061115657505f805160206119df8339815191528510155b1561117457604051631ff3747d60e21b815260040160405180910390fd5b5f5f805160206119df83398151915261119b60035f805160206119df8339815191526119bf565b5f805160206119df833981519152888a090990505f5f805160206119df833981519152885f805160206119df8339815191528a8b090990505f5f805160206119df833981519152885f805160206119df8339815191528a8b090990505f805160206119df833981519152805f805160206119df8339815191528a860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e50896506112895f805160206119df833981519152805f805160206119df8339815191528c870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e77508611329565b9550611296878786611389565b909750955084156112b8576112aa87611329565b96506112b586611329565b95505b50505050505b92959194509250565b5f6112f2827f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526114c5565b9050815f805160206119df8339815191528283091461132457604051631ff3747d60e21b815260040160405180910390fd5b919050565b5f805160206119df8339815191529081900681030690565b5f8061136d837f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526114c5565b9050825f805160206119df833981519152828309149392505050565b5f80806113b85f805160206119df833981519152808788095f805160206119df833981519152898a09086112c7565b905083156113cc576113c981611329565b90505b6114155f805160206119df8339815191527f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea45f805160206119df833981519152848a08096112c7565b92505f805160206119df83398151915261143f5f805160206119df83398151915260028609611528565b860991505f805160206119df83398151915261146a5f805160206119df833981519152848509611329565b5f805160206119df833981519152858609088614158061149e57505f805160206119df833981519152808385096002098514155b156114bc57604051631ff3747d60e21b815260040160405180910390fd5b50935093915050565b5f8060405160208152602080820152602060408201528460608201528360808201525f805160206119df83398151915260a082015260208160c08360055afa90519250905080610d7557604051631ff3747d60e21b815260040160405180910390fd5b5f611553827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd456114c5565b90505f805160206119df83398151915281830960011461132457604051631ff3747d60e21b815260040160405180910390fd5b6040518060a001604052806005906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518061030001604052806018906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b80610100810183101561064f575f80fd5b8060a0810183101561064f575f80fd5b5f806101a08385031215611632575f80fd5b61163c84846115ff565b915061164c846101008501611610565b90509250929050565b5f8083601f840112611665575f80fd5b50813567ffffffffffffffff81111561167c575f80fd5b602083019150836020828501011115611693575f80fd5b9250929050565b5f805f805f606086880312156116ae575f80fd5b85359450602086013567ffffffffffffffff808211156116cc575f80fd5b6116d889838a01611655565b909650945060408801359150808211156116f0575f80fd5b506116fd88828901611655565b969995985093965092949392505050565b5f610100828403121561171f575f80fd5b61172983836115ff565b9392505050565b6080810181835f5b6004811015611757578151835260209283019290910190600101611738565b50505092915050565b5f8060208385031215611771575f80fd5b823567ffffffffffffffff811115611787575f80fd5b61179385828601611655565b90969095509350505050565b5f8061012083850312156117b1575f80fd5b60808301848111156117c1575f80fd5b8392506117ce8582611610565b9150509250929050565b5f6020808352835180828501525f5b81811015611803578581018301518582016040015282016117e7565b505f604082860101526040601f19601f8301168501019250505092915050565b5f8085851115611831575f80fd5b8386111561183d575f80fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156118725780818660040360031b1b83161692505b505092915050565b634e487b7160e01b5f52604160045260245ffd5b5f805f806101608086880312156118a3575f80fd5b8535945060208087013594506040870135935087607f8801126118c4575f80fd5b604051610100810181811067ffffffffffffffff821117156118e8576118e861187a565b6040529187019180898411156118fc575f80fd5b606089015b848110156119185780358252908301908301611901565b505080935050505092959194509250565b6101a0810181845f5b6008811015611951578151835260209283019290910190600101611932565b5050506101008201835f5b600581101561197b57815183526020928301929091019060010161195c565b5050509392505050565b818382375f9101908152919050565b5f602082840312156119a4575f80fd5b5051919050565b634e487b7160e01b5f52601260045260245ffd5b8181038181111561064f57634e487b7160e01b5f52601160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220fb64900adc9aa14a5210dc320a76bf743fe75ad3802083bfcf05f84cbaa7d6e064736f6c63430008140033
Deployed Bytecode
0x608060405234801561000f575f80fd5b5060043610610085575f3560e01c80636b61d8e7116100585780636b61d8e7146101065780637cad4e1314610119578063a67086041461013e578063ffa1ad7414610151575f80fd5b80632a07d99a146100895780632a5104361461009e57806341493c60146100d357806344f63692146100e6575b5f80fd5b61009c610097366004611620565b610179565b005b7f0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec8965b6040519081526020015b60405180910390f35b61009c6100e136600461169a565b6103f6565b6100f96100f436600461170e565b610593565b6040516100ca9190611730565b6100c0610114366004611760565b6105f0565b7e8cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e86706100c0565b61009c61014c36600461179f565b610655565b6040805180820182526006815265076362e302e360d41b602082015290516100ca91906117d8565b5f806101848361096e565b915091505f6040516101008682377e4dc1973723ec3d0b4070ff5252997c42a13bde5927768bf8a427b13a7a84116101008201527f02e3c972f8d24e54fa806283471852a829579d53987c874db351f2da2d0bf5f76101208201527f2a7d99d860e085078e65c4fc54e89eb8c2a5590a57b09d19b4c4e119168e227a6101408201527f282f8b39b2044e8d391402421e461391815bb265f3e87e5a38cb54a1e73b71c76101608201527f2838edbc8aee47ec511c2837d538a49ffd752370e06ed44e109b4c0f35be6e3a6101808201527f1cbeed5cf07bc7baa706137b59f34086467c2ebc770205fd1038c2c70d5ada226101a08201527f028cbe84124fba3ad76d33e6ca441f570726da5692cae5335a52209a15b9fd456101c08201527f2f6457660eeb88acf2baf1e7aefc0958da27058879cc77ba162d2df754aaf9336101e08201527f19bd43a87907704ce03cb365e44c3375453e8d24ab626dcc7081b28d60f626836102008201527f202ab65c6ef68868df1a07b213125fd12b1c480090563941d2e74243dffd7ea861022082015283610240820152826102608201527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808201527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08201527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08201527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08201526020816103008360085afa9051169050806103ef57604051631ff3747d60e21b815260040160405180910390fd5b5050505050565b5f6104046004828486611823565b61040d9161184a565b90507f0e78f4db7a6771a3a6a7d9c3b0de6fe73d58781368967a7fe84d87aefffec896630e78f4db60e01b6001600160e01b03198316146104795760405163988066a160e01b81526001600160e01b031980841660048301528216602482015260440160405180910390fd5b7e8cd56e10c2fe24795cff1e1d1f40d3a324528d315674da45d26afb376e86705f6104a488886105f0565b90505f8080806104b7896004818d611823565b8101906104c4919061188e565b9350935093509350835f146104ec57604051631fcf917760e01b815260040160405180910390fd5b85831461050c57604051631ab15d8b60e31b815260040160405180910390fd5b610514611586565b8d8152602081018690526040808201869052606082018590526080820184905251631503eccd60e11b81523090632a07d99a906105579085908590600401611929565b5f6040518083038186803b15801561056d575f80fd5b505afa15801561057f573d5f803e3d5ffd5b505050505050505050505050505050505050565b61059b6115a4565b6105ae82358360015b6020020135610c90565b81526105cc6060830135604084013560a08501356080860135610d7c565b602083015260408201526105e660c08301358360076105a4565b6060820152919050565b5f6001600160fd1b035f1b6002848460405161060d929190611985565b602060405180830381855afa158015610628573d5f803e3d5ffd5b5050506040513d601f19601f8201168201806040525081019061064b9190611994565b1690505b92915050565b61065d6115c2565b5f8061066f85825b6020020135611055565b90925090505f80808061068a60408a013560208b01356110f3565b929650909450925090505f806106a18b6003610665565b915091505f806106b08c61096e565b8b8d5260208d018b905260408d0189905260608d018a905260808d0187905260a08d0188905260c08d0186905260e08d018590527e4dc1973723ec3d0b4070ff5252997c42a13bde5927768bf8a427b13a7a84116101008e01527f02e3c972f8d24e54fa806283471852a829579d53987c874db351f2da2d0bf5f76101208e01527f2a7d99d860e085078e65c4fc54e89eb8c2a5590a57b09d19b4c4e119168e227a6101408e01527f282f8b39b2044e8d391402421e461391815bb265f3e87e5a38cb54a1e73b71c76101608e01527f2838edbc8aee47ec511c2837d538a49ffd752370e06ed44e109b4c0f35be6e3a6101808e01527f1cbeed5cf07bc7baa706137b59f34086467c2ebc770205fd1038c2c70d5ada226101a08e01527f028cbe84124fba3ad76d33e6ca441f570726da5692cae5335a52209a15b9fd456101c08e01527f2f6457660eeb88acf2baf1e7aefc0958da27058879cc77ba162d2df754aaf9336101e08e01527f19bd43a87907704ce03cb365e44c3375453e8d24ab626dcc7081b28d60f626836102008e01527f202ab65c6ef68868df1a07b213125fd12b1c480090563941d2e74243dffd7ea86102208e01526102408d018290526102608d018190527f198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c26102808e01527f1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed6102a08e01527f275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec6102c08e01527f1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d6102e08e015290925090505f6109236115e1565b6020816103008f60085afa915081158061093f57508051600114155b1561095d57604051631ff3747d60e21b815260040160405180910390fd5b505050505050505050505050505050565b5f805f60019050604051604081015f7f2a2cd5881e62ead81dc6997cfff997745379facd38c972e0825deedb0e4fa56483527f208c7b9c6bf876a51b3d62d0a5bdc0d7188e7342dea7d32ddb9635e291e8dd9a60208401527f219e17d13bc5f5ae36d78093cd6d112374a69844b7d058a7a0a62493f1c369c482527f254c200a2cdb5bc5e4e262780b4c70a988c4317fb11ac5fd5491f10692d1e9296020830152863590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f258c71a2309359a248879ba915796e5e2e655acebace0ae7ef8fda2d40d2b2d682527f0b3cd73ef5ee90c6808893b3e4f81d8da3438cb5d2b601045825b2ab3990a3916020830152602087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f0945b0f65ee8acfce0b22bab7a27663bfaf8eed78d511a96a54b50f307cd2a2382527f1ef0708b683e9cbfeb8800001f06f9c80950d60869ebfc6b5cc58bd2bbfd6abe6020830152604087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa841693507f290b3cba8ec4c97f171261b17b9c90e101b65934db12f4a299d4d5b939e9235c82527f14914c2bf919019e575b0bd613363aa160d700bd929bcbc14de06a05e3a25eb06020830152606087013590508060408301525f805160206119ff83398151915281108416935060408260608460075afa8416935060408360808560065afa7f22474ea30b64abc35269a0c55be5972965bf920e937c3d1927da5e89e60cf91683527f272dd64ca95c75938da75797ef702ec5112808c36914020a4b1822fff576d3346020840152608088013560408085018290525f805160206119ff83398151915290911091909516169390508160608160075afa831692505060408160808360065afa81516020909201519194509092501680610c8a5760405163a54f8e2760e01b815260040160405180910390fd5b50915091565b5f5f805160206119df83398151915283101580610cba57505f805160206119df8339815191528210155b15610cd857604051631ff3747d60e21b815260040160405180910390fd5b82158015610ce4575081155b15610cf057505f61064f565b5f610d2b5f805160206119df83398151915260035f805160206119df833981519152875f805160206119df833981519152898a0909086112c7565b9050808303610d40575050600182901b61064f565b610d4981611329565b8303610d5c575050600182811b1761064f565b604051631ff3747d60e21b815260040160405180910390fd5b5092915050565b5f805f805160206119df83398151915286101580610da757505f805160206119df8339815191528510155b80610dbf57505f805160206119df8339815191528410155b80610dd757505f805160206119df8339815191528310155b15610df557604051631ff3747d60e21b815260040160405180910390fd5b828486881717175f03610e0c57505f90508061104c565b5f80805f805160206119df833981519152610e3560035f805160206119df8339815191526119bf565b5f805160206119df8339815191528a8c090990505f5f805160206119df8339815191528a5f805160206119df8339815191528c8d090990505f5f805160206119df8339815191528a5f805160206119df8339815191528c8d090990505f805160206119df833981519152805f805160206119df8339815191528c860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5089450610f235f805160206119df833981519152805f805160206119df8339815191528e870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e77508611329565b93505050505f80610f705f805160206119df83398151915280610f4857610f486119ab565b5f805160206119df8339815191528586095f805160206119df833981519152878809086112c7565b9050610fbb5f805160206119df8339815191527f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea45f805160206119df83398151915284880809611341565b15915050610fca838383611389565b90935091508683148015610fdd57508186145b156110055780610fed575f610ff0565b60025b60ff1660028a901b175f179450879350611048565b61100e83611329565b87148015611023575061102082611329565b86145b15610d5c5780611033575f611036565b60025b60ff1660028a901b1760011794508793505b5050505b94509492505050565b5f80825f0361106857505f928392509050565b600183811c9250808416145f805160206119df83398151915283106110a057604051631ff3747d60e21b815260040160405180910390fd5b6110da5f805160206119df83398151915260035f805160206119df833981519152865f805160206119df83398151915288890909086112c7565b91508015610c8a576110eb82611329565b915050915091565b5f80808085158015611103575084155b1561111857505f9250829150819050806112be565b600286811c945085935060018088161490808816145f805160206119df8339815191528610158061115657505f805160206119df8339815191528510155b1561117457604051631ff3747d60e21b815260040160405180910390fd5b5f5f805160206119df83398151915261119b60035f805160206119df8339815191526119bf565b5f805160206119df833981519152888a090990505f5f805160206119df833981519152885f805160206119df8339815191528a8b090990505f5f805160206119df833981519152885f805160206119df8339815191528a8b090990505f805160206119df833981519152805f805160206119df8339815191528a860984087f2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e50896506112895f805160206119df833981519152805f805160206119df8339815191528c870984087f2fcd3ac2a640a154eb23960892a85a68f031ca0c8344b23a577dcf1052b9e77508611329565b9550611296878786611389565b909750955084156112b8576112aa87611329565b96506112b586611329565b95505b50505050505b92959194509250565b5f6112f2827f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526114c5565b9050815f805160206119df8339815191528283091461132457604051631ff3747d60e21b815260040160405180910390fd5b919050565b5f805160206119df8339815191529081900681030690565b5f8061136d837f0c19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f526114c5565b9050825f805160206119df833981519152828309149392505050565b5f80806113b85f805160206119df833981519152808788095f805160206119df833981519152898a09086112c7565b905083156113cc576113c981611329565b90505b6114155f805160206119df8339815191527f183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea45f805160206119df833981519152848a08096112c7565b92505f805160206119df83398151915261143f5f805160206119df83398151915260028609611528565b860991505f805160206119df83398151915261146a5f805160206119df833981519152848509611329565b5f805160206119df833981519152858609088614158061149e57505f805160206119df833981519152808385096002098514155b156114bc57604051631ff3747d60e21b815260040160405180910390fd5b50935093915050565b5f8060405160208152602080820152602060408201528460608201528360808201525f805160206119df83398151915260a082015260208160c08360055afa90519250905080610d7557604051631ff3747d60e21b815260040160405180910390fd5b5f611553827f30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd456114c5565b90505f805160206119df83398151915281830960011461132457604051631ff3747d60e21b815260040160405180910390fd5b6040518060a001604052806005906020820280368337509192915050565b60405180608001604052806004906020820280368337509192915050565b6040518061030001604052806018906020820280368337509192915050565b60405180602001604052806001906020820280368337509192915050565b80610100810183101561064f575f80fd5b8060a0810183101561064f575f80fd5b5f806101a08385031215611632575f80fd5b61163c84846115ff565b915061164c846101008501611610565b90509250929050565b5f8083601f840112611665575f80fd5b50813567ffffffffffffffff81111561167c575f80fd5b602083019150836020828501011115611693575f80fd5b9250929050565b5f805f805f606086880312156116ae575f80fd5b85359450602086013567ffffffffffffffff808211156116cc575f80fd5b6116d889838a01611655565b909650945060408801359150808211156116f0575f80fd5b506116fd88828901611655565b969995985093965092949392505050565b5f610100828403121561171f575f80fd5b61172983836115ff565b9392505050565b6080810181835f5b6004811015611757578151835260209283019290910190600101611738565b50505092915050565b5f8060208385031215611771575f80fd5b823567ffffffffffffffff811115611787575f80fd5b61179385828601611655565b90969095509350505050565b5f8061012083850312156117b1575f80fd5b60808301848111156117c1575f80fd5b8392506117ce8582611610565b9150509250929050565b5f6020808352835180828501525f5b81811015611803578581018301518582016040015282016117e7565b505f604082860101526040601f19601f8301168501019250505092915050565b5f8085851115611831575f80fd5b8386111561183d575f80fd5b5050820193919092039150565b6001600160e01b031981358181169160048510156118725780818660040360031b1b83161692505b505092915050565b634e487b7160e01b5f52604160045260245ffd5b5f805f806101608086880312156118a3575f80fd5b8535945060208087013594506040870135935087607f8801126118c4575f80fd5b604051610100810181811067ffffffffffffffff821117156118e8576118e861187a565b6040529187019180898411156118fc575f80fd5b606089015b848110156119185780358252908301908301611901565b505080935050505092959194509250565b6101a0810181845f5b6008811015611951578151835260209283019290910190600101611932565b5050506101008201835f5b600581101561197b57815183526020928301929091019060010161195c565b5050509392505050565b818382375f9101908152919050565b5f602082840312156119a4575f80fd5b5051919050565b634e487b7160e01b5f52601260045260245ffd5b8181038181111561064f57634e487b7160e01b5f52601160045260245ffdfe30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4730644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001a2646970667358221220fb64900adc9aa14a5210dc320a76bf743fe75ad3802083bfcf05f84cbaa7d6e064736f6c63430008140033
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in HYPE
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.