ETH Price: $3,801.30 (-1.97%)
Gas: 9 Gwei

Transaction Decoder

Block:
10867840 at Sep-15-2020 04:52:03 PM +UTC
Transaction Fee:
0.10038424 ETH $381.59
Gas Used:
912,584 Gas / 110 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x12369488...536D14cAf
(tBTC: Deployer 1)
1.53818562 Eth
Nonce: 48
1.43780138 Eth
Nonce: 49
0.10038424
(Spark Pool)
120.907917222532566027 Eth121.008301462532566027 Eth0.10038424
0x8dAEBADE...f50815fAa
0 Eth
Nonce: 0
0 Eth
Nonce: 1
From: 0 To: 5333967909249984380559663898940029743109008112008544239835952151722187639469315642600417356228424386866826897857207165007238821998248758205198352658982564255741709669263040317835284644855889958191663149189294052938648792007691044925543882337098065969692788533532755085400270874316140563896510330919342510795452267166993378413151722372333372029165513518596113793067847302676729774624231037288878647192970991169445131210242442621644366028573471244929511185684072045296652138475713924382811087464204881782007887755636813820743499877266324142577784484238472910902920175993473586905569209373983586530809388280374809773309768874410879092727874345148995337585247806706574050516551765336363772700929645333296470149430370989119788069518820734243327222320913196767726329426747151550556833470606190675580082569684401920026523924016136230646895611999688356086164312782733706558764508112598342401087326946641276149118569171038192246464961238279589665926793728938130964525469271033693193901760230013063647226151531367098258492636680394558806464434476189551085230847750754502113371163207864401787954930106178972731823395685267119499040504737605396713022112368134001635939719161778857532441199806663775859368292105591430123106903106068001929097473363105278770560334522006247621094990443442996668023519582664075705080573102389796129788191908412083138435987502985538660911090492706315305503184284313317101368034837928097614947775929155689171335379192750272105557955369125465492424518163044282302719161329402501697562068636146373180416587601343206074987751161852623983499016377922115396201950165328289891082270459603670251727032922390969304763733459534925835818691082400867855420648257209839840158360180771423947543089968329032078036351541541056502945431712070110543644604639567451713091666110854001599202675863138506818811124701305190443293949661595073116210496058657361500929233081299160250274514424407892367927965425717274440282651109112239018703632516599669210364778087481090459411634579708612019367640873939077538088708683404666617551572307854687774675521706288104819946304685847377371596607444997349654180438385295103663197010149164519749579823086810170707639339213384118315408145419761634555005347335804026847987873196128247998250271136848653937647540782308975479580133077807745557566577580848956761865689729560113845994901656182164819703925349987627989713812319240285146550403109284148327992712259023561282772589350441092610771962800904669066324986437368287800762743352181324050810772503997221486812440142269286602218356135112285411965687541989990479119649290186201382791641198488859979174741863453545654128287090897220462918196766624140201056159044098604897689411936111588097899102751081303383835776983270054660885713511802597172590439190258250873250861751376086604980828946034916107819423735170144256322547855647923949551031923183152749054318633190929251486266871566015103318190995450130283509153919589105995796955656999222365210907094506684976539632107415528244982999076063511231777362473675058423183885707471131596748593575998676825914923572420690314785690857979632306091033778020085185130738289351952701253545271391688655274432105880719116178559644903079584177132183351215375596016077746629149134559647461916582217879811313406682757629588061171246859995748429765299151598246302898299545538510836056173726132230813323502644033201890366990022827534868647977119970686571064230854496913120567833965364552152678515498931419342008324504843897419251483648862957341689951643274594444252695101217439159552873093441635217730732411386319985264932826228644376417165434543052012940241158367703903616636826861833350026421931413662726920791566413887130526985389270489590976874254238867477291467946771315323821284476583618455280088733010621559292914001587599277651230174605257479271492418424109023935167775708189151138671965996081916731796608944125965124434816951075566744478018253538578080141193703334843213040314932507496993553419261046478903145056720929387839895676670546911983424555982217366680681516283591974116190956731173267514635335727865745016188166471046688340053508792177283805414958870123891606326746815351711967161481273651168930522647855027324207902375951353080172363241927448795253504998974735101781595558349801424711262814775875472672951529252348998222132635563153919883028470750787850617945401522641221423276252212594525502430478195062864981681445282642382240474909776446161704961906763502467202904329438259084611920886392450192381289426228649970188891394874182125344402599498938743509018351914561494050634205056825339384811240917628695907209800382774603856856492733905015715549568385750948547949400437077366422708065721834874247532699547772252399374465664198962505974615607361940572584127592469709197346416249071724012572293907794850773617240459292404016402578305455167248971891898382053933495813674622960459614915316622382899833550059149143809994603747348569208828961562794017868873428438502466653923457047778738104652161795153970487729667744492168334183492551820085469818531990285372184968665317357043425117076241211461506088538520500827971928215810407186992745138821924439946344601891788415504293906108958165938047482956404868170763945011246858609190657974172785008691154141816876632464879222148246028861695128837408450915190488999775475814971253113091070963139879123934650684135603391460630640160222132266756085374280293340219564302868597061949418297045514323017190384256904991110598276631437067481985066821237305734895141859390268345976424354181766466518825988612846194763154134679903324659385749924980209676888965136219062406325068550496622773383183639875222067511508108818917586615202133676574069963908495146274363211347595910588108390955387045939130297386713729686768166398712435072799343888945981904060113180281742093741494044325932502493361716915530632504055563690626227182714948721185790090478524502355393425213288744201700018339952108495422354327617233982496680985429172802548417195491481660757013910838453702170323378014410924081263357798242934377170069169033547868003797239730463775094320706695861920779706002786797342685753428920230822597790585360814870388944309257017893261239879043828468722981245422806832331631174176758304605860056815446673010982706088194590344563384716901090625427228806435282087029052503068954778650814574281726588927410608062714059035981877685469609792070262717576387585325102347516523264004285364464998791323472621294749638049319005302031099242026757281148053684545992985857115033231024743193079673678444333649669781997768752595172954940805112920422164776598155562736642172639659988468916739990412005876296626199349737242551520338859238284893769456712864874419383471566186190809484955531866426875053629362322766652754871944604864378864412512911631335194355627869128801867539634211650532482065400123653398553050876542830333733023402304997728370395904890584617837395158109996107321345803831286678007088158165768954742737702413274930813378597277034713228217613998928765070934651933791547916861733354069951229461640606139030262932370843515725517084625747398368017980966671828554933395759081418248870500668697513417806232515438302870987519899499485036041527734500487666429888970363088162602066157698326688966135657257538109068529285956587904375188522939651418845108064423244039886414142810820922785853886803315714055459204420151164111208145187440240228765254430061868281044513475170542758738084531312455295288661784326120913360225972859340847845946701230389069243067011392046522262587970974559419381866680902647372459438300113358728819680685625500370909013209402213869876529488814935615522059805304421772285213411604861149804438454583235963271395076420078581129839336924000082172880035985080713735299214894336319514845846561085190339435409932385562830716738901649702786887700393952236709519492065096939243156821838610454319324658045713955101771922422857327314748485899491000184298059276399310956629307260616031894834114049290716336828662426425785498215016880139762081961844143244145122572918015036561447497286714569114319353005155674544807734524062527386420801380420331450062158049456326762372071053933482252521466766732656723765923151924265567139359070268967135374959046160421647854030733293284775386266817971355886411309074471313621641673552929166567893211906252611752679577843705714106646500639765340812253524323597713436638708355956066478980291764270508424736894981729213213650911092694038375839941358127231698786704396408005090454737191618076648802766184620370489701940631512254174181042710310904286562917777660221000179627606208749948679253966315082773698715452321328971580448921005492960580964587484268075251202608978704506760749854886002738

Execution Trace

TBTCToken.60806040( )
pragma solidity 0.5.17;
import {ERC20} from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import {ERC20Detailed} from "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
import {VendingMachineAuthority} from "./VendingMachineAuthority.sol";
import {ITokenRecipient} from "../interfaces/ITokenRecipient.sol";
/// @title  TBTC Token.
/// @notice This is the TBTC ERC20 contract.
/// @dev    Tokens can only be minted by the `VendingMachine` contract.
contract TBTCToken is ERC20Detailed, ERC20, VendingMachineAuthority {
    /// @dev Constructor, calls ERC20Detailed constructor to set Token info
    ///      ERC20Detailed(TokenName, TokenSymbol, NumberOfDecimals)
    constructor(address _VendingMachine)
        ERC20Detailed("tBTC", "TBTC", 18)
        VendingMachineAuthority(_VendingMachine)
    public {
        // solium-disable-previous-line no-empty-blocks
    }
    /// @dev             Mints an amount of the token and assigns it to an account.
    ///                  Uses the internal _mint function.
    /// @param _account  The account that will receive the created tokens.
    /// @param _amount   The amount of tokens that will be created.
    function mint(address _account, uint256 _amount) external onlyVendingMachine returns (bool) {
        // NOTE: this is a public function with unchecked minting. Only the
        // vending machine is allowed to call it, and it is in charge of
        // ensuring minting is permitted.
        _mint(_account, _amount);
        return true;
    }
    /// @dev             Burns an amount of the token from the given account's balance.
    ///                  deducting from the sender's allowance for said account.
    ///                  Uses the internal _burn function.
    /// @param _account  The account whose tokens will be burnt.
    /// @param _amount   The amount of tokens that will be burnt.
    function burnFrom(address _account, uint256 _amount) external {
        _burnFrom(_account, _amount);
    }
    /// @dev Destroys `amount` tokens from `msg.sender`, reducing the
    /// total supply.
    /// @param _amount   The amount of tokens that will be burnt.
    function burn(uint256 _amount) external {
        _burn(msg.sender, _amount);
    }
    /// @notice           Set allowance for other address and notify.
    ///                   Allows `_spender` to spend no more than `_value`
    ///                   tokens on your behalf and then ping the contract about
    ///                   it.
    /// @dev              The `_spender` should implement the `ITokenRecipient`
    ///                   interface to receive approval notifications.
    /// @param _spender   Address of contract authorized to spend.
    /// @param _value     The max amount they can spend.
    /// @param _extraData Extra information to send to the approved contract.
    /// @return true if the `_spender` was successfully approved and acted on
    ///         the approval, false (or revert) otherwise.
    function approveAndCall(
        ITokenRecipient _spender,
        uint256 _value,
        bytes memory _extraData
    ) public returns (bool) { // not external to allow bytes memory parameters
        if (approve(address(_spender), _value)) {
            _spender.receiveApproval(msg.sender, _value, address(this), _extraData);
            return true;
        }
        return false;
    }
}
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
/**
 * @dev Implementation of the `IERC20` interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using `_mint`.
 * For a generic mechanism see `ERC20Mintable`.
 *
 * *For a detailed writeup see our guide [How to implement supply
 * mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).*
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an `Approval` event is emitted on calls to `transferFrom`.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard `decreaseAllowance` and `increaseAllowance`
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See `IERC20.approve`.
 */
contract ERC20 is IERC20 {
    using SafeMath for uint256;
    mapping (address => uint256) private _balances;
    mapping (address => mapping (address => uint256)) private _allowances;
    uint256 private _totalSupply;
    /**
     * @dev See `IERC20.totalSupply`.
     */
    function totalSupply() public view returns (uint256) {
        return _totalSupply;
    }
    /**
     * @dev See `IERC20.balanceOf`.
     */
    function balanceOf(address account) public view returns (uint256) {
        return _balances[account];
    }
    /**
     * @dev See `IERC20.transfer`.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public returns (bool) {
        _transfer(msg.sender, recipient, amount);
        return true;
    }
    /**
     * @dev See `IERC20.allowance`.
     */
    function allowance(address owner, address spender) public view returns (uint256) {
        return _allowances[owner][spender];
    }
    /**
     * @dev See `IERC20.approve`.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 value) public returns (bool) {
        _approve(msg.sender, spender, value);
        return true;
    }
    /**
     * @dev See `IERC20.transferFrom`.
     *
     * Emits an `Approval` event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of `ERC20`;
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `value`.
     * - the caller must have allowance for `sender`'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, msg.sender, _allowances[sender][msg.sender].sub(amount));
        return true;
    }
    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in `IERC20.approve`.
     *
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));
        return true;
    }
    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in `IERC20.approve`.
     *
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
        _approve(msg.sender, spender, _allowances[msg.sender][spender].sub(subtractedValue));
        return true;
    }
    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to `transfer`, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");
        _balances[sender] = _balances[sender].sub(amount);
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }
    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a `Transfer` event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal {
        require(account != address(0), "ERC20: mint to the zero address");
        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }
     /**
     * @dev Destoys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a `Transfer` event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 value) internal {
        require(account != address(0), "ERC20: burn from the zero address");
        _totalSupply = _totalSupply.sub(value);
        _balances[account] = _balances[account].sub(value);
        emit Transfer(account, address(0), value);
    }
    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
     *
     * This is internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");
        _allowances[owner][spender] = value;
        emit Approval(owner, spender, value);
    }
    /**
     * @dev Destoys `amount` tokens from `account`.`amount` is then deducted
     * from the caller's allowance.
     *
     * See `_burn` and `_approve`.
     */
    function _burnFrom(address account, uint256 amount) internal {
        _burn(account, amount);
        _approve(account, msg.sender, _allowances[account][msg.sender].sub(amount));
    }
}
pragma solidity ^0.5.0;
/**
 * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see `ERC20Detailed`.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);
    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);
    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);
    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through `transferFrom`. This is
     * zero by default.
     *
     * This value changes when `approve` or `transferFrom` are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);
    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * > Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an `Approval` event.
     */
    function approve(address spender, uint256 amount) external returns (bool);
    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);
    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to `approve`. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.5.0;
import "./IERC20.sol";
/**
 * @dev Optional functions from the ERC20 standard.
 */
contract ERC20Detailed is IERC20 {
    string private _name;
    string private _symbol;
    uint8 private _decimals;
    /**
     * @dev Sets the values for `name`, `symbol`, and `decimals`. All three of
     * these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol, uint8 decimals) public {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }
    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }
    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }
    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei.
     *
     * > Note that this information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * `IERC20.balanceOf` and `IERC20.transfer`.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }
}
pragma solidity 0.5.17;
/// @title  Vending Machine Authority.
/// @notice Contract to secure function calls to the Vending Machine.
/// @dev    Secured by setting the VendingMachine address and using the
///         onlyVendingMachine modifier on functions requiring restriction.
contract VendingMachineAuthority {
    address internal VendingMachine;
    constructor(address _vendingMachine) public {
        VendingMachine = _vendingMachine;
    }
    /// @notice Function modifier ensures modified function caller address is the vending machine.
    modifier onlyVendingMachine() {
        require(msg.sender == VendingMachine, "caller must be the vending machine");
        _;
    }
}
pragma solidity 0.5.17;
/// @title Interface of recipient contract for `approveAndCall` pattern.
///        Implementors will be able to be used in an `approveAndCall`
///        interaction with a supporting contract, such that a token approval
///        can call the contract acting on that approval in a single
///        transaction.
///
///        See the `FundingScript` and `RedemptionScript` contracts as examples.
interface ITokenRecipient {
    /// Typically called from a token contract's `approveAndCall` method, this
    /// method will receive the original owner of the token (`_from`), the
    /// transferred `_value` (in the case of an ERC721, the token id), the token
    /// address (`_token`), and a blob of `_extraData` that is informally
    /// specified by the implementor of this method as a way to communicate
    /// additional parameters.
    ///
    /// Token calls to `receiveApproval` should revert if `receiveApproval`
    /// reverts, and reverts should remove the approval.
    ///
    /// @param _from The original owner of the token approved for transfer.
    /// @param _value For an ERC20, the amount approved for transfer; for an
    ///        ERC721, the id of the token approved for transfer.
    /// @param _token The address of the contract for the token whose transfer
    ///        was approved.
    /// @param _extraData An additional data blob forwarded unmodified through
    ///        `approveAndCall`, used to allow the token owner to pass
    ///         additional parameters and data to this method. The structure of
    ///         the extra data is informally specified by the implementor of
    ///         this interface.
    function receiveApproval(
        address _from,
        uint256 _value,
        address _token,
        bytes calldata _extraData
    ) external;
}
pragma solidity ^0.5.0;
/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }
    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;
        return c;
    }
    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
        if (a == 0) {
            return 0;
        }
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }
    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        return c;
    }
    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}