Contract 0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b8 4

 
 
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x625eca6dc35984ceab75eb2714089565cf5119ad0448412dc8d3c44aacdd2312Execute EIP712335130222022-09-24 15:53:0218 secs ago0xf16ab9d71db547584d6a1209060e232b7ea38428 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004680695251 34.650000014
0x231d487d0ecc4ca386d149ce25d608eea054fa8032549d0bbf08d9f5329e5fa4Execute Personal...335130202022-09-24 15:52:5822 secs ago0x1adbd686b0b750b042c0742e72a88e413d9be36d IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004214098351 34.650000013
0xb2b740b1d9a2ebaf8e2ba256d13b8de88cd765e59fbdf4856baf0a35494fb0f6Execute EIP712335130032022-09-24 15:52:2456 secs ago0xda11a89d90c06dca3bb7366f05e9565c178ebfcd IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.009612083253 34.650000012
0x58f43b6abeca630e34376ed083bda65faba9e094f0692da2010c7b80d51f9aafExecute EIP712335129832022-09-24 15:51:441 min ago0x8644c5bb07b49467062d76634e389a794716c78c IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004738808591 35.080198328
0x60bbafb0a28dda287f7aad3e2d5f59bb875b34858868a44e76626392f865a57bExecute EIP712335129812022-09-24 15:51:401 min ago0x943f3f764272625ab76beac4f37a586af983baa2 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.005254149183 35.288798328
0x80b31d672daa2098db269ec780854819b797107d9fbe357dede7ea08220abb2aExecute EIP712335129772022-09-24 15:51:321 min ago0x410adfe44eb52b817defa3b89204e794d799c7dd IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.005113178138 34.994922649
0x3e1ebb1f8f822087f92f862260ba09c7c42c08b7a83262e8eb0049889db09dedExecute Personal...335129662022-09-24 15:51:102 mins ago0x2eb2c46f42f0fd692c860e5db91bf96d1e90b426 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.008890808853 34.650000013
0x95f3afc51af3d5f71611d73ab8c174896f4bb622d5efd2e9565366e273a09d58Execute EIP712335129632022-09-24 15:51:042 mins ago0xcca820619e667c8c168434a886587e7b195c6457 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004584021751 34.650000014
0xafd93be87af962faee9b78f6f16300f2bf96ca364e2104d701c74400250824c3Execute Personal...335129612022-09-24 15:51:002 mins ago0xcb36da4fac97790fd9abbea68501181096bbeb15 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.005842960202 34.650000012
0xd925362bb2b509cb410fd381208f7947f49516f37b2ea0015b21643f9d82b782Execute EIP712335129572022-09-24 15:50:482 mins ago0xc6316c7cb3ab4ce4407e8a4e356f09c7e787ae02 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004585026601 34.650000011
0xe5700009791d812346b0a9f9f836fc7370147ef99f55a147b0e4fc8d21fde782Execute EIP712335129522022-09-24 15:50:382 mins ago0x1e88a3e328ce8f187123ac83ec39eaada7c13c57 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004967285401 34.650000011
0xca92cefa497aaa540fa1cb28d6316e845c190d2acfe6f96cd88b84364a58f071Execute Personal...335129442022-09-24 15:50:222 mins ago0x4dad1f578aa8ee05a2aa343f9b158da5df060865 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004202767801 34.650000011
0x3dae3e721a304e1a7c87ec2f8ad62a2ed9e411ec80ca7ead64ab8971a0f10523Execute Personal...335129332022-09-24 15:50:003 mins ago0x860ea4f47bf3917549cf558b0173ee0898480afe IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.006472100252 34.650000011
0x391d90ea4024ae51b88316a5097eddfca87b44a702552c2c374fa6c394f2079bExecute EIP712335129292022-09-24 15:49:523 mins ago0xf59e2ffee162076e0a7b137e0a994f6f4ee9f561 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.018561242705 34.650000011
0x5d485a123a767e23643685c22e872e5413ac0b63c7dca57f5718943b0f85fa1eExecute EIP712335129182022-09-24 15:49:303 mins ago0x7ff5c94e61a36ea1f8b996edd2f2ff7071304e54 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004871200951 34.650000012
0x83e531c1133be18f86483c4613d44f0f579c0877828ef3179a89309f980e2369Execute EIP712335129122022-09-24 15:49:184 mins ago0x5cf5f873ade0874e39f092c443f753776a7d523b IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004776363901 34.650000013
0xa52a0cd34699441876ecf7eac18e10a25b074f96177da6b939b997f9bbeda042Execute EIP712335129002022-09-24 15:48:544 mins ago0xd925d04e81f0cd9b83ff6e6a264670195e817932 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004584021751 34.650000013
0xc025ca5b6b724dc2c1523d16992bc665a077c9cde4aa3ac607b545a72f840dd4Execute EIP712335128972022-09-24 15:48:484 mins ago0x9372d8d580d021662a1e923ad8c820af0a926050 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004680106201 34.650000013
0x4f0786f1cb04d490a14bdc687a3c85648b6af9663fd024d5f365ecb91645eaaeExecute EIP712335128972022-09-24 15:48:484 mins ago0x7bef0554b2273428219b1df49035d3cedb071082 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.020244262507 34.650000013
0x5dd599ff761f9259843be380268b634093480994fc8799d8b55ee24f75270232Execute EIP712335128912022-09-24 15:48:324 mins ago0xb7d809b72ca20669ff2e3819ed8873b07637326e IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.003333468601 34.650000013
0xcdd7ae1563629e7428e65dc4561f0783bb84212791478cc8ac7ffbf2e7cbcbdfExecute EIP712335128852022-09-24 15:48:205 mins ago0xe10e129d026eabcccd8e9d5b5c773097b692ea58 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004966280551 34.650000012
0xc3ab877187e4525ce3169f899176214960408b007fd9b6dc427940daef8f1b5cExecute EIP712335128782022-09-24 15:48:065 mins ago0x1f402e5dd00b2c3482cfc04c79ad1bdda4f56f94 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.00835516732 35.039200007
0xac3c0b5089d38d9975f6ed02512aae379ee60df2e633eaa158462b5c2cf1b03eExecute EIP712335128742022-09-24 15:47:585 mins ago0x6c48f45dca2b69cff3a1a3cc9824859ea30d88bf IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004749818245 35.161700005
0xc4c10393e25d45047fb13c2ee5bd803397e36b7bb9781873cad78c313648b06eExecute EIP712335128732022-09-24 15:47:565 mins ago0x1d038b43e4634a1246b50518b6bdc0ac5b7b62b2 IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.004651717102 35.161700005
0xa0228a4e0fdffda9434d60ef37ddf4f33990a024997ab8fb4f10408abbc9cb0eExecute EIP712335128682022-09-24 15:47:465 mins ago0x552139e695410302d570beb7f13d8eef22934aee IN  0x86c80a8aa58e0a4fa09a69624c31ab2a6cad56b80 MATIC0.009611910003 34.650000013
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
BiconomyForwarder

Compiler Version
v0.7.6+commit.7338295f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 5 : BiconomyForwarder.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "openzeppelin-solidity/contracts/cryptography/ECDSA.sol";
import "./ERC20ForwardRequestTypes.sol";
import "./libs/Ownable.sol";

/**
 *
 * @title BiconomyForwarder
 *
 * @notice A trusted forwarder for Biconomy relayed meta transactions
 *
 * @dev - Inherits the ERC20ForwarderRequest struct
 * @dev - Verifies EIP712 signatures
 * @dev - Verifies personalSign signatures
 * @dev - Implements 2D nonces... each Tx has a BatchId and a BatchNonce
 * @dev - Keeps track of highest BatchId used by a given address, to assist in encoding of transactions client-side
 * @dev - maintains a list of verified domain seperators
 *
 */
contract BiconomyForwarder is ERC20ForwardRequestTypes, Ownable {
    using ECDSA for bytes32;

    mapping(bytes32 => bool) public domains;

    uint256 chainId;

    string public constant EIP712_DOMAIN_TYPE =
        "EIP712Domain(string name,string version,address verifyingContract,bytes32 salt)";

    bytes32 public constant REQUEST_TYPEHASH =
        keccak256(
            bytes(
                "ERC20ForwardRequest(address from,address to,address token,uint256 txGas,uint256 tokenGasPrice,uint256 batchId,uint256 batchNonce,uint256 deadline,bytes data)"
            )
        );

    mapping(address => mapping(uint256 => uint256)) nonces;

    constructor(address _owner) public Ownable(_owner) {
        uint256 id;
        assembly {
            id := chainid()
        }
        chainId = id;
        require(_owner != address(0), "Owner Address cannot be 0");
    }

    /**
     * @dev registers domain seperators, maintaining that all domain seperators used for EIP712 forward requests use...
     * ... the address of this contract and the chainId of the chain this contract is deployed to
     * @param name : name of dApp/dApp fee proxy
     * @param version : version of dApp/dApp fee proxy
     */
    function registerDomainSeparator(
        string calldata name,
        string calldata version
    ) external onlyOwner {
        uint256 id;
        /* solhint-disable-next-line no-inline-assembly */
        assembly {
            id := chainid()
        }

        bytes memory domainValue = abi.encode(
            keccak256(bytes(EIP712_DOMAIN_TYPE)),
            keccak256(bytes(name)),
            keccak256(bytes(version)),
            address(this),
            bytes32(id)
        );

        bytes32 domainHash = keccak256(domainValue);

        domains[domainHash] = true;
        emit DomainRegistered(domainHash, domainValue);
    }

    event DomainRegistered(bytes32 indexed domainSeparator, bytes domainValue);

    /**
     * @dev returns a value from the nonces 2d mapping
     * @param from : the user address
     * @param batchId : the key of the user's batch being queried
     * @return nonce : the number of transaction made within said batch
     */
    function getNonce(address from, uint256 batchId)
        public
        view
        returns (uint256)
    {
        return nonces[from][batchId];
    }

    /**
     * @dev an external function which exposes the internal _verifySigEIP712 method
     * @param req : request being verified
     * @param domainSeparator : the domain separator presented to the user when signing
     * @param sig : the signature generated by the user's wallet
     */
    function verifyEIP712(
        ERC20ForwardRequest calldata req,
        bytes32 domainSeparator,
        bytes calldata sig
    ) external view {
        _verifySigEIP712(req, domainSeparator, sig);
    }

    /**
     * @dev verifies the call is valid by calling _verifySigEIP712
     * @dev executes the forwarded call if valid
     * @dev updates the nonce after
     * @param req : request being executed
     * @param domainSeparator : the domain separator presented to the user when signing
     * @param sig : the signature generated by the user's wallet
     * @return success : false if call fails. true otherwise
     * @return ret : any return data from the call
     */
    function executeEIP712(
        ERC20ForwardRequest calldata req,
        bytes32 domainSeparator,
        bytes calldata sig
    ) external returns (bool success, bytes memory ret) {
        _verifySigEIP712(req, domainSeparator, sig);
        _updateNonce(req);
        /* solhint-disable-next-line avoid-low-level-calls */
        (success, ret) = req.to.call{gas: req.txGas}(
            abi.encodePacked(req.data, req.from)
        );
        // Validate that the relayer has sent enough gas for the call.
        // See https://ronan.eth.link/blog/ethereum-gas-dangers/
        assert(gasleft() > req.txGas / 63);
        _verifyCallResult(
            success,
            ret,
            "Forwarded call to destination did not succeed"
        );
    }

    /**
     * @dev an external function which exposes the internal _verifySigPersonSign method
     * @param req : request being verified
     * @param sig : the signature generated by the user's wallet
     */
    function verifyPersonalSign(
        ERC20ForwardRequest calldata req,
        bytes calldata sig
    ) external view {
        _verifySigPersonalSign(req, sig);
    }

    /**
     * @dev verifies the call is valid by calling _verifySigPersonalSign
     * @dev executes the forwarded call if valid
     * @dev updates the nonce after
     * @param req : request being executed
     * @param sig : the signature generated by the user's wallet
     * @return success : false if call fails. true otherwise
     * @return ret : any return data from the call
     */
    function executePersonalSign(
        ERC20ForwardRequest calldata req,
        bytes calldata sig
    ) external returns (bool success, bytes memory ret) {
        _verifySigPersonalSign(req, sig);
        _updateNonce(req);
        (success, ret) = req.to.call{gas: req.txGas}(
            abi.encodePacked(req.data, req.from)
        );
        // Validate that the relayer has sent enough gas for the call.
        // See https://ronan.eth.link/blog/ethereum-gas-dangers/
        assert(gasleft() > req.txGas / 63);
        _verifyCallResult(
            success,
            ret,
            "Forwarded call to destination did not succeed"
        );
    }

    /**
     * @dev Increments the nonce of given user/batch pair
     * @dev Updates the highestBatchId of the given user if the request's batchId > current highest
     * @dev only intended to be called post call execution
     * @param req : request that was executed
     */
    function _updateNonce(ERC20ForwardRequest calldata req) internal {
        nonces[req.from][req.batchId]++;
    }

    /**
     * @dev verifies the domain separator used has been registered via registerDomainSeparator()
     * @dev recreates the 32 byte hash signed by the user's wallet (as per EIP712 specifications)
     * @dev verifies the signature using Open Zeppelin's ECDSA library
     * @dev signature valid if call doesn't throw
     *
     * @param req : request being executed
     * @param domainSeparator : the domain separator presented to the user when signing
     * @param sig : the signature generated by the user's wallet
     *
     */
    function _verifySigEIP712(
        ERC20ForwardRequest calldata req,
        bytes32 domainSeparator,
        bytes memory sig
    ) internal view {
        uint256 id;
        /* solhint-disable-next-line no-inline-assembly */
        assembly {
            id := chainid()
        }
        require(
            req.deadline == 0 || block.timestamp + 20 <= req.deadline,
            "request expired"
        );
        require(domains[domainSeparator], "unregistered domain separator");
        require(chainId == id, "potential replay attack on the fork");
        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                domainSeparator,
                keccak256(
                    abi.encode(
                        REQUEST_TYPEHASH,
                        req.from,
                        req.to,
                        req.token,
                        req.txGas,
                        req.tokenGasPrice,
                        req.batchId,
                        nonces[req.from][req.batchId],
                        req.deadline,
                        keccak256(req.data)
                    )
                )
            )
        );
        require(digest.recover(sig) == req.from, "signature mismatch");
    }

    /**
     * @dev encodes a 32 byte data string (presumably a hash of encoded data) as per eth_sign
     *
     * @param hash : hash of encoded data that signed by user's wallet using eth_sign
     * @return input hash encoded to matched what is signed by the user's key when using eth_sign*/
    function prefixed(bytes32 hash) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
            );
    }

    /**
     * @dev recreates the 32 byte hash signed by the user's wallet
     * @dev verifies the signature using Open Zeppelin's ECDSA library
     * @dev signature valid if call doesn't throw
     *
     * @param req : request being executed
     * @param sig : the signature generated by the user's wallet
     *
     */
    function _verifySigPersonalSign(
        ERC20ForwardRequest calldata req,
        bytes memory sig
    ) internal view {
        require(
            req.deadline == 0 || block.timestamp + 20 <= req.deadline,
            "request expired"
        );
        bytes32 digest = prefixed(
            keccak256(
                abi.encodePacked(
                    req.from,
                    req.to,
                    req.token,
                    req.txGas,
                    req.tokenGasPrice,
                    req.batchId,
                    nonces[req.from][req.batchId],
                    req.deadline,
                    keccak256(req.data)
                )
            )
        );
        require(digest.recover(sig) == req.from, "signature mismatch");
    }

    /**
     * @dev verifies the call result and bubbles up revert reason for failed calls
     *
     * @param success : outcome of forwarded call
     * @param returndata : returned data from the frowarded call
     * @param errorMessage : fallback error message to show
     */
    function _verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) private pure {
        if (!success) {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 2 of 5 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.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) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        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-contracts/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) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        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) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

File 3 of 5 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            revert("ECDSA: invalid signature length");
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
        require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

File 4 of 5 : ERC20ForwardRequestTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
pragma experimental ABIEncoderV2;

/* deadline can be removed : GSN reference https://github.com/opengsn/gsn/blob/master/contracts/forwarder/IForwarder.sol (Saves 250 more gas)*/
/**
 * This contract defines a struct which both ERC20FeeProxy and BiconomyForwarder inherit. ERC20ForwardRequest specifies all the fields present in the GSN V2 ForwardRequest struct,
 * but adds the following :
 * address token
 * uint256 tokenGasPrice
 * uint256 txGas
 * uint256 batchNonce (can be removed)
 * uint256 deadline
 * Fields are placed in type order, to minimise storage used when executing transactions.
 */
contract ERC20ForwardRequestTypes {
    /*allow the EVM to optimize for this, 
ensure that you try to order your storage variables and struct members such that they can be packed tightly*/

    struct ERC20ForwardRequest {
        address from;
        address to;
        address token;
        uint256 txGas;
        uint256 tokenGasPrice;
        uint256 batchId;
        uint256 batchNonce;
        uint256 deadline;
        bytes data;
    }

    struct PermitRequest {
        address holder;
        address spender;
        uint256 value;
        uint256 nonce;
        uint256 expiry;
        bool allowed;
        uint8 v;
        bytes32 r;
        bytes32 s;
    }
}

File 5 of 5 : Ownable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.7.6;

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
    address private _owner;

    event OwnershipTransferred(
        address indexed previousOwner,
        address indexed newOwner
    );

    /**
     * @dev The Ownable constructor sets the original `owner` of the contract to the sender
     * account.
     */
    constructor(address owner) public {
        _owner = owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(
            isOwner(),
            "Only contract owner is allowed to perform this operation"
        );
        _;
    }

    /**
     * @return the address of the owner.
     */
    function owner() public view returns (address) {
        return _owner;
    }

    /**
     * @return true if `msg.sender` is the owner of the contract.
     */
    function isOwner() public view returns (bool) {
        return msg.sender == _owner;
    }

    /**
     * @dev Allows the current owner to relinquish control of the contract.
     * @notice Renouncing to ownership will leave the contract without an owner.
     * It will not be possible to call the functions with the `onlyOwner`
     * modifier anymore.
     */
    function renounceOwnership() public onlyOwner {
        emit OwnershipTransferred(_owner, address(0));
        _owner = address(0);
    }

    /**
     * @dev Allows the current owner to transfer control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function transferOwnership(address newOwner) public onlyOwner {
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers control of the contract to a newOwner.
     * @param newOwner The address to transfer ownership to.
     */
    function _transferOwnership(address newOwner) internal {
        require(newOwner != address(0));
        emit OwnershipTransferred(_owner, newOwner);
        _owner = newOwner;
    }
}

Settings
{
  "evmVersion": "istanbul",
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"domainValue","type":"bytes"}],"name":"DomainRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"EIP712_DOMAIN_TYPE","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUEST_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"domains","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ERC20ForwardRequestTypes.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executeEIP712","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ERC20ForwardRequestTypes.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"executePersonalSign","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"ret","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"batchId","type":"uint256"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"}],"name":"registerDomainSeparator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ERC20ForwardRequestTypes.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes32","name":"domainSeparator","type":"bytes32"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"verifyEIP712","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"txGas","type":"uint256"},{"internalType":"uint256","name":"tokenGasPrice","type":"uint256"},{"internalType":"uint256","name":"batchId","type":"uint256"},{"internalType":"uint256","name":"batchNonce","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ERC20ForwardRequestTypes.ERC20ForwardRequest","name":"req","type":"tuple"},{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"verifyPersonalSign","outputs":[],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b506040516115d03803806115d083398101604081905261002f91610080565b600080546001600160a01b0319166001600160a01b038316908117909155466002819055906100795760405162461bcd60e51b8152600401610070906100ae565b60405180910390fd5b50506100e5565b600060208284031215610091578081fd5b81516001600160a01b03811681146100a7578182fd5b9392505050565b60208082526019908201527f4f776e657220416464726573732063616e6e6f74206265203000000000000000604082015260600190565b6114dc806100f46000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c80638f32d59b1161008c578063a41a03f211610066578063a41a03f214610193578063c3f28abd146101a6578063c722f177146101bb578063f2fde38b146101ce576100cf565b80638f32d59b146101635780639c7b4592146101785780639e39b73e1461018b576100cf565b806341706c4e146100d45780636e4cb075146100fe578063715018a6146101135780638171e6321461011b578063895358031461012e5780638da5cb5b1461014e575b600080fd5b6100e76100e2366004610f0f565b6101e1565b6040516100f5929190611112565b60405180910390f35b61011161010c366004610f63565b610319565b005b61011161035e565b6100e7610129366004610f63565b6103eb565b61014161013c366004610e65565b610521565b6040516100f59190611135565b610156610549565b6040516100f591906110f3565b61016b610558565b6040516100f59190611107565b610111610186366004610ea6565b610569565b61014161068e565b6101116101a1366004610f0f565b6106b1565b6101ae6106f8565b6040516100f591906111be565b61016b6101c9366004610e8e565b610714565b6101116101dc366004610e44565b610729565b60006060610226868686868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061077892505050565b61022f86610981565b61023f6040870160208801610e44565b6001600160a01b0316606087013561025b6101008901896112a0565b61026860208b018b610e44565b60405160200161027a93929190611062565b60408051601f19818403018152908290526102949161108b565b60006040518083038160008787f1925050503d80600081146102d2576040519150601f19603f3d011682016040523d82523d6000602084013e6102d7565b606091505b509092509050603f6060870135045a116102ed57fe5b61031082826040518060600160405280602d815260200161147a602d91396109c7565b94509492505050565b6103598383838080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109f692505050565b505050565b610366610558565b6103a15760405162461bcd60e51b81526004018080602001828103825260388152602001806113a56038913960400191505060405180910390fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000606061042f8585858080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109f692505050565b61043885610981565b6104486040860160208701610e44565b6001600160a01b031660608601356104646101008801886112a0565b61047160208a018a610e44565b60405160200161048393929190611062565b60408051601f198184030181529082905261049d9161108b565b60006040518083038160008787f1925050503d80600081146104db576040519150601f19603f3d011682016040523d82523d6000602084013e6104e0565b606091505b509092509050603f6060860135045a116104f657fe5b61051982826040518060600160405280602d815260200161147a602d91396109c7565b935093915050565b6001600160a01b03919091166000908152600360209081526040808320938352929052205490565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b610571610558565b6105ac5760405162461bcd60e51b81526004018080602001828103825260388152602001806113a56038913960400191505060405180910390fd5b600046905060006040518060800160405280604f8152602001611312604f91398051906020012086866040516105e3929190611052565b604051809103902085856040516105fb929190611052565b60405190819003812061061693929130908790602001611192565b60408051601f198184030181528282528051602080830191909120600081815260019283905293909320805460ff1916909117905592509081907f4bc68689cbe89a4a6333a3ab0a70093874da3e5bfb71e93102027f3f073687d89061067d9085906111be565b60405180910390a250505050505050565b6040518060c00160405280609d81526020016113dd609d91398051906020012081565b6106f2848484848080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061077892505050565b50505050565b6040518060800160405280604f8152602001611312604f913981565b60016020526000908152604090205460ff1681565b610731610558565b61076c5760405162461bcd60e51b81526004018080602001828103825260388152602001806113a56038913960400191505060405180910390fd5b61077581610b48565b50565b4660e0840135158061079157508360e001354260140111155b6107b65760405162461bcd60e51b81526004016107ad906111d1565b60405180910390fd5b60008381526001602052604090205460ff166107e45760405162461bcd60e51b81526004016107ad906111fa565b80600254146108055760405162461bcd60e51b81526004016107ad90611231565b6000836040518060c00160405280609d81526020016113dd609d913980516020918201209061083690880188610e44565b6108466040890160208a01610e44565b61085660608a0160408b01610e44565b89606001358a608001358b60a00135600360008e600001602081019061087c9190610e44565b6001600160a01b03166001600160a01b0316815260200190815260200160002060008e60a001358152602001908152602001600020548d60e001358e8061010001906108c891906112a0565b6040516108d6929190611052565b6040519081900381206108f49a99989796959493929160200161113e565b6040516020818303038152906040528051906020012060405160200161091b9291906110d8565b60408051601f198184030181529190528051602091820120915061094190860186610e44565b6001600160a01b03166109548285610bb6565b6001600160a01b03161461097a5760405162461bcd60e51b81526004016107ad90611274565b5050505050565b600360006109926020840184610e44565b6001600160a01b031681526020808201929092526040908101600090812060a090940135815292909152902080546001019055565b82610359578151156109dc5781518083602001fd5b8060405162461bcd60e51b81526004016107ad91906111be565b60e08201351580610a0e57508160e001354260140111155b610a2a5760405162461bcd60e51b81526004016107ad906111d1565b6000610b00610a3c6020850185610e44565b610a4c6040860160208701610e44565b610a5c6060870160408801610e44565b6060870135608088013560a089013560036000610a7c60208d018d610e44565b6001600160a01b031681526020808201929092526040908101600090812060a08e0135825290925290205460e08b0135610aba6101008d018d6112a0565b604051610ac8929190611052565b604051908190038120610ae5999897969594939291602001610ff5565b60405160208183030381529060405280519060200120610d9d565b9050610b0f6020840184610e44565b6001600160a01b0316610b228284610bb6565b6001600160a01b0316146103595760405162461bcd60e51b81526004016107ad90611274565b6001600160a01b038116610b5b57600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60008151604114610c0e576040805162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015290519081900360640190fd5b60208201516040830151606084015160001a7f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115610c7f5760405162461bcd60e51b81526004018080602001828103825260228152602001806113616022913960400191505060405180910390fd5b8060ff16601b1480610c9457508060ff16601c145b610ccf5760405162461bcd60e51b81526004018080602001828103825260228152602001806113836022913960400191505060405180910390fd5b600060018783868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610d2b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610d93576040805162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b9695505050505050565b600081604051602001610db091906110a7565b6040516020818303038152906040528051906020012090505b919050565b80356001600160a01b0381168114610dc957600080fd5b60008083601f840112610df6578182fd5b50813567ffffffffffffffff811115610e0d578182fd5b602083019150836020828501011115610e2557600080fd5b9250929050565b60006101208284031215610e3e578081fd5b50919050565b600060208284031215610e55578081fd5b610e5e82610dce565b9392505050565b60008060408385031215610e77578081fd5b610e8083610dce565b946020939093013593505050565b600060208284031215610e9f578081fd5b5035919050565b60008060008060408587031215610ebb578182fd5b843567ffffffffffffffff80821115610ed2578384fd5b610ede88838901610de5565b90965094506020870135915080821115610ef6578384fd5b50610f0387828801610de5565b95989497509550505050565b60008060008060608587031215610f24578384fd5b843567ffffffffffffffff80821115610f3b578586fd5b610f4788838901610e2c565b9550602087013594506040870135915080821115610ef6578384fd5b600080600060408486031215610f77578283fd5b833567ffffffffffffffff80821115610f8e578485fd5b610f9a87838801610e2c565b94506020860135915080821115610faf578384fd5b50610fbc86828701610de5565b9497909650939450505050565b60008151808452610fe18160208601602086016112e5565b601f01601f19169290920160200192915050565b6bffffffffffffffffffffffff1960609a8b1b81168252988a1b891660148201529690981b9096166028860152603c850193909352605c840191909152607c830152609c82015260bc81019190915260dc81019190915260fc0190565b6000828483379101908152919050565b6000838583375060609190911b6bffffffffffffffffffffffff19169101908152601401919050565b6000825161109d8184602087016112e5565b9190910192915050565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b901515815260200190565b600083151582526040602083015261112d6040830184610fc9565b949350505050565b90815260200190565b998a526001600160a01b0398891660208b015296881660408a0152949096166060880152608087019290925260a086015260c085015260e08401929092526101008301919091526101208201526101400190565b948552602085019390935260408401919091526001600160a01b03166060830152608082015260a00190565b600060208252610e5e6020830184610fc9565b6020808252600f908201526e1c995c5d595cdd08195e1c1a5c9959608a1b604082015260600190565b6020808252601d908201527f756e7265676973746572656420646f6d61696e20736570617261746f72000000604082015260600190565b60208082526023908201527f706f74656e7469616c207265706c61792061747461636b206f6e2074686520666040820152626f726b60e81b606082015260800190565b6020808252601290820152710e6d2cedcc2e8eae4ca40dad2e6dac2e8c6d60731b604082015260600190565b6000808335601e198436030181126112b6578283fd5b83018035915067ffffffffffffffff8211156112d0578283fd5b602001915036819003821315610e2557600080fd5b60005b838110156113005781810151838201526020016112e8565b838111156106f2575050600091015256fe454950373132446f6d61696e28737472696e67206e616d652c737472696e672076657273696f6e2c6164647265737320766572696679696e67436f6e74726163742c627974657333322073616c742945434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c75654f6e6c7920636f6e7472616374206f776e657220697320616c6c6f77656420746f20706572666f726d2074686973206f7065726174696f6e4552433230466f72776172645265717565737428616464726573732066726f6d2c6164647265737320746f2c6164647265737320746f6b656e2c75696e743235362074784761732c75696e7432353620746f6b656e47617350726963652c75696e7432353620626174636849642c75696e743235362062617463684e6f6e63652c75696e7432353620646561646c696e652c6279746573206461746129466f727761726465642063616c6c20746f2064657374696e6174696f6e20646964206e6f742073756363656564a26469706673582212207108fdb9cc163850b436f3826051f7138cd7eaf630ca1226c5ff63e71eef39e664736f6c63430007060033000000000000000000000000221cadcac35e18ecc89d1c3d8af88613b9d7518b

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000221cadcac35e18ecc89d1c3d8af88613b9d7518b

-----Decoded View---------------
Arg [0] : _owner (address): 0x221cadcac35e18ecc89d1c3d8af88613b9d7518b

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000221cadcac35e18ecc89d1c3d8af88613b9d7518b


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.