I will try to be brief in my doubt, below I am putting a model of a Smart Contract referring to a currency that I am creating for my game.

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";

contract SATOKCoin is ERC20, ERC20Burnable, Pausable, AccessControl, Ownable  {
    using SafeMath for uint256;

    bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");  

    constructor() ERC20("TOK COIN", "TOK") {
        _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
        _setupRole(PAUSER_ROLE, msg.sender);
        _mint(msg.sender, 100000 * 10 ** decimals());
        _setupRole(MINTER_ROLE, msg.sender);                

    function pause() public onlyRole(PAUSER_ROLE) {

    function unpause() public onlyRole(PAUSER_ROLE) {

    function mint(address to, uint256 amount) public onlyRole(MINTER_ROLE) {
        _mint(to, amount);        

    function _beforeTokenTransfer(address from, address to, uint256 amount)
        super._beforeTokenTransfer(from, to, amount);

The currency will be used in a web game, and my doubts are as follows...

Player actions will result in rewards, these rewards will be "virtually" saved in my database (off-chain). At some point, the player will be able to redeem the values ​​he has, at that moment I need to transfer to him the value X of my token (code above), below the doubts.

first doubt

  • the easiest way is to use the "mint" option and thus mint new coins directly for the calling player (msg.sender)? Or
  • Use the "transfer" option, and thus transfer the value you have in the contract to the player's wallet (msg.sender)?

second doubt Regarding security, how can I ensure that at the time of transferring the token the value that was passed in the function is the same one that the player has in my database (off-chain)? At this point I identified that there is Oracle, but I couldn't find a way and I don't know if there is a possibility of having a query in oracle before performing the transfer of the token to the player's wallet, is this possible? and if it is possible someone could give me an example in practice of a code that would have?

Thanks for help.

  • P.S. you don't need the SafeMath library if you're using Solidity 0.8 or above. The compiler will ensure that your functions automatically revert on over/underflow.
    – Ashraile
    Commented Nov 16, 2023 at 20:00

3 Answers 3


To accomplish these properties you could generate off-chain a signature of the amount and recipient's address. Then the contract will verify the signature is valid before performing the mint.

  • Thanks for the answer... and now the important question... hahaha, would you have a code or something sample for that? I would be speechless to thank.
    – Crazy
    Commented Oct 31, 2021 at 8:06
  • @Crazy OpenZepplin has helpers functions to validate signatures github.com/OpenZeppelin/openzeppelin-contracts/blob/master/…. This answer has links to a few examples ethereum.stackexchange.com/a/76852.
    – Ismael
    Commented Oct 31, 2021 at 17:59
  • I read the post and found it very interesting and I'm even doing a test, a problem I have is that the coin value can be random and from what I understand the signature depends on the same value that I send is expected on the solidity side , it is not? How to make sending data dynamic?
    – Crazy
    Commented Nov 2, 2021 at 8:55
  • @Crazy It is not required you can sign an arbitrary message.
    – Ismael
    Commented Nov 2, 2021 at 14:35
  • Thank you @Ismael! This was very useful for my understanding about signature with ECDSA. I made a solution to mint tokens using this one, however I'm researching if could exist any security lack on that. ethereum.stackexchange.com/questions/119268/… Commented Jan 18, 2022 at 20:32

@Crazy, using the technique brought by @Ismael, I created one, however I'm still in doubt about any possible security issues on that:

Using ECDSA to verify a signature inside smart contract

  • I don't think it would, because the privatekey you use to sign something, ie it will generate something encrypted. Anyway, I'm going to do a test to see if it recovers my privatekey but I find it difficult, since I signed it using other data.
    – Crazy
    Commented Jan 19, 2022 at 8:26

1st doubt: Usually it's done by transferring tokens from the owner / contract address to msg.sender.

2nd doubt: You may need to use a Merkle Tree. However you may just be able to store the value within the contract itself, and simply prevent that transfer until certain conditions are met. Unless you have need of absolute time precision within your contract, you can write something like:

struct StoredValue {
    uint value;
    uint[] rewards;
    address to;

mapping(address => uint) internal timestamps;
mapping(address => StoredValue) StoredValues;

StoredValue[] arrayOfStoredValues;

function setTimestamp(uint time, address account_to_lock) internal {
    timestamps[account_to_lock] = block.timestamp + time;

at transfer:

if (timestamps[address] != 0) {
   require(block.timestamp > timestamps[address], "You cannot yet transfer tokens");
   // transfer your token with stored value
     StoredValue memory values = arrayOfStoredValues[3];
     transfer(msg.sender, values.to, values.value);
     timestamps[address] = 0; // reset timestamp

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.