Transaction Hash:
Block:
16753939 at Mar-04-2023 08:37:47 AM +UTC
Transaction Fee:
0.00134706 ETH
$2.56
Gas Used:
44,902 Gas / 30 Gwei
Emitted Events:
5 |
GalaTreasureChestClaimFee.PaymentExecuted( refId=640303511fe0eb07700cb4f7, amount=1227650000000000, blockSigned=16753938 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x7199C48D...aEbb28eaA
Miner
| 0.060738189149550868 Eth | 0.061234226578546834 Eth | 0.000496037428995966 | ||
0xc5aa18A9...Fb0356cAb |
0.030091790842153126 Eth
Nonce: 36
|
0.027517080842153126 Eth
Nonce: 37
| 0.00257471 | ||
0xFD4492E7...a39b6F096 | 4.352735680288005593 Eth | 4.353963330288005593 Eth | 0.00122765 |
Execution Trace
ETH 0.00122765
GalaTreasureChestClaimFee.pay( refId=640303511fe0eb07700cb4f7, amount=1227650000000000, blockSigned=16753938, sig=0xB8B767B9C6C8F249F2DDA765F2B7A11DF9DE9C89CA23A06C2DF793AA78EC7CE85AE219E56EE120277BF7CE2F35E7A85299FED6CA1B367D250A35C65AF57A26561C )
-
Null: 0x000...001.02fd0610( )
- ETH 0.00122765
0xfd4492e70df97a6155c6d244f5ec5b5a39b6f096.CALL( )
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import './MessageValidator.sol'; contract GalaTreasureChestClaimFee is MessageValidator { event PaymentExecuted(string refId, uint256 amount, uint256 blockSigned); constructor(address _signer) { setSignerAddress(_signer); } function pay( string memory refId, uint256 amount, uint256 blockSigned, bytes memory sig ) public payable isValidMessage(refId, amount, blockSigned, sig, msg.value) { payable(address(signerAddress)).transfer(msg.value); emit PaymentExecuted(refId, msg.value, blockSigned); } } // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.9; import '@openzeppelin/contracts/access/Ownable.sol'; contract MessageValidator is Ownable { address public signerAddress; uint256 public blockMaxThreshold = 10; function setSignerAddress(address _signer) public onlyOwner { signerAddress = _signer; } modifier isValidMessage( string memory refId, uint256 amount, uint256 blockSigned, bytes memory sig, uint256 value ) { bytes32 message = keccak256( abi.encodePacked(refId, amount, blockSigned) ); require( recoverSigner(message, sig) == signerAddress, 'Invalid signature' ); require( (block.number - blockSigned) <= blockMaxThreshold, 'Signature expired' ); require(value >= amount, 'Invalid amount'); _; } function recoverSigner(bytes32 message, bytes memory sig) internal pure returns (address) { uint8 v; bytes32 r; bytes32 s; (v, r, s) = splitSignature(sig); return ecrecover(message, v, r, s); } function splitSignature(bytes memory sig) internal pure returns ( uint8, bytes32, bytes32 ) { require(sig.length == 65, 'Signature must be 65 bytes long'); bytes32 r; bytes32 s; uint8 v; assembly { // first 32 bytes, after the length prefix r := mload(add(sig, 32)) // second 32 bytes s := mload(add(sig, 64)) // final byte (first byte of the next 32 bytes) v := byte(0, mload(add(sig, 96))) } return (v, r, s); } function setBlockMaxThreshold(uint256 _blockThreshold) public onlyOwner { blockMaxThreshold = _blockThreshold; } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } // SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }