// SPDX-License-Identifier: Apache-2.0 pragma solidity >=0.5.0 <0.9.0; pragma experimental ABIEncoderV2; import '../common/HederaResponseCodes.sol'; import './IHederaAccountService.sol'; abstract contract HederaAccountService { address constant HASPrecompileAddress = address(0x16a); /// Returns the amount of hbars that the spender has been authorized to spend on behalf of the owner. /// @param owner The account that has authorized the spender /// @param spender The account that has been authorized by the owner /// @return responseCode The response code for the status of the request. SUCCESS is 22. /// @return amount The amount of hbar that the spender has been authorized to spend on behalf of the owner. function hbarAllowance( address owner, address spender ) internal returns (int64 responseCode, int256 amount) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.hbarAllowance.selector, owner, spender ) ); (responseCode, amount) = success ? abi.decode(result, (int32, int256)) : (HederaResponseCodes.UNKNOWN, (int256)(0)); } /// Allows spender to withdraw hbars from the owner account multiple times, up to the value amount. If this function is called /// again it overwrites the current allowance with the new amount. /// @param owner The owner of the hbars /// @param spender the account address authorized to spend /// @param amount the amount of hbars authorized to spend. /// @return responseCode The response code for the status of the request. SUCCESS is 22. function hbarApprove( address owner, address spender, int256 amount ) internal returns (int64 responseCode) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.hbarApprove.selector, owner, spender, amount ) ); responseCode = success ? abi.decode(result, (int32)) : HederaResponseCodes.UNKNOWN; } /// Returns the EVM address alias for a given Hedera account. /// @param accountNumAlias The Hedera account number alias to lookup. Must satisfy all of the following: /// - Must be in long-zero format (0x000...0) /// - Must reference an existing Hedera account /// - Referenced account must have an associated EVM address alias /// @return responseCode The response code indicating the status of the request: /// - SUCCESS (22) if successful /// - INVALID_ACCOUNT_ID (15) if any validation of the accountNumAlias fails /// - UNKNOWN (21) if the precompile call fails /// @return evmAddressAlias The EVM address alias associated with the Hedera account, or address(0) if the request fails function getEvmAddressAlias( address accountNumAlias ) internal returns (int64 responseCode, address evmAddressAlias) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.getEvmAddressAlias.selector, accountNumAlias ) ); (responseCode, evmAddressAlias) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0)); } /// Returns the Hedera Account ID (as account num alias) for the given EVM address alias /// @param evmAddressAlias The EVM address alias to get the Hedera account for. Must satisfy all of the following: /// - Must be in EVM format (not a long-zero address) /// - Must reference an existing Hedera account /// - Referenced account must have an associated account num alias (long-zero format) /// @return responseCode The response code indicating the status of the request: /// - SUCCESS (22) if successful /// - INVALID_SOLIDITY_ADDRESS (29) if any validation of the evmAddressAlias fails /// - UNKNOWN (21) if the precompile call fails /// @return accountNumAlias The Hedera account's num alias in long-zero format, or address(0) if the request fails function getHederaAccountNumAlias( address evmAddressAlias ) internal returns (int64 responseCode, address accountNumAlias) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.getHederaAccountNumAlias.selector, evmAddressAlias ) ); (responseCode, accountNumAlias) = success ? abi.decode(result, (int32, address)) : (HederaResponseCodes.UNKNOWN, address(0)); } /// Returns true iff a Hedera account num alias or EVM address alias. /// @param addr Some 20-byte address. /// @return responseCode The response code for the status of the request. SUCCESS is 22. /// @return response true iff addr is a Hedera account num alias or an EVM address alias (and false otherwise). function isValidAlias( address addr ) internal returns (int64 responseCode, bool response) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector(IHederaAccountService.isValidAlias.selector, addr) ); (responseCode, response) = success ? (HederaResponseCodes.SUCCESS, abi.decode(result, (bool))) : (HederaResponseCodes.UNKNOWN, false); } /// Determines if the signature is valid for the given message hash and account. /// It is assumed that the signature is composed of a single ECDSA or ED25519 key. /// The underlying precompile returns a bare `bool`; this wrapper synthesises the /// responseCode from the low-level call's success for parity with the other helpers. /// @param account The account to check the signature against /// @param messageHash The hash of the message to check the signature against /// @param signature The signature to check /// @return responseCode SUCCESS (22) if the precompile call succeeded, otherwise UNKNOWN. /// @return authorized True if the signature is valid, false otherwise function isAuthorizedRaw( address account, bytes memory messageHash, bytes memory signature ) internal returns (int64 responseCode, bool authorized) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.isAuthorizedRaw.selector, account, messageHash, signature ) ); (responseCode, authorized) = success ? (HederaResponseCodes.SUCCESS, abi.decode(result, (bool))) : (HederaResponseCodes.UNKNOWN, false); } /// Determines if the signature is valid for the given message and account. /// It is assumed that the signature is composed of a possibly complex cryptographic key. /// @param account The account to check the signature against. /// @param message The message to check the signature against. /// @param signature The signature to check encoded as bytes. /// @return responseCode The response code for the status of the request. SUCCESS is 22. /// @return authorized True if the signature is valid, false otherwise. function isAuthorized( address account, bytes memory message, bytes memory signature ) internal returns (int64 responseCode, bool authorized) { (bool success, bytes memory result) = HASPrecompileAddress.call( abi.encodeWithSelector( IHederaAccountService.isAuthorized.selector, account, message, signature ) ); (responseCode, authorized) = success ? abi.decode(result, (int32, bool)) : (HederaResponseCodes.UNKNOWN, false); } }