Last active
April 24, 2023 16:33
-
-
Save uF4No/659a633db7d427474e2349180a5c0cfd to your computer and use it in GitHub Desktop.
zkSync Era smart contract account
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity ^0.8.16; | |
import "@matterlabs/zksync-contracts/l2/system-contracts/interfaces/IAccount.sol"; | |
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/TransactionHelper.sol"; | |
// Access zkSync system contracts for nonce validation via NONCE_HOLDER_SYSTEM_CONTRACT | |
import "@matterlabs/zksync-contracts/l2/system-contracts/Constants.sol"; | |
// to call non-view function of system contracts | |
import "@matterlabs/zksync-contracts/l2/system-contracts/libraries/SystemContractsCaller.sol"; | |
contract SmartAccount is IAccount { | |
// to get transaction hash | |
using TransactionHelper for Transaction; | |
bytes4 constant EIP1271_SUCCESS_RETURN_VALUE = 0x1626ba7e; | |
modifier onlyBootloader() { | |
require( | |
msg.sender == BOOTLOADER_FORMAL_ADDRESS, | |
"Only bootloader can call this function" | |
); | |
// Continue execution if called from the bootloader. | |
_; | |
} | |
function validateTransaction( | |
bytes32, // _txHash | |
bytes32 _suggestedSignedHash, | |
Transaction calldata _transaction | |
) external payable override onlyBootloader returns (bytes4 magic) { | |
// Incrementing the nonce of the account. | |
SystemContractsCaller.systemCallWithPropagatedRevert( | |
uint32(gasleft()), address(NONCE_HOLDER_SYSTEM_CONTRACT),0, | |
abi.encodeCall(INonceHolder.incrementMinNonceIfEquals, (_transaction.nonce)) | |
); | |
// Verify account has balance to pay fee | |
uint256 totalRequiredBalance = _transaction.totalRequiredBalance(); | |
require(totalRequiredBalance <= address(this).balance, "Not enough balance for fee + value"); | |
// Verify signature | |
if (isValidSignature(txHash, _transaction.signature) == EIP1271_SUCCESS_RETURN_VALUE) { | |
magic = ACCOUNT_VALIDATION_SUCCESS_MAGIC; | |
} else { | |
magic = bytes4(0); | |
} | |
} | |
function executeTransaction( | |
bytes32, // _txHash | |
bytes32, // _suggestedSignedHash | |
Transaction calldata _transaction | |
) external payable override onlyBootloader { | |
address to = address(uint160(_transaction.to)); | |
uint128 value = Utils.safeCastToU128(_transaction.value); | |
bytes memory data = _transaction.data; | |
if (to == address(DEPLOYER_SYSTEM_CONTRACT)) { | |
uint32 gas = Utils.safeCastToU32(gasleft()); | |
SystemContractsCaller.systemCallWithPropagatedRevert(gas, to, value, data); | |
} else { | |
bool success; | |
assembly { | |
success := call(gas(), to, value, add(data, 0x20), mload(data), 0, 0) | |
} | |
require(success); | |
} | |
} | |
function payForTransaction( | |
bytes32, // _txHash | |
bytes32, // _suggestedSignedHash | |
Transaction calldata _transaction | |
) external payable override onlyBootloader { | |
bool success = _transaction.payToTheBootloader(); | |
require(success, "Failed to pay the fee to the operator"); | |
} | |
function prepareForPaymaster( | |
bytes32, // _txHash | |
bytes32, // _suggestedSignedHash | |
Transaction calldata _transaction | |
) external payable override onlyBootloader { | |
_transaction.processPaymasterInput(); | |
} | |
function executeTransactionFromOutside(Transaction calldata _transaction) | |
external | |
payable | |
{ | |
validateTransaction(bytes32(0), _transaction); | |
executeTransaction(_transaction); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment