Address Contract Partially Verified
Address
0x9a52283276A0ec8740DF50bF01B28A80D880eaf2
Balance
0 ETH
Nonce
1
Code Size
6539 bytes
Creator
Create2 Deployer at tx 0xc32d5e16...594a79
Indexed Transactions
0 (1 on-chain, 1.5% indexed)
Contract Bytecode
6539 bytes
0x6080604052600436101561001257600080fd5b6000803560e01c908163244d6cb2146100aa57508063309bfb76146100a55780636d61fe70146100a05780637129edce1461009b5780638a91b0e314610096578063d60b347f14610091578063d8ed2b3c1461008c578063ecd05961146100875763ffbb39f81461008257600080fd5b6107d3565b6107b3565b610755565b6106f6565b610670565b61046f565b6101d7565b61012b565b346100e55760203660031901126100e5576040906004356100ca816100e8565b6001600160a01b031681526020818152919020546080908152f35b80fd5b6001600160a01b038116036100f957565b600080fd5b9181601f840112156100f9578235916001600160401b0383116100f957602083818601950101116100f957565b346100f95760803660031901126100f9576101476024356100e8565b6064356001600160401b0381116100f9576101669036906004016100fe565b5050600435600090815260016020908152604080832033845290915290205460ff1660038110156101a4576001036100f95760405160008152602090f35b610735565b60206003198201126100f957600435906001600160401b0382116100f9576101d3916004016100fe565b9091565b6101e0366101a9565b906020916020116100f95790610248602083359361023a61022b610224610211886000526001602052604060002090565b3360009081526020919091526040902090565b5460ff1690565b6102348161074b565b15610849565b018035019060208201913590565b90916000925b8284106102b2576102956102888661027133916000526001602052604060002090565b9060018060a01b0316600052602052604060002090565b805460ff19166001179055565b3360009081526020819052604090206102ae8154610d08565b9055005b6102c56102c0858584610a7f565b610aa1565b6102da836102d4878786610a7f565b01610996565b946040916102f3836102ed848988610a7f565b01610ab6565b83516001600160f81b031990921686830190815260609890981b6001600160601b03191660018901526001600160e01b03191660158801529586601982010396610345601f19988981018352826109d9565b5190209661035e610357338a84610a19565b5115610acb565b6000975b61036d838887610a7f565b61037c60809182810190610b17565b90508a101561040a576001998a91899088878460066103ba6103b5836103af6103a6878b8a610a7f565b89810190610b17565b9061096f565b610b60565b6103c381610b56565b036103d6575b5050505050019850610362565b6103af87946103ef6103a694610400986103f897610a7f565b90810190610b17565b905014610b6a565b88388887846103c9565b50600194985061045f610467939492988a61045361044561043b898d6060610433838389610a7f565b013595610a7f565b6080810190610b17565b9096519687938c8501610c01565b039081018452836109d9565b339088611930565b01929361024e565b604060031981813601126100f95760049081356024356001600160401b0381116100f9576101208185019382360301126100f957606461051d91016104e36104c06104ba83876108cf565b90610850565b63e9ae5c5360e01b916001600160e01b0319916104dc91610901565b1614610849565b6105146105026104fc6104f684886108cf565b9061085e565b906108b2565b90818060081b918160301b9160501b90565b505050936108cf565b506024810135019183602484019301359060ff60f81b809116801560001461057e5750509061055261055c9261056094611908565b92909193336115d4565b1590565b61057057505b5160008152602090f35b905163016754b960e61b8152fd5b600160f81b8103610619575050509061059e908035019060208201913590565b60009291925b8181106105b5575050505050610566565b6105fd61055c6105ce6105c984868961096f565b610996565b6105e56105dc85878a61096f565b8a8101906108cf565b9060206105f387898c61096f565b013592883361127e565b610609576001016105a4565b855163016754b960e61b81528590fd5b03610660579161055c9161064d848061064761064161063b610656998861086f565b9061092d565b60601c90565b9461087d565b92909133610ec1565b6105705750610566565b84516339d2eb5560e01b81528490fd5b610679366101a9565b6020116100f95735600081815260016020908152604080832033845290915281205490919060ff1660038110156101a4576001036106f2578152600160209081526040808320336000908152908352818120805460ff19166002179055918290529020805480156106ed5760001901905580f35b610cf2565b5080fd5b346100f95760203660031901126100f957600435610713816100e8565b60018060a01b0316600052600060205260206040600020541515604051908152f35b634e487b7160e01b600052602160045260246000fd5b600311156101a457565b346100f95760403660031901126100f95760ff61079e602435610777816100e8565b600435600052600160205260406000209060018060a01b0316600052602052604060002090565b541660405160038210156101a4576020918152f35b346100f95760203660031901126100f95760206040516005600435148152f35b346100f95760603660031901126100f9576107fe6044356107f3816100e8565b602435600435610a19565b6040805190602080835283519182602085015260005b8381106108365784604081866000838284010152601f80199101168101030190f35b8581018301518582018301528201610814565b156100f957565b906004116100f95790600490565b906024116100f95760040190602090565b906014116100f95790601490565b90929192836014116100f95783116100f957601401916013190190565b909392938483116100f95784116100f9578101920390565b3590602081106108c0575090565b6000199060200360031b1b1690565b903590601e19813603018212156100f957018035906001600160401b0382116100f9576020019181360383136100f957565b6001600160e01b0319903581811693926004811061091e57505050565b60040360031b82901b16169150565b6001600160601b0319903581811693926014811061094a57505050565b60140360031b82901b16169150565b634e487b7160e01b600052603260045260246000fd5b91908110156109915760051b81013590605e19813603018212156100f9570190565b610959565b356109a0816100e8565b90565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b038211176109d457604052565b6109a3565b90601f801991011681019081106001600160401b038211176109d457604052565b9190604051926020840152604083015260408252610a17826109b9565b565b610a4191610a29919493946109fa565b805160209182012090936001600160a01b03166109fa565b80519083012060405181548082529093918183019083805b838110610a6c5750505050830101604052565b8060051c83015481890152018490610a59565b91908110156109915760051b81013590609e19813603018212156100f9570190565b356001600160f81b0319811681036100f95790565b356001600160e01b0319811681036100f95790565b15610ad257565b60405162461bcd60e51b815260206004820152601860248201527f6475706c6963617465207065726d697373696f6e4861736800000000000000006044820152606490fd5b903590601e19813603018212156100f957018035906001600160401b0382116100f957602001918160051b360383136100f957565b600711156100f957565b600711156101a457565b356109a081610b4c565b15610b7157565b60405162461bcd60e51b815260206004820152602d60248201527f6f6e6c79204f6e654f6620636f6e646974696f6e2063616e2068617665206d7560448201526c6c7469706c6520706172616d7360981b6064820152608490fd5b6001600160401b038116036100f957565b81835290916001600160fb1b0383116100f95760209260051b809284830137010190565b90926040936040830190835281602091604083860152526060926060810160059660608560051b84010197876000945b878610610c45575050505050505050505090565b90919293949596979899605f198282030186528a35605e19843603018112156100f95783018035610c7581610b4c565b60078110156101a45782528881013590610c8e82610bcc565b6001600160401b038092168a84015286810135601e19823603018112156100f9570189813591019181116100f95780861b360382136100f957610cde8a9283928e86818c60019901520191610bdd565b9c0196019601949897969593929190610c31565b634e487b7160e01b600052601160045260246000fd5b60001981146106ed5760010190565b6001600160401b0381116109d45760051b60200190565b6040929181810384136100f957815193602091828401516001600160401b03948582116100f957019181601f840112156100f957825194610d6e86610d17565b95610d7b835197886109d9565b808752858701928660059260051b870101958587116100f957878101945b878610610dac5750505050505050505090565b85518581116100f957820160609081601f19828b0301126100f957845191610dd3836109b9565b8b820151610de081610b4c565b835285820151610def81610bcc565b8c840152810151908782116100f9570188603f820112156100f9578a81015190610e1882610d17565b91610e25875193846109d9565b808352868d840191891b830101918b83116100f95790878e959396949201905b868210610e6057505083945086820152815201950194610d99565b815181528e959182019101610e45565b8051156109915760200190565b80518210156109915760209160051b010190565b906001600160401b038092166004019182116106ed57565b9060206001600160401b03809316019182116106ed57565b90929084611265576000905b604080516001600160f81b0319602080830191825260609790971b6001600160601b03191660218301526001600160e01b031985166035830152919690939091610f3690849086603981015b0396610f2d601f19988981018352826109d9565b51902084610a19565b9384511561120d575b505050508051156111fc5780602080610f5d93518301019101610d2e565b905060005b81518110156111f157610f758183610e7d565b51610fc86104fc868301610fb4610faf610f9c610fa1610f9c85516001600160401b031690565b610e91565b93516001600160401b031690565b610ea9565b6001600160401b0380911691168a8861089a565b8151610fd381610b56565b610fdc81610b56565b15806111db575b15610ff5575050505050505050600090565b81519061100182610b56565b61100a82610b56565b6001809214806111c5575b1561102857505050505050505050600090565b6002835161103581610b56565b61103e81610b56565b14806111af575b1561105857505050505050505050600090565b6003835161106581610b56565b61106e81610b56565b148061119a575b1561108857505050505050505050600090565b6004835161109581610b56565b61109e81610b56565b1480611185575b156110b857505050505050505050600090565b600583516110c581610b56565b6110ce81610b56565b1480611170575b156110e857505050505050505050600090565b600683516110f581610b56565b6110fe81610b56565b1461110f575b505050600101610f62565b600092880183835b611138575b505050501561112d57388080611104565b505050505050600090565b8151805182101561116a578161114d91610e7d565b51831461115c57830183611117565b50505090503880808061111c565b5061111c565b5061117d88840151610e70565b5181146110d5565b5061119288840151610e70565b5181116110a5565b506111a788840151610e70565b518110611075565b506111bc88840151610e70565b51811015611045565b506111d288840151610e70565b51811115611015565b506111e887830151610e70565b51811415610fe3565b505050505050600190565b8351631c49f4d160e01b8152600490fd5b87516001600160f81b031960208201908152600060218301526001600160e01b0319909316603582015261125c9550906112539082603981015b039081018352826109d9565b51902090610a19565b38808080610f3f565b6112786112728684610850565b90610901565b90610ecd565b93949093919291856115c1576000905b6040958651926112d98360209886610f19856020830193849091601992600083526bffffffffffffffffffffffff199060601b16600183015263ffffffff60e01b1660158201520190565b93845115611583575b50505050805115611572578060208061130093518301019101610d2e565b91116115615760005b81518110156111f15761131c8183610e7d565b516113436104fc868301610fb4610faf610f9c610fa1610f9c85516001600160401b031690565b815161134e81610b56565b61135781610b56565b158061154b575b15611370575050505050505050600090565b81519061137c82610b56565b61138582610b56565b600180921480611535575b156113a357505050505050505050600090565b600283516113b081610b56565b6113b981610b56565b148061151f575b156113d357505050505050505050600090565b600383516113e081610b56565b6113e981610b56565b148061150a575b1561140357505050505050505050600090565b6004835161141081610b56565b61141981610b56565b14806114f5575b1561143357505050505050505050600090565b6005835161144081610b56565b61144981610b56565b14806114e0575b1561146357505050505050505050600090565b6006835161147081610b56565b61147981610b56565b1461148a575b505050600101611309565b600092880183835b6114a8575b505050501561112d5738808061147f565b815180518210156114da57816114bd91610e7d565b5183146114cc57830183611492565b505050905038808080611497565b50611497565b506114ed88840151610e70565b518114611450565b5061150288840151610e70565b518111611420565b5061151788840151610e70565b5181106113f0565b5061152c88840151610e70565b518110156113c0565b5061154288840151610e70565b51811115611390565b5061155887830151610e70565b5181141561135e565b8351631ed604b560e21b8152600490fd5b8451631c49f4d160e01b8152600490fd5b6115b8945061125389519182611247602082019586601991600082526000600183015263ffffffff60e01b1660158201520190565b388080806112e2565b6115ce6112728785610850565b9061128e565b93949093919291856118f5576000905b60409586519261162f8360209886610f19856020830193849091601992600083526bffffffffffffffffffffffff199060601b16600183015263ffffffff60e01b1660158201520190565b938451156118b7575b50505050805115611572578060208061165693518301019101610d2e565b91116115615760005b81518110156111f1576116728183610e7d565b516116996104fc868301610fb4610faf610f9c610fa1610f9c85516001600160401b031690565b81516116a481610b56565b6116ad81610b56565b15806118a1575b156116c6575050505050505050600090565b8151906116d282610b56565b6116db82610b56565b60018092148061188b575b156116f957505050505050505050600090565b6002835161170681610b56565b61170f81610b56565b1480611875575b1561172957505050505050505050600090565b6003835161173681610b56565b61173f81610b56565b1480611860575b1561175957505050505050505050600090565b6004835161176681610b56565b61176f81610b56565b148061184b575b1561178957505050505050505050600090565b6005835161179681610b56565b61179f81610b56565b1480611836575b156117b957505050505050505050600090565b600683516117c681610b56565b6117cf81610b56565b146117e0575b50505060010161165f565b600092880183835b6117fe575b505050501561112d573880806117d5565b81518051821015611830578161181391610e7d565b518314611822578301836117e8565b5050509050388080806117ed565b506117ed565b5061184388840151610e70565b5181146117a6565b5061185888840151610e70565b518111611776565b5061186d88840151610e70565b518110611746565b5061188288840151610e70565b51811015611716565b5061189888840151610e70565b518111156116e6565b506118ae87830151610e70565b518114156116b4565b6118ec945061125389519182611247602082019586601991600082526000600183015263ffffffff60e01b1660158201520190565b38808080611638565b6119026112728785610850565b906115e4565b90806014116100f957813560601c92816034116100f957601483013592603401916033190190565b61195891611940919594956109fa565b805160209182012090926001600160a01b03166109fa565b805160209182012084518082558201915b82811061197857505050509050565b8084918701518160051c8401550161196956
Verified Source Code Partial Match
Compiler: v0.8.24+commit.e11b9ed9
EVM: paris
Optimization: Yes (200 runs)
CallPolicy.sol 229 lines
pragma solidity ^0.8.0;
import "kernel/sdk/moduleBase/PolicyBase.sol";
import "kernel/utils/ExecLib.sol";
import {IERC7579Account} from "kernel/interfaces/IERC7579Account.sol";
struct Permission {
CallType callType; // calltype can be CALLTYPE_SINGLE/CALLTYPE_DELEGATECALL
address target;
bytes4 selector;
uint256 valueLimit;
ParamRule[] rules;
}
struct ParamRule {
ParamCondition condition;
uint64 offset;
bytes32[] params;
}
enum ParamCondition {
EQUAL,
GREATER_THAN,
LESS_THAN,
GREATER_THAN_OR_EQUAL,
LESS_THAN_OR_EQUAL,
NOT_EQUAL,
ONE_OF
}
enum Status {
NA,
Live,
Deprecated
}
contract CallPolicy is PolicyBase {
error InvalidCallType();
error InvalidCallData();
error CallViolatesParamRule();
error CallViolatesValueRule();
mapping(address => uint256) public usedIds;
mapping(bytes32 id => mapping(address => Status)) public status;
//mapping(bytes32 id => mapping(bytes32 permissionHash => mapping(address => bytes))) public encodedPermissions;
function isInitialized(address wallet) external view override returns (bool) {
return usedIds[wallet] > 0;
}
function setPermission(bytes32 _id, bytes32 _permissionHash, address _owner, bytes memory _permission) internal {
bytes32 slot = keccak256(bytes.concat(bytes32(uint256(uint160(_owner))), keccak256(bytes.concat(_id,_permissionHash))));
uint256 length = _permission.length;
assembly {
// store length on first slot, as usual
sstore(slot, length)
for { let cursor := 0x20 } lt(cursor, add(length, 0x20)) { cursor := add(cursor, 0x20) } {
sstore(add(slot, div(cursor, 0x20)), mload(add(_permission, cursor))) // slot + cursor/32
}
}
}
function encodedPermissions(bytes32 _id, bytes32 _permissionHash, address _owner) public view returns(bytes memory encoded) {
bytes32 slot = keccak256(bytes.concat(bytes32(uint256(uint160(_owner))), keccak256(bytes.concat(_id,_permissionHash))));
uint256 length;
assembly {
encoded := mload(0x40)
length := sload(slot)
mstore(encoded, length)
for { let cursor := 0x20 } lt(cursor, add(length, 0x20)) { cursor := add(cursor, 0x20) } {
mstore(add(encoded, cursor), sload(add(slot, div(cursor, 0x20))))
}
mstore(0x40, add(encoded, add(length, 0x20)))
}
}
function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp)
external
payable
override
returns (uint256)
{
require(bytes4(userOp.callData[0:4]) == IERC7579Account.execute.selector);
ExecMode mode = ExecMode.wrap(bytes32(userOp.callData[4:36]));
(CallType callType, ExecType execType,,) = ExecLib.decode(mode);
bytes calldata executionCallData = userOp.callData; // Cache calldata here
assembly {
executionCallData.offset :=
add(add(executionCallData.offset, 0x24), calldataload(add(executionCallData.offset, 0x24)))
executionCallData.length := calldataload(sub(executionCallData.offset, 0x20))
}
if (callType == CALLTYPE_SINGLE) {
(address target, uint256 value, bytes calldata callData) = ExecLib.decodeSingle(executionCallData);
bool permissionPass = _checkPermission(msg.sender, id, CALLTYPE_SINGLE, target, callData, value);
if (!permissionPass) {
revert CallViolatesParamRule();
}
} else if (callType == CALLTYPE_BATCH) {
Execution[] calldata exec = ExecLib.decodeBatch(executionCallData);
for (uint256 i = 0; i < exec.length; i++) {
bool permissionPass =
_checkPermission(msg.sender, id, CALLTYPE_SINGLE, exec[i].target, exec[i].callData, exec[i].value);
if (!permissionPass) {
revert CallViolatesParamRule();
}
}
} else if (callType == CALLTYPE_DELEGATECALL) {
address target = address(bytes20(executionCallData[0:20]));
bytes calldata callData = executionCallData[20:];
bool permissionPass = _checkPermission(msg.sender, id, CALLTYPE_DELEGATECALL, target, callData, 0);
if (!permissionPass) {
revert CallViolatesParamRule();
}
} else {
revert InvalidCallType();
}
}
function _checkPermission(
address wallet,
bytes32 id,
CallType callType,
address target,
bytes calldata data,
uint256 value
) internal returns (bool) {
bytes4 _data = data.length == 0 ? bytes4(0x0) : bytes4(data[0:4]);
bytes32 permissionHash = keccak256(abi.encodePacked(callType, target, _data));
bytes memory encodedPermission = encodedPermissions(id, permissionHash, wallet);
// try to find the permission with zero address which means ANY target address
// e.g. allow to call `approve` function of `ANY` ERC20 token contracts
if (encodedPermission.length == 0) {
bytes32 permissionHashWithZeroAddress = keccak256(abi.encodePacked(callType, address(0), _data));
encodedPermission = encodedPermissions(id,permissionHashWithZeroAddress,wallet);
}
// if still no permission found, then the call is not allowed
if (encodedPermission.length == 0) {
revert InvalidCallData();
}
(uint256 allowedValue, ParamRule[] memory rules) = abi.decode(encodedPermission, (uint256, ParamRule[]));
if (value > allowedValue) {
revert CallViolatesValueRule();
}
for (uint256 i = 0; i < rules.length; i++) {
ParamRule memory rule = rules[i];
bytes32 param = bytes32(data[4 + rule.offset:4 + rule.offset + 32]);
// only ONE_OF condition can have multiple params
if (rule.condition == ParamCondition.EQUAL && param != rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.GREATER_THAN && param <= rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.LESS_THAN && param >= rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.GREATER_THAN_OR_EQUAL && param < rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.LESS_THAN_OR_EQUAL && param > rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.NOT_EQUAL && param == rule.params[0]) {
return false;
} else if (rule.condition == ParamCondition.ONE_OF) {
bool oneOfStatus = false;
for (uint256 j = 0; j < rule.params.length; j++) {
if (param == rule.params[j]) {
oneOfStatus = true;
break;
}
}
if (!oneOfStatus) {
return false;
}
}
}
return true;
}
function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
override
returns (uint256)
{
require(status[id][msg.sender] == Status.Live);
return 0;
}
function _parsePermission(bytes calldata _sig) internal pure returns (Permission[] calldata permissions) {
assembly {
permissions.offset := add(add(_sig.offset, 32), calldataload(_sig.offset))
permissions.length := calldataload(sub(permissions.offset, 32))
}
}
function _policyOninstall(bytes32 id, bytes calldata _data) internal override {
require(status[id][msg.sender] == Status.NA);
Permission[] calldata permissions = _parsePermission(_data);
for (uint256 i = 0; i < permissions.length; i++) {
// check if the permissionHash is unique
bytes32 permissionHash =
keccak256(abi.encodePacked(permissions[i].callType, permissions[i].target, permissions[i].selector));
require(encodedPermissions(id, permissionHash, msg.sender).length == 0, "duplicate permissionHash");
// check if the params length is correct
for (uint256 j = 0; j < permissions[i].rules.length; j++) {
if (permissions[i].rules[j].condition != ParamCondition.ONE_OF) {
require(permissions[i].rules[j].params.length == 1, "only OneOf condition can have multiple params");
}
}
setPermission(
id,permissionHash,msg.sender,
abi.encode(permissions[i].valueLimit, permissions[i].rules)
);
}
status[id][msg.sender] = Status.Live;
usedIds[msg.sender]++;
}
function _policyOnUninstall(bytes32 id, bytes calldata _data) internal override {
require(status[id][msg.sender] == Status.Live);
//delete encodedPermissions[id][msg.sender];
status[id][msg.sender] = Status.Deprecated;
usedIds[msg.sender]--;
}
}
Types.sol 106 lines
pragma solidity ^0.8.23;
// Custom type for improved developer experience
type ExecMode is bytes32;
type CallType is bytes1;
type ExecType is bytes1;
type ExecModeSelector is bytes4;
type ExecModePayload is bytes22;
using {eqModeSelector as ==} for ExecModeSelector global;
using {eqCallType as ==} for CallType global;
using {eqExecType as ==} for ExecType global;
function eqCallType(CallType a, CallType b) pure returns (bool) {
return CallType.unwrap(a) == CallType.unwrap(b);
}
function eqExecType(ExecType a, ExecType b) pure returns (bool) {
return ExecType.unwrap(a) == ExecType.unwrap(b);
}
function eqModeSelector(ExecModeSelector a, ExecModeSelector b) pure returns (bool) {
return ExecModeSelector.unwrap(a) == ExecModeSelector.unwrap(b);
}
type ValidationMode is bytes1;
type ValidationId is bytes21;
type ValidationType is bytes1;
type PermissionId is bytes4;
type PolicyData is bytes22; // 2bytes for flag on skip, 20 bytes for validator address
type PassFlag is bytes2;
using {vModeEqual as ==} for ValidationMode global;
using {vTypeEqual as ==} for ValidationType global;
using {vIdentifierEqual as ==} for ValidationId global;
using {vModeNotEqual as !=} for ValidationMode global;
using {vTypeNotEqual as !=} for ValidationType global;
using {vIdentifierNotEqual as !=} for ValidationId global;
// nonce = uint192(key) + nonce
// key = mode + (vtype + validationDataWithoutType) + 2bytes parallelNonceKey
// key = 0x00 + 0x00 + 0x000 .. 00 + 0x0000
// key = 0x00 + 0x01 + 0x1234...ff + 0x0000
// key = 0x00 + 0x02 + ( ) + 0x000
function vModeEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
return ValidationMode.unwrap(a) == ValidationMode.unwrap(b);
}
function vModeNotEqual(ValidationMode a, ValidationMode b) pure returns (bool) {
return ValidationMode.unwrap(a) != ValidationMode.unwrap(b);
}
function vTypeEqual(ValidationType a, ValidationType b) pure returns (bool) {
return ValidationType.unwrap(a) == ValidationType.unwrap(b);
}
function vTypeNotEqual(ValidationType a, ValidationType b) pure returns (bool) {
return ValidationType.unwrap(a) != ValidationType.unwrap(b);
}
function vIdentifierEqual(ValidationId a, ValidationId b) pure returns (bool) {
return ValidationId.unwrap(a) == ValidationId.unwrap(b);
}
function vIdentifierNotEqual(ValidationId a, ValidationId b) pure returns (bool) {
return ValidationId.unwrap(a) != ValidationId.unwrap(b);
}
type ValidationData is uint256;
type ValidAfter is uint48;
type ValidUntil is uint48;
function getValidationResult(ValidationData validationData) pure returns (address result) {
assembly {
result := validationData
}
}
function packValidationData(ValidAfter validAfter, ValidUntil validUntil) pure returns (uint256) {
return uint256(ValidAfter.unwrap(validAfter)) << 208 | uint256(ValidUntil.unwrap(validUntil)) << 160;
}
function parseValidationData(uint256 validationData)
pure
returns (ValidAfter validAfter, ValidUntil validUntil, address result)
{
assembly {
result := validationData
validUntil := and(shr(160, validationData), 0xffffffffffff)
switch iszero(validUntil)
case 1 { validUntil := 0xffffffffffff }
validAfter := shr(208, validationData)
}
}
Structs.sol 8 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
struct Execution {
address target;
uint256 value;
bytes callData;
}
ExecLib.sol 209 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;
import {ExecMode, CallType, ExecType, ExecModeSelector, ExecModePayload} from "../types/Types.sol";
import {
CALLTYPE_SINGLE,
CALLTYPE_BATCH,
EXECTYPE_DEFAULT,
EXEC_MODE_DEFAULT,
EXECTYPE_TRY,
CALLTYPE_DELEGATECALL
} from "../types/Constants.sol";
import {Execution} from "../types/Structs.sol";
/**
* @dev ExecLib is a helper library for execution
*/
library ExecLib {
error ExecutionFailed();
event TryExecuteUnsuccessful(uint256 batchExecutionindex, bytes result);
function _execute(ExecMode execMode, bytes calldata executionCalldata)
internal
returns (bytes[] memory returnData)
{
(CallType callType, ExecType execType,,) = decode(execMode);
// check if calltype is batch or single
if (callType == CALLTYPE_BATCH) {
// destructure executionCallData according to batched exec
Execution[] calldata executions = decodeBatch(executionCalldata);
// check if execType is revert or try
if (execType == EXECTYPE_DEFAULT) returnData = _execute(executions);
else if (execType == EXECTYPE_TRY) returnData = _tryExecute(executions);
else revert("Unsupported");
} else if (callType == CALLTYPE_SINGLE) {
// destructure executionCallData according to single exec
(address target, uint256 value, bytes calldata callData) = decodeSingle(executionCalldata);
returnData = new bytes[](1);
bool success;
// check if execType is revert or try
if (execType == EXECTYPE_DEFAULT) {
returnData[0] = _execute(target, value, callData);
} else if (execType == EXECTYPE_TRY) {
(success, returnData[0]) = _tryExecute(target, value, callData);
if (!success) emit TryExecuteUnsuccessful(0, returnData[0]);
} else {
revert("Unsupported");
}
} else if (callType == CALLTYPE_DELEGATECALL) {
address delegate = address(bytes20(executionCalldata[0:20]));
bytes calldata callData = executionCalldata[20:];
_executeDelegatecall(delegate, callData);
} else {
revert("Unsupported");
}
}
function _execute(Execution[] calldata executions) internal returns (bytes[] memory result) {
uint256 length = executions.length;
result = new bytes[](length);
for (uint256 i; i < length; i++) {
Execution calldata _exec = executions[i];
result[i] = _execute(_exec.target, _exec.value, _exec.callData);
}
}
function _tryExecute(Execution[] calldata executions) internal returns (bytes[] memory result) {
uint256 length = executions.length;
result = new bytes[](length);
for (uint256 i; i < length; i++) {
Execution calldata _exec = executions[i];
bool success;
(success, result[i]) = _tryExecute(_exec.target, _exec.value, _exec.callData);
if (!success) emit TryExecuteUnsuccessful(i, result[i]);
}
}
function _execute(address target, uint256 value, bytes calldata callData) internal returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
if iszero(call(gas(), target, value, result, callData.length, codesize(), 0x00)) {
// Bubble up the revert if the call reverts.
returndatacopy(result, 0x00, returndatasize())
revert(result, returndatasize())
}
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
function _tryExecute(address target, uint256 value, bytes calldata callData)
internal
returns (bool success, bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
success := call(gas(), target, value, result, callData.length, codesize(), 0x00)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
/// @dev Execute a delegatecall with `delegate` on this account.
function _executeDelegatecall(address delegate, bytes calldata callData)
internal
returns (bool success, bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
calldatacopy(result, callData.offset, callData.length)
// Forwards the `data` to `delegate` via delegatecall.
success := delegatecall(gas(), delegate, result, callData.length, codesize(), 0x00)
mstore(result, returndatasize()) // Store the length.
let o := add(result, 0x20)
returndatacopy(o, 0x00, returndatasize()) // Copy the returndata.
mstore(0x40, add(o, returndatasize())) // Allocate the memory.
}
}
function decode(ExecMode mode)
internal
pure
returns (CallType _calltype, ExecType _execType, ExecModeSelector _modeSelector, ExecModePayload _modePayload)
{
assembly {
_calltype := mode
_execType := shl(8, mode)
_modeSelector := shl(48, mode)
_modePayload := shl(80, mode)
}
}
function encode(CallType callType, ExecType execType, ExecModeSelector mode, ExecModePayload payload)
internal
pure
returns (ExecMode)
{
return ExecMode.wrap(
bytes32(abi.encodePacked(callType, execType, bytes4(0), ExecModeSelector.unwrap(mode), payload))
);
}
function encodeSimpleBatch() internal pure returns (ExecMode mode) {
mode = encode(CALLTYPE_BATCH, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00));
}
function encodeSimpleSingle() internal pure returns (ExecMode mode) {
mode = encode(CALLTYPE_SINGLE, EXECTYPE_DEFAULT, EXEC_MODE_DEFAULT, ExecModePayload.wrap(0x00));
}
function getCallType(ExecMode mode) internal pure returns (CallType calltype) {
assembly {
calltype := mode
}
}
function decodeBatch(bytes calldata callData) internal pure returns (Execution[] calldata executionBatch) {
/*
* Batch Call Calldata Layout
* Offset (in bytes) | Length (in bytes) | Contents
* 0x0 | 0x4 | bytes4 function selector
* 0x4 | - |
abi.encode(IERC7579Execution.Execution[])
*/
// solhint-disable-next-line no-inline-assembly
assembly ("memory-safe") {
let dataPointer := add(callData.offset, calldataload(callData.offset))
// Extract the ERC7579 Executions
executionBatch.offset := add(dataPointer, 32)
executionBatch.length := calldataload(dataPointer)
}
}
function encodeBatch(Execution[] memory executions) internal pure returns (bytes memory callData) {
callData = abi.encode(executions);
}
function decodeSingle(bytes calldata executionCalldata)
internal
pure
returns (address target, uint256 value, bytes calldata callData)
{
target = address(bytes20(executionCalldata[0:20]));
value = uint256(bytes32(executionCalldata[20:52]));
callData = executionCalldata[52:];
}
function encodeSingle(address target, uint256 value, bytes memory callData)
internal
pure
returns (bytes memory userOpCalldata)
{
userOpCalldata = abi.encodePacked(target, value, callData);
}
}
Constants.sol 43 lines
pragma solidity ^0.8.0;
import {CallType, ExecType, ExecModeSelector} from "./Types.sol";
import {PassFlag, ValidationMode, ValidationType} from "./Types.sol";
import {ValidationData} from "./Types.sol";
// Default CallType
CallType constant CALLTYPE_SINGLE = CallType.wrap(0x00);
// Batched CallType
CallType constant CALLTYPE_BATCH = CallType.wrap(0x01);
// @dev Implementing delegatecall is OPTIONAL!
// implement delegatecall with extreme care.
CallType constant CALLTYPE_DELEGATECALL = CallType.wrap(0xFF);
// @dev default behavior is to revert on failure
// To allow very simple accounts to use mode encoding, the default behavior is to revert on failure
// Since this is value 0x00, no additional encoding is required for simple accounts
ExecType constant EXECTYPE_DEFAULT = ExecType.wrap(0x00);
// @dev account may elect to change execution behavior. For example "try exec" / "allow fail"
ExecType constant EXECTYPE_TRY = ExecType.wrap(0x01);
ExecModeSelector constant EXEC_MODE_DEFAULT = ExecModeSelector.wrap(bytes4(0x00000000));
PassFlag constant SKIP_USEROP = PassFlag.wrap(0x0001);
PassFlag constant SKIP_SIGNATURE = PassFlag.wrap(0x0002);
// FLAG
ValidationMode constant VALIDATION_MODE_DEFAULT = ValidationMode.wrap(0x00);
ValidationMode constant VALIDATION_MODE_ENABLE = ValidationMode.wrap(0x01);
ValidationMode constant VALIDATION_MODE_INSTALL = ValidationMode.wrap(0x02);
// TYPES, ENUM
ValidationType constant VALIDATION_TYPE_SUDO = ValidationType.wrap(0x00);
ValidationType constant VALIDATION_TYPE_VALIDATOR = ValidationType.wrap(0x01);
ValidationType constant VALIDATION_TYPE_PERMISSION = ValidationType.wrap(0x02);
// ERC4337 constants
uint256 constant SIG_VALIDATION_FAILED_UINT = 1;
ValidationData constant SIG_VALIDATION_FAILED = ValidationData.wrap(SIG_VALIDATION_FAILED_UINT);
// ERC-1271 constants
bytes4 constant ERC1271_MAGICVALUE = 0x1626ba7e;
bytes4 constant ERC1271_INVALID = 0xffffffff;
PolicyBase.sol 38 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IPolicy} from "../../interfaces/IERC7579Modules.sol";
import {PackedUserOperation} from "../../interfaces/PackedUserOperation.sol";
abstract contract PolicyBase is IPolicy {
function onInstall(bytes calldata data) external payable {
bytes32 id = bytes32(data[0:32]);
bytes calldata _data = data[32:];
_policyOninstall(id, _data);
}
function onUninstall(bytes calldata data) external payable {
bytes32 id = bytes32(data[0:32]);
bytes calldata _data = data[32:];
_policyOnUninstall(id, _data);
}
function isModuleType(uint256 id) external pure returns (bool) {
return id == 5;
}
function isInitialized(address) external view virtual returns (bool); // TODO : not sure if this is the right way to do it
function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp)
external
payable
virtual
returns (uint256);
function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
virtual
returns (uint256);
function _policyOninstall(bytes32 id, bytes calldata _data) internal virtual;
function _policyOnUninstall(bytes32 id, bytes calldata _data) internal virtual;
}
IERC7579Account.sol 109 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {CallType, ExecType, ExecMode} from "../utils/ExecLib.sol";
import {PackedUserOperation} from "./PackedUserOperation.sol";
struct Execution {
address target;
uint256 value;
bytes callData;
}
interface IERC7579Account {
event ModuleInstalled(uint256 moduleTypeId, address module);
event ModuleUninstalled(uint256 moduleTypeId, address module);
/**
* @dev Executes a transaction on behalf of the account.
* This function is intended to be called by ERC-4337 EntryPoint.sol
* @dev Ensure adequate authorization control: i.e. onlyEntryPointOrSelf
*
* @dev MSA MUST implement this function signature.
* If a mode is requested that is not supported by the Account, it MUST revert
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
*/
function execute(ExecMode mode, bytes calldata executionCalldata) external payable;
/**
* @dev Executes a transaction on behalf of the account.
* This function is intended to be called by Executor Modules
* @dev Ensure adequate authorization control: i.e. onlyExecutorModule
*
* @dev MSA MUST implement this function signature.
* If a mode is requested that is not supported by the Account, it MUST revert
* @param mode The encoded execution mode of the transaction. See ModeLib.sol for details
* @param executionCalldata The encoded execution call data
*/
function executeFromExecutor(ExecMode mode, bytes calldata executionCalldata)
external
payable
returns (bytes[] memory returnData);
/**
* @dev ERC-1271 isValidSignature
* This function is intended to be used to validate a smart account signature
* and may forward the call to a validator module
*
* @param hash The hash of the data that is signed
* @param data The data that is signed
*/
function isValidSignature(bytes32 hash, bytes calldata data) external view returns (bytes4);
/**
* @dev installs a Module of a certain type on the smart account
* @dev Implement Authorization control of your chosing
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param initData arbitrary data that may be required on the module during `onInstall`
* initialization.
*/
function installModule(uint256 moduleTypeId, address module, bytes calldata initData) external payable;
/**
* @dev uninstalls a Module of a certain type on the smart account
* @dev Implement Authorization control of your chosing
* @param moduleTypeId the module type ID according the ERC-7579 spec
* @param module the module address
* @param deInitData arbitrary data that may be required on the module during `onUninstall`
* de-initialization.
*/
function uninstallModule(uint256 moduleTypeId, address module, bytes calldata deInitData) external payable;
/**
* Function to check if the account supports a certain CallType or ExecType (see ModeLib.sol)
* @param encodedMode the encoded mode
*/
function supportsExecutionMode(ExecMode encodedMode) external view returns (bool);
/**
* Function to check if the account supports installation of a certain module type Id
* @param moduleTypeId the module type ID according the ERC-7579 spec
*/
function supportsModule(uint256 moduleTypeId) external view returns (bool);
/**
* Function to check if the account has a certain module installed
* @param moduleTypeId the module type ID according the ERC-7579 spec
* Note: keep in mind that some contracts can be multiple module types at the same time. It
* thus may be necessary to query multiple module types
* @param module the module address
* @param additionalContext additional context data that the smart account may interpret to
* identifiy conditions under which the module is installed.
* usually this is not necessary, but for some special hooks that
* are stored in mappings, this param might be needed
*/
function isModuleInstalled(uint256 moduleTypeId, address module, bytes calldata additionalContext)
external
view
returns (bool);
/**
* @dev Returns the account id of the smart account
* @return accountImplementationId the account id of the smart account
* the accountId should be structured like so:
* "vendorname.accountname.semver"
*/
function accountId() external view returns (string memory accountImplementationId);
}
IERC7579Modules.sol 108 lines
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;
import {PackedUserOperation} from "./PackedUserOperation.sol";
uint256 constant VALIDATION_SUCCESS = 0;
uint256 constant VALIDATION_FAILED = 1;
uint256 constant MODULE_TYPE_VALIDATOR = 1;
uint256 constant MODULE_TYPE_EXECUTOR = 2;
uint256 constant MODULE_TYPE_FALLBACK = 3;
uint256 constant MODULE_TYPE_HOOK = 4;
uint256 constant MODULE_TYPE_POLICY = 5;
uint256 constant MODULE_TYPE_SIGNER = 6;
uint256 constant MODULE_TYPE_ACTION = 7;
interface IModule {
error AlreadyInitialized(address smartAccount);
error NotInitialized(address smartAccount);
/**
* @dev This function is called by the smart account during installation of the module
* @param data arbitrary data that may be required on the module during `onInstall`
* initialization
*
* MUST revert on error (i.e. if module is already enabled)
*/
function onInstall(bytes calldata data) external payable;
/**
* @dev This function is called by the smart account during uninstallation of the module
* @param data arbitrary data that may be required on the module during `onUninstall`
* de-initialization
*
* MUST revert on error
*/
function onUninstall(bytes calldata data) external payable;
/**
* @dev Returns boolean value if module is a certain type
* @param moduleTypeId the module type ID according the ERC-7579 spec
*
* MUST return true if the module is of the given type and false otherwise
*/
function isModuleType(uint256 moduleTypeId) external view returns (bool);
/**
* @dev Returns if the module was already initialized for a provided smartaccount
*/
function isInitialized(address smartAccount) external view returns (bool);
}
interface IValidator is IModule {
error InvalidTargetAddress(address target);
/**
* @dev Validates a transaction on behalf of the account.
* This function is intended to be called by the MSA during the ERC-4337 validaton phase
* Note: solely relying on bytes32 hash and signature is not suffcient for some
* validation implementations (i.e. SessionKeys often need access to userOp.calldata)
* @param userOp The user operation to be validated. The userOp MUST NOT contain any metadata.
* The MSA MUST clean up the userOp before sending it to the validator.
* @param userOpHash The hash of the user operation to be validated
* @return return value according to ERC-4337
*/
function validateUserOp(PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
returns (uint256);
/**
* Validator can be used for ERC-1271 validation
*/
function isValidSignatureWithSender(address sender, bytes32 hash, bytes calldata data)
external
view
returns (bytes4);
}
interface IExecutor is IModule {}
interface IHook is IModule {
function preCheck(address msgSender, bytes calldata msgData) external payable returns (bytes memory hookData);
function postCheck(bytes calldata hookData) external payable returns (bool success);
}
interface IFallback is IModule {}
interface IPolicy is IModule {
function checkUserOpPolicy(bytes32 id, PackedUserOperation calldata userOp) external payable returns (uint256);
function checkSignaturePolicy(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
returns (uint256);
}
interface ISigner is IModule {
function checkUserOpSignature(bytes32 id, PackedUserOperation calldata userOp, bytes32 userOpHash)
external
payable
returns (uint256);
function checkSignature(bytes32 id, address sender, bytes32 hash, bytes calldata sig)
external
view
returns (bytes4);
}
interface IAction is IModule {}
PackedUserOperation.sol 28 lines
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.5;
/**
* 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 accountGasLimits - Packed gas limits for validateUserOp and gas limit passed to the callData method call.
* @param preVerificationGas - Gas not calculated by the handleOps method, but added to the gas paid.
* Covers batch overhead.
* @param gasFees - packed gas fields maxFeePerGas and maxPriorityFeePerGas - Same as EIP-1559 gas parameter.
* @param paymasterAndData - If set, this field holds the paymaster address, verification gas limit, postOp gas limit and paymaster-specific extra 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 PackedUserOperation {
address sender;
uint256 nonce;
bytes initCode;
bytes callData;
bytes32 accountGasLimits;
uint256 preVerificationGas;
bytes32 gasFees; //maxPriorityFee and maxFeePerGas;
bytes paymasterAndData;
bytes signature;
}
Read Contract
checkSignaturePolicy 0x309bfb76 → uint256
encodedPermissions 0xffbb39f8 → bytes
isInitialized 0xd60b347f → bool
isModuleType 0xecd05961 → bool
status 0xd8ed2b3c → uint8
usedIds 0x244d6cb2 → uint256
Write Contract 3 functions
These functions modify contract state and require a wallet transaction to execute.
checkUserOpPolicy 0xd0832c39
bytes32 id
tuple userOp
returns: uint256
onInstall 0x6d61fe70
bytes data
onUninstall 0x8a91b0e3
bytes data
Recent Transactions
This address has 1 on-chain transactions, but only 1.5% of the chain is indexed. Transactions will appear as indexing progresses. View on Etherscan →