Verify smart contract request with multi-signature approach

Nhan Cao
6 min readOct 15, 2021

First, create a mintable token

// SPDX-License-Identifier: MIT
// @nhancv
pragma solidity 0.8.4;

interface IMintable {
function mint(address account, uint256 amount) external;
}

ERC20Mintable

// SPDX-License-Identifier: MIT
// @nhancv
pragma solidity 0.8.4;

import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "./ERC20Token.sol";
import "./interfaces/IMintable.sol";

contract ERC20Mintable is ERC20Token, IMintable, AccessControlUpgradeable {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");

/**
* @dev Upgradable initializer
*/
function __ERC20Mintable_init(
string memory name_,
string memory symbol_,
uint8 decimals_,
uint256 initialSupply_,
address minter_
) public initializer {
__ERC20Token_init(name_, symbol_, decimals_, initialSupply_);
_setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
_setupRole(MINTER_ROLE, minter_);
}

/**
* @dev Mint tokens.
*/
function mint(address _to, uint256 _amount) public override onlyRole(MINTER_ROLE) {
_mint(_to, _amount);
}
}

Create EIP712 multi-signature

MultiSigEIP712

// SPDX-License-Identifier: MIT
// @nhancv
pragma solidity ^0.8.4;

import "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/draft-EIP712Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import "./interfaces/IMintable.sol";

contract MultiSigEIP712 is EIP712Upgradeable, OwnableUpgradeable, AccessControlUpgradeable, ReentrancyGuardUpgradeable {
// A valid validator must has VALIDATOR_ROLE
bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
// A valid request requires at least validatorsRequired
uint256 public validatorsRequired;

// Request entries
struct ProcessedEntry {
uint256 processId;
address user;
address token;
uint256…