Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x60808060 | 5468956 | 379 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Similar Match Source Code This contract matches the deployed Bytecode of the Source Code for Contract 0x31C8d2e8...3592ae08C The constructor portion of the code might be different and could alter the actual behaviour of the contract
Contract Name:
PasskeyRegistryModule
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 800 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity >=0.8.17; import {BaseAuthorizationModule} from "./BaseAuthorizationModule.sol"; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; import {Base64} from "@openzeppelin/contracts/utils/Base64.sol"; import {Secp256r1, PassKeyId} from "./PasskeyValidationModules/Secp256r1.sol"; /** * @title Passkey ownership Authorization module for Biconomy Smart Accounts. * @dev Compatible with Biconomy Modular Interface v 0.2 * - It allows to validate user operations signed by passkeys. * - One owner per Smart Account. * For Smart Contract Owners check SmartContractOwnership module instead * @author Aman Raj - <[email protected]> */ contract PasskeyRegistryModule is BaseAuthorizationModule { string public constant NAME = "PassKeys Ownership Registry Module"; string public constant VERSION = "0.2.0"; mapping(address => PassKeyId) public smartAccountPassKeys; error NoPassKeyRegisteredForSmartAccount(address smartAccount); error AlreadyInitedForSmartAccount(address smartAccount); /** * @dev Initializes the module for a Smart Account. * Should be used at a time of first enabling the module for a Smart Account. * @param _pubKeyX The x coordinate of the public key. * @param _pubKeyY The y coordinate of the public key. * @param _keyId The keyId of the Smart Account. * @return address of the module. */ function initForSmartAccount( uint256 _pubKeyX, uint256 _pubKeyY, string calldata _keyId ) external returns (address) { if ( smartAccountPassKeys[msg.sender].pubKeyX != 0 && smartAccountPassKeys[msg.sender].pubKeyY != 0 ) revert AlreadyInitedForSmartAccount(msg.sender); smartAccountPassKeys[msg.sender] = PassKeyId( _pubKeyX, _pubKeyY, _keyId ); return address(this); } /** * @dev validates userOperation * @param userOp User Operation to be validated. * @param userOpHash Hash of the User Operation to be validated. * @return sigValidationResult 0 if signature is valid, SIG_VALIDATION_FAILED otherwise. */ function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash ) external view virtual returns (uint256) { return _validateSignature(userOp, userOpHash); } function isValidSignature( bytes32 signedDataHash, bytes memory moduleSignature ) public view virtual override returns (bytes4) { return isValidSignatureForAddress(signedDataHash, moduleSignature); } function isValidSignatureForAddress( bytes32 signedDataHash, bytes memory moduleSignature ) public view virtual returns (bytes4) { if (_verifySignature(signedDataHash, moduleSignature)) { return EIP1271_MAGIC_VALUE; } return bytes4(0xffffffff); } function _verifySignature( bytes32 userOpDataHash, bytes memory moduleSignature ) internal view returns (bool) { ( bytes32 keyHash, uint256 sigx, uint256 sigy, bytes memory authenticatorData, string memory clientDataJSONPre, string memory clientDataJSONPost ) = abi.decode( moduleSignature, (bytes32, uint256, uint256, bytes, string, string) ); (keyHash); string memory opHashBase64 = Base64.encode( bytes.concat(userOpDataHash) ); string memory clientDataJSON = string.concat( clientDataJSONPre, opHashBase64, clientDataJSONPost ); bytes32 clientHash = sha256(bytes(clientDataJSON)); bytes32 sigHash = sha256(bytes.concat(authenticatorData, clientHash)); PassKeyId memory passKey = smartAccountPassKeys[msg.sender]; if (passKey.pubKeyX == 0 && passKey.pubKeyY == 0) revert NoPassKeyRegisteredForSmartAccount(msg.sender); return Secp256r1.verify(passKey, sigx, sigy, uint256(sigHash)); } function _validateSignature( UserOperation calldata userOp, bytes32 userOpHash ) internal view virtual returns (uint256 sigValidationResult) { if (_verifySignature(userOpHash, userOp.signature)) { return 0; } return SIG_VALIDATION_FAILED; } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ /** * returned data from validateUserOp. * validateUserOp returns a uint256, with is created by `_packedValidationData` and parsed by `_parseValidationData` * @param aggregator - address(0) - the account validated the signature by itself. * address(1) - the account failed to validate the signature. * otherwise - this is an address of a signature aggregator that must be used to validate the signature. * @param validAfter - this UserOp is valid only after this timestamp. * @param validaUntil - this UserOp is valid only up to this timestamp. */ struct ValidationData { address aggregator; uint48 validAfter; uint48 validUntil; } //extract sigFailed, validAfter, validUntil. // also convert zero validUntil to type(uint48).max function _parseValidationData(uint validationData) pure returns (ValidationData memory data) { address aggregator = address(uint160(validationData)); uint48 validUntil = uint48(validationData >> 160); if (validUntil == 0) { validUntil = type(uint48).max; } uint48 validAfter = uint48(validationData >> (48 + 160)); return ValidationData(aggregator, validAfter, validUntil); } // intersect account and paymaster ranges. function _intersectTimeRange(uint256 validationData, uint256 paymasterValidationData) pure returns (ValidationData memory) { ValidationData memory accountValidationData = _parseValidationData(validationData); ValidationData memory pmValidationData = _parseValidationData(paymasterValidationData); address aggregator = accountValidationData.aggregator; if (aggregator == address(0)) { aggregator = pmValidationData.aggregator; } uint48 validAfter = accountValidationData.validAfter; uint48 validUntil = accountValidationData.validUntil; uint48 pmValidAfter = pmValidationData.validAfter; uint48 pmValidUntil = pmValidationData.validUntil; if (validAfter < pmValidAfter) validAfter = pmValidAfter; if (validUntil > pmValidUntil) validUntil = pmValidUntil; return ValidationData(aggregator, validAfter, validUntil); } /** * helper to pack the return value for validateUserOp * @param data - the ValidationData to pack */ function _packValidationData(ValidationData memory data) pure returns (uint256) { return uint160(data.aggregator) | (uint256(data.validUntil) << 160) | (uint256(data.validAfter) << (160 + 48)); } /** * helper to pack the return value for validateUserOp, when not using an aggregator * @param sigFailed - true for signature failure, false for success * @param validUntil last timestamp this UserOperation is valid (or zero for infinite) * @param validAfter first timestamp this UserOperation is valid */ function _packValidationData(bool sigFailed, uint48 validUntil, uint48 validAfter) pure returns (uint256) { return (sigFailed ? 1 : 0) | (uint256(validUntil) << 160) | (uint256(validAfter) << (160 + 48)); } /** * keccak function over calldata. * @dev copy calldata into memory, do keccak and drop allocated memory. Strangely, this is more efficient than letting solidity do it. */ function calldataKeccak(bytes calldata data) pure returns (bytes32 ret) { assembly { let mem := mload(0x40) let len := data.length calldatacopy(mem, data.offset, len) ret := keccak256(mem, len) } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.12; /* solhint-disable no-inline-assembly */ import {calldataKeccak} from "../core/Helpers.sol"; /** * User Operation struct * @param sender the sender account of this request. * @param nonce unique value the sender uses to verify it is not a replay. * @param initCode if set, the account contract will be created by this constructor/ * @param callData the method call to execute on this account. * @param callGasLimit the gas limit passed to the callData method call. * @param verificationGasLimit gas used for validateUserOp and validatePaymasterUserOp. * @param preVerificationGas gas not calculated by the handleOps method, but added to the gas paid. Covers batch overhead. * @param maxFeePerGas same as EIP-1559 gas parameter. * @param maxPriorityFeePerGas same as EIP-1559 gas parameter. * @param paymasterAndData if set, this field holds the paymaster address and paymaster-specific data. the paymaster will pay for the transaction instead of the sender. * @param signature sender-verified signature over the entire request, the EntryPoint address and the chain ID. */ struct UserOperation { address sender; uint256 nonce; bytes initCode; bytes callData; uint256 callGasLimit; uint256 verificationGasLimit; uint256 preVerificationGas; uint256 maxFeePerGas; uint256 maxPriorityFeePerGas; bytes paymasterAndData; bytes signature; } /** * Utility functions helpful when working with UserOperation structs. */ library UserOperationLib { function getSender(UserOperation calldata userOp) internal pure returns (address) { address data; //read sender from userOp, which is first userOp member (saves 800 gas...) assembly {data := calldataload(userOp)} return address(uint160(data)); } //relayer/block builder might submit the TX with higher priorityFee, but the user should not // pay above what he signed for. function gasPrice(UserOperation calldata userOp) internal view returns (uint256) { unchecked { uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; if (maxFeePerGas == maxPriorityFeePerGas) { //legacy mode (for networks that don't support basefee opcode) return maxFeePerGas; } return min(maxFeePerGas, maxPriorityFeePerGas + block.basefee); } } function pack(UserOperation calldata userOp) internal pure returns (bytes memory ret) { address sender = getSender(userOp); uint256 nonce = userOp.nonce; bytes32 hashInitCode = calldataKeccak(userOp.initCode); bytes32 hashCallData = calldataKeccak(userOp.callData); uint256 callGasLimit = userOp.callGasLimit; uint256 verificationGasLimit = userOp.verificationGasLimit; uint256 preVerificationGas = userOp.preVerificationGas; uint256 maxFeePerGas = userOp.maxFeePerGas; uint256 maxPriorityFeePerGas = userOp.maxPriorityFeePerGas; bytes32 hashPaymasterAndData = calldataKeccak(userOp.paymasterAndData); return abi.encode( sender, nonce, hashInitCode, hashCallData, callGasLimit, verificationGasLimit, preVerificationGas, maxFeePerGas, maxPriorityFeePerGas, hashPaymasterAndData ); } function hash(UserOperation calldata userOp) internal pure returns (bytes32) { return keccak256(pack(userOp)); } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol) pragma solidity ^0.8.0; /** * @dev Provides a set of functions to operate with Base64 strings. * * _Available since v4.5._ */ library Base64 { /** * @dev Base64 Encoding/Decoding Table */ string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** * @dev Converts a `bytes` to its Bytes64 `string` representation. */ function encode(bytes memory data) internal pure returns (string memory) { /** * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol */ if (data.length == 0) return ""; // Loads the table into memory string memory table = _TABLE; // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter // and split into 4 numbers of 6 bits. // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up // - `data.length + 2` -> Round up // - `/ 3` -> Number of 3-bytes chunks // - `4 *` -> 4 characters for each chunk string memory result = new string(4 * ((data.length + 2) / 3)); /// @solidity memory-safe-assembly assembly { // Prepare the lookup table (skip the first "length" byte) let tablePtr := add(table, 1) // Prepare result pointer, jump over length let resultPtr := add(result, 32) // Run over the input, 3 bytes at a time for { let dataPtr := data let endPtr := add(data, mload(data)) } lt(dataPtr, endPtr) { } { // Advance 3 bytes dataPtr := add(dataPtr, 3) let input := mload(dataPtr) // To write each character, shift the 3 bytes (18 bits) chunk // 4 times in blocks of 6 bits for each character (18, 12, 6, 0) // and apply logical AND with 0x3F which is the number of // the previous character in the ASCII table prior to the Base64 Table // The result is then added to the table to get the character to write, // and finally write it in the result pointer but with a left shift // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F)))) resultPtr := add(resultPtr, 1) // Advance mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F)))) resultPtr := add(resultPtr, 1) // Advance } // When data `bytes` is not exactly 3 bytes long // it is padded with `=` characters at the end switch mod(mload(data), 3) case 1 { mstore8(sub(resultPtr, 1), 0x3d) mstore8(sub(resultPtr, 2), 0x3d) } case 2 { mstore8(sub(resultPtr, 1), 0x3d) } } return result; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; import {UserOperation} from "@account-abstraction/contracts/interfaces/UserOperation.sol"; // interface for modules to verify singatures signed over userOpHash interface IAuthorizationModule { function validateUserOp( UserOperation calldata userOp, bytes32 userOpHash ) external returns (uint256 validationData); }
// SPDX-License-Identifier: LGPL-3.0-only pragma solidity 0.8.17; contract ISignatureValidatorConstants { // bytes4(keccak256("isValidSignature(bytes32,bytes)") bytes4 internal constant EIP1271_MAGIC_VALUE = 0x1626ba7e; } abstract contract ISignatureValidator is ISignatureValidatorConstants { /** * @dev Should return whether the signature provided is valid for the provided data * @param _dataHash Arbitrary length data signed on behalf of address(this) * @param _signature Signature byte array associated with _data * * MUST return the bytes4 magic value 0x1626ba7e when function passes. * MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5) * MUST allow external calls */ function isValidSignature( bytes32 _dataHash, bytes memory _signature ) public view virtual returns (bytes4); }
// SPDX-License-Identifier: MIT pragma solidity 0.8.17; /* solhint-disable no-empty-blocks */ import {IAuthorizationModule} from "../interfaces/IAuthorizationModule.sol"; import {ISignatureValidator} from "../interfaces/ISignatureValidator.sol"; contract AuthorizationModulesConstants { uint256 internal constant VALIDATION_SUCCESS = 0; uint256 internal constant SIG_VALIDATION_FAILED = 1; } abstract contract BaseAuthorizationModule is IAuthorizationModule, ISignatureValidator, AuthorizationModulesConstants {}
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.8.17; // // Heavily inspired from // https://github.com/maxrobot/elliptic-solidity/blob/master/contracts/Secp256r1.sol // https://github.com/tdrerup/elliptic-curve-solidity/blob/master/contracts/curves/EllipticCurve.sol // modified to use precompile 0x05 modexp // and modified jacobian double // optimisations to avoid to an from from affine and jacobian coordinates // struct PassKeyId { uint256 pubKeyX; uint256 pubKeyY; string keyId; } struct JPoint { uint256 x; uint256 y; uint256 z; } library Secp256r1 { uint256 private constant GX = 0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296; uint256 private constant GY = 0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5; uint256 private constant PP = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF; uint256 private constant NN = 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551; uint256 private constant A = 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC; uint256 private constant B = 0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B; uint256 private constant MOST_SIGNIFICANT = 0xc000000000000000000000000000000000000000000000000000000000000000; /* * verify * @description - verifies that a public key has signed a given message * @param X - public key coordinate X * @param Y - public key coordinate Y * @param R - signature half R * @param S - signature half S * @param input - hashed message */ function verify( PassKeyId memory passKey, uint256 r, uint256 s, uint256 e ) internal view returns (bool) { if (r >= NN || s >= NN) { return false; } JPoint[16] memory points = preComputeJacobianPoints(passKey); return verifyWithPrecompute(points, r, s, e); } function verifyWithPrecompute( JPoint[16] memory points, uint256 r, uint256 s, uint256 e ) internal view returns (bool) { if (r >= NN || s >= NN) { return false; } uint256 w = primemod(s, NN); uint256 u1 = mulmod(e, w, NN); uint256 u2 = mulmod(r, w, NN); uint256 x; uint256 y; (x, y) = shamirMultJacobian(points, u1, u2); return (x == r); } /* * Strauss Shamir trick for EC multiplication * https://stackoverflow.com/questions/50993471/ec-scalar-multiplication-with-strauss-shamir-method * we optimise on this a bit to do with 2 bits at a time rather than a single bit * the individual points for a single pass are precomputed * overall this reduces the number of additions while keeping the same number of doublings */ function shamirMultJacobian( JPoint[16] memory points, uint256 u1, uint256 u2 ) internal view returns (uint256, uint256) { uint256 x = 0; uint256 y = 0; uint256 z = 0; uint256 bits = 128; uint256 index = 0; while (bits > 0) { if (z > 0) { (x, y, z) = modifiedJacobianDouble(x, y, z); (x, y, z) = modifiedJacobianDouble(x, y, z); } index = ((u1 & MOST_SIGNIFICANT) >> 252) | ((u2 & MOST_SIGNIFICANT) >> 254); if (index > 0) { (x, y, z) = jAdd( x, y, z, points[index].x, points[index].y, points[index].z ); } u1 <<= 2; u2 <<= 2; bits--; } (x, y) = affineFromJacobian(x, y, z); return (x, y); } /* affineFromJacobian * @desription returns affine coordinates from a jacobian input follows * golang elliptic/crypto library */ function affineFromJacobian( uint256 x, uint256 y, uint256 z ) internal view returns (uint256 ax, uint256 ay) { if (z == 0) { return (0, 0); } uint256 zinv = primemod(z, PP); uint256 zinvsq = mulmod(zinv, zinv, PP); ax = mulmod(x, zinvsq, PP); ay = mulmod(y, mulmod(zinvsq, zinv, PP), PP); } // Fermats little theorem https://en.wikipedia.org/wiki/Fermat%27s_little_theorem // a^(p-1) = 1 mod p // a^(-1) ≅ a^(p-2) (mod p) // we then use the precompile bigModExp to compute a^(-1) function primemod( uint256 value, uint256 p ) internal view returns (uint256 ret) { ret = modexp(value, p - 2, p); return ret; } // Wrapper for built-in BigNumber_modexp (contract 0x5) as described here. https://github.com/ethereum/EIPs/pull/198 function modexp( uint256 _base, uint256 _exp, uint256 _mod ) internal view returns (uint256 ret) { // bigModExp(_base, _exp, _mod); assembly { if gt(_base, _mod) { _base := mod(_base, _mod) } // Free memory pointer is always stored at 0x40 let freemem := mload(0x40) mstore(freemem, 0x20) mstore(add(freemem, 0x20), 0x20) mstore(add(freemem, 0x40), 0x20) mstore(add(freemem, 0x60), _base) mstore(add(freemem, 0x80), _exp) mstore(add(freemem, 0xa0), _mod) let success := staticcall(1500, 0x5, freemem, 0xc0, freemem, 0x20) switch success case 0 { revert(0x0, 0x0) } default { ret := mload(freemem) } } } function preComputeJacobianPoints( PassKeyId memory passKey ) internal pure returns (JPoint[16] memory points) { // JPoint[] memory u1Points = new JPoint[](4); // u1Points[0] = JPoint(0, 0, 0); // u1Points[1] = JPoint(GX, GY, 1); // u1 // u1Points[2] = jPointDouble(u1Points[1]); // u1Points[3] = jPointAdd(u1Points[1], u1Points[2]); // avoiding this intermediate step by using it in a single array below // these are pre computed points for u1 // JPoint[16] memory points; points[0] = JPoint(0, 0, 0); points[1] = JPoint(passKey.pubKeyX, passKey.pubKeyY, 1); // u2 points[2] = jPointDouble(points[1]); points[3] = jPointAdd(points[1], points[2]); points[4] = JPoint(GX, GY, 1); // u1Points[1] points[5] = jPointAdd(points[4], points[1]); points[6] = jPointAdd(points[4], points[2]); points[7] = jPointAdd(points[4], points[3]); points[8] = jPointDouble(points[4]); // u1Points[2] points[9] = jPointAdd(points[8], points[1]); points[10] = jPointAdd(points[8], points[2]); points[11] = jPointAdd(points[8], points[3]); points[12] = jPointAdd(points[4], points[8]); // u1Points[3] points[13] = jPointAdd(points[12], points[1]); points[14] = jPointAdd(points[12], points[2]); points[15] = jPointAdd(points[12], points[3]); } function jPointAdd( JPoint memory p1, JPoint memory p2 ) internal pure returns (JPoint memory) { uint256 x; uint256 y; uint256 z; (x, y, z) = jAdd(p1.x, p1.y, p1.z, p2.x, p2.y, p2.z); return JPoint(x, y, z); } function jPointDouble( JPoint memory p ) internal pure returns (JPoint memory) { uint256 x; uint256 y; uint256 z; (x, y, z) = modifiedJacobianDouble(p.x, p.y, p.z); return JPoint(x, y, z); } /* * jAdd * @description performs double Jacobian as defined below: * https://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-3/doubling/mdbl-2007-bl.op3 */ function jAdd( uint256 p1, uint256 p2, uint256 p3, uint256 q1, uint256 q2, uint256 q3 ) internal pure returns (uint256 r1, uint256 r2, uint256 r3) { if (p3 == 0) { r1 = q1; r2 = q2; r3 = q3; return (r1, r2, r3); } else if (q3 == 0) { r1 = p1; r2 = p2; r3 = p3; return (r1, r2, r3); } assembly { let pd := 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF let z1z1 := mulmod(p3, p3, pd) // Z1Z1 = Z1^2 let z2z2 := mulmod(q3, q3, pd) // Z2Z2 = Z2^2 let u1 := mulmod(p1, z2z2, pd) // U1 = X1*Z2Z2 let u2 := mulmod(q1, z1z1, pd) // U2 = X2*Z1Z1 let s1 := mulmod(p2, mulmod(z2z2, q3, pd), pd) // S1 = Y1*Z2*Z2Z2 let s2 := mulmod(q2, mulmod(z1z1, p3, pd), pd) // S2 = Y2*Z1*Z1Z1 let p3q3 := addmod(p3, q3, pd) if lt(u2, u1) { u2 := add(pd, u2) // u2 = u2+pd } let h := sub(u2, u1) // H = U2-U1 let i := mulmod(0x02, h, pd) i := mulmod(i, i, pd) // I = (2*H)^2 let j := mulmod(h, i, pd) // J = H*I if lt(s2, s1) { s2 := add(pd, s2) // u2 = u2+pd } let rr := mulmod(0x02, sub(s2, s1), pd) // r = 2*(S2-S1) r1 := mulmod(rr, rr, pd) // X3 = R^2 let v := mulmod(u1, i, pd) // V = U1*I let j2v := addmod(j, mulmod(0x02, v, pd), pd) if lt(r1, j2v) { r1 := add(pd, r1) // X3 = X3+pd } r1 := sub(r1, j2v) // Y3 = r*(V-X3)-2*S1*J let s12j := mulmod(mulmod(0x02, s1, pd), j, pd) if lt(v, r1) { v := add(pd, v) } r2 := mulmod(rr, sub(v, r1), pd) if lt(r2, s12j) { r2 := add(pd, r2) } r2 := sub(r2, s12j) // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2)*H z1z1 := addmod(z1z1, z2z2, pd) j2v := mulmod(p3q3, p3q3, pd) if lt(j2v, z1z1) { j2v := add(pd, j2v) } r3 := mulmod(sub(j2v, z1z1), h, pd) } return (r1, r2, r3); } // Point doubling on the modified jacobian coordinates // http://point-at-infinity.org/ecc/Prime_Curve_Modified_Jacobian_Coordinates.html function modifiedJacobianDouble( uint256 x, uint256 y, uint256 z ) internal pure returns (uint256 x3, uint256 y3, uint256 z3) { assembly { let pd := 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF let z2 := mulmod(z, z, pd) let az4 := mulmod( 0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC, mulmod(z2, z2, pd), pd ) let y2 := mulmod(y, y, pd) let s := mulmod(0x04, mulmod(x, y2, pd), pd) let u := mulmod(0x08, mulmod(y2, y2, pd), pd) let m := addmod(mulmod(0x03, mulmod(x, x, pd), pd), az4, pd) let twos := mulmod(0x02, s, pd) let m2 := mulmod(m, m, pd) if lt(m2, twos) { m2 := add(pd, m2) } x3 := sub(m2, twos) if lt(s, x3) { s := add(pd, s) } y3 := mulmod(m, sub(s, x3), pd) if lt(y3, u) { y3 := add(pd, y3) } y3 := sub(y3, u) z3 := mulmod(0x02, mulmod(y, z, pd), pd) } } }
{ "optimizer": { "enabled": true, "runs": 800 }, "viaIR": true, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
Contract ABI
API[{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"AlreadyInitedForSmartAccount","type":"error"},{"inputs":[{"internalType":"address","name":"smartAccount","type":"address"}],"name":"NoPassKeyRegisteredForSmartAccount","type":"error"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pubKeyX","type":"uint256"},{"internalType":"uint256","name":"_pubKeyY","type":"uint256"},{"internalType":"string","name":"_keyId","type":"string"}],"name":"initForSmartAccount","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"signedDataHash","type":"bytes32"},{"internalType":"bytes","name":"moduleSignature","type":"bytes"}],"name":"isValidSignature","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"signedDataHash","type":"bytes32"},{"internalType":"bytes","name":"moduleSignature","type":"bytes"}],"name":"isValidSignatureForAddress","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"smartAccountPassKeys","outputs":[{"internalType":"uint256","name":"pubKeyX","type":"uint256"},{"internalType":"uint256","name":"pubKeyY","type":"uint256"},{"internalType":"string","name":"keyId","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes","name":"initCode","type":"bytes"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"callGasLimit","type":"uint256"},{"internalType":"uint256","name":"verificationGasLimit","type":"uint256"},{"internalType":"uint256","name":"preVerificationGas","type":"uint256"},{"internalType":"uint256","name":"maxFeePerGas","type":"uint256"},{"internalType":"uint256","name":"maxPriorityFeePerGas","type":"uint256"},{"internalType":"bytes","name":"paymasterAndData","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct UserOperation","name":"userOp","type":"tuple"},{"internalType":"bytes32","name":"userOpHash","type":"bytes32"}],"name":"validateUserOp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]
Deployed Bytecode
0x60806040526004361015610013575b600080fd5b6000803560e01c908163032ff9f11461010f5781631626ba7e1461010f5781637301609614610090575080638d2bc52914610087578063a3f4df7e1461007e578063ffa1ad74146100755763fff35b721461006d57600080fd5b61000e61050b565b5061000e6104ac565b5061000e610442565b5061000e6103a9565b3461010c57606036600319011261010c5760443567ffffffffffffffff9182821161010c573660238301121561010c57816004013592831161010c57366024848401011161010c576101086100ee84602485016024356004356105ac565b6040516001600160a01b0390911681529081906020820190565b0390f35b80fd5b505061000e610208565b50634e487b7160e01b600052604160045260246000fd5b6060810190811067ffffffffffffffff82111761014c57604052565b610154610119565b604052565b6040810190811067ffffffffffffffff82111761014c57604052565b90601f8019910116810190811067ffffffffffffffff82111761014c57604052565b604051906101a482610130565b565b60209067ffffffffffffffff81116101c4575b601f01601f19160190565b6101cc610119565b6101b9565b9291926101dd826101a6565b916101eb6040519384610175565b82948184528183011161000e578281602093846000960137010152565b503461000e57604036600319011261000e5760243567ffffffffffffffff811161000e573660238201121561000e5761025861025060209236906024816004013591016101d1565b600435610741565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152f35b90600182811c921680156102b3575b602083101461029d57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610292565b90604051918260008254926102d184610283565b90818452600194858116908160001461033e57506001146102fb575b50506101a492500383610175565b9093915060005260209081600020936000915b8183106103265750506101a4935082010138806102ed565b8554888401850152948501948794509183019161030e565b9150506101a494506020925060ff191682840152151560051b82010138806102ed565b60005b8381106103745750506000910152565b8181015183820152602001610364565b9060209161039d81518092818552858086019101610361565b601f01601f1916010190565b503461000e57602036600319011261000e576004356001600160a01b03811680910361000e576000526000602052604060002080546101086103f26002600185015494016102bd565b60405193849384526020840152606060408401526060830190610384565b604051906020820182811067ffffffffffffffff821117610435575b60405260008252565b61043d610119565b61042c565b503461000e57600036600319011261000e5761010860405161046381610130565b602281527f506173734b657973204f776e657273686970205265676973747279204d6f64756020820152616c6560f01b6040820152604051918291602083526020830190610384565b503461000e57600036600319011261000e576101086040516104cd81610159565b600581527f302e322e300000000000000000000000000000000000000000000000000000006020820152604051918291602083526020830190610384565b503461000e5760031960403682011261000e576004359067ffffffffffffffff821161000e5761016090823603011261000e5761055060209160243590600401610bdc565b604051908152f35b90601f811161056657505050565b600091825260208220906020601f850160051c830194106105a2575b601f0160051c01915b82811061059757505050565b81815560010161058b565b9092508290610582565b929190926000913383526020938385526040842054151580610718575b610700576002916105f091604051946105e186610130565b855286850197885236916101d1565b9460408301958652610615336001600160a01b03166000526000602052604060002090565b925183555191600192838201550193519182519267ffffffffffffffff84116106f3575b61064d846106478854610283565b88610558565b8491601f851160011461068757939450849291908361067c575b50501b916000199060031b1c19161790553090565b015192503880610667565b92948490601f198216906106a089600052602060002090565b95905b888383106106d957505050106106c0575b505050811b0190553090565b015160001960f88460031b161c191690553880806106b4565b8587015188559096019594850194879350908101906106a3565b6106fb610119565b610639565b604051632c4dfb7d60e21b8152336004820152602490fd5b506001610738336001600160a01b03166000526000602052604060002090565b015415156105c9565b9061074b91610926565b610773577fffffffff0000000000000000000000000000000000000000000000000000000090565b630b135d3f60e11b90565b81601f8201121561000e578051610794816101a6565b926107a26040519485610175565b8184526020828401011161000e576107c09160208085019101610361565b90565b909160c08284031261000e5781519260208301519260408101519260608201519167ffffffffffffffff9283811161000e578461080191830161077e565b93608082015184811161000e578161081a91840161077e565b9360a083015190811161000e576107c0920161077e565b90604051916020830152602082526101a482610159565b9061085b60209282815194859201610361565b0190565b6101a491939293604051948591835161088081602096878088019101610361565b830161089482518093878085019101610361565b016108a782518093868085019101610361565b01038085520183610175565b506040513d6000823e3d90fd5b60406101a491939293815194816108e1879351809260208087019101610361565b8201906020820152036020810185520183610175565b9060405161090481610130565b6040610921600283958054855260018101546020860152016102bd565b910152565b6020600061098961096961095e9484846109756109696109516109639b8580825183010191016107c3565b9450929e919d9098610831565b610b01565b9061085f565b60405191828092610848565b039060025afa15610a06575b8351906108c0565b039060025afa156109f9575b600051906109be6109b9336001600160a01b03166000526000602052604060002090565b6108f7565b92835115806109ed575b6109d5576107c093610c35565b60405163ce777ecf60e01b8152336004820152602490fd5b506020840151156109c8565b610a016108b3565b610995565b610a0e6108b3565b610981565b60405190610a2082610130565b604082527f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392b2f6040837f4142434445464748494a4b4c4d4e4f505152535455565758595a61626364656660208201520152565b50634e487b7160e01b600052601160045260246000fd5b9060028201809211610a9757565b6101a4610a72565b908160021b917f3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811603610a9757565b90610ad9826101a6565b610ae66040519182610175565b8281528092610af7601f19916101a6565b0190602036910137565b805115610bd357610b10610a13565b610b34610b2f610b2a610b238551610a89565b6003900490565b610a9f565b610acf565b9160208301918182518301915b828210610b8157505050600390510680600114610b6e57600214610b63575090565b603d90600019015390565b50603d9081600019820153600119015390565b9091936004906003809401938451600190603f9082828260121c16880101518553828282600c1c16880101518386015382828260061c1688010151600286015316850101519082015301939190610b41565b506107c0610410565b61014081013590601e198136030182121561000e57019081359167ffffffffffffffff831161000e5760200191803603831361000e57610c2792610c219136916101d1565b90610926565b610c3057600190565b600090565b9291907fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255180821090811591610e13575b50610e0a576107c093610dff610c796110de565b91610c82610197565b600081526000602082015260006040820152835260208151910151610ca5610197565b918252602082015260016040820152610cc4602084019180835261117b565b90610df0610cda60408601938085528351611131565b9260608601938452610de0610dd0610cf0610197565b7f6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c29681527f4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5602082015260016040820152610d5360808a0191808352875190611131565b60a08a0152610d658151855190611131565b60c08a0152610d778151885190611131565b60e08a0152610d86815161117b565b90610d9b6101008b0192808452885190611131565b6101208b0152610dae8251865190611131565b6101408b0152610dc18251895190611131565b6101608b015251905190611131565b6101808801948186525190611131565b6101a08701528251905190611131565b6101c085015251905190611131565b6101e0820152610e1e565b50505050600090565b905082101538610c65565b939290917fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63255190818410801590610f2e575b610f2457610e5d8291611033565b809309918309600080918193608091825b610e8657505050610e8193949550610f7a565b501490565b85610f02575b888160fe1c600c8460fc1c161780610eb9575b5050610eb290600292831b921b92610f5f565b9182610e6e565b610ef59397610eb2976040610eec610ed485879b989b610f38565b5151946020610ee38289610f38565b51015196610f38565b5101519461119b565b9590945090928838610e9f565b9294610f139194610f1993966112b8565b916112b8565b949193909392610e8c565b5060009450505050565b5081811015610e4f565b906010811015610f495760051b0190565b634e487b7160e01b600052603260045260246000fd5b8015610f6d575b6000190190565b610f75610a72565b610f66565b9291908115611027578160007fffffffff00000001000000000000000000000000ffffffffffffffffffffffff848180961161101d575b505060405191602083526020808401526020604084015260608301527fffffffff00000001000000000000000000000000fffffffffffffffffffffffd60808301528360a083015260208260c08160056105dcfa1561010c575082905181808280098097099509900990565b0691508338610fb1565b50509050600090600090565b7fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc6325518082116110b6575b60405191602083526020808401526020604084015260608301527fffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc63254f608083015260a082015260208160c08160056105dcfa1561000e575190565b8091069061105c565b604051906110cc82610130565b60006040838281528260208201520152565b6040519061020080830183811067ffffffffffffffff821117611124575b6040528260005b82811061110f57505050565b60209061111a6110bf565b8184015201611103565b61112c610119565b6110fc565b61115e9161113d6110bf565b5081519160406020820151910151825191604060208501519401519461119b565b906040519261116c84610130565b83526020830152604082015290565b61115e906111876110bf565b5080519060406020820151910151916112b8565b9395939190816111ad57505050929190565b909291949586156112ae577fffffffff00000001000000000000000000000000ffffffffffffffffffffffff9586858196958280838199099b818d999781868180808f9d888009809d099c8d99099c81878d0990099c0990099308958181106112a7575b03958280808960020980099281808481878d09938181106112a0575b036002099481868009980996828089600209830890818110611299575b039b8c936002090994818110611292575b03900997828910611289575b859182910892800995828710611280575b960394030990565b95840195611278565b97850197611267565b830161125b565b830161124a565b820161122d565b8301611211565b5094505091929190565b9290917fffffffff00000001000000000000000000000000ffffffffffffffffffffffff809181858009958280808080808c87096004099a800960080992818080808089800980097fffffffff00000001000000000000000000000000fffffffffffffffffffffffc0992800960030908818960020982828009818110611367575b038981809b10611360575b039009818110611359575b03940960020990565b8301611350565b8301611345565b830161133a56fea26469706673582212208f8479a500d1ac9e7a70443fa9e6aed9eb85130f9070f492e48581206fda9bdb64736f6c63430008110033
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.