ETH Price: $2,152.93 (-0.53%)

Transaction Decoder

Block:
11231136 at Nov-10-2020 05:29:31 PM +UTC
Transaction Fee:
0.008424288 ETH $18.14
Gas Used:
234,008 Gas / 36 Gwei

Emitted Events:

287 0xe840e26bc732e182fd14f4874788d3e89368968d.0xdc949ee4159e00c6f6c0277af4718b4329c1e113164f629e30029915196c530f( 0xdc949ee4159e00c6f6c0277af4718b4329c1e113164f629e30029915196c530f, 0x00000000000000000000000052947d2dba2f0ae7723c68beb0db856089443ce8 )
288 InstaIndex.LogAccountCreated( sender=[Sender] 0x52947d2dba2f0ae7723c68beb0db856089443ce8, owner=[Sender] 0x52947d2dba2f0ae7723c68beb0db856089443ce8, account=0xe840e26bc732e182fd14f4874788d3e89368968d, origin=0x00000000...000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x2971AdFa...A9c74f723
(InstaDApp: Index)
0x4c8a1BEb...55194AbEb
(InstaDApp: List)
0x52947d2D...089443CE8
0.18021237525 Eth
Nonce: 6
0.17178808725 Eth
Nonce: 7
0.008424288
(Spark Pool)
84.611675099343959409 Eth84.620099387343959409 Eth0.008424288
0xe840E26B...89368968D
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 497590261154554171967157198924864193802432745422121272256820198452287316404765880652365614607539052576857075

Execution Trace

InstaIndex.build( _owner=0x52947d2DBa2F0AE7723C68bEB0Db856089443CE8, accountVersion=1, _origin=0x0000000000000000000000000000000000000000 ) => ( _account=0xe840E26Bc732E182FD14F4874788d3e89368968D )
  • 0xe840e26bc732e182fd14f4874788d3e89368968d.3d602d80( )
  • InstaList.init( _account=0xe840E26Bc732E182FD14F4874788d3e89368968D )
  • 0xe840e26bc732e182fd14f4874788d3e89368968d.5bfa1b68( )
    • InstaAccount.enable( user=0x52947d2DBa2F0AE7723C68bEB0Db856089443CE8 )
      • InstaIndex.STATICCALL( )
      • InstaList.addAuth( _owner=0x52947d2DBa2F0AE7723C68bEB0Db856089443CE8 )
        • 0xe840e26bc732e182fd14f4874788d3e89368968d.2520e7ff( )
          • InstaAccount.isAuth( user=0x52947d2DBa2F0AE7723C68bEB0Db856089443CE8 ) => ( True )
            File 1 of 3: InstaIndex
            pragma solidity ^0.6.0;
            pragma experimental ABIEncoderV2;
            
            /**
             * @title InstaIndex
             * @dev Main Contract For DeFi Smart Accounts. This is also a factory contract, Which deploys new Smart Account.
             * Also Registry for DeFi Smart Accounts.
             */
            
            interface AccountInterface {
                function version() external view returns (uint);
                function enable(address authority) external;
                function cast(address[] calldata _targets, bytes[] calldata _datas, address _origin) external payable returns (bytes32[] memory responses);
            }
            
            interface ListInterface {
                function init(address _account) external;
            }
            
            contract AddressIndex {
            
                event LogNewMaster(address indexed master);
                event LogUpdateMaster(address indexed master);
                event LogNewCheck(uint indexed accountVersion, address indexed check);
                event LogNewAccount(address indexed _newAccount, address indexed _connectors, address indexed _check);
            
                // New Master Address.
                address private newMaster;
                // Master Address.
                address public master;
                // List Registry Address.
                address public list;
            
                // Connectors Modules(Account Module Version => Connectors Registry Module Address).
                mapping (uint => address) public connectors;
                // Check Modules(Account Module Version => Check Module Address).
                mapping (uint => address) public check;
                // Account Modules(Account Module Version => Account Module Address).
                mapping (uint => address) public account;
                // Version Count of Account Modules.
                uint public versionCount;
            
                /**
                * @dev Throws if the sender not is Master Address.
                */
                modifier isMaster() {
                    require(msg.sender == master, "not-master");
                    _;
                }
            
                /**
                 * @dev Change the Master Address.
                 * @param _newMaster New Master Address.
                 */
                function changeMaster(address _newMaster) external isMaster {
                    require(_newMaster != master, "already-a-master");
                    require(_newMaster != address(0), "not-valid-address");
                    require(newMaster != _newMaster, "already-a-new-master");
                    newMaster = _newMaster;
                    emit LogNewMaster(_newMaster);
                }
            
                function updateMaster() external {
                    require(newMaster != address(0), "not-valid-address");
                    require(msg.sender == newMaster, "not-master");
                    master = newMaster;
                    newMaster = address(0);
                    emit LogUpdateMaster(master);
                }
            
                /**
                 * @dev Change the Check Address of a specific Account Module version.
                 * @param accountVersion Account Module version.
                 * @param _newCheck The New Check Address.
                 */
                function changeCheck(uint accountVersion, address _newCheck) external isMaster {
                    require(_newCheck != check[accountVersion], "already-a-check");
                    check[accountVersion] = _newCheck;
                    emit LogNewCheck(accountVersion, _newCheck);
                }
            
                /**
                 * @dev Add New Account Module.
                 * @param _newAccount The New Account Module Address.
                 * @param _connectors Connectors Registry Module Address.
                 * @param _check Check Module Address.
                 */
                function addNewAccount(address _newAccount, address _connectors, address _check) external isMaster {
                    require(_newAccount != address(0), "not-valid-address");
                    versionCount++;
                    require(AccountInterface(_newAccount).version() == versionCount, "not-valid-version");
                    account[versionCount] = _newAccount;
                    if (_connectors != address(0)) connectors[versionCount] = _connectors;
                    if (_check != address(0)) check[versionCount] = _check;
                    emit LogNewAccount(_newAccount, _connectors, _check);
                }
            
            }
            
            contract CloneFactory is AddressIndex {
                /**
                 * @dev Clone a new Account Module.
                 * @param version Account Module version to clone.
                 */
                function createClone(uint version) internal returns (address result) {
                    bytes20 targetBytes = bytes20(account[version]);
                    // solium-disable-next-line security/no-inline-assembly
                    assembly {
                        let clone := mload(0x40)
                        mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
                        mstore(add(clone, 0x14), targetBytes)
                        mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
                        result := create(0, clone, 0x37)
                    }
                }
            
                /**
                 * @dev Check if Account Module is a clone.
                 * @param version Account Module version.
                 * @param query Account Module Address.
                 */
                function isClone(uint version, address query) external view returns (bool result) {
                    bytes20 targetBytes = bytes20(account[version]);
                    // solium-disable-next-line security/no-inline-assembly
                    assembly {
                        let clone := mload(0x40)
                        mstore(clone, 0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000)
                        mstore(add(clone, 0xa), targetBytes)
                        mstore(add(clone, 0x1e), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            
                        let other := add(clone, 0x40)
                        extcodecopy(query, other, 0, 0x2d)
                        result := and(
                            eq(mload(clone), mload(other)),
                            eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
                        )
                    }
                }
            }
            
            contract InstaIndex is CloneFactory {
            
                event LogAccountCreated(address sender, address indexed owner, address indexed account, address indexed origin);
            
                /**
                 * @dev Create a new DeFi Smart Account for a user and run cast function in the new Smart Account.
                 * @param _owner Owner of the Smart Account.
                 * @param accountVersion Account Module version.
                 * @param _targets Array of Target to run cast function.
                 * @param _datas Array of Data(callData) to run cast function.
                 * @param _origin Where Smart Account is created.
                 */
                function buildWithCast(
                    address _owner,
                    uint accountVersion,
                    address[] calldata _targets,
                    bytes[] calldata _datas,
                    address _origin
                ) external payable returns (address _account) {
                    _account = build(_owner, accountVersion, _origin);
                    if (_targets.length > 0) AccountInterface(_account).cast.value(msg.value)(_targets, _datas, _origin);
                }
            
                /**
                 * @dev Create a new DeFi Smart Account for a user.
                 * @param _owner Owner of the Smart Account.
                 * @param accountVersion Account Module version.
                 * @param _origin Where Smart Account is created.
                 */
                function build(
                    address _owner,
                    uint accountVersion,
                    address _origin
                ) public returns (address _account) {
                    require(accountVersion != 0 && accountVersion <= versionCount, "not-valid-account");
                    _account = createClone(accountVersion);
                    ListInterface(list).init(_account);
                    AccountInterface(_account).enable(_owner);
                    emit LogAccountCreated(msg.sender, _owner, _account, _origin);
                }
            
                /**
                 * @dev Setup Initial things for InstaIndex, after its been deployed and can be only run once.
                 * @param _master The Master Address.
                 * @param _list The List Address.
                 * @param _account The Account Module Address.
                 * @param _connectors The Connectors Registry Module Address.
                 */
                function setBasics(
                    address _master,
                    address _list,
                    address _account,
                    address _connectors
                ) external {
                    require(
                        master == address(0) &&
                        list == address(0) &&
                        account[1] == address(0) &&
                        connectors[1] == address(0) &&
                        versionCount == 0,
                        "already-defined"
                    );
                    master = _master;
                    list = _list;
                    versionCount++;
                    account[versionCount] = _account;
                    connectors[versionCount] = _connectors;
                }
            
            }

            File 2 of 3: InstaList
            pragma solidity ^0.6.0;
            
            /**
             * @title InstaList
             * @dev Registry For DeFi Smart Account Authorised user.
             */
            
            interface AccountInterface {
                function isAuth(address _user) external view returns (bool);
            }
            
            
            contract DSMath {
            
                function add(uint64 x, uint64 y) internal pure returns (uint64 z) {
                    require((z = x + y) >= x, "ds-math-add-overflow");
                }
            
                function sub(uint64 x, uint64 y) internal pure returns (uint64 z) {
                    require((z = x - y) <= x, "ds-math-sub-underflow");
                }
            
            }
            
            
            contract Variables is DSMath {
            
                // InstaIndex Address.
                address public constant instaIndex = 0x2971AdFa57b20E5a416aE5a708A8655A9c74f723;
            
                // Smart Account Count.
                uint64 public accounts;
                // Smart Account ID (Smart Account Address => Account ID).
                mapping (address => uint64) public accountID;
                // Smart Account Address (Smart Account ID => Smart Account Address).
                mapping (uint64 => address) public accountAddr;
            
                // User Link (User Address => UserLink(Account ID of First and Last And Count of Smart Accounts)).
                mapping (address => UserLink) public userLink;
                // Linked List of Users (User Address => Smart Account ID => UserList(Previous and next Account ID)).
                mapping (address => mapping(uint64 => UserList)) public userList;
            
                struct UserLink {
                    uint64 first;
                    uint64 last;
                    uint64 count;
                }
                struct UserList {
                    uint64 prev;
                    uint64 next;
                }
            
                // Account Link (Smart Account ID => AccountLink).
                mapping (uint64 => AccountLink) public accountLink; // account => account linked list connection
                // Linked List of Accounts (Smart Account ID => Account Address => AccountList).
                mapping (uint64 => mapping (address => AccountList)) public accountList; // account => user address => list
            
                struct AccountLink {
                    address first;
                    address last;
                    uint64 count;
                }
                struct AccountList {
                    address prev;
                    address next;
                }
            
            }
            
            contract Configure is Variables {
            
                /**
                 * @dev Add Account to User Linked List.
                 * @param _owner Account Owner.
                 * @param _account Smart Account Address.
                */
                function addAccount(address _owner, uint64 _account) internal {
                    if (userLink[_owner].last != 0) {
                        userList[_owner][_account].prev = userLink[_owner].last;
                        userList[_owner][userLink[_owner].last].next = _account;
                    }
                    if (userLink[_owner].first == 0) userLink[_owner].first = _account;
                    userLink[_owner].last = _account;
                    userLink[_owner].count = add(userLink[_owner].count, 1);
                }
            
                /**
                 * @dev Remove Account from User Linked List.
                 * @param _owner Account Owner/User.
                 * @param _account Smart Account Address.
                */
                function removeAccount(address _owner, uint64 _account) internal {
                    uint64 _prev = userList[_owner][_account].prev;
                    uint64 _next = userList[_owner][_account].next;
                    if (_prev != 0) userList[_owner][_prev].next = _next;
                    if (_next != 0) userList[_owner][_next].prev = _prev;
                    if (_prev == 0) userLink[_owner].first = _next;
                    if (_next == 0) userLink[_owner].last = _prev;
                    userLink[_owner].count = sub(userLink[_owner].count, 1);
                    delete userList[_owner][_account];
                }
            
                /**
                 * @dev Add Owner to Account Linked List.
                 * @param _owner Account Owner.
                 * @param _account Smart Account Address.
                */
                function addUser(address _owner, uint64 _account) internal {
                    if (accountLink[_account].last != address(0)) {
                        accountList[_account][_owner].prev = accountLink[_account].last;
                        accountList[_account][accountLink[_account].last].next = _owner;
                    }
                    if (accountLink[_account].first == address(0)) accountLink[_account].first = _owner;
                    accountLink[_account].last = _owner;
                    accountLink[_account].count = add(accountLink[_account].count, 1);
                }
            
                /**
                 * @dev Remove Owner from Account Linked List.
                 * @param _owner Account Owner.
                 * @param _account Smart Account Address.
                */
                function removeUser(address _owner, uint64 _account) internal {
                    address _prev = accountList[_account][_owner].prev;
                    address _next = accountList[_account][_owner].next;
                    if (_prev != address(0)) accountList[_account][_prev].next = _next;
                    if (_next != address(0)) accountList[_account][_next].prev = _prev;
                    if (_prev == address(0)) accountLink[_account].first = _next;
                    if (_next == address(0)) accountLink[_account].last = _prev;
                    accountLink[_account].count = sub(accountLink[_account].count, 1);
                    delete accountList[_account][_owner];
                }
            
            }
            
            contract InstaList is Configure {
            
                /**
                 * @dev Enable Auth for Smart Account.
                 * @param _owner Owner Address.
                */
                function addAuth(address _owner) external {
                    require(accountID[msg.sender] != 0, "not-account");
                    require(AccountInterface(msg.sender).isAuth(_owner), "not-owner");
                    addAccount(_owner, accountID[msg.sender]);
                    addUser(_owner, accountID[msg.sender]);
                }
            
                /**
                 * @dev Disable Auth for Smart Account.
                 * @param _owner Owner Address.
                */
                function removeAuth(address _owner) external {
                    require(accountID[msg.sender] != 0, "not-account");
                    require(!AccountInterface(msg.sender).isAuth(_owner), "already-owner");
                    removeAccount(_owner, accountID[msg.sender]);
                    removeUser(_owner, accountID[msg.sender]);
                }
            
                /**
                 * @dev Setup Initial configuration of Smart Account.
                 * @param _account Smart Account Address.
                */
                function init(address  _account) external {
                    require(msg.sender == instaIndex, "not-index");
                    accounts++;
                    accountID[_account] = accounts;
                    accountAddr[accounts] = _account;
                }
            
            }

            File 3 of 3: InstaAccount
            pragma solidity ^0.6.0;
            pragma experimental ABIEncoderV2;
            
            /**
             * @title InstaAccount.
             * @dev DeFi Smart Account Wallet.
             */
            
            interface IndexInterface {
                function connectors(uint version) external view returns (address);
                function check(uint version) external view returns (address);
                function list() external view returns (address);
            }
            
            interface ConnectorsInterface {
                function isConnector(address[] calldata logicAddr) external view returns (bool);
                function isStaticConnector(address[] calldata logicAddr) external view returns (bool);
            }
            
            interface CheckInterface {
                function isOk() external view returns (bool);
            }
            
            interface ListInterface {
                function addAuth(address user) external;
                function removeAuth(address user) external;
            }
            
            
            contract Record {
            
                event LogEnable(address indexed user);
                event LogDisable(address indexed user);
                event LogSwitchShield(bool _shield);
            
                // InstaIndex Address.
                address public constant instaIndex = 0x2971AdFa57b20E5a416aE5a708A8655A9c74f723;
                // The Account Module Version.
                uint public constant version = 1;
                // Auth Module(Address of Auth => bool).
                mapping (address => bool) private auth;
                // Is shield true/false.
                bool public shield;
            
                /**
                 * @dev Check for Auth if enabled.
                 * @param user address/user/owner.
                 */
                function isAuth(address user) public view returns (bool) {
                    return auth[user];
                }
            
                /**
                 * @dev Change Shield State.
                */
                function switchShield(bool _shield) external {
                    require(auth[msg.sender], "not-self");
                    require(shield != _shield, "shield is set");
                    shield = _shield;
                    emit LogSwitchShield(shield);
                }
            
                /**
                 * @dev Enable New User.
                 * @param user Owner of the Smart Account.
                */
                function enable(address user) public {
                    require(msg.sender == address(this) || msg.sender == instaIndex, "not-self-index");
                    require(user != address(0), "not-valid");
                    require(!auth[user], "already-enabled");
                    auth[user] = true;
                    ListInterface(IndexInterface(instaIndex).list()).addAuth(user);
                    emit LogEnable(user);
                }
            
                /**
                 * @dev Disable User.
                 * @param user Owner of the Smart Account.
                */
                function disable(address user) public {
                    require(msg.sender == address(this), "not-self");
                    require(user != address(0), "not-valid");
                    require(auth[user], "already-disabled");
                    delete auth[user];
                    ListInterface(IndexInterface(instaIndex).list()).removeAuth(user);
                    emit LogDisable(user);
                }
            
            }
            
            contract InstaAccount is Record {
            
                event LogCast(address indexed origin, address indexed sender, uint value);
            
                receive() external payable {}
            
                 /**
                 * @dev Delegate the calls to Connector And this function is ran by cast().
                 * @param _target Target to of Connector.
                 * @param _data CallData of function in Connector.
                */
                function spell(address _target, bytes memory _data) internal {
                    require(_target != address(0), "target-invalid");
                    assembly {
                        let succeeded := delegatecall(gas(), _target, add(_data, 0x20), mload(_data), 0, 0)
            
                        switch iszero(succeeded)
                            case 1 {
                                // throw if delegatecall failed
                                let size := returndatasize()
                                returndatacopy(0x00, 0x00, size)
                                revert(0x00, size)
                            }
                    }
                }
            
                /**
                 * @dev This is the main function, Where all the different functions are called
                 * from Smart Account.
                 * @param _targets Array of Target(s) to of Connector.
                 * @param _datas Array of Calldata(S) of function.
                */
                function cast(
                    address[] calldata _targets,
                    bytes[] calldata _datas,
                    address _origin
                )
                external
                payable
                {
                    require(isAuth(msg.sender) || msg.sender == instaIndex, "permission-denied");
                    require(_targets.length == _datas.length , "array-length-invalid");
                    IndexInterface indexContract = IndexInterface(instaIndex);
                    bool isShield = shield;
                    if (!isShield) {
                        require(ConnectorsInterface(indexContract.connectors(version)).isConnector(_targets), "not-connector");
                    } else {
                        require(ConnectorsInterface(indexContract.connectors(version)).isStaticConnector(_targets), "not-static-connector");
                    }
                    for (uint i = 0; i < _targets.length; i++) {
                        spell(_targets[i], _datas[i]);
                    }
                    address _check = indexContract.check(version);
                    if (_check != address(0) && !isShield) require(CheckInterface(_check).isOk(), "not-ok");
                    emit LogCast(_origin, msg.sender, msg.value);
                }
            
            }