Address: 0x0000001d15BEA64A9584078917f8DB51Fb44C678
Balance (XRP): 0 XRP
Bytecode: 0x608060405234801561001057600080fd5b50600436106100ea5760003560e01c8063a25acb251161008c578063d9acbe6b11610066578063d9acbe6b14610243578063dac6c58714610273578063ebc27b821461028f578063f4364de6146102bf576100ea565b8063a25acb25146101c7578063d4c9c5c4146101f7578063d4df101814610213576100ea565b80633808a90b116100c85780633808a90b14610143578063520994f11461017357806356cd2b921461018f5780639630aff8146101ab576100ea565b8063065d6c69146100ef5780631b31f01b1461010b5780632f28c69d14610127575b600080fd5b61010960048036038101906101049190611436565b6102ef565b005b610125600480360381019061012091906114c8565b6103ca565b005b610141600480360381019061013c91906115d0565b610473565b005b61015d600480360381019061015891906116ae565b610522565b60405161016a919061172c565b60405180910390f35b61018d60048036038101906101889190611747565b610625565b005b6101a960048036038101906101a49190611868565b6106cc565b005b6101c560048036038101906101c091906118c4565b6107af565b005b6101e160048036038101906101dc9190611747565b610947565b6040516101ee919061191f565b60405180910390f35b610211600480360381019061020c91906119fd565b610976565b005b61022d60048036038101906102289190611ae0565b610b48565b60405161023a919061172c565b60405180910390f35b61025d60048036038101906102589190611b0d565b610d14565b60405161026a919061172c565b60405180910390f35b61028d600480360381019061028891906115d0565b610d45565b005b6102a960048036038101906102a49190611b4d565b610e98565b6040516102b69190611b89565b60405180910390f35b6102d960048036038101906102d49190611b4d565b610ecb565b6040516102e69190611c62565b60405180910390f35b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610387576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156103c4576103b7848483815181106103aa576103a9611c84565b5b6020026020010151610f36565b808060010191505061038a565b50505050565b823373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610462576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61046d848484611047565b50505050565b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161461050b576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61051d8361051884611200565b610f36565b505050565b60008061058f848060a001906105389190611cc2565b80600001906105479190611cea565b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050611200565b905060016000848152602001908152602001600020600082815260200190815260200160002060009054906101000a900460ff16156105ec576105e485856105d690611fd4565b61123090919063ffffffff16565b91505061061e565b6040517fd7abef4e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16146106bd576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6106c78383610f36565b505050565b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610764576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b82518110156107a95761079c8461079785848151811061078a57610789611c84565b5b6020026020010151611200565b610f36565b8080600101915050610767565b50505050565b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610847576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16036108ad576040517fff7d580d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160008085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff16837f7869f0fa3d7efaa83c69bf6de987567787178b8d7e41fea0cadfea68a2e27de560405160405180910390a3505050565b60016020528160005260406000206020528060005260406000206000915091509054906101000a900460ff1681565b823373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610a0e576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8151835114610a49576040517f526c768700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b60018351610a5a9190612016565b811015610ae85782600182610a6f919061204a565b81518110610a8057610a7f611c84565b5b6020026020010151838281518110610a9b57610a9a611c84565b5b60200260200101511015610adb576040517f526c768700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8080600101915050610a4c565b5060005b8351811015610b4157610b3485858381518110610b0c57610b0b611c84565b5b6020026020010151858481518110610b2757610b26611c84565b5b6020026020010151611047565b8080600101915050610aec565b5050505050565b600080339050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610bb4576040517fff7d580d00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8281604051602001610bc79291906120e7565b604051602081830303815290604052610bdf90612150565b9150600073ffffffffffffffffffffffffffffffffffffffff1660008084815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610c79576040517ffeabeb4b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8060008084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508073ffffffffffffffffffffffffffffffffffffffff16827f0f01cd0734cc8ed416ac6ca25cb4fe02dbab63f1236af3858deb14a56663623860405160405180910390a350919050565b60026020528160005260406000208181548110610d3057600080fd5b90600052602060002001600091509150505481565b813373ffffffffffffffffffffffffffffffffffffffff1660008083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614610ddd576040517f7c2411e900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610de883611200565b905060005b6002600086815260200190815260200160002080549050811015610e605781600260008781526020019081526020016000208281548110610e3157610e30611c84565b5b906000526020600020015403610e5357610e4c858383611047565b5050610e93565b8080600101915050610ded565b506040517f4745a4ee00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505050565b60006020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606060026000838152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015610f2a57602002820191906000526020600020905b815481526020019060010190808311610f16575b50505050509050919050565b60016000838152602001908152602001600020600082815260200190815260200160002060009054906101000a900460ff1615610f9f576040517f2d86c03a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001806000848152602001908152602001600020600083815260200190815260200160002060006101000a81548160ff0219169083151502179055506002600083815260200190815260200160002081908060018154018082558091505060019003906000526020600020016000909190919091505580827fceac3080d7874c4bba80ceae14b6aa96e0df9d4f673d9e5a352d66444f50206760405160405180910390a35050565b60026000848152602001908152602001600020805490508110158061109b57508160026000858152602001908152602001600020828154811061108d5761108c611c84565b5b906000526020600020015414155b156110d2576040517f526c768700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060016000858152602001908152602001600020600084815260200190815260200160002060006101000a81548160ff02191690831515021790555060026000848152602001908152602001600020600160026000868152602001908152602001600020805490506111459190612016565b8154811061115657611155611c84565b5b906000526020600020015460026000858152602001908152602001600020828154811061118657611185611c84565b5b9060005260206000200181905550600260008481526020019081526020016000208054806111b7576111b66121b7565b5b6001900381819060005260206000200160009055905581837f13d94de535e503661de3c84adf637590f269f37c8d4ed5daabae98376a442a6a60405160405180910390a3505050565b6000816040516020016112139190612257565b604051602081830303815290604052805190602001209050919050565b6000604051602001611241906122ba565b60405160208183030381529060405280519060200120828460600151856040015160405160200161127594939291906122f0565b60405160208183030381529060405280519060200120905092915050565b6000604051905090565b600080fd5b600080fd5b6000819050919050565b6112ba816112a7565b81146112c557600080fd5b50565b6000813590506112d7816112b1565b92915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61132b826112e2565b810181811067ffffffffffffffff8211171561134a576113496112f3565b5b80604052505050565b600061135d611293565b90506113698282611322565b919050565b600067ffffffffffffffff821115611389576113886112f3565b5b602082029050602081019050919050565b600080fd5b60006113b26113ad8461136e565b611353565b905080838252602082019050602084028301858111156113d5576113d461139a565b5b835b818110156113fe57806113ea88826112c8565b8452602084019350506020810190506113d7565b5050509392505050565b600082601f83011261141d5761141c6112dd565b5b813561142d84826020860161139f565b91505092915050565b6000806040838503121561144d5761144c61129d565b5b600061145b858286016112c8565b925050602083013567ffffffffffffffff81111561147c5761147b6112a2565b5b61148885828601611408565b9150509250929050565b6000819050919050565b6114a581611492565b81146114b057600080fd5b50565b6000813590506114c28161149c565b92915050565b6000806000606084860312156114e1576114e061129d565b5b60006114ef868287016112c8565b9350506020611500868287016112c8565b9250506040611511868287016114b3565b9150509250925092565b600080fd5b600067ffffffffffffffff82111561153b5761153a6112f3565b5b611544826112e2565b9050602081019050919050565b82818337600083830152505050565b600061157361156e84611520565b611353565b90508281526020810184848401111561158f5761158e61151b565b5b61159a848285611551565b509392505050565b600082601f8301126115b7576115b66112dd565b5b81356115c7848260208601611560565b91505092915050565b600080604083850312156115e7576115e661129d565b5b60006115f5858286016112c8565b925050602083013567ffffffffffffffff811115611616576116156112a2565b5b611622858286016115a2565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006116578261162c565b9050919050565b6116678161164c565b811461167257600080fd5b50565b6000813590506116848161165e565b92915050565b600080fd5b600060c082840312156116a5576116a461168a565b5b81905092915050565b6000806000606084860312156116c7576116c661129d565b5b60006116d586828701611675565b935050602084013567ffffffffffffffff8111156116f6576116f56112a2565b5b6117028682870161168f565b9250506040611713868287016112c8565b9150509250925092565b611726816112a7565b82525050565b6000602082019050611741600083018461171d565b92915050565b6000806040838503121561175e5761175d61129d565b5b600061176c858286016112c8565b925050602061177d858286016112c8565b9150509250929050565b600067ffffffffffffffff8211156117a2576117a16112f3565b5b602082029050602081019050919050565b60006117c66117c184611787565b611353565b905080838252602082019050602084028301858111156117e9576117e861139a565b5b835b8181101561183057803567ffffffffffffffff81111561180e5761180d6112dd565b5b80860161181b89826115a2565b855260208501945050506020810190506117eb565b5050509392505050565b600082601f83011261184f5761184e6112dd565b5b813561185f8482602086016117b3565b91505092915050565b6000806040838503121561187f5761187e61129d565b5b600061188d858286016112c8565b925050602083013567ffffffffffffffff8111156118ae576118ad6112a2565b5b6118ba8582860161183a565b9150509250929050565b600080604083850312156118db576118da61129d565b5b60006118e9858286016112c8565b92505060206118fa85828601611675565b9150509250929050565b60008115159050919050565b61191981611904565b82525050565b60006020820190506119346000830184611910565b92915050565b600067ffffffffffffffff821115611955576119546112f3565b5b602082029050602081019050919050565b60006119796119748461193a565b611353565b9050808382526020820190506020840283018581111561199c5761199b61139a565b5b835b818110156119c557806119b188826114b3565b84526020840193505060208101905061199e565b5050509392505050565b600082601f8301126119e4576119e36112dd565b5b81356119f4848260208601611966565b91505092915050565b600080600060608486031215611a1657611a1561129d565b5b6000611a24868287016112c8565b935050602084013567ffffffffffffffff811115611a4557611a446112a2565b5b611a5186828701611408565b925050604084013567ffffffffffffffff811115611a7257611a716112a2565b5b611a7e868287016119cf565b9150509250925092565b60007fffffffffffffffffffffffff000000000000000000000000000000000000000082169050919050565b611abd81611a88565b8114611ac857600080fd5b50565b600081359050611ada81611ab4565b92915050565b600060208284031215611af657611af561129d565b5b6000611b0484828501611acb565b91505092915050565b60008060408385031215611b2457611b2361129d565b5b6000611b32858286016112c8565b9250506020611b43858286016114b3565b9150509250929050565b600060208284031215611b6357611b6261129d565b5b6000611b71848285016112c8565b91505092915050565b611b838161164c565b82525050565b6000602082019050611b9e6000830184611b7a565b92915050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b611bd9816112a7565b82525050565b6000611beb8383611bd0565b60208301905092915050565b6000602082019050919050565b6000611c0f82611ba4565b611c198185611baf565b9350611c2483611bc0565b8060005b83811015611c55578151611c3c8882611bdf565b9750611c4783611bf7565b925050600181019050611c28565b5085935050505092915050565b60006020820190508181036000830152611c7c8184611c04565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600080fd5b600080fd5b600080fd5b600082356001604003833603038112611cde57611cdd611cb3565b5b80830191505092915050565b60008083356001602003843603038112611d0757611d06611cb3565b5b80840192508235915067ffffffffffffffff821115611d2957611d28611cb8565b5b602083019250600182023603831315611d4557611d44611cbd565b5b509250929050565b600080fd5b600080fd5b60007fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b611d8c81611d57565b8114611d9757600080fd5b50565b600081359050611da981611d83565b92915050565b600067ffffffffffffffff821115611dca57611dc96112f3565b5b611dd3826112e2565b9050602081019050919050565b6000611df3611dee84611daf565b611353565b905082815260208101848484011115611e0f57611e0e61151b565b5b611e1a848285611551565b509392505050565b600082601f830112611e3757611e366112dd565b5b8135611e47848260208601611de0565b91505092915050565b600067ffffffffffffffff82169050919050565b611e6d81611e50565b8114611e7857600080fd5b50565b600081359050611e8a81611e64565b92915050565b600060408284031215611ea657611ea5611d4d565b5b611eb06040611353565b9050600082013567ffffffffffffffff811115611ed057611ecf611d52565b5b611edc848285016115a2565b6000830152506020611ef084828501611e7b565b60208301525092915050565b600060c08284031215611f1257611f11611d4d565b5b611f1c60c0611353565b90506000611f2c84828501611675565b6000830152506020611f4084828501611d9a565b6020830152506040611f54848285016112c8565b6040830152506060611f68848285016112c8565b606083015250608082013567ffffffffffffffff811115611f8c57611f8b611d52565b5b611f9884828501611e22565b60808301525060a082013567ffffffffffffffff811115611fbc57611fbb611d52565b5b611fc884828501611e90565b60a08301525092915050565b6000611fe03683611efc565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061202182611492565b915061202c83611492565b925082820390508181111561204457612043611fe7565b5b92915050565b600061205582611492565b915061206083611492565b925082820190508082111561207857612077611fe7565b5b92915050565b6000819050919050565b61209961209482611a88565b61207e565b82525050565b60008160601b9050919050565b60006120b78261209f565b9050919050565b60006120c9826120ac565b9050919050565b6120e16120dc8261164c565b6120be565b82525050565b60006120f38285612088565b600c8201915061210382846120d0565b6014820191508190509392505050565b600081519050919050565b6000819050602082019050919050565b600061213a82516112a7565b80915050919050565b600082821b905092915050565b600061215b82612113565b826121658461211e565b90506121708161212e565b925060208210156121b0576121ab7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83602003600802612143565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b600081519050919050565b600081905092915050565b60005b8381101561221a5780820151818401526020810190506121ff565b60008484015250505050565b6000612231826121e6565b61223b81856121f1565b935061224b8185602086016121fc565b80840191505092915050565b60006122638284612226565b915081905092915050565b7f616363657074496d706c69636974526571756573740000000000000000000000600082015250565b60006122a46015836121f1565b91506122af8261226e565b601582019050919050565b60006122c582612297565b9150819050919050565b6000819050919050565b6122ea6122e5826112a7565b6122cf565b82525050565b60006122fc82876122d9565b60208201915061230c82866120d0565b60148201915061231c82856122d9565b60208201915061232c82846122d9565b6020820191508190509594505050505056fea2646970667358221220e95e358701690c763774ab1b8a33de4dc0d143023d26c53779c93169a478087764736f6c634300081c0033
Attestation.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { LibBytes } from "../../../utils/LibBytes.sol"; import { ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX } from "./ISignalsImplicitMode.sol"; using LibBytes for bytes; /// @notice Attestation for a specific session /// @param approvedSigner Address of the approved signer /// @param identityType Identity type /// @param issuerHash Hash of the issuer /// @param audienceHash Hash of the audience /// @param applicationData Unspecified application data /// @param authData Auth data struct Attestation { address approvedSigner; bytes4 identityType; bytes32 issuerHash; bytes32 audienceHash; bytes applicationData; AuthData authData; } /// @notice Auth data for an attestation /// @param redirectUrl Authorization redirect URL /// @param issuedAt Timestamp of the attestation issuance struct AuthData { string redirectUrl; uint64 issuedAt; } /// @title LibAttestation /// @author Michael Standen /// @notice Library for attestation management library LibAttestation { /// @notice Hashes an attestation function toHash( Attestation memory attestation ) internal pure returns (bytes32) { return keccak256(toPacked(attestation)); } /// @notice Decodes an attestation from a packed bytes array /// @param encoded The packed bytes array /// @param pointer The pointer to the start of the attestation /// @return attestation The decoded attestation /// @return newPointer The new pointer to the end of the attestation function fromPacked( bytes calldata encoded, uint256 pointer ) internal pure returns (Attestation memory attestation, uint256 newPointer) { newPointer = pointer; (attestation.approvedSigner, newPointer) = encoded.readAddress(newPointer); (attestation.identityType, newPointer) = encoded.readBytes4(newPointer); (attestation.issuerHash, newPointer) = encoded.readBytes32(newPointer); (attestation.audienceHash, newPointer) = encoded.readBytes32(newPointer); // Application data (arbitrary bytes) uint256 dataSize; (dataSize, newPointer) = encoded.readUint24(newPointer); attestation.applicationData = encoded[newPointer:newPointer + dataSize]; newPointer += dataSize; // Auth data (attestation.authData, newPointer) = fromPackedAuthData(encoded, newPointer); return (attestation, newPointer); } /// @notice Decodes the auth data from a packed bytes /// @param encoded The packed bytes containing the auth data /// @param pointer The pointer to the start of the auth data within the encoded data /// @return authData The decoded auth data /// @return newPointer The pointer to the end of the auth data within the encoded data function fromPackedAuthData( bytes calldata encoded, uint256 pointer ) internal pure returns (AuthData memory authData, uint256 newPointer) { uint24 redirectUrlLength; (redirectUrlLength, pointer) = encoded.readUint24(pointer); authData.redirectUrl = string(encoded[pointer:pointer + redirectUrlLength]); pointer += redirectUrlLength; (authData.issuedAt, pointer) = encoded.readUint64(pointer); return (authData, pointer); } /// @notice Encodes an attestation into a packed bytes array /// @param attestation The attestation to encode /// @return encoded The packed bytes array function toPacked( Attestation memory attestation ) internal pure returns (bytes memory encoded) { return abi.encodePacked( attestation.approvedSigner, attestation.identityType, attestation.issuerHash, attestation.audienceHash, uint24(attestation.applicationData.length), attestation.applicationData, toPackAuthData(attestation.authData) ); } /// @notice Encodes the auth data into a packed bytes array /// @param authData The auth data to encode /// @return encoded The packed bytes array function toPackAuthData( AuthData memory authData ) internal pure returns (bytes memory encoded) { return abi.encodePacked(uint24(bytes(authData.redirectUrl).length), bytes(authData.redirectUrl), authData.issuedAt); } /// @notice Generates the implicit request magic return value /// @param attestation The attestation /// @param wallet The wallet /// @return magic The expected implicit request magic function generateImplicitRequestMagic(Attestation memory attestation, address wallet) internal pure returns (bytes32) { return keccak256( abi.encodePacked(ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX, wallet, attestation.audienceHash, attestation.issuerHash) ); } }
ISignalsImplicitMode.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { Payload } from "../../../modules/Payload.sol"; import { Attestation } from "./Attestation.sol"; /// @dev Magic prefix for the implicit request bytes32 constant ACCEPT_IMPLICIT_REQUEST_MAGIC_PREFIX = keccak256(abi.encodePacked("acceptImplicitRequest")); /// @title ISignalsImplicitMode /// @author Agustin Aguilar, Michael Standen /// @notice Interface for the contracts that support implicit mode validation interface ISignalsImplicitMode { /// @notice Determines if an implicit request is valid /// @param wallet The wallet's address /// @param attestation The attestation data /// @param call The call to validate /// @return magic The hash of the implicit request if valid function acceptImplicitRequest( address wallet, Attestation calldata attestation, Payload.Call calldata call ) external view returns (bytes32 magic); }
Payload.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.27; import { LibBytes } from "../utils/LibBytes.sol"; using LibBytes for bytes; /// @title Payload /// @author Agustin Aguilar, Michael Standen, William Hua /// @notice Library for encoding and decoding payloads library Payload { /// @notice Error thrown when the kind is invalid error InvalidKind(uint8 kind); /// @dev keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)") bytes32 private constant EIP712_DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; /// @dev keccak256("Sequence Wallet") bytes32 private constant EIP712_DOMAIN_NAME_SEQUENCE = 0x4aa45ca7ad825ceb1bf35643f0a58c295239df563b1b565c2485f96477c56318; /// @dev keccak256("3") bytes32 private constant EIP712_DOMAIN_VERSION_SEQUENCE = 0x2a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de; function domainSeparator(bool _noChainId, address _wallet) internal view returns (bytes32 _domainSeparator) { return keccak256( abi.encode( EIP712_DOMAIN_TYPEHASH, EIP712_DOMAIN_NAME_SEQUENCE, EIP712_DOMAIN_VERSION_SEQUENCE, _noChainId ? uint256(0) : uint256(block.chainid), _wallet ) ); } /// @dev keccak256("Call(address to,uint256 value,bytes data,uint256 gasLimit,bool delegateCall,bool onlyFallback,uint256 behaviorOnError)") bytes32 private constant CALL_TYPEHASH = 0x0603985259a953da1f65a522f589c17bd1d0117ec1d3abb7c0788aef251ef437; /// @dev keccak256("Calls(Call[] calls,uint256 space,uint256 nonce,address[] wallets)Call(address to,uint256 value,bytes data,uint256 gasLimit,bool delegateCall,bool onlyFallback,uint256 behaviorOnError)") bytes32 private constant CALLS_TYPEHASH = 0x11e1e4079a79a66e4ade50033cfe2678cdd5341d2dfe5ef9513edb1a0be147a2; /// @dev keccak256("Message(bytes message,address[] wallets)") bytes32 private constant MESSAGE_TYPEHASH = 0xe19a3b94fc3c7ece3f890d98a99bc422615537a08dea0603fa8425867d87d466; /// @dev keccak256("ConfigUpdate(bytes32 imageHash,address[] wallets)") bytes32 private constant CONFIG_UPDATE_TYPEHASH = 0x11fdeb7e8373a1aa96bfac8d0ea91526b2c5d15e5cee20e0543e780258f3e8e4; /// @notice Kind of transaction uint8 public constant KIND_TRANSACTIONS = 0x00; /// @notice Kind of digest uint8 public constant KIND_MESSAGE = 0x01; /// @notice Kind of config update uint8 public constant KIND_CONFIG_UPDATE = 0x02; /// @notice Kind of message uint8 public constant KIND_DIGEST = 0x03; /// @notice Behavior on error: ignore error uint8 public constant BEHAVIOR_IGNORE_ERROR = 0x00; /// @notice Behavior on error: revert on error uint8 public constant BEHAVIOR_REVERT_ON_ERROR = 0x01; /// @notice Behavior on error: abort on error uint8 public constant BEHAVIOR_ABORT_ON_ERROR = 0x02; /// @notice Payload call information /// @param to Address of the target contract /// @param value Value to send with the call /// @param data Data to send with the call /// @param gasLimit Gas limit for the call /// @param delegateCall If the call is a delegate call /// @param onlyFallback If the call should only be executed in an error scenario /// @param behaviorOnError Behavior on error struct Call { address to; uint256 value; bytes data; uint256 gasLimit; bool delegateCall; bool onlyFallback; uint256 behaviorOnError; } /// @notice Decoded payload /// @param kind Kind of payload /// @param noChainId If the chain ID should be omitted /// @param calls Array of calls (transaction kind) /// @param space Nonce space for the calls (transaction kind) /// @param nonce Nonce value for the calls (transaction kind) /// @param message Message to validate (message kind) /// @param imageHash Image hash to update to (config update kind) /// @param digest Digest to validate (digest kind) /// @param parentWallets Parent wallets struct Decoded { uint8 kind; bool noChainId; // Transaction kind Call[] calls; uint256 space; uint256 nonce; // Message kind bytes message; // Config update kind bytes32 imageHash; // Digest kind for 1271 bytes32 digest; // Parent wallets address[] parentWallets; } function fromMessage( bytes memory message ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_MESSAGE; _decoded.message = message; } function fromConfigUpdate( bytes32 imageHash ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_CONFIG_UPDATE; _decoded.imageHash = imageHash; } function fromDigest( bytes32 digest ) internal pure returns (Decoded memory _decoded) { _decoded.kind = KIND_DIGEST; _decoded.digest = digest; } function fromPackedCalls( bytes calldata packed ) internal view returns (Decoded memory _decoded) { _decoded.kind = KIND_TRANSACTIONS; // Read the global flag (uint256 globalFlag, uint256 pointer) = packed.readFirstUint8(); // First bit determines if space is zero or not if (globalFlag & 0x01 == 0x01) { _decoded.space = 0; } else { (_decoded.space, pointer) = packed.readUint160(pointer); } // Next 3 bits determine the size of the nonce uint256 nonceSize = (globalFlag >> 1) & 0x07; if (nonceSize > 0) { // Read the nonce (_decoded.nonce, pointer) = packed.readUintX(pointer, nonceSize); } uint256 numCalls; // Bit 5 determines if the batch contains a single call if (globalFlag & 0x10 == 0x10) { numCalls = 1; } else { // Bit 6 determines if the number of calls uses 1 byte or 2 bytes if (globalFlag & 0x20 == 0x20) { (numCalls, pointer) = packed.readUint16(pointer); } else { (numCalls, pointer) = packed.readUint8(pointer); } } // Read the calls _decoded.calls = new Call[](numCalls); for (uint256 i = 0; i < numCalls; i++) { uint8 flags; (flags, pointer) = packed.readUint8(pointer); // First bit determines if this is a call to self // or a call to another address if (flags & 0x01 == 0x01) { // Call to self _decoded.calls[i].to = address(this); } else { // Call to another address (_decoded.calls[i].to, pointer) = packed.readAddress(pointer); } // Second bit determines if the call has value or not if (flags & 0x02 == 0x02) { (_decoded.calls[i].value, pointer) = packed.readUint256(pointer); } // Third bit determines if the call has data or not if (flags & 0x04 == 0x04) { // 3 bytes determine the size of the calldata uint256 calldataSize; (calldataSize, pointer) = packed.readUint24(pointer); _decoded.calls[i].data = packed[pointer:pointer + calldataSize]; pointer += calldataSize; } // Fourth bit determines if the call has a gas limit or not if (flags & 0x08 == 0x08) { (_decoded.calls[i].gasLimit, pointer) = packed.readUint256(pointer); } // Fifth bit determines if the call is a delegate call or not _decoded.calls[i].delegateCall = (flags & 0x10 == 0x10); // Sixth bit determines if the call is fallback only _decoded.calls[i].onlyFallback = (flags & 0x20 == 0x20); // Last 2 bits are directly mapped to the behavior on error _decoded.calls[i].behaviorOnError = (flags & 0xC0) >> 6; } } function hashCall( Call memory c ) internal pure returns (bytes32) { return keccak256( abi.encode( CALL_TYPEHASH, c.to, c.value, keccak256(c.data), c.gasLimit, c.delegateCall, c.onlyFallback, c.behaviorOnError ) ); } function hashCalls( Call[] memory calls ) internal pure returns (bytes32) { // In EIP712, an array is often hashed as the keccak256 of the concatenated // hashes of each item. So we hash each Call, pack them, and hash again. bytes32[] memory callHashes = new bytes32[](calls.length); for (uint256 i = 0; i < calls.length; i++) { callHashes[i] = hashCall(calls[i]); } return keccak256(abi.encodePacked(callHashes)); } function toEIP712( Decoded memory _decoded ) internal pure returns (bytes32) { bytes32 walletsHash = keccak256(abi.encodePacked(_decoded.parentWallets)); if (_decoded.kind == KIND_TRANSACTIONS) { bytes32 callsHash = hashCalls(_decoded.calls); // The top-level struct for Calls might be something like: // Calls(bytes32 callsHash,uint256 space,uint256 nonce,bytes32 walletsHash) return keccak256(abi.encode(CALLS_TYPEHASH, callsHash, _decoded.space, _decoded.nonce, walletsHash)); } else if (_decoded.kind == KIND_MESSAGE) { // If you define your top-level as: Message(bytes32 messageHash,bytes32 walletsHash) return keccak256(abi.encode(MESSAGE_TYPEHASH, keccak256(_decoded.message), walletsHash)); } else if (_decoded.kind == KIND_CONFIG_UPDATE) { // Top-level: ConfigUpdate(bytes32 imageHash,bytes32 walletsHash) return keccak256(abi.encode(CONFIG_UPDATE_TYPEHASH, _decoded.imageHash, walletsHash)); } else if (_decoded.kind == KIND_DIGEST) { // Top-level: Use MESSAGE_TYPEHASH but assume the digest is already the hashed message return keccak256(abi.encode(MESSAGE_TYPEHASH, _decoded.digest, walletsHash)); } else { // Unknown kind revert InvalidKind(_decoded.kind); } } function hash( Decoded memory _decoded ) internal view returns (bytes32) { bytes32 domain = domainSeparator(_decoded.noChainId, address(this)); bytes32 structHash = toEIP712(_decoded); return keccak256(abi.encodePacked("\x19\x01", domain, structHash)); } function hashFor(Decoded memory _decoded, address _wallet) internal view returns (bytes32) { bytes32 domain = domainSeparator(_decoded.noChainId, _wallet); bytes32 structHash = toEIP712(_decoded); return keccak256(abi.encodePacked("\x19\x01", domain, structHash)); } }
LibBytes.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.18; /// @title Library for reading data from bytes arrays /// @author Agustin Aguilar (aa@horizon.io), Michael Standen (mstan@horizon.io) /// @notice This library contains functions for reading data from bytes arrays. /// @dev These functions do not check if the input index is within the bounds of the data array. /// @dev Reading out of bounds may return dirty values. library LibBytes { function readFirstUint8( bytes calldata _data ) internal pure returns (uint8 a, uint256 newPointer) { assembly { let word := calldataload(_data.offset) a := shr(248, word) newPointer := 1 } } function readUint8(bytes calldata _data, uint256 _index) internal pure returns (uint8 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(248, word) newPointer := add(_index, 1) } } function readUint16(bytes calldata _data, uint256 _index) internal pure returns (uint16 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(240, word) newPointer := add(_index, 2) } } function readUint24(bytes calldata _data, uint256 _index) internal pure returns (uint24 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(232, word) newPointer := add(_index, 3) } } function readUint64(bytes calldata _data, uint256 _index) internal pure returns (uint64 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(192, word) newPointer := add(_index, 8) } } function readUint160(bytes calldata _data, uint256 _index) internal pure returns (uint160 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := shr(96, word) newPointer := add(_index, 20) } } function readUint256(bytes calldata _data, uint256 _index) internal pure returns (uint256 a, uint256 newPointer) { assembly { a := calldataload(add(_index, _data.offset)) newPointer := add(_index, 32) } } function readUintX( bytes calldata _data, uint256 _index, uint256 _length ) internal pure returns (uint256 a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) let shift := sub(256, mul(_length, 8)) a := and(shr(shift, word), sub(shl(mul(8, _length), 1), 1)) newPointer := add(_index, _length) } } function readBytes4(bytes calldata _data, uint256 _pointer) internal pure returns (bytes4 a, uint256 newPointer) { assembly { let word := calldataload(add(_pointer, _data.offset)) a := and(word, 0xffffffff00000000000000000000000000000000000000000000000000000000) newPointer := add(_pointer, 4) } } function readBytes32(bytes calldata _data, uint256 _pointer) internal pure returns (bytes32 a, uint256 newPointer) { assembly { a := calldataload(add(_pointer, _data.offset)) newPointer := add(_pointer, 32) } } function readAddress(bytes calldata _data, uint256 _index) internal pure returns (address a, uint256 newPointer) { assembly { let word := calldataload(add(_index, _data.offset)) a := and(shr(96, word), 0xffffffffffffffffffffffffffffffffffffffff) newPointer := add(_index, 20) } } /// @dev ERC-2098 Compact Signature function readRSVCompact( bytes calldata _data, uint256 _index ) internal pure returns (bytes32 r, bytes32 s, uint8 v, uint256 newPointer) { uint256 yParityAndS; assembly { r := calldataload(add(_index, _data.offset)) yParityAndS := calldataload(add(_index, add(_data.offset, 32))) newPointer := add(_index, 64) } uint256 yParity = uint256(yParityAndS >> 255); s = bytes32(uint256(yParityAndS) & ((1 << 255) - 1)); v = uint8(yParity) + 27; } }
IImplicitProjectRegistry.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import { IImplicitProjectValidation } from "./IImplicitProjectValidation.sol"; /// @title IImplicitProjectRegistry /// @author Michael Standen /// @notice Interface for the registry of projects supporting implicit sessions interface IImplicitProjectRegistry is IImplicitProjectValidation { /// @notice Claim a project /// @param projectIdUpper The project id upper /// @return projectId The concatenation of the `projectIdUpper` and the `msg.sender` function claimProject( bytes12 projectIdUpper ) external returns (bytes32 projectId); /// @notice Transfer a project /// @param projectId The project id /// @param newOwner The new owner function transferProject(bytes32 projectId, address newOwner) external; /// @notice Add a project URL /// @param projectId The project id /// @param projectUrl The project URL function addProjectUrl(bytes32 projectId, string memory projectUrl) external; /// @notice Remove a project URL /// @param projectId The project id /// @param projectUrl The project URL function removeProjectUrl(bytes32 projectId, string memory projectUrl) external; /// @notice List project URLs /// @param projectId The project id /// @return projectUrls The project URLs function listProjectUrls( bytes32 projectId ) external view returns (bytes32[] memory); /// @notice Not project owner error error NotProjectOwner(); /// @notice Project already claimed error error ProjectAlreadyClaimed(); /// @notice Invalid project owner error error InvalidProjectOwner(); /// @notice Project URL not found error error ProjectUrlNotFound(); /// @notice Project URL already exists error error ProjectUrlAlreadyExists(); /// @notice Invalid project URL index error error InvalidProjectUrlIndex(); /// @notice Emitted when a project is claimed event ProjectClaimed(bytes32 indexed projectId, address indexed owner); /// @notice Emitted when a project owner is transferred event ProjectOwnerTransferred(bytes32 indexed projectId, address indexed newOwner); /// @notice Emitted when a project URL is added event ProjectUrlAdded(bytes32 indexed projectId, bytes32 indexed urlHash); /// @notice Emitted when a project URL is removed event ProjectUrlRemoved(bytes32 indexed projectId, bytes32 indexed urlHash); }
IImplicitProjectValidation.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import { Attestation } from "sequence-v3/src/extensions/sessions/implicit/Attestation.sol"; /// @title IImplicitProjectValidation /// @author Michael Standen /// @notice Interface for contracts supporting validation of implicit sessions for projects interface IImplicitProjectValidation { /// @notice Invalid redirect url error error InvalidRedirectUrl(); /// @notice Check if a project has a code /// @param wallet The wallet address /// @param attestation The attestation /// @param projectId The project id /// @return magic The attestation magic bytes for the wallet address function validateAttestation( address wallet, Attestation calldata attestation, bytes32 projectId ) external view returns (bytes32); }
ImplicitProjectRegistry.sol
// SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.13; import { IImplicitProjectRegistry } from "./IImplicitProjectRegistry.sol"; import { IImplicitProjectValidation } from "./IImplicitProjectValidation.sol"; import { Attestation, LibAttestation } from "sequence-v3/src/extensions/sessions/implicit/Attestation.sol"; /// @title ImplicitProjectRegistry /// @author Michael Standen /// @notice Registry of projects supporting implicit sessions contract ImplicitProjectRegistry is IImplicitProjectRegistry { using LibAttestation for Attestation; /// @notice Project owner mapping(bytes32 => address) public projectOwner; /// @notice Project URLs mapping(bytes32 => mapping(bytes32 => bool)) public isProjectUrl; mapping(bytes32 => bytes32[]) public projectUrlsList; modifier onlyProjectOwner( bytes32 projectId ) { if (projectOwner[projectId] != msg.sender) { revert IImplicitProjectRegistry.NotProjectOwner(); } _; } /// @inheritdoc IImplicitProjectRegistry function claimProject( bytes12 projectIdUpper ) public returns (bytes32 projectId) { address owner = msg.sender; if (owner == address(0)) { revert IImplicitProjectRegistry.InvalidProjectOwner(); } projectId = bytes32(abi.encodePacked(projectIdUpper, owner)); if (projectOwner[projectId] != address(0)) { revert IImplicitProjectRegistry.ProjectAlreadyClaimed(); } projectOwner[projectId] = owner; emit IImplicitProjectRegistry.ProjectClaimed(projectId, owner); return projectId; } /// @inheritdoc IImplicitProjectRegistry function transferProject(bytes32 projectId, address newOwner) public onlyProjectOwner(projectId) { if (newOwner == address(0)) { revert IImplicitProjectRegistry.InvalidProjectOwner(); } projectOwner[projectId] = newOwner; emit IImplicitProjectRegistry.ProjectOwnerTransferred(projectId, newOwner); } function _addProjectUrlHash(bytes32 projectId, bytes32 projectUrlHash) internal { if (isProjectUrl[projectId][projectUrlHash]) { revert IImplicitProjectRegistry.ProjectUrlAlreadyExists(); } isProjectUrl[projectId][projectUrlHash] = true; projectUrlsList[projectId].push(projectUrlHash); emit IImplicitProjectRegistry.ProjectUrlAdded(projectId, projectUrlHash); } /// @notice Add a project URL hash /// @param projectId The project id /// @param projectUrlHash The project URL hash function addProjectUrlHash(bytes32 projectId, bytes32 projectUrlHash) external onlyProjectOwner(projectId) { _addProjectUrlHash(projectId, projectUrlHash); } /// @notice Add a list of project URL hashes /// @param projectId The project id /// @param projectUrlHashes The project URL hashes function addProjectUrlHashBatch( bytes32 projectId, bytes32[] memory projectUrlHashes ) external onlyProjectOwner(projectId) { for (uint256 i; i < projectUrlHashes.length; i++) { _addProjectUrlHash(projectId, projectUrlHashes[i]); } } /// @inheritdoc IImplicitProjectRegistry function addProjectUrl(bytes32 projectId, string memory projectUrl) public onlyProjectOwner(projectId) { _addProjectUrlHash(projectId, _hashUrl(projectUrl)); } /// @notice Add a list of project URLs /// @param projectId The project id /// @param projectUrls The project URLs function addProjectUrlBatch(bytes32 projectId, string[] memory projectUrls) external onlyProjectOwner(projectId) { for (uint256 i; i < projectUrls.length; i++) { _addProjectUrlHash(projectId, _hashUrl(projectUrls[i])); } } function _removeProjectUrlHash(bytes32 projectId, bytes32 projectUrlHash, uint256 urlIdx) internal { if (urlIdx >= projectUrlsList[projectId].length || projectUrlsList[projectId][urlIdx] != projectUrlHash) { revert IImplicitProjectRegistry.InvalidProjectUrlIndex(); } isProjectUrl[projectId][projectUrlHash] = false; projectUrlsList[projectId][urlIdx] = projectUrlsList[projectId][projectUrlsList[projectId].length - 1]; projectUrlsList[projectId].pop(); emit IImplicitProjectRegistry.ProjectUrlRemoved(projectId, projectUrlHash); } /// @notice Remove a project URL hash /// @param projectId The project id /// @param projectUrlHash The project URL hash /// @param urlIdx The index of the project URL hash to remove function removeProjectUrlHash( bytes32 projectId, bytes32 projectUrlHash, uint256 urlIdx ) external onlyProjectOwner(projectId) { _removeProjectUrlHash(projectId, projectUrlHash, urlIdx); } /// @notice Remove a list of project URL hashes /// @param projectId The project id /// @param projectUrlHashes The project URL hashes /// @param urlIdxs The indexes of the project URL hashes to remove /// @dev The urlIdxs must be sorted in descending order function removeProjectUrlHashBatch( bytes32 projectId, bytes32[] memory projectUrlHashes, uint256[] memory urlIdxs ) external onlyProjectOwner(projectId) { if (projectUrlHashes.length != urlIdxs.length) { revert IImplicitProjectRegistry.InvalidProjectUrlIndex(); } // Ensure the urlIdxs are sorted descending to prevent issues with reordering during removals for (uint256 i; i < urlIdxs.length - 1; i++) { if (urlIdxs[i] < urlIdxs[i + 1]) { revert IImplicitProjectRegistry.InvalidProjectUrlIndex(); } } for (uint256 i; i < projectUrlHashes.length; i++) { _removeProjectUrlHash(projectId, projectUrlHashes[i], urlIdxs[i]); } } /// @inheritdoc IImplicitProjectRegistry /// @dev This function is not optimized. Prefer to use removeProjectUrlHash. function removeProjectUrl(bytes32 projectId, string memory projectUrl) external onlyProjectOwner(projectId) { // Find the index of the project URL hash bytes32 projectUrlHash = _hashUrl(projectUrl); for (uint256 i; i < projectUrlsList[projectId].length; i++) { if (projectUrlsList[projectId][i] == projectUrlHash) { _removeProjectUrlHash(projectId, projectUrlHash, i); return; } } revert IImplicitProjectRegistry.ProjectUrlNotFound(); } /// @inheritdoc IImplicitProjectRegistry function listProjectUrls( bytes32 projectId ) external view returns (bytes32[] memory) { return projectUrlsList[projectId]; } /// @inheritdoc IImplicitProjectValidation function validateAttestation( address wallet, Attestation calldata attestation, bytes32 projectId ) external view returns (bytes32) { bytes32 hashedUrl = _hashUrl(attestation.authData.redirectUrl); if (isProjectUrl[projectId][hashedUrl]) { return attestation.generateImplicitRequestMagic(wallet); } revert IImplicitProjectValidation.InvalidRedirectUrl(); } function _hashUrl( string memory url ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(url)); } }
Gas Token: