Contract 0x4de5cB2EB81A37DD768fc58fe0ca7b811C997c35

 

Contract Overview

Balance:
0 BNB

BNB Value:
$0.00

Token:
Txn Hash Method
Block
From
To
Value [Txn Fee]
0x548b325c9f13cafe7b51684f26c5e151f0bf2d1dc885eda3c7402be0040dde920xc3b6dcdc118555062021-10-17 16:13:084 days 1 hr ago0x705be3d0701427dc925f90506752b4eaa8f07f83 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.001490275
0xd01b974b3e2764bbf763af7fd4d2f82136f9324f8e3227ae3d372d56fddf87f10x042ed32a118352042021-10-16 23:13:264 days 18 hrs ago0x0955c6965df31558c5d2a7a0f66631c16dd42980 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.000599665
0xbe0dd23a12f824b61805f0b8a370fb418cf920d7d718f990eab1c8724f98c4f70x042ed32a118351692021-10-16 23:11:414 days 18 hrs ago0x0955c6965df31558c5d2a7a0f66631c16dd42980 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.000599665
0xcf69fa0d5e50d7c0254f5509b1e2732fa4077defff0175bd50227ac6676d78860xc3b6dcdc117882942021-10-15 7:55:446 days 10 hrs ago0x24680aae004c3826b2f311b2c924ce8e58ba2006 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01207837
0xcae86ea245a00c3759b7572aaaa331a6660276ce539c772fd8c037739fda49910xc3b6dcdc111184642021-09-21 21:30:4829 days 20 hrs ago0x8a622bc901de1fa2384d42ffa79606e446ed788f IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01200341
0x1e1fe58bf205b6f8f771f4a1489696190e62f4d571985c5a93900c677c231b2f0xc3b6dcdc110443822021-09-19 7:23:3532 days 10 hrs ago0x31e40209cfcdda86baabfe93a428cc9143a9ed30 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01200345
0x702c95ee4b1687b22a75d882daf05b6be216e6db00d8db81bd4b84e0c16e418c0x9b0d85d3108252422021-09-11 16:16:4040 days 1 hr ago0x3b3ab217313050a36c8c86fb036abc343d020fc0 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00068472
0x4247f7a7b75c1126b3fc04d7229b018aad9b581aff216f44cb11d545aa0440310xc3b6dcdc106940252021-09-07 1:28:3844 days 16 hrs ago0x8af4bb42454aa77dc1e8e67a2e1b0961a4203f46 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011945915
0x3449cb06b513d46e293d004c37d15757fb8eeb2e9d75f79f2255517b946fab680xc3b6dcdc106827692021-09-06 15:58:1545 days 2 hrs ago0x233f681ff98e18fa46fd9d6203520a6a301aeaa1 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01207857
0x592d6dc072ecf0299e32e213e5c93e9c1c39e54212332be42aec935002d83b480xc3b6dcdc106827492021-09-06 15:57:1545 days 2 hrs ago0x233f681ff98e18fa46fd9d6203520a6a301aeaa1 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00214194
0x575a5ab9aa8109829b6e6bddad1dbb67c535687975808021cadb6f41fe701aee0x9b0d85d3106735892021-09-06 8:17:3545 days 9 hrs ago0x094dc639f0c47b6eca92936e142ecea207b963e4 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00068478
0xc5f2098b562206a900ae0a90b268f7e4ba11c58cd00b0ab5fc184c8d674567ae0xc3b6dcdc106227982021-09-04 13:48:3647 days 4 hrs ago0x9e37cc6695438f1d3bd44aaef9e433501ca99620 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011999915
0xf74432f2b8989c71c50beabc2dba17d9c16e6bd8d915c8d972ece896eee68b940xc3b6dcdc105919582021-09-03 11:58:0548 days 6 hrs ago0x9186eb0108a37b1982a8a1ad1bc64b8d9060be07 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011999715
0xd60581f1eb5193657144ee41864ba3e0d2912145fc919a569b936852843db0ed0x9b0d85d3105039442021-08-31 9:36:4451 days 8 hrs ago0x75535d7ed58682dd1f2c1faccda0e81e8c7792db IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00068478
0xcf756ba0c2b0c214a79f6158bff70f6f49e6ab1f7490c5609a37f9b00deb14800x9b0d85d3105034882021-08-31 9:13:4651 days 8 hrs ago0x4195ef205fd29077b2472d4672a62f62e88bd40f IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00068478
0xfd9f1ed225a1aa54eb7dbde91de9b32d3408d5627942ea3eae26399202ff0be10xc3b6dcdc105011462021-08-31 7:13:5151 days 10 hrs ago0xb0db0a18ba8309b66aa54ea5bb55f4f457ca3ea8 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01200359
0x99e58f59d741c409aaca1bc478bfe7fb866a4c36e368a4e868073c5a141b9ed60x9b0d85d3103894632021-08-27 8:20:5455 days 9 hrs ago0x5861254a45b83d13209abfafc572d8e347b3e1f3 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.00068472
0xd6cdbbb2c24756ffb862ee3425bdfe5a7d262eabe901d0acf6a3e84ca1a075e50xc3b6dcdc102809462021-08-23 13:31:0859 days 4 hrs ago0x502e9868cb34e2527c9516456df280ba59ce92b0 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011945695
0xf1921b3496b70a257de53c16ab04f4a37411b7edf6031ebd5b4a9c6617bdcee20xc3b6dcdc102808712021-08-23 13:27:1759 days 4 hrs ago0x7b0b35b416631f05f321fe74990817dca81cabde IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011924635
0x5445050639869f355da87d269a75aadb2b3673316973cf674b70ad7c0a86971d0xc3b6dcdc101986732021-08-20 16:35:0162 days 1 hr ago0x48fb385c4e0e3c1e82662e445005c318509666af IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01207855
0x3d736177bd8c179270aee68a3beb47b229279b14caec02e01afa49fa273e14b70xc3b6dcdc101922922021-08-20 11:09:2762 days 6 hrs ago0xc36fdf387cf4412b62fc79ca8134308e9a161cdb IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.01223612
0x3d935f68970efccaaceed49ba457d8305819c7fc666c59a526a3210732236e380xc3b6dcdc101922712021-08-20 11:08:2462 days 6 hrs ago0xc36fdf387cf4412b62fc79ca8134308e9a161cdb IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.001905835
0x5e259fa7c4a3d1e1c4a3e6d1bfe00c0fbafa7c8b636ddaf721752438b94dbf230xc3b6dcdc101885372021-08-20 8:00:5662 days 9 hrs ago0xcf36aa16b6571a0bb1cf3f83c9486b70d0aca9f5 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.012103405
0x9f619cc9f7778198c5fa90ea2d6523448d2f049b4334bf4beb462c96652841d00xc3b6dcdc100266652021-08-14 16:41:0968 days 1 hr ago0xb8541d67d1b05b5f32555371411b159c30caeab5 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.001490275
0x9eeda3b256cc0fd411b50b7d7de916baf88cb8b2720d99b39b0e1d3d05a4e53a0xc3b6dcdc100165842021-08-14 8:10:2368 days 9 hrs ago0xaf884fc78e7446e3e11e8e4c7d4e2085b8aaf956 IN  0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350 BNB0.011925055
[ Download CSV Export 
Latest 8 internal transactions
Parent Txn Hash Block From To Value
0xab2907f40b428d0db81f4000c4d1a87711463f140d34518f940a7055a060ad0a84896622021-06-21 12:20:29122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350x171a496bf2de4bd8469fb7d0ca94cc7872e255c80.022495515 BNB
0xab2907f40b428d0db81f4000c4d1a87711463f140d34518f940a7055a060ad0a84896622021-06-21 12:20:29122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350xe6ee8e8829e65fe4ff406231ed1418dcb9afdb570.004854485 BNB
0xd5cc97f81bf5d28f857f695bebd4a2165b7284c9f90ba0e8447fade1ce2cd33284895122021-06-21 12:12:59122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350x0f16f0c34ce1414e3b50764fb5c122e8d2f2cd280.022473935 BNB
0xd5cc97f81bf5d28f857f695bebd4a2165b7284c9f90ba0e8447fade1ce2cd33284895122021-06-21 12:12:59122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350xe6ee8e8829e65fe4ff406231ed1418dcb9afdb570.004876065 BNB
0x6058b4fce623634c0430657a9fd12a03805b002afbe50b7219f422a34c2ece4584894392021-06-21 12:09:20122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350x171a496bf2de4bd8469fb7d0ca94cc7872e255c80.022442465 BNB
0x6058b4fce623634c0430657a9fd12a03805b002afbe50b7219f422a34c2ece4584894392021-06-21 12:09:20122 days 5 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350xe6ee8e8829e65fe4ff406231ed1418dcb9afdb570.004907535 BNB
0x8799b3d4de54d2ca574c33eddf8fd219d10930150dff591247e34c80ba816f2284562492021-06-20 8:27:32123 days 9 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350x171a496bf2de4bd8469fb7d0ca94cc7872e255c80.02239846 BNB
0x8799b3d4de54d2ca574c33eddf8fd219d10930150dff591247e34c80ba816f2284562492021-06-20 8:27:32123 days 9 hrs ago 0x4de5cb2eb81a37dd768fc58fe0ca7b811c997c350xe6ee8e8829e65fe4ff406231ed1418dcb9afdb570.00495154 BNB
[ Download CSV Export 
Loading

Contract Source Code Verified (Similar Match)
Note: This contract matches the deployed ByteCode of the Source Code for Contract 0x2b2449a235e9389d69af22f5fee710f8e2d254b9

Contract Name:
SuterERC20

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
No with 200 runs

Other Settings:
default evmVersion, None license

Contract Source Code (Solidity Multiple files format)

File 1 of 10: SuterERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./ERC20.sol";
import "./Utils.sol";
import "./SuterBase.sol";


contract SuterERC20 is SuterBase {

    ERC20 token;

    //constructor(address payable _suterAgency, Utils.G1Point memory _suterAgencyPublicKey, address _token, address _transfer, address _burn, uint256 _epochBase, uint256 _epochLength, uint256 _unit) SuterBase(_suterAgency, _suterAgencyPublicKey, _transfer, _burn, _epochBase, _epochLength, _unit) public {
        //token = ERC20(_token);
    //}

    constructor(address _token, address _transfer, address _burn, uint256 _unit) SuterBase(_transfer, _burn, _unit) public {
        token = ERC20(_token);
    }

    function fund(Utils.G1Point memory y, uint256 unitAmount, bytes memory encGuess) public {
        fundBase(y, unitAmount, encGuess);

        uint256 nativeAmount = toNativeAmount(unitAmount);

        // In order for the following to succeed, `msg.sender` have to first approve `this` to spend the nativeAmount.
        require(token.transferFrom(msg.sender, address(this), nativeAmount), "Native 'transferFrom' failed.");
    }

    function burn(Utils.G1Point memory y, uint256 unitAmount, Utils.G1Point memory u, bytes memory proof, bytes memory encGuess) public {
        uint256 nativeAmount = toNativeAmount(unitAmount);
        uint256 fee = nativeAmount * BURN_FEE_MULTIPLIER / BURN_FEE_DIVIDEND; 

        burnBase(y, unitAmount, u, proof, encGuess);

        if (fee > 0) {
            require(token.transfer(suterAgency, fee), "Fail to charge fee.");
            totalBurnFee = totalBurnFee + fee;
        }
        require(token.transfer(msg.sender, nativeAmount - fee), "Fail to transfer tokens.");
    }
}



File 2 of 10: BurnVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./Utils.sol";
import "./InnerProductVerifier.sol";

contract BurnVerifier {
    using Utils for uint256;
    using Utils for Utils.G1Point;

    InnerProductVerifier ip;

    struct BurnStatement {
        Utils.G1Point CLn;
        Utils.G1Point CRn;
        Utils.G1Point y;
        uint256 epoch; // or uint8?
        address sender;
        Utils.G1Point u;
    }

    struct BurnProof {
        Utils.G1Point BA;
        Utils.G1Point BS;

        Utils.G1Point[2] tCommits;
        uint256 tHat;
        uint256 mu;

        uint256 c;
        uint256 s_sk;
        uint256 s_b;
        uint256 s_tau;

        InnerProductVerifier.InnerProductProof ipProof;
    }

    constructor(address _ip) public {
        ip = InnerProductVerifier(_ip);
    }

    function verifyBurn(Utils.G1Point memory CLn, Utils.G1Point memory CRn, Utils.G1Point memory y, uint256 epoch, Utils.G1Point memory u, address sender, bytes memory proof) public view returns (bool) {
        BurnStatement memory statement; // WARNING: if this is called directly in the console,
        // and your strings are less than 64 characters, they will be padded on the right, not the left. should hopefully not be an issue,
        // as this will typically be called simply by the other contract. still though, beware
        statement.CLn = CLn;
        statement.CRn = CRn;
        statement.y = y;
        statement.epoch = epoch;
        statement.u = u;
        statement.sender = sender;
        BurnProof memory burnProof = unserialize(proof);
        return verify(statement, burnProof);
    }

    struct BurnAuxiliaries {
        uint256 y;
        uint256[32] ys;
        uint256 z;
        uint256[1] zs; // silly. just to match zether.
        uint256 zSum;
        uint256[32] twoTimesZSquared;
        uint256 x;
        uint256 t;
        uint256 k;
        Utils.G1Point tEval;
    }

    struct SigmaAuxiliaries {
        uint256 c;
        Utils.G1Point A_y;
        Utils.G1Point A_b;
        Utils.G1Point A_t;
        Utils.G1Point gEpoch;
        Utils.G1Point A_u;
    }

    struct IPAuxiliaries {
        Utils.G1Point P;
        Utils.G1Point u_x;
        Utils.G1Point[] hPrimes;
        Utils.G1Point hPrimeSum;
        uint256 o;
    }

    function gSum() internal pure returns (Utils.G1Point memory) {
        return Utils.G1Point(0x2257118d30fe5064dda298b2fac15cf96fd51f0e7e3df342d0aed40b8d7bb151, 0x0d4250e7509c99370e6b15ebfe4f1aa5e65a691133357901aa4b0641f96c80a8);
    }

    function verify(BurnStatement memory statement, BurnProof memory proof) internal view returns (bool) {
        uint256 statementHash = uint256(keccak256(abi.encode(statement.CLn, statement.CRn, statement.y, statement.epoch, statement.sender))).gMod(); // stacktoodeep?

        BurnAuxiliaries memory burnAuxiliaries;
        burnAuxiliaries.y = uint256(keccak256(abi.encode(statementHash, proof.BA, proof.BS))).gMod();
        burnAuxiliaries.ys[0] = 1;
        burnAuxiliaries.k = 1;
        for (uint256 i = 1; i < 32; i++) {
            burnAuxiliaries.ys[i] = burnAuxiliaries.ys[i - 1].gMul(burnAuxiliaries.y);
            burnAuxiliaries.k = burnAuxiliaries.k.gAdd(burnAuxiliaries.ys[i]);
        }
        burnAuxiliaries.z = uint256(keccak256(abi.encode(burnAuxiliaries.y))).gMod();
        burnAuxiliaries.zs = [burnAuxiliaries.z.gExp(2)];
        burnAuxiliaries.zSum = burnAuxiliaries.zs[0].gMul(burnAuxiliaries.z); // trivial sum
        burnAuxiliaries.k = burnAuxiliaries.k.gMul(burnAuxiliaries.z.gSub(burnAuxiliaries.zs[0])).gSub(burnAuxiliaries.zSum.gMul(2 ** 32).gSub(burnAuxiliaries.zSum));
        burnAuxiliaries.t = proof.tHat.gSub(burnAuxiliaries.k);
        for (uint256 i = 0; i < 32; i++) {
            burnAuxiliaries.twoTimesZSquared[i] = burnAuxiliaries.zs[0].gMul(2 ** i);
        }

        burnAuxiliaries.x = uint256(keccak256(abi.encode(burnAuxiliaries.z, proof.tCommits))).gMod();
        burnAuxiliaries.tEval = proof.tCommits[0].pMul(burnAuxiliaries.x).pAdd(proof.tCommits[1].pMul(burnAuxiliaries.x.gMul(burnAuxiliaries.x))); // replace with "commit"?

        SigmaAuxiliaries memory sigmaAuxiliaries;
        sigmaAuxiliaries.A_y = Utils.g().pMul(proof.s_sk).pAdd(statement.y.pMul(proof.c.gNeg()));
        sigmaAuxiliaries.A_b = Utils.g().pMul(proof.s_b).pAdd(statement.CRn.pMul(proof.s_sk).pAdd(statement.CLn.pMul(proof.c.gNeg())).pMul(burnAuxiliaries.zs[0]));
        sigmaAuxiliaries.A_t = Utils.g().pMul(burnAuxiliaries.t).pAdd(burnAuxiliaries.tEval.pNeg()).pMul(proof.c).pAdd(Utils.h().pMul(proof.s_tau)).pAdd(Utils.g().pMul(proof.s_b.gNeg()));
        sigmaAuxiliaries.gEpoch = Utils.mapInto("Suter", statement.epoch);
        sigmaAuxiliaries.A_u = sigmaAuxiliaries.gEpoch.pMul(proof.s_sk).pAdd(statement.u.pMul(proof.c.gNeg()));

        sigmaAuxiliaries.c = uint256(keccak256(abi.encode(burnAuxiliaries.x, sigmaAuxiliaries.A_y, sigmaAuxiliaries.A_b, sigmaAuxiliaries.A_t, sigmaAuxiliaries.A_u))).gMod();
        require(sigmaAuxiliaries.c == proof.c, string(abi.encodePacked("Sigma protocol challenge equality failure. Epoch: ", Utils.uint2str(statement.epoch))));

        IPAuxiliaries memory ipAuxiliaries;
        ipAuxiliaries.o = uint256(keccak256(abi.encode(sigmaAuxiliaries.c))).gMod();
        ipAuxiliaries.u_x = Utils.g().pMul(ipAuxiliaries.o);
        ipAuxiliaries.hPrimes = new Utils.G1Point[](32);
        for (uint256 i = 0; i < 32; i++) {
            ipAuxiliaries.hPrimes[i] = ip.hs(i).pMul(burnAuxiliaries.ys[i].gInv());
            ipAuxiliaries.hPrimeSum = ipAuxiliaries.hPrimeSum.pAdd(ipAuxiliaries.hPrimes[i].pMul(burnAuxiliaries.ys[i].gMul(burnAuxiliaries.z).gAdd(burnAuxiliaries.twoTimesZSquared[i])));
        }
        ipAuxiliaries.P = proof.BA.pAdd(proof.BS.pMul(burnAuxiliaries.x)).pAdd(gSum().pMul(burnAuxiliaries.z.gNeg())).pAdd(ipAuxiliaries.hPrimeSum);
        ipAuxiliaries.P = ipAuxiliaries.P.pAdd(Utils.h().pMul(proof.mu.gNeg()));
        ipAuxiliaries.P = ipAuxiliaries.P.pAdd(ipAuxiliaries.u_x.pMul(proof.tHat));
        require(ip.verifyInnerProduct(ipAuxiliaries.hPrimes, ipAuxiliaries.u_x, ipAuxiliaries.P, proof.ipProof, ipAuxiliaries.o), "Inner product proof verification failed.");

        return true;
    }

    function unserialize(bytes memory arr) internal pure returns (BurnProof memory proof) {
        proof.BA = Utils.G1Point(Utils.slice(arr, 0), Utils.slice(arr, 32));
        proof.BS = Utils.G1Point(Utils.slice(arr, 64), Utils.slice(arr, 96));

        proof.tCommits = [Utils.G1Point(Utils.slice(arr, 128), Utils.slice(arr, 160)), Utils.G1Point(Utils.slice(arr, 192), Utils.slice(arr, 224))];
        proof.tHat = uint256(Utils.slice(arr, 256));
        proof.mu = uint256(Utils.slice(arr, 288));

        proof.c = uint256(Utils.slice(arr, 320));
        proof.s_sk = uint256(Utils.slice(arr, 352));
        proof.s_b = uint256(Utils.slice(arr, 384));
        proof.s_tau = uint256(Utils.slice(arr, 416));

        InnerProductVerifier.InnerProductProof memory ipProof;
        ipProof.ls = new Utils.G1Point[](5);
        ipProof.rs = new Utils.G1Point[](5);
        for (uint256 i = 0; i < 5; i++) { // 2^5 = 32.
            ipProof.ls[i] = Utils.G1Point(Utils.slice(arr, 448 + i * 64), Utils.slice(arr, 480 + i * 64));
            ipProof.rs[i] = Utils.G1Point(Utils.slice(arr, 448 + (5 + i) * 64), Utils.slice(arr, 480 + (5 + i) * 64));
        }
        ipProof.a = uint256(Utils.slice(arr, 448 + 5 * 128));
        ipProof.b = uint256(Utils.slice(arr, 480 + 5 * 128));
        proof.ipProof = ipProof;

        return proof;
    }
}

File 3 of 10: Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.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) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 4 of 10: ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "./IERC20.sol";
import "./IERC20Metadata.sol";
import "./Context.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 {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * 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 Context, IERC20, IERC20Metadata {
    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The defaut value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name_, string memory symbol_) public {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override 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. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: 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 virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override 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 virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        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 `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);

        uint256 currentAllowance = _allowances[sender][_msgSender()];
        require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
        _approve(sender, _msgSender(), currentAllowance - 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 virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + 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 virtual returns (bool) {
        uint256 currentAllowance = _allowances[_msgSender()][spender];
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        _approve(_msgSender(), spender, currentAllowance - 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 virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += 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 virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `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 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        _balances[account] = accountBalance - amount;
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This 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 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

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

pragma solidity ^0.6.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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.
     *
     * IMPORTANT: 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);
}

File 6 of 10: IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.6.0;

import "./IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 7 of 10: InnerProductVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./Utils.sol";

contract InnerProductVerifier {
    using Utils for uint256;
    using Utils for Utils.G1Point;

    struct InnerProductStatement {
        Utils.G1Point[] hs; // "overridden" parameters.
        Utils.G1Point u;
        Utils.G1Point P;
    }

    struct InnerProductProof {
        Utils.G1Point[] ls;
        Utils.G1Point[] rs;
        uint256 a;
        uint256 b;
    }

    function verifyInnerProduct(Utils.G1Point[] memory hs, Utils.G1Point memory u, Utils.G1Point memory P, InnerProductProof memory proof, uint256 salt) public view returns (bool) {
        InnerProductStatement memory statement;
        statement.hs = hs;
        statement.u = u;
        statement.P = P;

        return verify(statement, proof, salt);
    }

    function gs(uint256 i) public pure returns (Utils.G1Point memory) {
        if (i == 0) return Utils.G1Point(0x0d1fff31f8dfb29333568b00628a0f92a752e8dee420dfede1be731810a807b9, 0x06c3001c74387dae9deddc75b76959ef5f98f1be48b0d9fc8ff6d7d76106b41b);
        if (i == 1) return Utils.G1Point(0x06e1b58cb1420e3d12020c5be2c4e48955efc64310ab10002164d0e2a767018e, 0x229facdebea78bd67f5b332bcdab7d692d0c4b18d77e92a8b3ffaee450c797c7);
        if (i == 2) return Utils.G1Point(0x22f32c65b43f3e770b793ea6e31c85d1aea2c41ea3204fc08a036004e5adef3a, 0x1d63e3737f864f05f62e2be0a6b7528b76cdabcda9703edc304c015480fb5543);
        if (i == 3) return Utils.G1Point(0x01df5e3e2818cfce850bd5d5f57872abc34b1315748e0280c4f0d3d6a40f94a9, 0x0d622581880ddba6a3911aa0df64f4fd816800c6dee483f07aa542a6e61534d5);
        if (i == 4) return Utils.G1Point(0x18d7f2117b1144f5035218384d817c6d1b4359497489a52bcf9d16c44624c1d0, 0x115f00d2f27917b5a3e8e6754451a4e990931516cf47e742949b8cbdda0e2c20);
        if (i == 5) return Utils.G1Point(0x093a9e9ba588d1b8eae48cf96b97def1fb8dccd519678520314e96d289ad1d11, 0x0f94a152edd0254ece896bc7e56708ba623c1ed3a27e4fd4c449f8e98fee1b5e);
        if (i == 6) return Utils.G1Point(0x0a7e8bc3cecaff1d9ec3e7d9c1fab7b5397bd6b6739c99bfe4bcb21d08d25934, 0x18d0114fa64774f712044e9a05b818fea4734db2b91fc7f049e120ce01c096be);
        if (i == 7) return Utils.G1Point(0x2095c16aea6e127aa3394d0124b545a45323708ae1c227575270d99b9900673a, 0x24c5a6afc36ef443197217591e084cdd69820401447163b5ab5f015801551a03);
        if (i == 8) return Utils.G1Point(0x041ee7d5aa6e191ba063876fda64b87728fa3ed39531400118b83372cbb5af75, 0x2dc2abc7d618ae4e1522f90d294c23627b6bc4f60093e8f07a7cd3869dac9836);
        if (i == 9) return Utils.G1Point(0x16dc75831b780dc5806dd5b8973f57f2f4ce8ad2a6bb152fbd9ccb58534115b4, 0x17b434c3b65a2f754c99f7bacf2f20bdcd7517a38e5eb301d2d88fe7735ebc9c);
        if (i == 10) return Utils.G1Point(0x18f1393a76e0af102ffeb380787ed950dc35b04b0cc6de1a6d806d4007b30dba, 0x1d640e43bab253bf176b69dffdb3ffc02640c591c392f400596155c8c3f668ef);
        if (i == 11) return Utils.G1Point(0x2bf3f58b4c957a8ae697aa57eb3f7428527fcb0c7e8d099efae80b97bde600e0, 0x14072f8bfdbe285b203cd0a2ebc1aed9ad1de309794226aee63c89397b187abf);
        if (i == 12) return Utils.G1Point(0x028eb6852c2827302aeb09def685b57bef74ff1a3ff72eda972e32b9ea80c32f, 0x1ba2dfb85a585de4b8a189f7b764f87c6f8e06c10d68d4493fc469504888837d);
        if (i == 13) return Utils.G1Point(0x19003e6b8f14f3583435527eac51a460c705dc6a042a2b7dd56b4f598af50886, 0x10e755ac3373f769e7e092f9eca276d911cd31833e82c70b8af09787e2c02d20);
        if (i == 14) return Utils.G1Point(0x0d493d4d49aa1a4fdf3bc3ba6d969b3e203741b3d570dbc511dd3171baf96f85, 0x1d103731795bcc57ddb8514e0e232446bfd9834f6a8ae9ff5235330d2a9e5ffa);
        if (i == 15) return Utils.G1Point(0x0ce438e766aae8c59b4006ee1749f40370fe5ec9fe29edce6b98e945915db97f, 0x02dba20dff83b373d2b47282e08d2c7883254a56701f2dbeea7ccc167ffb49a5);
        if (i == 16) return Utils.G1Point(0x05092110319650610a94fa0f9d50536404ba526380fc31b99ce95fbc1423a26f, 0x18a40146a4e79c2830d6d6e56314c538b0da4a2a72b7533e63f7d0a7e5ab2d22);
        if (i == 17) return Utils.G1Point(0x25b9ad9c4235b0a2e9f1b2ed20a5ca63814e1fb0eb95540c6f4f163c1a9fc2bd, 0x0a726ff7b655ad45468bcfd2d77f8aa0786ff3012d4edb77b5118f863dcdcbc0);
        if (i == 18) return Utils.G1Point(0x291ff28fa0a9840e230de0f0da725900bd18ce31d2369ffc80abbc4a77c1aff3, 0x1ffed5e9dffcd885ac867e2279836a11225548a8c253c47efe24f7d95a4bdd61);
        if (i == 19) return Utils.G1Point(0x0a01c96340d6bb4c94e028a522f74bef899d8f9d1a6d0b0d832f83275efa68de, 0x119c6a17ecb14721ac9eb331abccf2748868855fae43392391c37037d1b150a1);
        if (i == 20) return Utils.G1Point(0x2c846ad384d3ea063001f34fd60f0b8dc12b3b3ab7a5757f1d394f19850d8309, 0x1ff69942134c51e7315ccf1431e66fb5f70c24148c668f4fbe3861fbe535e39c);
        if (i == 21) return Utils.G1Point(0x0dafb5ae6accb6048e6dbc52f455c262dd2876b565792d68189618a3e630ade0, 0x236e97c592c19a2f2244f2938021671045787501e5a4a26de3580628ce37eb3b);
        if (i == 22) return Utils.G1Point(0x10df3e10a8d613058eae3278e2c80c3366c482354260f501447d15797de7378a, 0x10b25f7e075c93203ceba523afc44e0d5cd9e45a60b6dc11d2034180c40a004d);
        if (i == 23) return Utils.G1Point(0x1437b718d075d54da65adccdd3b6f758a5b76a9e5c5c7a13bf897a92e23fcde2, 0x0f0b988d70298608d02c73c410dc8b8bb6b95f0dde0dedcd5ea5692f0c07f3ed);
        if (i == 24) return Utils.G1Point(0x2705c71a95661231956d10845933f43cd973f4626e3a31dbf6287e01a00beb70, 0x27d09bd21d44269e2e7c85e1555fd351698eca14686d5aa969cb08e33db6691b);
        if (i == 25) return Utils.G1Point(0x1614dabf48099c315f244f8763f4b99ca2cef559781bf55e8e4d912d952edb4a, 0x16bf2f8fb1021b47be88ceb6fce08bf3b3a17026509cf9756c1a3fbf3b9d70bd);
        if (i == 26) return Utils.G1Point(0x21c448cfdcf007959812b2c5977cd4a808fa25408547e660c3fc12ed47501eb3, 0x14495c361cf9dc10222549bc258a76a20058f4795c2e65cd27f013c940b7dc7b);
        if (i == 27) return Utils.G1Point(0x1ac35f37ee0bfcb173d513ea7ac1daf5b46c6f70ce5f82a0396e7afac270ff35, 0x2f5f4480260b838ffcba9d34396fc116f75d1d5c24396ed4f7e01fd010ab9970);
        if (i == 28) return Utils.G1Point(0x0caaa12a18563703797d9be6ef74cbfb9e532cd027a1021f34ad337ce231e074, 0x2281c11389906c02bb15e995ffd6db136c3cdb4ec0829b88aec6db8dda05d5af);
        if (i == 29) return Utils.G1Point(0x1f3d91f1dfbbf01002a7e339ff6754b4ad2290493757475a062a75ec44bc3d50, 0x207b99884d9f7ca1e2f04457b90982ec6f8fb0a5b2ffd5b50d9cf4b2d850a920);
        if (i == 30) return Utils.G1Point(0x1fe58e4e4b1d155fb0a97dc9bae46f401edb2828dc4f96dafb86124cba424455, 0x01ad0a57feb7eeda4319a70ea56ded5e9fef71c78ff84413399d51f647d55113);
        if (i == 31) return Utils.G1Point(0x044e80195798557e870554d7025a8bc6b2ee9a05fa6ae016c3ab3b9e97af5769, 0x2c141a12135c4d14352fc60d851cdde147270f76405291b7c5d01da8f5dfed4d);
        if (i == 32) return Utils.G1Point(0x2883d31d84e605c858cf52260183f09d18bd55dc330f8bf12785e7a2563f8da4, 0x0e681e5c997f0bb609af7a95f920f23c4be78ded534832b514510518ede888b2);
        if (i == 33) return Utils.G1Point(0x2cdf5738c2690b263dfdc2b4235620d781bbff534d3363c4f3cfe5d1c67767c1, 0x15f4fb05e5facfd1988d61fd174a14b20e1dbe6ac37946e1527261be8742f5cf);
        if (i == 34) return Utils.G1Point(0x05542337765c24871e053bb8ec4e1baaca722f58b834426431c6d773788e9c66, 0x00e64d379c28d138d394f2cf9f0cc0b5a71e93a055bad23a2c6de74b217f3fac);
        if (i == 35) return Utils.G1Point(0x2efe9c1359531adb8a104242559a320593803c89a6ff0c6c493d7da5832603ab, 0x295898b3b86cf9e09e99d7f80e539078d3b5455bba60a5aa138b2995b75f0409);
        if (i == 36) return Utils.G1Point(0x2a3740ca39e35d23a5107fdae38209eaebdcd70ae740c873caf8b0b64d92db31, 0x05bab66121bccf807b1f776dc487057a5adf5f5791019996a2b7a2dbe1488797);
        if (i == 37) return Utils.G1Point(0x11ef5ef35b895540be39974ac6ad6697ef4337377f06092b6a668062bf0d8019, 0x1a42e3b4b73119a4be1dde36a8eaf553e88717cecb3fdfdc65ed2e728fda0782);
        if (i == 38) return Utils.G1Point(0x245aac96c5353f38ae92c6c17120e123c223b7eaca134658ebf584a8580ec096, 0x25ec55531155156663f8ba825a78f41f158def7b9d082e80259958277369ed08);
        if (i == 39) return Utils.G1Point(0x0fb13a72db572b1727954bb77d014894e972d7872678200a088febe8bd949986, 0x151af2ae374e02dec2b8c5dbde722ae7838d70ab4fd0857597b616a96a1db57c);
        if (i == 40) return Utils.G1Point(0x155fa64e4c8bf5f5aa53c1f5e44d961f688132c8545323d3bdc6c43a83220f89, 0x188507b59213816846bc9c763a93b52fb7ae8e8c8cc7549ce3358728415338a4);
        if (i == 41) return Utils.G1Point(0x28631525d5192140fd4fb04efbad8dcfddd5b8d0f5dc54442e5530989ef5b7fe, 0x0ad3a3d4845b4bc6a92563e72db2bc836168a295c56987c7bb1eea131a3760ac);
        if (i == 42) return Utils.G1Point(0x043b2963b1c5af8e2e77dfb89db7a0d907a40180929f3fd630a4a37811030b6d, 0x0721a4b292b41a3d948237bf076aabeedba377c43a10f78f368042ad155a3c91);
        if (i == 43) return Utils.G1Point(0x14bfb894e332921cf925f726f7c242a70dbd9366b68b50e14b618a86ecd45bd6, 0x09b1c50016fff7018a9483ce00b8ec3b6a0df36db21ae3b8282ca0b4be2e283c);
        if (i == 44) return Utils.G1Point(0x2758e65c03fdb27e58eb300bde8ada18372aa268b393ad5414e4db097ce9492d, 0x041f685536314ddd11441a3d7e01157f7ea7e474aae449dbba70c2edc70cd573);
        if (i == 45) return Utils.G1Point(0x191365dba9df566e0e6403fb9bcd6847c0964ea516c403fd88543a6a9b3fa1f2, 0x0ae815170115c7ce78323cbd9399735847552b379c2651af6fc29184e95eef7f);
        if (i == 46) return Utils.G1Point(0x027a2a874ba2ab278be899fe96528b6d39f9d090ef4511e68a3e4979bc18a526, 0x2272820981fe8a9f0f7c4910dd601cea6dd7045aa4d91843d3cf2afa959fbe68);
        if (i == 47) return Utils.G1Point(0x13feec071e0834433193b7be17ce48dec58d7610865d9876a08f91ea79c7e28d, 0x26325544133c7ec915c317ac358273eb2bf2e6b6119922d7f0ab0727e5eb9e64);
        if (i == 48) return Utils.G1Point(0x08e6096c8425c13b79e6fa38dffcc92c930d1d0bff9671303dbc0445e73c77bc, 0x03e884c8dc85f0d80baf968ae0516c1a7927808f83b4615665c67c59389db606);
        if (i == 49) return Utils.G1Point(0x1217ff3c630396cd92aa13aa6fee99880afc00f47162625274090278f09cbed3, 0x270b44f96accb061e9cad4a3341d72986677ed56157f3ba02520fdf484bb740d);
        if (i == 50) return Utils.G1Point(0x239128d2e007217328aae4e510c3d9fe1a3ef2b23212dfaf6f2dcb75ef08ed04, 0x2d5495372c759fdba858b7f6fa89a948eb4fd277bae9aebf9785c86ea3f9c07d);
        if (i == 51) return Utils.G1Point(0x305747313ea4d7d17bd14b69527094fa79bdc05c3cc837a668a97eb81cffd3d4, 0x0aa43bd7ad9090012e12f78ac3cb416903c2e1aabb61161ca261892465b3555d);
        if (i == 52) return Utils.G1Point(0x267742bd96caad20a76073d5060085103b7d29c88f0a0d842ef610472a1764ef, 0x0086485faeedd1ea8f6595b2edaf5f99044864271a178bd33e6d5b73b6d240a0);
        if (i == 53) return Utils.G1Point(0x00aed2e1ac448b854a44c7aa43cabb93d92316460c8f5eacb038f4cf554dfa01, 0x1b2ec095d370b234214a0c68fdfe8da1e06cbfdc5e889e2337ccb28c49089fcf);
        if (i == 54) return Utils.G1Point(0x06f37ac505236b2ed8c520ea36b0448229eb2f2536465b14e6e115dc810c6e39, 0x174db60e92b421e4d59c81e2c0666f7081067255c8e0d775e085278f34663490);
        if (i == 55) return Utils.G1Point(0x2af094e58a7961c4a1dba0685d8b01dacbb01f0fc0e7a648085a38aa380a7ab6, 0x108ade796501042dab10a83d878cf1deccf74e05edc92460b056d31f3e39fd53);
        if (i == 56) return Utils.G1Point(0x051ec23f1166a446caa4c8ff443470e98e753697fcceb4fbe5a49bf7a2db7199, 0x00f938707bf367e519d0c5efcdb61cc5a606901c0fbd4565abeeb5d020081d96);
        if (i == 57) return Utils.G1Point(0x1132459cf7287884b102467a71fad0992f1486178f7385ef159277b6e800239d, 0x257fedb1e126363af3fb3a80a4ad850d43041d64ef27cc5947730901f3019138);
        if (i == 58) return Utils.G1Point(0x14a571bbbb8d2a442855cde5fe6ed635d91668eded003d7698f9f744557887ea, 0x0f65f76e6fa6f6c7f765f947d905b015c3ad077219fc715c2ec40e37607c1041);
        if (i == 59) return Utils.G1Point(0x0e303c28b0649b95c624d01327a61fd144d29bfed6d3a1cf83216b45b78180cf, 0x229975c2e3aaba1d6203a5d94ea92605edb2af04f41e3783ec4e64755eeb1d1b);
        if (i == 60) return Utils.G1Point(0x05a62a2f1dfe368e81d9ae5fe150b9a57e0f85572194de27f48fec1c5f3b0dad, 0x200eb8097c91fe825adb0e3920e6bdff2e40114bd388298b85a0094a9a5bc654);
        if (i == 61) return Utils.G1Point(0x06545efc18dfc2f444e147c77ed572decd2b58d0668bbaaf0d31f1297cde6b99, 0x29ecbbeb81fe6c14279e9e46637ad286ba71e4c4e5da1416d8501e691f9e5bed);
        if (i == 62) return Utils.G1Point(0x045ce430f0713c29748e30d024cd703a5672633faebe1fd4d210b5af56a50e70, 0x0e3ec93722610f4599ffaac0db0c1b2bb446ff5aea5117710c271d1e64348844);
        if (i == 63) return Utils.G1Point(0x243de1ee802dd7a3ca9a991ec228fbbfb4973260f905b5106e5f738183d5cacd, 0x133d25bb8dc9f54932b9d6ee98e0432676f5278e9878967fbbd8f5dfc46df4f8);
    }

    function hs(uint256 i) public pure returns (Utils.G1Point memory) {
        if (i == 0) return Utils.G1Point(0x01d39aef1308fae84642befcdb6c07f655cc4d092f6a66f464cb9c959bff743a, 0x277420423ebed18174bd2730d4387b06c10958e564af6444333ac5b30767c59c);
        if (i == 1) return Utils.G1Point(0x2f1a6e72cf51c976df65f69457491bd852b4cf8a172183537dc413d0801bef0a, 0x0fc8845b156f86c3018d7a193c089c8d02ea38ba2cec11b1b6118a3b37f4cb08);
        if (i == 2) return Utils.G1Point(0x00f698cd9c34ea5fc62bd7d91c3a8b7f70bb12596d3c6d99b9be4d7acf2e72ea, 0x23abea6d9096d3c23f3aee1447570211efc5d2add2f310a2acaf3afc1faa0ed1);
        if (i == 3) return Utils.G1Point(0x06e93364d8080a84ab1dac7fa743b3f3f139f84c602cc67a899e3739abf11cc0, 0x2246590e06850a6f55b3e9bb81d7316fe7b08bef9f9a06d43b30226d626a979d);
        if (i == 4) return Utils.G1Point(0x1fb8f0bbb173c6d8f7ae2e1fa1e3770aa8c66fbed8d459d8e6fa972c990e0e22, 0x23d30ccd0b4747679bbd29620c3efb39ee1d7018b0281c448ad1501a5e04dc1a);
        if (i == 5) return Utils.G1Point(0x1b5f7c9fa9f3ef4adbed1f09bc6e151ba5e7c1d098c2d94e2dbe95897e6675cd, 0x23ff89ca0d326bd98629bf7ccf343ababdb330821a495b7624d8720fd1ead1e3);
        if (i == 6) return Utils.G1Point(0x2ffd2415cb4cd71a9f3cf4ed64d4a85d4d3eb06bfa10f98cb8a2ab7e2d96797c, 0x1d770c3d19238753457dd36280bd6685f6f214461a81aa95962f1c80a6c4168d);
        if (i == 7) return Utils.G1Point(0x2d344a9de673000e4108f8b6eb21b8cf39e223fad81cef47cd599b5e548a092b, 0x1abe37b046f84fa46b7629e432e298ae7dda657d2cdde851775431cab1d34402);
        if (i == 8) return Utils.G1Point(0x131bea29a212d81278492c44179c04f2a3f7e72151a0a4870b01e2fa96cdf84a, 0x0e5a783a7d6e044761fa10b801de33a1c4de8d4569f132b86a5be6aa13726127);
        if (i == 9) return Utils.G1Point(0x2e9de6196c9d4be4d765078245515d02b18ee6073ca0afb1afe98dcca2378d76, 0x1a5be81d26e9261e5072bb86f5cbd1dd8075316c8fec769ac839819a17ec3841);
        if (i == 10) return Utils.G1Point(0x21ccb04d241aa8108e9e5f2487fffe82debc69e4cff3a7ee292609fbe49cb6ad, 0x14d2e86d8bea6af2ad1cde303c9b2993a37c5b7bf0567278854ca666e61f2e80);
        if (i == 11) return Utils.G1Point(0x164314a3b09437cc1cd0f7726b8291be0bd293876093e51f989feab3238cfd85, 0x043bb4c392fbf35b9991d01ffaf6c59d7e72559ed7f338f85beebdf74ed3132f);
        if (i == 12) return Utils.G1Point(0x08a85c13ee191db8c043a21db38c016e27376d82063a93f8a6ff603b0f396433, 0x19be7f870a4bbd255c61ca01588bc3be2632c015753a3320309915e600d78a0a);
        if (i == 13) return Utils.G1Point(0x2090c3ab526ff54497f984b860682c77c0a89842f6612928cf4188c5c0f1ee20, 0x151a9c9fcdc438b3197d85ab51317d969d66e03fe26e05f6be466058cb8b7e65);
        if (i == 14) return Utils.G1Point(0x220b0c31ba1c84a2c1235d987e79d8fb1854fb59cce44719a13e4b83331da63b, 0x19a161498b4d63a027670174b424260b2180ccb02e05e4e061363ac3a87642da);
        if (i == 15) return Utils.G1Point(0x018eb881dd184f8abff3b91b50676a12945e205f200fdaf25ffb7e8c97385334, 0x1dea48b102351f75ce4977a6c3c908455a9e269aab69c3f66e642791052d0cfb);
        if (i == 16) return Utils.G1Point(0x07b0183a2450ccb5a001554ac3fe1a763bb69a0222316c1a553124a915cd0720, 0x282216c8c2711780ed3b24281fdd358d0e3d2e05e9cd1ab6842432f818a4a40c);
        if (i == 17) return Utils.G1Point(0x2b3f257e1258a3c2bda28be60fdc4cf2a74a19bb17d61783a91ec478d379e1a5, 0x1a8ddf17a83d7b89a6c7ae59601b736c4c7022f29c74700bd5d51cbd70b5051d);
        if (i == 18) return Utils.G1Point(0x0485fd181e30eef43c4356c6cdfb8957267795c838e6e64c52fd81a697dd8505, 0x17105695b4bfc555a55c8449182a6335584f971a0058172bd2b5441db3129843);
        if (i == 19) return Utils.G1Point(0x2008a80d7c60d7dc6e069b174efd31984a0933da7f89a574aae52e8805b40095, 0x052398552fb4706758b6eafb50bed493568670961058586735bca016e875e6ef);
        if (i == 20) return Utils.G1Point(0x119ff93e1bce3d5c7c57d1fea845e9335e04c729ec7a62ca2283d6c5dc0acc7c, 0x2042b68991a4d4c959df76947ef2594afb6735d760c3629825db8451b4830a3c);
        if (i == 21) return Utils.G1Point(0x0ed374dfa5daee92868812764c47ffd9c0c832abe09124f6f55283869d639eb7, 0x267767cb5017979990d9fa6db5f741de043afb70ee8a5e29045e926486f00858);
        if (i == 22) return Utils.G1Point(0x1c3786f37ee4f7eb9493551cea3c2a4e8ddcdd3c86e9f9ea2a41199efa1da476, 0x147d40e13345ec2f38975b09989d2c01954122796f83bfc19974ab647f754a32);
        if (i == 23) return Utils.G1Point(0x0040bf79ad3c473ffd4d7e15dbe0fa0a9b06e765a6d5adb372f98b8ea107f2c6, 0x17bf761b14f52da007532fcdf1bbdec180750af1b7b3804e29d6d45af62042f8);
        if (i == 24) return Utils.G1Point(0x01a9c26d59a9962250ce2b20b477884d11ce2c2404b749ceee59c51c2dcc0918, 0x1603d5448eb9b7528b247c0cdf8b0d9275322975bc7e4b13b8d0312cf032c467);
        if (i == 25) return Utils.G1Point(0x215ecf3e09641d5a38d4f510ed72e2ee586d4fbfc7e46411e1a3396f07b1e276, 0x28ece25edfb8c48631b861e838641f8e61e58afcf4e6c8f336c86fe5b7c0dfc9);
        if (i == 26) return Utils.G1Point(0x0beda6c3cbaec7226ed3bd6e0a27a626e0022b1afa820ac509e21b646f23dc60, 0x212f09e343da69ec34d90491282e69499c779973c0352126a38aabbf5783b288);
        if (i == 27) return Utils.G1Point(0x27f5c2199a6cebc34e3b5376b4db3ac6db08d2f302aa9b99f808e20a95e9ef8c, 0x0ccc4c0723e2a255e9b649eae9c16d72f4ddb97d088d7b3154c00e9a1dd94fe8);
        if (i == 28) return Utils.G1Point(0x2af5191d45c6ca76563c6f936f0cd2dcaa4311719675c2bb5f65d3df2270f636, 0x1252aca114b1fda7f43c06d1f2b60718e7bc99b8544138f9c67aad8dfca863d7);
        if (i == 29) return Utils.G1Point(0x13bdce5de7cf1c2250bac0be0d23d3be0140ce3838c8966ea2870e64b87adaee, 0x2f3770a6b5a9babcc5fa7cae8ffbb2a63ff312f2d3352e4fe8c173b12ff847e0);
        if (i == 30) return Utils.G1Point(0x18d1242b7bee604de29b4511814b02c8fd1519a4fc6daf9dbc95f8bb64ee097b, 0x0f828debef5bd4115c91f419718bdb59464bd8bb78fd0dc250d1efb1a51366df);
        if (i == 31) return Utils.G1Point(0x04b4102e8d3a2d3ba330257de8d18861db5652d685efb297d9c116eb1a7b1299, 0x08a3fd325f19ddebb53063d60fccdb8f0321fe41d4d93d98c65e05c9b4101aa0);
        if (i == 32) return Utils.G1Point(0x20f38c332b7117550a2462637fd38dfa08eb063e5bbc1838de2d8a933b052a5d, 0x0de3339a34e84bc8d57daf4fe55855a02df1c6fe4ce1cd07ca3060f67e1d75b2);
        if (i == 33) return Utils.G1Point(0x02f501714aa467e8b06ec808af8a3278f58faa7b87b678a1e36ee779adb01def, 0x1b8f1369d47a1d7b4da91b777bbcd7a2a4bde8ad09cc2eeeb9e8c0036ef5df47);
        if (i == 34) return Utils.G1Point(0x059c89b0e337c65e8132ac7c78f29d1a016edbff65da6663ef114f85bc414f20, 0x0b6e3d301ca62d0946299c6b79f2207479351ac27478901cdf5be144cf77435f);
        if (i == 35) return Utils.G1Point(0x02f51c34b66cd01304c185bcc087b9430beb0e6738e97491550740e18c262948, 0x27e42ced0bf3356a10e9685f1365a2ac3fdb3f3e89b9cd2f0309cd9ffcd6dfc0);
        if (i == 36) return Utils.G1Point(0x28c0affe0178e407e8196e3d0af3674aecc46a94342a97fec96d1eaa0e24ce3a, 0x1056737f11d45d9de7ff2d6de4ae31af9aa6a3ca2a0d56e5748059c7c39a02e7);
        if (i == 37) return Utils.G1Point(0x0100b2eb3ec56d3c557be418c4aabf0229ba4fb58c0bbb0756802e9f1573e245, 0x10a6e05da67b0cab1b2ded1f6e29f2c55279c738e18bbb91687fb046bac7789c);
        if (i == 38) return Utils.G1Point(0x0fe1fdb40a1c4b49772635241e37196fdca6a3cbd8ac2c550e1a48c90ec30029, 0x064ac2c20c146923131bab9ff316498a29fdce765a06c4a891f5b36993f52dba);
        if (i == 39) return Utils.G1Point(0x0c0aadc1d96e9b0b609e9f455c85ecf9506bbb7972f4adf58a3731f40cfd5d77, 0x1f3941c16c4c9da3c169c71abb9557d8b7b54d4b0998410d91d1b4a759f15028);
        if (i == 40) return Utils.G1Point(0x0a46308afef5a8af8f3b822aaa413d2961845a361f05cab5524144e74699cdec, 0x1035f4f2bf0b1ae6d0524d1309829c6d997cd7010650ca05a1bf585206e1aa3b);
        if (i == 41) return Utils.G1Point(0x1ccf854703b8608e10416032eaeadcc7ef236f2d1d33fec289d6db28db10b517, 0x1dbd7e3ed44a0fc339078bcb420b2641210a930a95eecc2aec0147a1abcbbb1a);
        if (i == 42) return Utils.G1Point(0x1408a19ef2793b8af811e95ffbdf901671a3b76bdc2203be5fde5475de4c54bc, 0x26431b0fbb7fb432a0edc0b247fee08d8f44a2abb0cb9b4b8a8a040bdea3cbf8);
        if (i == 43) return Utils.G1Point(0x2eb3aa4eb2234e4de8d30bcfeca595e758bc542da4ee111722fd6be47defd7e8, 0x1a7d7ab203974731e8f33dbbc7af481bbb64e47407e998d2d26dfa90a9dc321b);
        if (i == 44) return Utils.G1Point(0x1b6c0f4b954626f03f4fe59bc83ecc9ac2279d7d20746829583b66735cbb4830, 0x2eb200acc2138afec4e5f53438273760ca4d46bd0ebfa0155ae62a8055fee316);
        if (i == 45) return Utils.G1Point(0x0241820580d821b485c5d3f905cfc4a407881bbc7e041b4e50e2f628f88afc49, 0x2ee28fcaecd349babc91cb6fc9d65ed51dac6e2dd118898e3a0ee1bf0e94793d);
        if (i == 46) return Utils.G1Point(0x0b7b54391ce78ebf1aa3b4b2a75958f1702100aef8163810f89d0ad81c04ed78, 0x129075ea4b1ab58683019ab79340b2b090b9720721046332d8e0e80b2039406e);
        if (i == 47) return Utils.G1Point(0x18c8880c588c4dd3d657439a3357ff3bf0f44b9074d5d7aebb384fbac7e58090, 0x305de2ed95fe36ca48642098d98180b4ab92a03978fa6a038d80e546da989e6a);
        if (i == 48) return Utils.G1Point(0x00f185128b4341f79c914ef9739c830294df8da311891416babcc53e364ef245, 0x0a1ee67a755420fe0835770271142c883ebe3721140075a1677f2d57c6cec4b3);
        if (i == 49) return Utils.G1Point(0x2cf787f4957c6af6a6431d4a1577df0c71b6b44cca9771d8dee49ed83b024008, 0x25dfce7a0c6515b610f0b602d4083adfa436cbf1cce0e3dbec14338bee6ef501);
        if (i == 50) return Utils.G1Point(0x19934b0990d3b31864dcd3a9a7fe8ea20c87ef0abc3980c81035234b961b6c20, 0x2b8ca35cc74606b825937545131cb3c9248ec880b8df7c5eeac6d2be85aff646);
        if (i == 51) return Utils.G1Point(0x2adbdb8197cd82851b706df9c38a53950b1ba5953c8e7fcf3a037e4af817f706, 0x0cd2df6ffbde434614d0288d75ef6afd5d8f0c1b831d38b7de57785658b4bfe9);
        if (i == 52) return Utils.G1Point(0x1ee70de811fe6abb48823d75549e97bb81e3e98aea57e03b03164601b45a8889, 0x18ff1b711d742b30520fb8aeb174940d0e78ad926e0747cd3cf6cd9fdac1eb83);
        if (i == 53) return Utils.G1Point(0x2d831e2ba4c03354502c9ec8569eb4f1b7617b92e90e6bd2df617273793af02e, 0x1d838e04c75622032862a0ad64e997f99b64f9dce9dfd71b25214dc75371ef53);
        if (i == 54) return Utils.G1Point(0x0816128c1a69aacf266b28efd029bd12998f9abbfaa42c6b175d13452e81ec74, 0x084f00999de16016819beea6c19bade38d1802ac9ea2a59c70a94ab43676423f);
        if (i == 55) return Utils.G1Point(0x19fbf07d90fb1fc051cf76bc3ca6fb551463834456cac5a40a7e50dc492b6e07, 0x136cccfcd75ba252a946fc7e8d323ed9afdba4990600f97c8ea69ed72759c756);
        if (i == 56) return Utils.G1Point(0x2c0dca3a80d643d69ac2ccff2c16e727aa5eb81839a0b46e9b9f351941100e86, 0x0d90cee7e881d7484d76b29524af629358dc9795a2a789606fdec6d73e161435);
        if (i == 57) return Utils.G1Point(0x134b5d77b0c39945e9c8a7701bf5058183c5dc2010ab6ab6061243b2d748c4fa, 0x0d6297624431107091b2ccfc7c4f6964a14521ebecc4ca4687ad11ac439c9bc1);
        if (i == 58) return Utils.G1Point(0x1eff41015f3733fb8a295ff8a513d992d8723a159a294b5c444919ba22beb549, 0x0006941da956684261258a79a72fcf1b10e23e3f5844f808749fe10818cade97);
        if (i == 59) return Utils.G1Point(0x05d6227f2a9650a4b35412a9369f96155487d28e0f1827bce5fe2748e2b39c4f, 0x1640729260ba5f06592f23e8d2cf9b0a40ba5d090539b3d3f03e9a9bf8f6aad3);
        if (i == 60) return Utils.G1Point(0x166793ff28c5d31cf3c50fe736340af6cc6d6c80749bbcfd66db78ed80408e50, 0x2015c5c83fb2bb673aeb63e79928fa4c3a8ac6eb758b643e6bb9ff416ec6f3a5);
        if (i == 61) return Utils.G1Point(0x09ea2a4226678267f88c933e6f947fa16648a7710d169e715048e336d1b4129d, 0x26bb40f1b5f88a0a63acebd040aba0bbf85b03e04760bf5be723bd42d0f7d0ae);
        if (i == 62) return Utils.G1Point(0x0fe50825f829d35375a488cff7df34638241bce1a5b2f48c39635651e24c470d, 0x049b06661bb12c19ba643933a06d93035ecec6f53c61b8d4d2b39cc5c0459e68);
        if (i == 63) return Utils.G1Point(0x0b8871057f2a8bf0f794c099fba2481b9f39457d55d7e472e5dc994d69f0fbb8, 0x072c9e81fc2e118414a9fb6d9fff6e5b615f07fa980e3ce692a09bce95cc54f2);
    }

    struct IPAuxiliaries {
        uint256 o;
        uint256[] challenges;
        uint256[] otherExponents;
    }

    function verify(InnerProductStatement memory statement, InnerProductProof memory proof, uint256 salt) internal view returns (bool) {
        uint256 log_n = proof.ls.length;
        uint256 n = 2 ** log_n;

        IPAuxiliaries memory ipAuxiliaries; // for stacktoodeep
        ipAuxiliaries.o = salt; // could probably just access / overwrite the parameter directly.
        ipAuxiliaries.challenges = new uint256[](log_n);
        for (uint256 i = 0; i < log_n; i++) {
            ipAuxiliaries.o = uint256(keccak256(abi.encode(ipAuxiliaries.o, proof.ls[i], proof.rs[i]))).gMod(); // overwrites
            ipAuxiliaries.challenges[i] = ipAuxiliaries.o;
            statement.P = statement.P.pAdd(proof.ls[i].pMul(ipAuxiliaries.o.gExp(2)).pAdd(proof.rs[i].pMul(ipAuxiliaries.o.gInv().gExp(2))));
        }

        ipAuxiliaries.otherExponents = new uint256[](n);
        ipAuxiliaries.otherExponents[0] = 1;
        for (uint256 i = 0; i < log_n; i++) {
            ipAuxiliaries.otherExponents[0] = ipAuxiliaries.otherExponents[0].gMul(ipAuxiliaries.challenges[i]);
        }
        bool[] memory bitSet = new bool[](n);

        ipAuxiliaries.otherExponents[0] = ipAuxiliaries.otherExponents[0].gInv();
        for (uint256 i = 0; i < n / 2; ++i) {
            for (uint256 j = 0; (1 << j) + i < n; ++j) {
                uint256 i1 = i + (1 << j);
                if (!bitSet[i1]) {
                    uint256 temp = ipAuxiliaries.challenges[log_n - 1 - j].gExp(2);
                    ipAuxiliaries.otherExponents[i1] = ipAuxiliaries.otherExponents[i].gMul(temp);
                    bitSet[i1] = true;
                }
            }
        }

        Utils.G1Point memory gTemp;
        Utils.G1Point memory hTemp;
        for (uint256 i = 0; i < n; i++) {
            gTemp = gTemp.pAdd(gs(i).pMul(ipAuxiliaries.otherExponents[i]));
            hTemp = hTemp.pAdd(statement.hs[i].pMul(ipAuxiliaries.otherExponents[n - 1 - i]));
        }
        require(gTemp.pMul(proof.a).pAdd(hTemp.pMul(proof.b)).pAdd(statement.u.pMul(proof.a.gMul(proof.b))).pEqual(statement.P), "Inner product equality check failure.");

        return true;
    }
}


File 8 of 10: SuterBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./Utils.sol";
import "./TransferVerifier.sol";
import "./BurnVerifier.sol";

contract SuterBase {

    using Utils for uint256;
    using Utils for Utils.G1Point;

    address payable public suterAgency; 
    //Utils.G1Point public suterAgencyPublicKey;

    /* burn fee: 1/100 of burn amount */
    uint256 public BURN_FEE_MULTIPLIER = 1;
    uint256 public BURN_FEE_DIVIDEND = 100;
    /* transfer fee: 1/5 of gas */
    uint256 public TRANSFER_FEE_MULTIPLIER = 1;
    uint256 public TRANSFER_FEE_DIVIDEND = 5;

    //mapping(uint256 => bool) usedFeeStrategyNonces;


    TransferVerifier transferverifier;
    BurnVerifier burnverifier;
    //uint256 public epochLength = 12; 
    uint256 public epochLength = 24; 
    uint256 public epochBase = 0; // 0 for block, 1 for second (usually just for test)

    /* 
       The # of tokens that constitute one unit.
       Balances, funds, burns, and transfers are all interpreted in terms of unit, rather than token. 
    */
    uint256 public unit; 

    /*
       Max units that can be handled by suter.
       (No sload for constants...!)
    */
    uint256 public constant MAX = 2**32-1;

    uint256 public totalBalance = 0;
    uint256 public totalUsers = 0;
    uint256 public totalBurnFee = 0;
    uint256 public totalTransferFee = 0;
    uint256 public totalDeposits = 0;
    uint256 public totalFundCount = 0;
    

    mapping(bytes32 => Utils.G1Point[2]) acc; // main account mapping
    mapping(bytes32 => Utils.G1Point[2]) pending; // storage for pending transfers
    mapping(bytes32 => uint256) public lastRollOver;
    bytes32[] nonceSet; // would be more natural to use a mapping, but they can't be deleted / reset!
    uint256 public lastGlobalUpdate = 0; // will be also used as a proxy for "current epoch", seeing as rollovers will be anticipated
    //// not implementing account locking for now...revisit

    mapping(bytes32 => bytes) guess;

    event TransferOccurred(Utils.G1Point[] parties); // all parties will be notified, client can determine whether it was real or not.
    //// arg is still necessary for transfers---not even so much to know when you received a transfer, as to know when you got rolled over.
    event LogUint256(string label, uint256 indexed value);

    //constructor(address payable _suterAgency, Utils.G1Point memory _suterAgencyPublicKey, address _transfer, address _burn, uint256 _epochBase, uint256 _epochLength, uint256 _unit) public {
    constructor(address _transfer, address _burn, uint256 _unit) public {
        suterAgency = msg.sender;
        //suterAgencyPublicKey = _suterAgencyPublicKey;
        transferverifier = TransferVerifier(_transfer);
        burnverifier = BurnVerifier(_burn);
        //epochBase = _epochBase;
        //epochLength = _epochLength;
        unit = _unit;
    }

    function toUnitAmount(uint256 nativeAmount) internal view returns (uint256) {
        require(nativeAmount % unit == 0, "Native amount must be multiple of a unit.");
        uint256 amount = nativeAmount / unit;
        require(0 <= amount && amount <= MAX, "Amount out of range."); 
        return amount;
    }

    function toNativeAmount(uint256 unitAmount) internal view returns (uint256) {
        require(0 <= unitAmount && unitAmount <= MAX, "Amount out of range");
        return unitAmount * unit;
    }

    //function changeBurnFeeStrategy(uint256 multiplier, uint256 dividend, uint256 nonce, uint256 c, uint256 s) public {
        //require(!usedFeeStrategyNonces[nonce], "Fee strategy nonce has been used!");
        //usedFeeStrategyNonces[nonce] = true;

        //Utils.G1Point memory K = Utils.g().pMul(s).pAdd(suterAgencyPublicKey.pMul(c.gNeg()));
        //// Use block number to avoid replay attack
        //uint256 challenge = uint256(keccak256(abi.encode(address(this), multiplier, dividend, "burn", nonce, suterAgencyPublicKey, K))).gMod();
        ////uint256 challenge = uint256(keccak256(abi.encode(multiplier, dividend, "burn", block.number, suterAgencyPublicKey, K))).gMod();
        //require(challenge == c, string(abi.encodePacked("Invalid signature for changing the burn strategy.", Utils.uint2str(nonce))));
        //BURN_FEE_MULTIPLIER = multiplier;
        //BURN_FEE_DIVIDEND = dividend;
    //}

    function setBurnFeeStrategy(uint256 multiplier, uint256 dividend) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change burn fee strategy.");
        BURN_FEE_MULTIPLIER = multiplier;
        BURN_FEE_DIVIDEND = dividend;
    }

    //function changeTransferFeeStrategy(uint256 multiplier, uint256 dividend, uint256 nonce, uint256 c, uint256 s) public {
        //require(!usedFeeStrategyNonces[nonce], "Fee strategy nonce has been used!");
        //usedFeeStrategyNonces[nonce] = true;

        //Utils.G1Point memory K = Utils.g().pMul(s).pAdd(suterAgencyPublicKey.pMul(c.gNeg()));
        //// Use block number to avoid replay attack
        //uint256 challenge = uint256(keccak256(abi.encode(address(this), multiplier, dividend, "transfer", nonce, suterAgencyPublicKey, K))).gMod();
        //require(challenge == c, "Invalid signature for changing the transfer strategy.");
        //TRANSFER_FEE_MULTIPLIER = multiplier;
        //TRANSFER_FEE_DIVIDEND = dividend;
    //}

    function setTransferFeeStrategy(uint256 multiplier, uint256 dividend) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change transfer fee strategy.");
        TRANSFER_FEE_MULTIPLIER = multiplier;
        TRANSFER_FEE_DIVIDEND = dividend;
    }

    function setEpochBase (uint256 _epochBase) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change epoch base.");
        epochBase = _epochBase;
    }

    function setEpochLength (uint256 _epochLength) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change epoch length.");
        epochLength = _epochLength;
    }

    function setUnit (uint256 _unit) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change unit.");
        unit = _unit;
    }

    function setSuterAgency (address payable _suterAgency) public {
        require(msg.sender == suterAgency, "Permission denied: Only admin can change agency.");
        suterAgency = _suterAgency;
    }

    function register(Utils.G1Point memory y, uint256 c, uint256 s) public {
        // allows y to participate. c, s should be a Schnorr signature on "this"
        Utils.G1Point memory K = Utils.g().pMul(s).pAdd(y.pMul(c.gNeg()));
        uint256 challenge = uint256(keccak256(abi.encode(address(this), y, K))).gMod();
        require(challenge == c, "Invalid registration signature!");
        bytes32 yHash = keccak256(abi.encode(y));
        require(!registered(yHash), "Account already registered!");
        // pending[yHash] = [y, Utils.g()]; // "not supported" yet, have to do the below

        /*
            The following initial value of pending[yHash] is equivalent to an ElGamal encryption of m = 0, with nonce r = 1:
            (mG + ry, rG) --> (y, G)
            If we don't set pending in this way, then we can't differentiate two cases:
            1. The account is not registered (both acc and pending are 0, because `mapping` has initial value for all keys)
            2. The account has a total balance of 0 (both acc and pending are 0)

            With such a setting, we can guarantee that, once an account is registered, its `acc` and `pending` can never (crytographically negligible) BOTH equal to Point zero.
            NOTE: `pending` can be reset to Point zero after a roll over.
        */
        pending[yHash][0] = y;
        pending[yHash][1] = Utils.g();

        totalUsers = totalUsers + 1;
    }

    function registered(bytes32 yHash) public view returns (bool) {
        Utils.G1Point memory zero = Utils.G1Point(0, 0);
        Utils.G1Point[2][2] memory scratch = [acc[yHash], pending[yHash]];
        return !(scratch[0][0].pEqual(zero) && scratch[0][1].pEqual(zero) && scratch[1][0].pEqual(zero) && scratch[1][1].pEqual(zero));
    }

    /**
      Get the current balances of accounts. If the given `epoch` is larger than the last roll over epoch, the returned balances
      will include pending transfers. 
    */
    function getBalance(Utils.G1Point[] memory y, uint256 epoch) view public returns (Utils.G1Point[2][] memory accounts) {
        // in this function and others, i have to use public + memory (and hence, a superfluous copy from calldata)
        // only because calldata structs aren't yet supported by solidity. revisit this in the future.
        uint256 size = y.length;
        accounts = new Utils.G1Point[2][](size);
        for (uint256 i = 0; i < size; i++) {
            bytes32 yHash = keccak256(abi.encode(y[i]));
            accounts[i] = acc[yHash];
            if (lastRollOver[yHash] < epoch) {
                Utils.G1Point[2] memory scratch = pending[yHash];
                accounts[i][0] = accounts[i][0].pAdd(scratch[0]);
                accounts[i][1] = accounts[i][1].pAdd(scratch[1]);
            }
        }
    }

    function getAccountState (Utils.G1Point memory y) public view returns (Utils.G1Point[2] memory y_available, Utils.G1Point[2] memory y_pending) {
        bytes32 yHash = keccak256(abi.encode(y));
        y_available = acc[yHash];
        y_pending = pending[yHash];
        return (y_available, y_pending);
    }

    function getGuess (Utils.G1Point memory y) public view returns (bytes memory y_guess) {
        bytes32 yHash = keccak256(abi.encode(y));
        y_guess = guess[yHash];
        return y_guess;
    }

    function rollOver(bytes32 yHash) internal {
        uint256 e = 0;
        if (epochBase == 0)
            e = block.number / epochLength;
        else if (epochBase == 1)
            e = block.timestamp / epochLength;
        else
            revert("Invalid epoch base.");

        if (lastRollOver[yHash] < e) {
            Utils.G1Point[2][2] memory scratch = [acc[yHash], pending[yHash]];
            acc[yHash][0] = scratch[0][0].pAdd(scratch[1][0]);
            acc[yHash][1] = scratch[0][1].pAdd(scratch[1][1]);
            // acc[yHash] = scratch[0]; // can't do this---have to do the above instead (and spend 2 sloads / stores)---because "not supported". revisit
            delete pending[yHash]; // pending[yHash] = [Utils.G1Point(0, 0), Utils.G1Point(0, 0)];
            lastRollOver[yHash] = e;
        }
        if (lastGlobalUpdate < e) {
            lastGlobalUpdate = e;
            delete nonceSet;
        }
    }

    function fundBase(Utils.G1Point memory y, uint256 amount, bytes memory encGuess) internal {

        require(amount <= MAX && totalBalance + amount <= MAX, "Fund pushes contract past maximum value.");
        totalBalance += amount;
        totalDeposits += amount;
        totalFundCount += 1;

        bytes32 yHash = keccak256(abi.encode(y));
        require(registered(yHash), "Account not yet registered.");
        rollOver(yHash);

        Utils.G1Point memory scratch = pending[yHash][0];
        scratch = scratch.pAdd(Utils.g().pMul(amount));
        pending[yHash][0] = scratch;

        guess[yHash] = encGuess;
    }

    function burnBase(Utils.G1Point memory y, uint256 amount, Utils.G1Point memory u, bytes memory proof, bytes memory encGuess) internal {
        //require(msg.value == BURN_FEE, "0.03 ETH for the burn transaction is expected to be sent along.");

        require(totalBalance >= amount, "Burn fails the sanity check.");
        totalBalance -= amount;
        

        bytes32 yHash = keccak256(abi.encode(y));
        require(registered(yHash), "Account not yet registered.");
        rollOver(yHash);

        Utils.G1Point[2] memory scratch = pending[yHash];
        pending[yHash][0] = scratch[0].pAdd(Utils.g().pMul(amount.gNeg()));

        scratch = acc[yHash]; // simulate debit of acc---just for use in verification, won't be applied
        scratch[0] = scratch[0].pAdd(Utils.g().pMul(amount.gNeg()));
        bytes32 uHash = keccak256(abi.encode(u));
        for (uint256 i = 0; i < nonceSet.length; i++) {
            require(nonceSet[i] != uHash, "Nonce already seen!");
        }
        nonceSet.push(uHash);

        guess[yHash] = encGuess;

        require(burnverifier.verifyBurn(scratch[0], scratch[1], y, lastGlobalUpdate, u, msg.sender, proof), "Burn proof verification failed!");
        //suterAgency.transfer(BURN_FEE);
    }

    function transfer(Utils.G1Point[] memory C, Utils.G1Point memory D, 
                      Utils.G1Point[] memory y, Utils.G1Point memory u, 
                      bytes memory proof) public payable {

        uint256 startGas = gasleft();

        // TODO: check that sender and receiver should NOT be equal.
        uint256 size = y.length;
        Utils.G1Point[] memory CLn = new Utils.G1Point[](size);
        Utils.G1Point[] memory CRn = new Utils.G1Point[](size);
        require(C.length == size, "Input array length mismatch!");


        for (uint256 i = 0; i < size; i++) {
            bytes32 yHash = keccak256(abi.encode(y[i]));
            require(registered(yHash), "Account not yet registered.");
            rollOver(yHash);
            Utils.G1Point[2] memory scratch = pending[yHash];
            pending[yHash][0] = scratch[0].pAdd(C[i]);
            pending[yHash][1] = scratch[1].pAdd(D);
            // pending[yHash] = scratch; // can't do this, so have to use 2 sstores _anyway_ (as in above)

            scratch = acc[yHash];
            CLn[i] = scratch[0].pAdd(C[i]);
            CRn[i] = scratch[1].pAdd(D);
        }

        bytes32 uHash = keccak256(abi.encode(u));
        for (uint256 i = 0; i < nonceSet.length; i++) {
            require(nonceSet[i] != uHash, "Nonce already seen!");
        }
        nonceSet.push(uHash);

        require(transferverifier.verifyTransfer(CLn, CRn, C, D, y, lastGlobalUpdate, u, proof), "Transfer proof verification failed!");

        uint256 usedGas = startGas - gasleft();
        
        uint256 fee = (usedGas * TRANSFER_FEE_MULTIPLIER / TRANSFER_FEE_DIVIDEND) * tx.gasprice;
        if (fee > 0) {
            require(msg.value >= fee, "Not enough fee sent with the transfer transaction.");
            suterAgency.transfer(fee);
            totalTransferFee = totalTransferFee + fee;
        }
        msg.sender.transfer(msg.value - fee);

        emit TransferOccurred(y);
    }
}



File 9 of 10: TransferVerifier.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

import "./Utils.sol";
import "./InnerProductVerifier.sol";

contract TransferVerifier {
    using Utils for uint256;
    using Utils for Utils.G1Point;

    uint256 constant UNITY = 0x14a3074b02521e3b1ed9852e5028452693e87be4e910500c7ba9bbddb2f46edd; // primitive 2^28th root of unity modulo q.

    InnerProductVerifier ip;

    struct TransferStatement {
        Utils.G1Point[] CLn;
        Utils.G1Point[] CRn;
        Utils.G1Point[] C;
        Utils.G1Point D;
        Utils.G1Point[] y;
        uint256 epoch;
        Utils.G1Point u;
    }

    struct TransferProof {
        Utils.G1Point BA;
        Utils.G1Point BS;
        Utils.G1Point A;
        Utils.G1Point B;

        Utils.G1Point[] CLnG;
        Utils.G1Point[] CRnG;
        Utils.G1Point[] C_0G;
        Utils.G1Point[] DG;
        Utils.G1Point[] y_0G;
        Utils.G1Point[] gG;
        Utils.G1Point[] C_XG;
        Utils.G1Point[] y_XG;

        uint256[] f;
        uint256 z_A;
        uint256 z_C;
        uint256 z_E;

        Utils.G1Point[2] tCommits;
        uint256 tHat;
        uint256 mu;

        uint256 c;
        uint256 s_sk;
        uint256 s_r;
        uint256 s_b;
        uint256 s_tau;

        InnerProductVerifier.InnerProductProof ipProof;
    }

    constructor(address _ip) public {
        ip = InnerProductVerifier(_ip);
    }

    function verifyTransfer(Utils.G1Point[] memory CLn, Utils.G1Point[] memory CRn, Utils.G1Point[] memory C, Utils.G1Point memory D, Utils.G1Point[] memory y, uint256 epoch, Utils.G1Point memory u, bytes memory proof) public view returns (bool) {
        TransferStatement memory statement;
        statement.CLn = CLn; // do i need to allocate / set size?!
        statement.CRn = CRn;
        statement.C = C;
        statement.D = D;
        statement.y = y;
        statement.epoch = epoch;
        statement.u = u;
        TransferProof memory zetherProof = unserialize(proof);
        return verify(statement, zetherProof);
    }

    struct TransferAuxiliaries {
        uint256 y;
        uint256[64] ys;
        uint256 z;
        uint256[2] zs; // [z^2, z^3]
        uint256[64] twoTimesZSquared;
        uint256 zSum;
        uint256 x;
        uint256 t;
        uint256 k;
        Utils.G1Point tEval;
    }

    struct SigmaAuxiliaries {
        uint256 c;
        Utils.G1Point A_y;
        Utils.G1Point A_D;
        Utils.G1Point A_b;
        Utils.G1Point A_X;
        Utils.G1Point A_t;
        Utils.G1Point gEpoch;
        Utils.G1Point A_u;
    }

    struct AnonAuxiliaries {
        uint256 m;
        uint256 N;
        uint256 v;
        uint256 w;
        uint256 vPow;
        uint256 wPow;
        uint256[2][] f; // could just allocate extra space in the proof?
        uint256[2][] r; // each poly is an array of length N. evaluations of prods
        Utils.G1Point temp;
        Utils.G1Point CLnR;
        Utils.G1Point CRnR;
        Utils.G1Point[2][] CR;
        Utils.G1Point[2][] yR;
        Utils.G1Point C_XR;
        Utils.G1Point y_XR;
        Utils.G1Point gR;
        Utils.G1Point DR;
    }

    struct IPAuxiliaries {
        Utils.G1Point P;
        Utils.G1Point u_x;
        Utils.G1Point[] hPrimes;
        Utils.G1Point hPrimeSum;
        uint256 o;
    }

    function gSum() internal pure returns (Utils.G1Point memory) {
        return Utils.G1Point(0x00715f13ea08d6b51bedcde3599d8e12163e090921309d5aafc9b5bfaadbcda0, 0x27aceab598af7bf3d16ca9d40fe186c489382c21bb9d22b19cb3af8b751b959f);
    }

    function verify(TransferStatement memory statement, TransferProof memory proof) internal view returns (bool) {
        uint256 statementHash = uint256(keccak256(abi.encode(statement.CLn, statement.CRn, statement.C, statement.D, statement.y, statement.epoch))).gMod();

        AnonAuxiliaries memory anonAuxiliaries;
        anonAuxiliaries.v = uint256(keccak256(abi.encode(statementHash, proof.BA, proof.BS, proof.A, proof.B))).gMod();
        anonAuxiliaries.w = uint256(keccak256(abi.encode(anonAuxiliaries.v, proof.CLnG, proof.CRnG, proof.C_0G, proof.DG, proof.y_0G, proof.gG, proof.C_XG, proof.y_XG))).gMod();
        anonAuxiliaries.m = proof.f.length / 2;
        anonAuxiliaries.N = 2 ** anonAuxiliaries.m;
        anonAuxiliaries.f = new uint256[2][](2 * anonAuxiliaries.m);
        for (uint256 k = 0; k < 2 * anonAuxiliaries.m; k++) {
            anonAuxiliaries.f[k][1] = proof.f[k];
            anonAuxiliaries.f[k][0] = anonAuxiliaries.w.gSub(proof.f[k]);
        }

        for (uint256 k = 0; k < 2 * anonAuxiliaries.m; k++) {
            anonAuxiliaries.temp = anonAuxiliaries.temp.pAdd(ip.gs(k).pMul(anonAuxiliaries.f[k][1]));
            anonAuxiliaries.temp = anonAuxiliaries.temp.pAdd(ip.gs(k + 2 * anonAuxiliaries.m).pMul(anonAuxiliaries.f[k][1].gMul(anonAuxiliaries.w.gSub(anonAuxiliaries.f[k][1]))));
        }
        anonAuxiliaries.temp = anonAuxiliaries.temp.pAdd(ip.gs(4 * anonAuxiliaries.m).pMul(anonAuxiliaries.f[0][1].gMul(anonAuxiliaries.f[anonAuxiliaries.m][1])).pAdd(ip.gs(1 + 4 * anonAuxiliaries.m).pMul(anonAuxiliaries.f[0][0].gMul(anonAuxiliaries.f[anonAuxiliaries.m][0]))));
        require(proof.B.pMul(anonAuxiliaries.w).pAdd(proof.A).pEqual(anonAuxiliaries.temp.pAdd(Utils.h().pMul(proof.z_A))), "Recovery failure for B^w * A.");

        anonAuxiliaries.r = assemblePolynomials(anonAuxiliaries.f);

        anonAuxiliaries.CR = assembleConvolutions(anonAuxiliaries.r, statement.C);
        anonAuxiliaries.yR = assembleConvolutions(anonAuxiliaries.r, statement.y);
        for (uint256 i = 0; i < anonAuxiliaries.N; i++) {
            anonAuxiliaries.CLnR = anonAuxiliaries.CLnR.pAdd(statement.CLn[i].pMul(anonAuxiliaries.r[i][0]));
            anonAuxiliaries.CRnR = anonAuxiliaries.CRnR.pAdd(statement.CRn[i].pMul(anonAuxiliaries.r[i][0]));
        }
        anonAuxiliaries.vPow = 1;
        for (uint256 i = 0; i < anonAuxiliaries.N; i++) {
            anonAuxiliaries.C_XR = anonAuxiliaries.C_XR.pAdd(anonAuxiliaries.CR[i / 2][i % 2].pMul(anonAuxiliaries.vPow));
            anonAuxiliaries.y_XR = anonAuxiliaries.y_XR.pAdd(anonAuxiliaries.yR[i / 2][i % 2].pMul(anonAuxiliaries.vPow));
            if (i > 0) {
                anonAuxiliaries.vPow = anonAuxiliaries.vPow.gMul(anonAuxiliaries.v);
            }
        }
        anonAuxiliaries.wPow = 1;
        for (uint256 k = 0; k < anonAuxiliaries.m; k++) {
            anonAuxiliaries.CLnR = anonAuxiliaries.CLnR.pAdd(proof.CLnG[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.CRnR = anonAuxiliaries.CRnR.pAdd(proof.CRnG[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.CR[0][0] = anonAuxiliaries.CR[0][0].pAdd(proof.C_0G[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.DR = anonAuxiliaries.DR.pAdd(proof.DG[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.yR[0][0] = anonAuxiliaries.yR[0][0].pAdd(proof.y_0G[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.gR = anonAuxiliaries.gR.pAdd(proof.gG[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.C_XR = anonAuxiliaries.C_XR.pAdd(proof.C_XG[k].pMul(anonAuxiliaries.wPow.gNeg()));
            anonAuxiliaries.y_XR = anonAuxiliaries.y_XR.pAdd(proof.y_XG[k].pMul(anonAuxiliaries.wPow.gNeg()));

            anonAuxiliaries.wPow = anonAuxiliaries.wPow.gMul(anonAuxiliaries.w);
        }
        anonAuxiliaries.DR = anonAuxiliaries.DR.pAdd(statement.D.pMul(anonAuxiliaries.wPow));
        anonAuxiliaries.gR = anonAuxiliaries.gR.pAdd(Utils.g().pMul(anonAuxiliaries.wPow));

        TransferAuxiliaries memory zetherAuxiliaries;
        zetherAuxiliaries.y = uint256(keccak256(abi.encode(anonAuxiliaries.w))).gMod();
        zetherAuxiliaries.ys[0] = 1;
        zetherAuxiliaries.k = 1;
        for (uint256 i = 1; i < 64; i++) {
            zetherAuxiliaries.ys[i] = zetherAuxiliaries.ys[i - 1].gMul(zetherAuxiliaries.y);
            zetherAuxiliaries.k = zetherAuxiliaries.k.gAdd(zetherAuxiliaries.ys[i]);
        }
        zetherAuxiliaries.z = uint256(keccak256(abi.encode(zetherAuxiliaries.y))).gMod();
        zetherAuxiliaries.zs = [zetherAuxiliaries.z.gExp(2), zetherAuxiliaries.z.gExp(3)];        
        zetherAuxiliaries.zSum = zetherAuxiliaries.zs[0].gAdd(zetherAuxiliaries.zs[1]).gMul(zetherAuxiliaries.z);
        zetherAuxiliaries.k = zetherAuxiliaries.k.gMul(zetherAuxiliaries.z.gSub(zetherAuxiliaries.zs[0])).gSub(zetherAuxiliaries.zSum.gMul(2 ** 32).gSub(zetherAuxiliaries.zSum));
        zetherAuxiliaries.t = proof.tHat.gSub(zetherAuxiliaries.k); // t = tHat - delta(y, z)
        for (uint256 i = 0; i < 32; i++) {
            zetherAuxiliaries.twoTimesZSquared[i] = zetherAuxiliaries.zs[0].gMul(2 ** i);
            zetherAuxiliaries.twoTimesZSquared[i + 32] = zetherAuxiliaries.zs[1].gMul(2 ** i);
        }

        zetherAuxiliaries.x = uint256(keccak256(abi.encode(zetherAuxiliaries.z, proof.tCommits))).gMod();
        zetherAuxiliaries.tEval = proof.tCommits[0].pMul(zetherAuxiliaries.x).pAdd(proof.tCommits[1].pMul(zetherAuxiliaries.x.gMul(zetherAuxiliaries.x))); // replace with "commit"?

        SigmaAuxiliaries memory sigmaAuxiliaries;
        sigmaAuxiliaries.A_y = anonAuxiliaries.gR.pMul(proof.s_sk).pAdd(anonAuxiliaries.yR[0][0].pMul(proof.c.gNeg()));
        sigmaAuxiliaries.A_D = Utils.g().pMul(proof.s_r).pAdd(statement.D.pMul(proof.c.gNeg())); // add(mul(anonAuxiliaries.gR, proof.s_r), mul(anonAuxiliaries.DR, proof.c.neg()));
        sigmaAuxiliaries.A_b = Utils.g().pMul(proof.s_b).pAdd(anonAuxiliaries.DR.pMul(zetherAuxiliaries.zs[0].gNeg()).pAdd(anonAuxiliaries.CRnR.pMul(zetherAuxiliaries.zs[1])).pMul(proof.s_sk).pAdd(anonAuxiliaries.CR[0][0].pMul(zetherAuxiliaries.zs[0].gNeg()).pAdd(anonAuxiliaries.CLnR.pMul(zetherAuxiliaries.zs[1])).pMul(proof.c.gNeg())));
        sigmaAuxiliaries.A_X = anonAuxiliaries.y_XR.pMul(proof.s_r).pAdd(anonAuxiliaries.C_XR.pMul(proof.c.gNeg()));
        sigmaAuxiliaries.A_t = Utils.g().pMul(zetherAuxiliaries.t).pAdd(zetherAuxiliaries.tEval.pNeg()).pMul(proof.c.gMul(anonAuxiliaries.wPow)).pAdd(Utils.h().pMul(proof.s_tau)).pAdd(Utils.g().pMul(proof.s_b.gNeg()));
        sigmaAuxiliaries.gEpoch = Utils.mapInto("Suter", statement.epoch);
        sigmaAuxiliaries.A_u = sigmaAuxiliaries.gEpoch.pMul(proof.s_sk).pAdd(statement.u.pMul(proof.c.gNeg()));

        sigmaAuxiliaries.c = uint256(keccak256(abi.encode(zetherAuxiliaries.x, sigmaAuxiliaries.A_y, sigmaAuxiliaries.A_D, sigmaAuxiliaries.A_b, sigmaAuxiliaries.A_X, sigmaAuxiliaries.A_t, sigmaAuxiliaries.A_u))).gMod();
        require(sigmaAuxiliaries.c == proof.c, string(abi.encodePacked("Sigma protocol challenge equality failure. Epoch: ", Utils.uint2str(statement.epoch))));

        IPAuxiliaries memory ipAuxiliaries;
        ipAuxiliaries.o = uint256(keccak256(abi.encode(sigmaAuxiliaries.c))).gMod();
        ipAuxiliaries.u_x = Utils.g().pMul(ipAuxiliaries.o);
        ipAuxiliaries.hPrimes = new Utils.G1Point[](64);
        for (uint256 i = 0; i < 64; i++) {
            ipAuxiliaries.hPrimes[i] = ip.hs(i).pMul(zetherAuxiliaries.ys[i].gInv());
            ipAuxiliaries.hPrimeSum = ipAuxiliaries.hPrimeSum.pAdd(ipAuxiliaries.hPrimes[i].pMul(zetherAuxiliaries.ys[i].gMul(zetherAuxiliaries.z).gAdd(zetherAuxiliaries.twoTimesZSquared[i])));
        }
        ipAuxiliaries.P = proof.BA.pAdd(proof.BS.pMul(zetherAuxiliaries.x)).pAdd(gSum().pMul(zetherAuxiliaries.z.gNeg())).pAdd(ipAuxiliaries.hPrimeSum);
        ipAuxiliaries.P = ipAuxiliaries.P.pAdd(Utils.h().pMul(proof.mu.gNeg()));
        ipAuxiliaries.P = ipAuxiliaries.P.pAdd(ipAuxiliaries.u_x.pMul(proof.tHat));
        require(ip.verifyInnerProduct(ipAuxiliaries.hPrimes, ipAuxiliaries.u_x, ipAuxiliaries.P, proof.ipProof, ipAuxiliaries.o), "Inner product proof verification failed.");

        return true;
    }

    function assemblePolynomials(uint256[2][] memory f) internal view returns (uint256[2][] memory result) {
        uint256 m = f.length / 2;
        uint256 N = 2 ** m;
        result = new uint256[2][](N);
        for (uint256 i = 0; i < 2; i++) {
            uint256[] memory half = recursivePolynomials(i * m, (i + 1) * m, 1, f);
            for (uint256 j = 0; j < N; j++) {
                result[j][i] = half[j];
            }
        }
    }

    function recursivePolynomials(uint256 baseline, uint256 current, uint256 accum, uint256[2][] memory f) internal view returns (uint256[] memory result) {
        // have to do a bunch of re-allocating because solidity won't let me have something which is internal and also modifies (internal) state. (?)
        uint256 size = 2 ** (current - baseline); // size is at least 2...
        result = new uint256[](size);

        if (current == baseline) {
            result[0] = accum;
            return result;
        }
        current = current - 1;

        uint256[] memory left = recursivePolynomials(baseline, current, accum.gMul(f[current][0]), f);
        uint256[] memory right = recursivePolynomials(baseline, current, accum.gMul(f[current][1]), f);
        for (uint256 i = 0; i < size / 2; i++) {
            result[i] = left[i];
            result[i + size / 2] = right[i];
        }
    }

    function assembleConvolutions(uint256[2][] memory exponent, Utils.G1Point[] memory base) internal view returns (Utils.G1Point[2][] memory result) {
        // exponent is two "rows" (actually columns).
        // will return two rows, each of half the length of the exponents;
        // namely, we will return the Hadamards of "base" by the even circular shifts of "exponent"'s rows.
        uint256 size = exponent.length;
        uint256 half = size / 2;
        result = new Utils.G1Point[2][](half); // assuming that this is necessary even when return is declared up top

        Utils.G1Point[] memory base_fft = fft(base, false);

        uint256[] memory exponent_fft = new uint256[](size);
        for (uint256 i = 0; i < 2; i++) {
            for (uint256 j = 0; j < size; j++) {
                exponent_fft[j] = exponent[(size - j) % size][i]; // convolutional flip plus copy
            }

            exponent_fft = fft(exponent_fft);
            Utils.G1Point[] memory inverse_fft = new Utils.G1Point[](half);
            uint256 compensation = 2;
            compensation = compensation.gInv();
            for (uint256 j = 0; j < half; j++) { // Hadamard
                inverse_fft[j] = base_fft[j].pMul(exponent_fft[j]).pAdd(base_fft[j + half].pMul(exponent_fft[j + half])).pMul(compensation);
            }

            inverse_fft = fft(inverse_fft, true);
            for (uint256 j = 0; j < half; j++) {
                result[j][i] = inverse_fft[j];
            }
        }
    }

    function fft(Utils.G1Point[] memory input, bool inverse) internal view returns (Utils.G1Point[] memory result) {
        uint256 size = input.length;
        if (size == 1) {
            return input;
        }
        require(size % 2 == 0, "Input size is not a power of 2!");

        uint256 omega = UNITY.gExp(2**28 / size);
        uint256 compensation = 1;
        if (inverse) {
            omega = omega.gInv();
            compensation = 2;
        }
        compensation = compensation.gInv();
        Utils.G1Point[] memory even = fft(extract(input, 0), inverse);
        Utils.G1Point[] memory odd = fft(extract(input, 1), inverse);
        uint256 omega_run = 1;
        result = new Utils.G1Point[](size);
        for (uint256 i = 0; i < size / 2; i++) {
            Utils.G1Point memory temp = odd[i].pMul(omega_run);
            result[i] = even[i].pAdd(temp).pMul(compensation);
            result[i + size / 2] = even[i].pAdd(temp.pNeg()).pMul(compensation);
            omega_run = omega_run.gMul(omega);
        }
    }

    function extract(Utils.G1Point[] memory input, uint256 parity) internal pure returns (Utils.G1Point[] memory result) {
        result = new Utils.G1Point[](input.length / 2);
        for (uint256 i = 0; i < input.length / 2; i++) {
            result[i] = input[2 * i + parity];
        }
    }

    function fft(uint256[] memory input) internal view returns (uint256[] memory result) {
        uint256 size = input.length;
        if (size == 1) {
            return input;
        }
        require(size % 2 == 0, "Input size is not a power of 2!");

        uint256 omega = UNITY.gExp(2**28 / size);
        uint256[] memory even = fft(extract(input, 0));
        uint256[] memory odd = fft(extract(input, 1));
        uint256 omega_run = 1;
        result = new uint256[](size);
        for (uint256 i = 0; i < size / 2; i++) {
            uint256 temp = odd[i].gMul(omega_run);
            result[i] = even[i].gAdd(temp);
            result[i + size / 2] = even[i].gSub(temp);
            omega_run = omega_run.gMul(omega);
        }
    }

    function extract(uint256[] memory input, uint256 parity) internal pure returns (uint256[] memory result) {
        result = new uint256[](input.length / 2);
        for (uint256 i = 0; i < input.length / 2; i++) {
            result[i] = input[2 * i + parity];
        }
    }

    function unserialize(bytes memory arr) internal pure returns (TransferProof memory proof) {
        proof.BA = Utils.G1Point(Utils.slice(arr, 0), Utils.slice(arr, 32));
        proof.BS = Utils.G1Point(Utils.slice(arr, 64), Utils.slice(arr, 96));
        proof.A = Utils.G1Point(Utils.slice(arr, 128), Utils.slice(arr, 160));
        proof.B = Utils.G1Point(Utils.slice(arr, 192), Utils.slice(arr, 224));

        uint256 m = (arr.length - 1472) / 576;
        proof.CLnG = new Utils.G1Point[](m);
        proof.CRnG = new Utils.G1Point[](m);
        proof.C_0G = new Utils.G1Point[](m);
        proof.DG = new Utils.G1Point[](m);
        proof.y_0G = new Utils.G1Point[](m);
        proof.gG = new Utils.G1Point[](m);
        proof.C_XG = new Utils.G1Point[](m);
        proof.y_XG = new Utils.G1Point[](m);
        proof.f = new uint256[](2 * m);
        for (uint256 k = 0; k < m; k++) {
            proof.CLnG[k] = Utils.G1Point(Utils.slice(arr, 256 + k * 64), Utils.slice(arr, 288 + k * 64));
            proof.CRnG[k] = Utils.G1Point(Utils.slice(arr, 256 + (m + k) * 64), Utils.slice(arr, 288 + (m + k) * 64));
            proof.C_0G[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 128 + k * 64), Utils.slice(arr, 288 + m * 128 + k * 64));
            proof.DG[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 192 + k * 64), Utils.slice(arr, 288 + m * 192 + k * 64));
            proof.y_0G[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 256 + k * 64), Utils.slice(arr, 288 + m * 256 + k * 64));
            proof.gG[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 320 + k * 64), Utils.slice(arr, 288 + m * 320 + k * 64));
            proof.C_XG[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 384 + k * 64), Utils.slice(arr, 288 + m * 384 + k * 64));
            proof.y_XG[k] = Utils.G1Point(Utils.slice(arr, 256 + m * 448 + k * 64), Utils.slice(arr, 288 + m * 448 + k * 64));
            proof.f[k] = uint256(Utils.slice(arr, 256 + m * 512 + k * 32));
            proof.f[k + m] = uint256(Utils.slice(arr, 256 + m * 544 + k * 32));
        }
        uint256 starting = m * 576;
        proof.z_A = uint256(Utils.slice(arr, 256 + starting));

        proof.tCommits = [Utils.G1Point(Utils.slice(arr, 288 + starting), Utils.slice(arr, 320 + starting)), Utils.G1Point(Utils.slice(arr, 352 + starting), Utils.slice(arr, 384 + starting))];
        proof.tHat = uint256(Utils.slice(arr, 416 + starting));
        proof.mu = uint256(Utils.slice(arr, 448 + starting));

        proof.c = uint256(Utils.slice(arr, 480 + starting));
        proof.s_sk = uint256(Utils.slice(arr, 512 + starting));
        proof.s_r = uint256(Utils.slice(arr, 544 + starting));
        proof.s_b = uint256(Utils.slice(arr, 576 + starting));
        proof.s_tau = uint256(Utils.slice(arr, 608 + starting));

        InnerProductVerifier.InnerProductProof memory ipProof;
        ipProof.ls = new Utils.G1Point[](6);
        ipProof.rs = new Utils.G1Point[](6);
        for (uint256 i = 0; i < 6; i++) { // 2^6 = 64.
            ipProof.ls[i] = Utils.G1Point(Utils.slice(arr, 640 + starting + i * 64), Utils.slice(arr, 672 + starting + i * 64));
            ipProof.rs[i] = Utils.G1Point(Utils.slice(arr, 640 + starting + (6 + i) * 64), Utils.slice(arr, 672 + starting + (6 + i) * 64));
        }
        ipProof.a = uint256(Utils.slice(arr, 640 + starting + 6 * 128));
        ipProof.b = uint256(Utils.slice(arr, 672 + starting + 6 * 128));
        proof.ipProof = ipProof;

        return proof;
    }
}

File 10 of 10: Utils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;

library Utils {

    uint256 constant GROUP_ORDER = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001;
    uint256 constant FIELD_ORDER = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47;

    function gAdd(uint256 x, uint256 y) internal pure returns (uint256) {
        return addmod(x, y, GROUP_ORDER);
    }

    function gMul(uint256 x, uint256 y) internal pure returns (uint256) {
        return mulmod(x, y, GROUP_ORDER);
    }

    function gInv(uint256 x) internal view returns (uint256) {
        return gExp(x, GROUP_ORDER - 2);
    }

    function gMod(uint256 x) internal pure returns (uint256) {
        return x % GROUP_ORDER;
    }

    function gSub(uint256 x, uint256 y) internal pure returns (uint256) {
        return x >= y ? x - y : GROUP_ORDER - y + x;
    }

    function gNeg(uint256 x) internal pure returns (uint256) {
        return GROUP_ORDER - x;
    }

    function gExp(uint256 base, uint256 exponent) internal view returns (uint256 output) {
        uint256 order = GROUP_ORDER;
        assembly {
            let m := mload(0x40)
            mstore(m, 0x20)
            mstore(add(m, 0x20), 0x20)
            mstore(add(m, 0x40), 0x20)
            mstore(add(m, 0x60), base)
            mstore(add(m, 0x80), exponent)
            mstore(add(m, 0xa0), order)
            if iszero(staticcall(gas(), 0x05, m, 0xc0, m, 0x20)) { // staticcall or call?
                revert(0, 0)
            }
            output := mload(m)
        }
    }

    function fieldExp(uint256 base, uint256 exponent) internal view returns (uint256 output) { // warning: mod p, not q
        uint256 order = FIELD_ORDER;
        assembly {
            let m := mload(0x40)
            mstore(m, 0x20)
            mstore(add(m, 0x20), 0x20)
            mstore(add(m, 0x40), 0x20)
            mstore(add(m, 0x60), base)
            mstore(add(m, 0x80), exponent)
            mstore(add(m, 0xa0), order)
            if iszero(staticcall(gas(), 0x05, m, 0xc0, m, 0x20)) { // staticcall or call?
                revert(0, 0)
            }
            output := mload(m)
        }
    }

    struct G1Point {
        bytes32 x;
        bytes32 y;
    }

    function pAdd(G1Point memory p1, G1Point memory p2) internal view returns (G1Point memory r) {
        assembly {
            let m := mload(0x40)
            mstore(m, mload(p1))
            mstore(add(m, 0x20), mload(add(p1, 0x20)))
            mstore(add(m, 0x40), mload(p2))
            mstore(add(m, 0x60), mload(add(p2, 0x20)))
            // Address of the desired EC ADD instruction: 0x06
            // Reference: https://eips.ethereum.org/EIPS/eip-196#implementation
            if iszero(staticcall(gas(), 0x06, m, 0x80, r, 0x40)) {
                revert(0, 0)
            }
        }
    }

    function pMul(G1Point memory p, uint256 s) internal view returns (G1Point memory r) {
        assembly {
            let m := mload(0x40)
            mstore(m, mload(p))
            mstore(add(m, 0x20), mload(add(p, 0x20)))
            mstore(add(m, 0x40), s)
            // Address of the desired EC MUL instruction: 0x07
            // Reference: https://eips.ethereum.org/EIPS/eip-196#implementation
            if iszero(staticcall(gas(), 0x07, m, 0x60, r, 0x40)) {
                revert(0, 0)
            }
        }
    }

    function pNeg(G1Point memory p) internal pure returns (G1Point memory) {
        return G1Point(p.x, bytes32(FIELD_ORDER - uint256(p.y))); // p.y should already be reduced mod P?
    }

    function pEqual(G1Point memory p1, G1Point memory p2) internal pure returns (bool) {
        return p1.x == p2.x && p1.y == p2.y;
    }

    function g() internal pure returns (G1Point memory) {
        return G1Point(0x077da99d806abd13c9f15ece5398525119d11e11e9836b2ee7d23f6159ad87d4, 0x01485efa927f2ad41bff567eec88f32fb0a0f706588b4e41a8d587d008b7f875);
    }

    function h() internal pure returns (G1Point memory) {
        return G1Point(0x01b7de3dcf359928dd19f643d54dc487478b68a5b2634f9f1903c9fb78331aef, 0x2bda7d3ae6a557c716477c108be0d0f94abc6c4dc6b1bd93caccbcceaaa71d6b);
    }

    function mapInto(uint256 seed) internal view returns (G1Point memory) {
        uint256 y;
        while (true) {
            uint256 ySquared = fieldExp(seed, 3) + 3; // addmod instead of add: waste of gas, plus function overhead cost
            y = fieldExp(ySquared, (FIELD_ORDER + 1) / 4);
            if (fieldExp(y, 2) == ySquared) {
                break;
            }
            seed += 1;
        }
        return G1Point(bytes32(seed), bytes32(y));
    }

    function mapInto(string memory input) internal view returns (G1Point memory) {
        return mapInto(uint256(keccak256(abi.encodePacked(input))) % FIELD_ORDER);
    }

    function mapInto(string memory input, uint256 i) internal view returns (G1Point memory) {
        return mapInto(uint256(keccak256(abi.encodePacked(input, i))) % FIELD_ORDER);
    }

    function slice(bytes memory input, uint256 start) internal pure returns (bytes32 result) {
        assembly {
            let m := mload(0x40)
            mstore(m, mload(add(add(input, 0x20), start))) // why only 0x20?
            result := mload(m)
        }
    }

    function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint j = _i;
        uint len;
        while (j != 0) {
            len++;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint k = len - 1;
        while (_i != 0) {
            bstr[k--] = byte(uint8(48 + _i % 10));
            _i /= 10;
        }
        return string(bstr);
    }
}


Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_transfer","type":"address"},{"internalType":"address","name":"_burn","type":"address"},{"internalType":"uint256","name":"_unit","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"label","type":"string"},{"indexed":true,"internalType":"uint256","name":"value","type":"uint256"}],"name":"LogUint256","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"indexed":false,"internalType":"struct Utils.G1Point[]","name":"parties","type":"tuple[]"}],"name":"TransferOccurred","type":"event"},{"inputs":[],"name":"BURN_FEE_DIVIDEND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"BURN_FEE_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_FEE_DIVIDEND","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_FEE_MULTIPLIER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"y","type":"tuple"},{"internalType":"uint256","name":"unitAmount","type":"uint256"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"u","type":"tuple"},{"internalType":"bytes","name":"proof","type":"bytes"},{"internalType":"bytes","name":"encGuess","type":"bytes"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"epochBase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epochLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"y","type":"tuple"},{"internalType":"uint256","name":"unitAmount","type":"uint256"},{"internalType":"bytes","name":"encGuess","type":"bytes"}],"name":"fund","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"y","type":"tuple"}],"name":"getAccountState","outputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[2]","name":"y_available","type":"tuple[2]"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[2]","name":"y_pending","type":"tuple[2]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[]","name":"y","type":"tuple[]"},{"internalType":"uint256","name":"epoch","type":"uint256"}],"name":"getBalance","outputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[2][]","name":"accounts","type":"tuple[2][]"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"y","type":"tuple"}],"name":"getGuess","outputs":[{"internalType":"bytes","name":"y_guess","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastGlobalUpdate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"lastRollOver","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"y","type":"tuple"},{"internalType":"uint256","name":"c","type":"uint256"},{"internalType":"uint256","name":"s","type":"uint256"}],"name":"register","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"yHash","type":"bytes32"}],"name":"registered","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint256","name":"dividend","type":"uint256"}],"name":"setBurnFeeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochBase","type":"uint256"}],"name":"setEpochBase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_epochLength","type":"uint256"}],"name":"setEpochLength","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"_suterAgency","type":"address"}],"name":"setSuterAgency","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"multiplier","type":"uint256"},{"internalType":"uint256","name":"dividend","type":"uint256"}],"name":"setTransferFeeStrategy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_unit","type":"uint256"}],"name":"setUnit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"suterAgency","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBurnFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalFundCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalTransferFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalUsers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[]","name":"C","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"D","type":"tuple"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point[]","name":"y","type":"tuple[]"},{"components":[{"internalType":"bytes32","name":"x","type":"bytes32"},{"internalType":"bytes32","name":"y","type":"bytes32"}],"internalType":"struct Utils.G1Point","name":"u","type":"tuple"},{"internalType":"bytes","name":"proof","type":"bytes"}],"name":"transfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

608060405260018055606460025560016003556005600455601860075560006008556000600a556000600b556000600c556000600d556000600e556000600f5560006014553480156200005157600080fd5b506040516200446a3803806200446a8339818101604052810190620000779190620001bf565b828282336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600560006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555081600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060098190555050505083601660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050506200029d565b600081519050620001a28162000269565b92915050565b600081519050620001b98162000283565b92915050565b60008060008060808587031215620001d657600080fd5b6000620001e68782880162000191565b9450506020620001f98782880162000191565b93505060406200020c8782880162000191565b92505060606200021f87828801620001a8565b91505092959194509250565b600062000238826200023f565b9050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b62000274816200022b565b81146200028057600080fd5b50565b6200028e816200025f565b81146200029a57600080fd5b50565b6141bd80620002ad6000396000f3fe6080604052600436106101d85760003560e01c806395e9524811610102578063bc939a4711610095578063de3d3d0811610064578063de3d3d08146106b3578063e708278f146106de578063eff4d17814610707578063f9a5375b14610723576101d8565b8063bc939a4714610609578063bff1f9e114610634578063c3b6dcdc1461065f578063d49d518114610688576101d8565b8063aae07890116100d1578063aae078901461054d578063ad7a672f14610576578063ae364d8f146105a1578063b1537596146105cc576101d8565b806395e952481461047e5780639b0d85d3146104a9578063a568ce51146104d2578063a9b05a5614610510576101d8565b806357d775f81161017a5780637d84839c116101495780637d84839c146103d25780637d882097146103fd578063840cd74c14610428578063907af6c014610453576101d8565b806357d775f8146103285780635a6fcd40146103535780637207f20e1461037e5780637601a39e146103a7576101d8565b806327d084e7116101b657806327d084e71461025a578063324db30f1461029757806354eea796146102c25780635524d548146102eb576101d8565b8063042ed32a146101dd5780630e2249321461020657806318131f6a14610231575b600080fd5b3480156101e957600080fd5b5061020460048036038101906101ff9190612eb5565b61074c565b005b34801561021257600080fd5b5061021b61085a565b6040516102289190613ecb565b60405180910390f35b34801561023d57600080fd5b506102586004803603810190610253919061303b565b610860565b005b34801561026657600080fd5b50610281600480360381019061027c9190612de6565b610900565b60405161028e9190613a4a565b60405180910390f35b3480156102a357600080fd5b506102ac610bad565b6040516102b99190613ecb565b60405180910390f35b3480156102ce57600080fd5b506102e960048036038101906102e49190613012565b610bb3565b005b3480156102f757600080fd5b50610312600480360381019061030d9190612e63565b610c4b565b60405161031f9190613b5a565b60405180910390f35b34801561033457600080fd5b5061033d610e59565b60405161034a9190613ecb565b60405180910390f35b34801561035f57600080fd5b50610368610e5f565b6040516103759190613ecb565b60405180910390f35b34801561038a57600080fd5b506103a560048036038101906103a0919061303b565b610e65565b005b3480156103b357600080fd5b506103bc610f05565b6040516103c99190613ecb565b60405180910390f35b3480156103de57600080fd5b506103e7610f0b565b6040516103f49190613ecb565b60405180910390f35b34801561040957600080fd5b50610412610f11565b60405161041f9190613ecb565b60405180910390f35b34801561043457600080fd5b5061043d610f17565b60405161044a9190613ecb565b60405180910390f35b34801561045f57600080fd5b50610468610f1d565b6040516104759190613ecb565b60405180910390f35b34801561048a57600080fd5b50610493610f23565b6040516104a09190613ecb565b60405180910390f35b3480156104b557600080fd5b506104d060048036038101906104cb9190612fc3565b610f29565b005b3480156104de57600080fd5b506104f960048036038101906104f49190612e8c565b6110fa565b604051610507929190613a6c565b60405180910390f35b34801561051c57600080fd5b5061053760048036038101906105329190612e8c565b611213565b6040516105449190613b75565b60405180910390f35b34801561055957600080fd5b50610574600480360381019061056f9190613012565b6112f4565b005b34801561058257600080fd5b5061058b61138c565b6040516105989190613ecb565b60405180910390f35b3480156105ad57600080fd5b506105b6611392565b6040516105c39190613ecb565b60405180910390f35b3480156105d857600080fd5b506105f360048036038101906105ee9190612e63565b611398565b6040516106009190613ecb565b60405180910390f35b34801561061557600080fd5b5061061e6113b0565b60405161062b9190613998565b60405180910390f35b34801561064057600080fd5b506106496113d4565b6040516106569190613ecb565b60405180910390f35b34801561066b57600080fd5b5061068660048036038101906106819190612f1c565b6113da565b005b34801561069457600080fd5b5061069d611624565b6040516106aa9190613ecb565b60405180910390f35b3480156106bf57600080fd5b506106c861162c565b6040516106d59190613ecb565b60405180910390f35b3480156106ea57600080fd5b5061070560048036038101906107009190613012565b611632565b005b610721600480360381019061071c9190612d27565b6116ca565b005b34801561072f57600080fd5b5061074a60048036038101906107459190612cfe565b611dd6565b005b610757838383611ea7565b600061076283612093565b9050601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330846040518463ffffffff1660e01b81526004016107c3939291906139b3565b602060405180830381600087803b1580156107dd57600080fd5b505af11580156107f1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108159190612e3a565b610854576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161084b90613d97565b60405180910390fd5b50505050565b600d5481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146108ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e590613dd7565b60405180910390fd5b81600181905550806002819055505050565b60606000835190508067ffffffffffffffff8111801561091f57600080fd5b5060405190808252806020026020018201604052801561095957816020015b610946612a07565b81526020019060019003908161093e5790505b50915060005b81811015610ba557600085828151811061097557fe5b602002602001015160405160200161098d9190613e37565b60405160208183030381529060405280519060200120905060106000828152602001908152602001600020600280602002604051908101604052809291906000905b82821015610a0b5783826002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906109cf565b50505050848381518110610a1b57fe5b60200260200101819052508460126000838152602001908152602001600020541015610b9757610a49612a07565b60116000838152602001908152602001600020600280602002604051908101604052809291906000905b82821015610aaf578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190610a73565b505050509050610afd81600060028110610ac557fe5b6020020151868581518110610ad657fe5b6020026020010151600060028110610aea57fe5b60200201516120f590919063ffffffff16565b858481518110610b0957fe5b6020026020010151600060028110610b1d57fe5b6020020181905250610b6d81600160028110610b3557fe5b6020020151868581518110610b4657fe5b6020026020010151600160028110610b5a57fe5b60200201516120f590919063ffffffff16565b858481518110610b7957fe5b6020026020010151600160028110610b8d57fe5b6020020181905250505b50808060010191505061095f565b505092915050565b600c5481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610c41576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610c3890613c17565b60405180910390fd5b8060078190555050565b6000610c55612a34565b60405180604001604052806000801b81526020016000801b8152509050610c7a612a54565b604051806040016040528060106000878152602001908152602001600020600280602002604051908101604052809291906000905b82821015610ceb578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190610caf565b50505050815260200160116000878152602001908152602001600020600280602002604051908101604052809291906000905b82821015610d5a578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190610d1e565b505050508152509050610d988282600060028110610d7457fe5b6020020151600060028110610d8557fe5b602002015161213990919063ffffffff16565b8015610dd55750610dd48282600060028110610db057fe5b6020020151600160028110610dc157fe5b602002015161213990919063ffffffff16565b5b8015610e125750610e118282600160028110610ded57fe5b6020020151600060028110610dfe57fe5b602002015161213990919063ffffffff16565b5b8015610e4f5750610e4e8282600160028110610e2a57fe5b6020020151600160028110610e3b57fe5b602002015161213990919063ffffffff16565b5b1592505050919050565b60075481565b60145481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610ef3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610eea90613d37565b60405180910390fd5b81600381905550806004819055505050565b60045481565b60015481565b600e5481565b60025481565b60095481565b60035481565b610f31612a34565b610f77610f4f610f4085612161565b8661218d90919063ffffffff16565b610f6984610f5b6121c6565b61218d90919063ffffffff16565b6120f590919063ffffffff16565b90506000610fb1308684604051602001610f9393929190613a13565b6040516020818303038152906040528051906020012060001c61222e565b9050838114610ff5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610fec90613cb7565b60405180910390fd5b6000856040516020016110089190613e37565b60405160208183030381529060405280519060200120905061102981610c4b565b15611069576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161106090613bd7565b60405180910390fd5b856011600083815260200190815260200160002060006002811061108957fe5b6002020160008201518160000155602082015181600101559050506110ac6121c6565b601160008381526020019081526020016000206001600281106110cb57fe5b6002020160008201518160000155602082015181600101559050506001600b5401600b81905550505050505050565b611102612a07565b61110a612a07565b60008360405160200161111d9190613e37565b60405160208183030381529060405280519060200120905060106000828152602001908152602001600020600280602002604051908101604052809291906000905b8282101561119b57838260020201604051806040016040529081600082015481526020016001820154815250508152602001906001019061115f565b50505050925060116000828152602001908152602001600020600280602002604051908101604052809291906000905b828210156112075783826002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906111cb565b50505050915050915091565b60606000826040516020016112289190613e37565b604051602081830303815290604052805190602001209050601560008281526020019081526020016000208054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156112e75780601f106112bc576101008083540402835291602001916112e7565b820191906000526020600020905b8154815290600101906020018083116112ca57829003601f168201915b5050505050915050919050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611382576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161137990613cd7565b60405180910390fd5b8060098190555050565b600a5481565b600f5481565b60126020528060005260406000206000915090505481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600b5481565b60006113e585612093565b905060006002546001548302816113f857fe5b0490506114088787878787612261565b600081111561152b57601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16836040518363ffffffff1660e01b815260040161148e9291906139ea565b602060405180830381600087803b1580156114a857600080fd5b505af11580156114bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114e09190612e3a565b61151f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161151690613d77565b60405180910390fd5b80600c5401600c819055505b601660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb338385036040518363ffffffff1660e01b815260040161158a9291906139ea565b602060405180830381600087803b1580156115a457600080fd5b505af11580156115b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115dc9190612e3a565b61161b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161161290613c97565b60405180910390fd5b50505050505050565b63ffffffff81565b60085481565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146116c0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016116b790613c57565b60405180910390fd5b8060088190555050565b60005a905060008451905060608167ffffffffffffffff811180156116ee57600080fd5b5060405190808252806020026020018201604052801561172857816020015b611715612a34565b81526020019060019003908161170d5790505b50905060608267ffffffffffffffff8111801561174457600080fd5b5060405190808252806020026020018201604052801561177e57816020015b61176b612a34565b8152602001906001900390816117635790505b509050828951146117c4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016117bb90613b97565b60405180910390fd5b60005b83811015611aa55760008882815181106117dd57fe5b60200260200101516040516020016117f59190613e37565b60405160208183030381529060405280519060200120905061181681610c4b565b611855576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161184c90613d57565b60405180910390fd5b61185e81612703565b611866612a07565b60116000838152602001908152602001600020600280602002604051908101604052809291906000905b828210156118cc578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190611890565b5050505090506119098c84815181106118e157fe5b6020026020010151826000600281106118f657fe5b60200201516120f590919063ffffffff16565b6011600084815260200190815260200160002060006002811061192857fe5b6002020160008201518160000155602082015181600101559050506119678b8260016002811061195457fe5b60200201516120f590919063ffffffff16565b6011600084815260200190815260200160002060016002811061198657fe5b60020201600082015181600001556020820151816001015590505060106000838152602001908152602001600020600280602002604051908101604052809291906000905b82821015611a075783826002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906119cb565b505050509050611a448c8481518110611a1c57fe5b602002602001015182600060028110611a3157fe5b60200201516120f590919063ffffffff16565b858481518110611a5057fe5b6020026020010181905250611a7f8b82600160028110611a6c57fe5b60200201516120f590919063ffffffff16565b848481518110611a8b57fe5b6020026020010181905250505080806001019150506117c7565b50600086604051602001611ab99190613e37565b60405160208183030381529060405280519060200120905060005b601380549050811015611b48578160138281548110611aef57fe5b90600052602060002001541415611b3b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611b3290613c37565b60405180910390fd5b8080600101915050611ad4565b506013819080600181540180825580915050600190039060005260206000200160009091909190915055600560009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d2d5e70a84848d8d8d6014548e8e6040518963ffffffff1660e01b8152600401611bdd989796959493929190613ab8565b60206040518083038186803b158015611bf557600080fd5b505afa158015611c09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c2d9190612e3a565b611c6c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611c6390613cf7565b60405180910390fd5b60005a8603905060003a600454600354840281611c8557fe5b040290506000811115611d485780341015611cd5576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ccc90613bf7565b60405180910390fd5b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050158015611d3b573d6000803e3d6000fd5b5080600d5401600d819055505b3373ffffffffffffffffffffffffffffffffffffffff166108fc8234039081150290604051600060405180830381858888f19350505050158015611d90573d6000803e3d6000fd5b507f9b814ae8a45a4c40d4c60ffa92e0c4b76dec41407cb28b43df9daffa3685f9ac8a604051611dc09190613a96565b60405180910390a1505050505050505050505050565b60008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614611e64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611e5b90613bb7565b60405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b63ffffffff8211158015611ec3575063ffffffff82600a540111155b611f02576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611ef990613c77565b60405180910390fd5b81600a6000828254019250508190555081600e600082825401925050819055506001600f60008282540192505081905550600083604051602001611f469190613e37565b604051602081830303815290604052805190602001209050611f6781610c4b565b611fa6576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401611f9d90613d57565b60405180910390fd5b611faf81612703565b611fb7612a34565b60116000838152602001908152602001600020600060028110611fd657fe5b600202016040518060400160405290816000820154815260200160018201548152505090506120276120188561200a6121c6565b61218d90919063ffffffff16565b826120f590919063ffffffff16565b9050806011600084815260200190815260200160002060006002811061204957fe5b6002020160008201518160000155602082015181600101559050508260156000848152602001908152602001600020908051906020019061208b929190612a81565b505050505050565b6000816000111580156120aa575063ffffffff8211155b6120e9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016120e090613db7565b60405180910390fd5b60095482029050919050565b6120fd612a34565b6040518351815260208401516020820152825160408201526020830151606082015260408260808360065afa61213257600080fd5b5092915050565b600081600001518360000151148015612159575081602001518360200151145b905092915050565b6000817f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001039050919050565b612195612a34565b604051835181526020840151602082015282604082015260408260608360075afa6121bf57600080fd5b5092915050565b6121ce612a34565b60405180604001604052807f077da99d806abd13c9f15ece5398525119d11e11e9836b2ee7d23f6159ad87d460001b81526020017f01485efa927f2ad41bff567eec88f32fb0a0f706588b4e41a8d587d008b7f87560001b815250905090565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001828161225957fe5b069050919050565b83600a5410156122a6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161229d90613d17565b60405180910390fd5b83600a600082825403925050819055506000856040516020016122c99190613e37565b6040516020818303038152906040528051906020012090506122ea81610c4b565b612329576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161232090613d57565b60405180910390fd5b61233281612703565b61233a612a07565b60116000838152602001908152602001600020600280602002604051908101604052809291906000905b828210156123a0578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190612364565b5050505090506123eb6123cb6123b588612161565b6123bd6121c6565b61218d90919063ffffffff16565b826000600281106123d857fe5b60200201516120f590919063ffffffff16565b6011600084815260200190815260200160002060006002811061240a57fe5b60020201600082015181600001556020820151816001015590505060106000838152602001908152602001600020600280602002604051908101604052809291906000905b8282101561248b57838260020201604051806040016040529081600082015481526020016001820154815250508152602001906001019061244f565b5050505090506124d66124b66124a088612161565b6124a86121c6565b61218d90919063ffffffff16565b826000600281106124c357fe5b60200201516120f590919063ffffffff16565b816000600281106124e357fe5b60200201819052506000856040516020016124fe9190613e37565b60405160208183030381529060405280519060200120905060005b60138054905081101561258d57816013828154811061253457fe5b90600052602060002001541415612580576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161257790613c37565b60405180910390fd5b8080600101915050612519565b506013819080600181540180825580915050600190039060005260206000200160009091909190915055836015600085815260200190815260200160002090805190602001906125de929190612a81565b50600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166391d16ac88360006002811061262a57fe5b60200201518460016002811061263c57fe5b60200201518b6014548b338c6040518863ffffffff1660e01b815260040161266a9796959493929190613e52565b60206040518083038186803b15801561268257600080fd5b505afa158015612696573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ba9190612e3a565b6126f9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016126f090613df7565b60405180910390fd5b5050505050505050565b600080600854141561272257600754438161271a57fe5b04905061277c565b6001600854141561274057600754428161273857fe5b04905061277b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161277290613e17565b60405180910390fd5b5b80601260008481526020019081526020016000205410156129e35761279f612a54565b604051806040016040528060106000868152602001908152602001600020600280602002604051908101604052809291906000905b828210156128105783826002020160405180604001604052908160008201548152602001600182015481525050815260200190600101906127d4565b50505050815260200160116000868152602001908152602001600020600280602002604051908101604052809291906000905b8282101561287f578382600202016040518060400160405290816000820154815260200160018201548152505081526020019060010190612843565b5050505081525090506128df8160016002811061289857fe5b60200201516000600281106128a957fe5b6020020151826000600281106128bb57fe5b60200201516000600281106128cc57fe5b60200201516120f590919063ffffffff16565b601060008581526020019081526020016000206000600281106128fe57fe5b6002020160008201518160000155602082015181600101559050506129708160016002811061292957fe5b602002015160016002811061293a57fe5b60200201518260006002811061294c57fe5b602002015160016002811061295d57fe5b60200201516120f590919063ffffffff16565b6010600085815260200190815260200160002060016002811061298f57fe5b6002020160008201518160000155602082015181600101559050506011600084815260200190815260200160002060006129c99190612b01565b816012600085815260200190815260200160002081905550505b806014541015612a03578060148190555060136000612a029190612b2c565b5b5050565b60405180604001604052806002905b612a1e612a34565b815260200190600190039081612a165790505090565b604051806040016040528060008019168152602001600080191681525090565b60405180604001604052806002905b612a6b612a07565b815260200190600190039081612a635790505090565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10612ac257805160ff1916838001178555612af0565b82800160010185558215612af0579182015b82811115612aef578251825591602001919060010190612ad4565b5b509050612afd9190612b4d565b5090565b5060008082016000905560018201600090555060020160008082016000905560018201600090555050565b5080546000825590600052602060002090810190612b4a9190612b6a565b50565b5b80821115612b66576000816000905550600101612b4e565b5090565b5b80821115612b83576000816000905550600101612b6b565b5090565b600081359050612b968161412b565b92915050565b600082601f830112612bad57600080fd5b8135612bc0612bbb82613f13565b613ee6565b91508181835260208401935060208101905083856040840282011115612be557600080fd5b60005b83811015612c155781612bfb8882612c9d565b845260208401935060408301925050600181019050612be8565b5050505092915050565b600081519050612c2e81614142565b92915050565b600081359050612c4381614159565b92915050565b600082601f830112612c5a57600080fd5b8135612c6d612c6882613f3b565b613ee6565b91508082526020830160208301858383011115612c8957600080fd5b612c948382846140d8565b50505092915050565b600060408284031215612caf57600080fd5b612cb96040613ee6565b90506000612cc984828501612c34565b6000830152506020612cdd84828501612c34565b60208301525092915050565b600081359050612cf881614170565b92915050565b600060208284031215612d1057600080fd5b6000612d1e84828501612b87565b91505092915050565b600080600080600060e08688031215612d3f57600080fd5b600086013567ffffffffffffffff811115612d5957600080fd5b612d6588828901612b9c565b9550506020612d7688828901612c9d565b945050606086013567ffffffffffffffff811115612d9357600080fd5b612d9f88828901612b9c565b9350506080612db088828901612c9d565b92505060c086013567ffffffffffffffff811115612dcd57600080fd5b612dd988828901612c49565b9150509295509295909350565b60008060408385031215612df957600080fd5b600083013567ffffffffffffffff811115612e1357600080fd5b612e1f85828601612b9c565b9250506020612e3085828601612ce9565b9150509250929050565b600060208284031215612e4c57600080fd5b6000612e5a84828501612c1f565b91505092915050565b600060208284031215612e7557600080fd5b6000612e8384828501612c34565b91505092915050565b600060408284031215612e9e57600080fd5b6000612eac84828501612c9d565b91505092915050565b600080600060808486031215612eca57600080fd5b6000612ed886828701612c9d565b9350506040612ee986828701612ce9565b925050606084013567ffffffffffffffff811115612f0657600080fd5b612f1286828701612c49565b9150509250925092565b600080600080600060e08688031215612f3457600080fd5b6000612f4288828901612c9d565b9550506040612f5388828901612ce9565b9450506060612f6488828901612c9d565b93505060a086013567ffffffffffffffff811115612f8157600080fd5b612f8d88828901612c49565b92505060c086013567ffffffffffffffff811115612faa57600080fd5b612fb688828901612c49565b9150509295509295909350565b600080600060808486031215612fd857600080fd5b6000612fe686828701612c9d565b9350506040612ff786828701612ce9565b925050606061300886828701612ce9565b9150509250925092565b60006020828403121561302457600080fd5b600061303284828501612ce9565b91505092915050565b6000806040838503121561304e57600080fd5b600061305c85828601612ce9565b925050602061306d85828601612ce9565b9150509250929050565b60006130838383613132565b60808301905092915050565b600061309b838361392b565b60408301905092915050565b6130b0816140a2565b82525050565b6130bf81614050565b82525050565b6130ce8161403e565b82525050565b60006130df82613f91565b6130e98185613fe4565b93506130f483613f67565b8060005b8381101561312557815161310c8882613077565b975061311783613fbd565b9250506001810190506130f8565b5085935050505092915050565b61313b81613f9c565b6131458184613ff5565b925061315082613f77565b8060005b83811015613181578151613168878261308f565b965061317383613fca565b925050600181019050613154565b505050505050565b61319281613f9c565b61319c8184614000565b92506131a782613f77565b8060005b838110156131d85781516131bf878261308f565b96506131ca83613fca565b9250506001810190506131ab565b505050505050565b60006131eb82613fa7565b6131f5818561400b565b935061320083613f81565b8060005b83811015613231578151613218888261308f565b975061322383613fd7565b925050600181019050613204565b5085935050505092915050565b61324781614062565b82525050565b6132568161406e565b82525050565b600061326782613fb2565b613271818561401c565b93506132818185602086016140e7565b61328a8161411a565b840191505092915050565b60006132a2601c8361402d565b91507f496e707574206172726179206c656e677468206d69736d6174636821000000006000830152602082019050919050565b60006132e260308361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e6765206167656e63792e000000000000000000000000000000006020830152604082019050919050565b6000613348601b8361402d565b91507f4163636f756e7420616c726561647920726567697374657265642100000000006000830152602082019050919050565b600061338860328361402d565b91507f4e6f7420656e6f756768206665652073656e742077697468207468652074726160008301527f6e73666572207472616e73616374696f6e2e00000000000000000000000000006020830152604082019050919050565b60006133ee60368361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e67652065706f6368206c656e6774682e000000000000000000006020830152604082019050919050565b600061345460138361402d565b91507f4e6f6e636520616c7265616479207365656e21000000000000000000000000006000830152602082019050919050565b600061349460348361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e67652065706f636820626173652e0000000000000000000000006020830152604082019050919050565b60006134fa60288361402d565b91507f46756e642070757368657320636f6e74726163742070617374206d6178696d7560008301527f6d2076616c75652e0000000000000000000000000000000000000000000000006020830152604082019050919050565b600061356060188361402d565b91507f4661696c20746f207472616e7366657220746f6b656e732e00000000000000006000830152602082019050919050565b60006135a0601f8361402d565b91507f496e76616c696420726567697374726174696f6e207369676e617475726521006000830152602082019050919050565b60006135e0602e8361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e676520756e69742e0000000000000000000000000000000000006020830152604082019050919050565b600061364660238361402d565b91507f5472616e736665722070726f6f6620766572696669636174696f6e206661696c60008301527f65642100000000000000000000000000000000000000000000000000000000006020830152604082019050919050565b60006136ac601c8361402d565b91507f4275726e206661696c73207468652073616e69747920636865636b2e000000006000830152602082019050919050565b60006136ec603f8361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e6765207472616e73666572206665652073747261746567792e006020830152604082019050919050565b6000613752601b8361402d565b91507f4163636f756e74206e6f742079657420726567697374657265642e00000000006000830152602082019050919050565b600061379260138361402d565b91507f4661696c20746f20636861726765206665652e000000000000000000000000006000830152602082019050919050565b60006137d2601d8361402d565b91507f4e617469766520277472616e7366657246726f6d27206661696c65642e0000006000830152602082019050919050565b600061381260138361402d565b91507f416d6f756e74206f7574206f662072616e6765000000000000000000000000006000830152602082019050919050565b6000613852603b8361402d565b91507f5065726d697373696f6e2064656e6965643a204f6e6c792061646d696e20636160008301527f6e206368616e6765206275726e206665652073747261746567792e00000000006020830152604082019050919050565b60006138b8601f8361402d565b91507f4275726e2070726f6f6620766572696669636174696f6e206661696c656421006000830152602082019050919050565b60006138f860138361402d565b91507f496e76616c69642065706f636820626173652e000000000000000000000000006000830152602082019050919050565b604082016000820151613941600085018261324d565b506020820151613954602085018261324d565b50505050565b604082016000820151613970600085018261324d565b506020820151613983602085018261324d565b50505050565b61399281614098565b82525050565b60006020820190506139ad60008301846130b6565b92915050565b60006060820190506139c860008301866130a7565b6139d560208301856130c5565b6139e26040830184613989565b949350505050565b60006040820190506139ff60008301856130a7565b613a0c6020830184613989565b9392505050565b600060a082019050613a2860008301866130c5565b613a35602083018561395a565b613a42606083018461395a565b949350505050565b60006020820190508181036000830152613a6481846130d4565b905092915050565b600061010082019050613a826000830185613189565b613a8f6080830184613189565b9392505050565b60006020820190508181036000830152613ab081846131e0565b905092915050565b6000610140820190508181036000830152613ad3818b6131e0565b90508181036020830152613ae7818a6131e0565b90508181036040830152613afb81896131e0565b9050613b0a606083018861395a565b81810360a0830152613b1c81876131e0565b9050613b2b60c0830186613989565b613b3860e083018561395a565b818103610120830152613b4b818461325c565b90509998505050505050505050565b6000602082019050613b6f600083018461323e565b92915050565b60006020820190508181036000830152613b8f818461325c565b905092915050565b60006020820190508181036000830152613bb081613295565b9050919050565b60006020820190508181036000830152613bd0816132d5565b9050919050565b60006020820190508181036000830152613bf08161333b565b9050919050565b60006020820190508181036000830152613c108161337b565b9050919050565b60006020820190508181036000830152613c30816133e1565b9050919050565b60006020820190508181036000830152613c5081613447565b9050919050565b60006020820190508181036000830152613c7081613487565b9050919050565b60006020820190508181036000830152613c90816134ed565b9050919050565b60006020820190508181036000830152613cb081613553565b9050919050565b60006020820190508181036000830152613cd081613593565b9050919050565b60006020820190508181036000830152613cf0816135d3565b9050919050565b60006020820190508181036000830152613d1081613639565b9050919050565b60006020820190508181036000830152613d308161369f565b9050919050565b60006020820190508181036000830152613d50816136df565b9050919050565b60006020820190508181036000830152613d7081613745565b9050919050565b60006020820190508181036000830152613d9081613785565b9050919050565b60006020820190508181036000830152613db0816137c5565b9050919050565b60006020820190508181036000830152613dd081613805565b9050919050565b60006020820190508181036000830152613df081613845565b9050919050565b60006020820190508181036000830152613e10816138ab565b9050919050565b60006020820190508181036000830152613e30816138eb565b9050919050565b6000604082019050613e4c600083018461395a565b92915050565b600061016082019050613e68600083018a61395a565b613e75604083018961395a565b613e82608083018861395a565b613e8f60c0830187613989565b613e9c60e083018661395a565b613eaa6101208301856130a7565b818103610140830152613ebd818461325c565b905098975050505050505050565b6000602082019050613ee06000830184613989565b92915050565b6000604051905081810181811067ffffffffffffffff82111715613f0957600080fd5b8060405250919050565b600067ffffffffffffffff821115613f2a57600080fd5b602082029050602081019050919050565b600067ffffffffffffffff821115613f5257600080fd5b601f19601f8301169050602081019050919050565b6000819050602082019050919050565b6000819050919050565b6000819050602082019050919050565b600081519050919050565b600060029050919050565b600081519050919050565b600081519050919050565b6000602082019050919050565b6000602082019050919050565b6000602082019050919050565b600082825260208201905092915050565b600081905092915050565b600081905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600082825260208201905092915050565b600061404982614078565b9050919050565b600061405b82614078565b9050919050565b60008115159050919050565b6000819050919050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006140ad826140b4565b9050919050565b60006140bf826140c6565b9050919050565b60006140d182614078565b9050919050565b82818337600083830152505050565b60005b838110156141055780820151818401526020810190506140ea565b83811115614114576000848401525b50505050565b6000601f19601f8301169050919050565b61413481614050565b811461413f57600080fd5b50565b61414b81614062565b811461415657600080fd5b50565b6141628161406e565b811461416d57600080fd5b50565b61417981614098565b811461418457600080fd5b5056fea264697066735822122056695844caa0f1ebe5998444fb454f3d0114d09e71859029212c139d916547d464736f6c634300060c00330000000000000000000000004cfbbdfbd5bf0814472ff35c72717bd095ada055000000000000000000000000076010bfc6377b24d10545e69840c9a6b79d6471000000000000000000000000d3a56c7fd5493268d299a4111a1b493c95b0b56900000000000000000000000000000000000000000000000000005af3107a4000

Deployed ByteCode Sourcemap

163:1589:7:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;732:429;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1353:35:6;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;4350:267;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;8406:835;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1316:31;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5859:199;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;7881:337;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;783:31;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1785:35;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5375:283;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;570:40;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;399:38;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1394:32;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;443:38;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1076:19;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;522:42;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;6440:1435;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;9247:311;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;;:::i;:::-;;;;;;;;9564:199;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;6064:163;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1244:31;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1432:33;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1630:47;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;267:34;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1281:29;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;1167:583:7;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;1200:37:6;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;821:28;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;:::-;;;;;;;;5664:189;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;12599:1959;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;6233:201;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::i;:::-;;732:429:7;830:33;839:1;842:10;854:8;830;:33::i;:::-;874:20;897:26;912:10;897:14;:26::i;:::-;874:49;;1061:5;;;;;;;;;;;:18;;;1080:10;1100:4;1107:12;1061:59;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1053:101;;;;;;;;;;;;:::i;:::-;;;;;;;;;732:429;;;;:::o;1353:35:6:-;;;;:::o;4350:267::-;4455:11;;;;;;;;;;4441:25;;:10;:25;;;4433:97;;;;;;;;;;;;:::i;:::-;;;;;;;;;4562:10;4540:19;:32;;;;4602:8;4582:17;:28;;;;4350:267;;:::o;8406:835::-;8488:34;8753:12;8768:1;:8;8753:23;;8820:4;8797:28;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;8786:39;;8840:9;8835:400;8859:4;8855:1;:8;8835:400;;;8884:13;8921:1;8923;8921:4;;;;;;;;;;;;;;8910:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;8900:27;;;;;;8884:43;;8955:3;:10;8959:5;8955:10;;;;;;;;;;;8941:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:8;8950:1;8941:11;;;;;;;;;;;;;:24;;;;9005:5;8983:12;:19;8996:5;8983:19;;;;;;;;;;;;:27;8979:246;;;9030:31;;:::i;:::-;9064:7;:14;9072:5;9064:14;;;;;;;;;;;9030:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9113:31;9133:7;9141:1;9133:10;;;;;;;;;;;9113:8;9122:1;9113:11;;;;;;;;;;;;;;9125:1;9113:14;;;;;;;;;;;:19;;:31;;;;:::i;:::-;9096:8;9105:1;9096:11;;;;;;;;;;;;;;9108:1;9096:14;;;;;;;;;;:48;;;;9179:31;9199:7;9207:1;9199:10;;;;;;;;;;;9179:8;9188:1;9179:11;;;;;;;;;;;;;;9191:1;9179:14;;;;;;;;;;;:19;;:31;;;;:::i;:::-;9162:8;9171:1;9162:11;;;;;;;;;;;;;;9174:1;9162:14;;;;;;;;;;:48;;;;8979:246;;8835:400;8865:3;;;;;;;8835:400;;;;8406:835;;;;;:::o;1316:31::-;;;;:::o;5859:199::-;5945:11;;;;;;;;;;5931:25;;:10;:25;;;5923:92;;;;;;;;;;;;:::i;:::-;;;;;;;;;6039:12;6025:11;:26;;;;5859:199;:::o;7881:337::-;7937:4;7953:25;;:::i;:::-;7981:19;;;;;;;;7995:1;7981:19;;;;;;7998:1;7981:19;;;;;7953:47;;8010:34;;:::i;:::-;:65;;;;;;;;8048:3;:10;8052:5;8048:10;;;;;;;;;;;8010:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8060:7;:14;8068:5;8060:14;;;;;;;;;;;8010:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8094:26;8115:4;8094:7;8102:1;8094:10;;;;;;;;;;;8105:1;8094:13;;;;;;;;;;;:20;;:26;;;;:::i;:::-;:56;;;;;8124:26;8145:4;8124:7;8132:1;8124:10;;;;;;;;;;;8135:1;8124:13;;;;;;;;;;;:20;;:26;;;;:::i;:::-;8094:56;:86;;;;;8154:26;8175:4;8154:7;8162:1;8154:10;;;;;;;;;;;8165:1;8154:13;;;;;;;;;;;:20;;:26;;;;:::i;:::-;8094:86;:116;;;;;8184:26;8205:4;8184:7;8192:1;8184:10;;;;;;;;;;;8195:1;8184:13;;;;;;;;;;;:20;;:26;;;;:::i;:::-;8094:116;8092:119;8085:126;;;;7881:337;;;:::o;783:31::-;;;;:::o;1785:35::-;;;;:::o;5375:283::-;5484:11;;;;;;;;;;5470:25;;:10;:25;;;5462:101;;;;;;;;;;;;:::i;:::-;;;;;;;;;5599:10;5573:23;:36;;;;5643:8;5619:21;:32;;;;5375:283;;:::o;570:40::-;;;;:::o;399:38::-;;;;:::o;1394:32::-;;;;:::o;443:38::-;;;;:::o;1076:19::-;;;;:::o;522:42::-;;;;:::o;6440:1435::-;6602:22;;:::i;:::-;6627:40;6650:16;6657:8;:1;:6;:8::i;:::-;6650:1;:6;;:16;;;;:::i;:::-;6627:17;6642:1;6627:9;:7;:9::i;:::-;:14;;:17;;;;:::i;:::-;:22;;:40;;;;:::i;:::-;6602:65;;6677:17;6697:58;6734:4;6741:1;6744;6715:31;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;6705:42;;;;;;6697:51;;:56;:58::i;:::-;6677:78;;6786:1;6773:9;:14;6765:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;6833:13;6870:1;6859:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;6849:24;;;;;;6833:40;;6892:17;6903:5;6892:10;:17::i;:::-;6891:18;6883:58;;;;;;;;;;;;:::i;:::-;;;;;;;;;7790:1;7770:7;:14;7778:5;7770:14;;;;;;;;;;;7785:1;7770:17;;;;;;;;;;:21;;;;;;;;;;;;;;;;;;;7821:9;:7;:9::i;:::-;7801:7;:14;7809:5;7801:14;;;;;;;;;;;7816:1;7801:17;;;;;;;;;;:29;;;;;;;;;;;;;;;;;;;7867:1;7854:10;;:14;7841:10;:27;;;;6440:1435;;;;;;:::o;9247:311::-;9318:35;;:::i;:::-;9355:33;;:::i;:::-;9400:13;9437:1;9426:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;9416:24;;;;;;9400:40;;9464:3;:10;9468:5;9464:10;;;;;;;;;;;9450:24;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9496:7;:14;9504:5;9496:14;;;;;;;;;;;9484:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9520:31;9247:311;;;:::o;9564:199::-;9628:20;9660:13;9697:1;9686:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;9676:24;;;;;;9660:40;;9720:5;:12;9726:5;9720:12;;;;;;;;;;;9710:22;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;9742:14;9564:199;;;:::o;6064:163::-;6136:11;;;;;;;;;;6122:25;;:10;:25;;;6114:84;;;;;;;;;;;;:::i;:::-;;;;;;;;;6215:5;6208:4;:12;;;;6064:163;:::o;1244:31::-;;;;:::o;1432:33::-;;;;:::o;1630:47::-;;;;;;;;;;;;;;;;;:::o;267:34::-;;;;;;;;;;;;:::o;1281:29::-;;;;:::o;1167:583:7:-;1309:20;1332:26;1347:10;1332:14;:26::i;:::-;1309:49;;1368:11;1419:17;;1397:19;;1382:12;:34;:54;;;;;;1368:68;;1448:43;1457:1;1460:10;1472:1;1475:5;1482:8;1448;:43::i;:::-;1512:1;1506:3;:7;1502:149;;;1537:5;;;;;;;;;;;:14;;;1552:11;;;;;;;;;;1565:3;1537:32;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1529:64;;;;;;;;;;;;:::i;:::-;;;;;;;;;1637:3;1622:12;;:18;1607:12;:33;;;;1502:149;1668:5;;;;;;;;;;;:14;;;1683:10;1710:3;1695:12;:18;1668:46;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;1660:83;;;;;;;;;;;;:::i;:::-;;;;;;;;;1167:583;;;;;;;:::o;1200:37:6:-;1230:7;1200:37;:::o;821:28::-;;;;:::o;5664:189::-;5746:11;;;;;;;;;;5732:25;;:10;:25;;;5724:90;;;;;;;;;;;;:::i;:::-;;;;;;;;;5836:10;5824:9;:22;;;;5664:189;:::o;12599:1959::-;12809:16;12828:9;12809:28;;12917:12;12932:1;:8;12917:23;;12950:26;12999:4;12979:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;12950:54;;13014:26;13063:4;13043:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;13014:54;;13098:4;13086:1;:8;:16;13078:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;13152:9;13147:599;13171:4;13167:1;:8;13147:599;;;13196:13;13233:1;13235;13233:4;;;;;;;;;;;;;;13222:16;;;;;;;;:::i;:::-;;;;;;;;;;;;;13212:27;;;;;;13196:43;;13261:17;13272:5;13261:10;:17::i;:::-;13253:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;13324:15;13333:5;13324:8;:15::i;:::-;13353:31;;:::i;:::-;13387:7;:14;13395:5;13387:14;;;;;;;;;;;13353:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13435:21;13451:1;13453;13451:4;;;;;;;;;;;;;;13435:7;13443:1;13435:10;;;;;;;;;;;:15;;:21;;;;:::i;:::-;13415:7;:14;13423:5;13415:14;;;;;;;;;;;13430:1;13415:17;;;;;;;;;;:41;;;;;;;;;;;;;;;;;;;13490:18;13506:1;13490:7;13498:1;13490:10;;;;;;;;;;;:15;;:18;;;;:::i;:::-;13470:7;:14;13478:5;13470:14;;;;;;;;;;;13485:1;13470:17;;;;;;;;;;:38;;;;;;;;;;;;;;;;;;;13640:3;:10;13644:5;13640:10;;;;;;;;;;;13630:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13673:21;13689:1;13691;13689:4;;;;;;;;;;;;;;13673:7;13681:1;13673:10;;;;;;;;;;;:15;;:21;;;;:::i;:::-;13664:3;13668:1;13664:6;;;;;;;;;;;;;:30;;;;13717:18;13733:1;13717:7;13725:1;13717:10;;;;;;;;;;;:15;;:18;;;;:::i;:::-;13708:3;13712:1;13708:6;;;;;;;;;;;;;:27;;;;13147:599;;13177:3;;;;;;;13147:599;;;;13756:13;13793:1;13782:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;13772:24;;;;;;13756:40;;13811:9;13806:123;13830:8;:15;;;;13826:1;:19;13806:123;;;13889:5;13874:8;13883:1;13874:11;;;;;;;;;;;;;;;;:20;;13866:52;;;;;;;;;;;;:::i;:::-;;;;;;;;;13847:3;;;;;;;13806:123;;;;13938:8;13952:5;13938:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13977:16;;;;;;;;;;;:31;;;14009:3;14014;14019:1;14022;14025;14028:16;;14046:1;14049:5;13977:78;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;13969:126;;;;;;;;;;;;:::i;:::-;;;;;;;;;14106:15;14135:9;14124:8;:20;14106:38;;14163:11;14239;14214:21;;14188:23;;14178:7;:33;:57;;;;;;14177:73;14163:87;;14270:1;14264:3;:7;14260:211;;;14308:3;14295:9;:16;;14287:79;;;;;;;;;;;;:::i;:::-;;;;;;;;;14380:11;;;;;;;;;;:20;;:25;14401:3;14380:25;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14457:3;14438:16;;:22;14419:16;:41;;;;14260:211;14480:10;:19;;:36;14512:3;14500:9;:15;14480:36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14532:19;14549:1;14532:19;;;;;;:::i;:::-;;;;;;;;12599:1959;;;;;;;;;;;;:::o;6233:201::-;6327:11;;;;;;;;;;6313:25;;:10;:25;;;6305:86;;;;;;;;;;;;:::i;:::-;;;;;;;;;6415:12;6401:11;;:26;;;;;;;;;;;;;;;;;;6233:201;:::o;10708:629::-;1230:7;10817:6;:13;;:45;;;;;1230:7;10849:6;10834:12;;:21;:28;;10817:45;10809:98;;;;;;;;;;;;:::i;:::-;;;;;;;;;10933:6;10917:12;;:22;;;;;;;;;;;10966:6;10949:13;;:23;;;;;;;;;;;11000:1;10982:14;;:19;;;;;;;;;;;11012:13;11049:1;11038:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;11028:24;;;;;;11012:40;;11070:17;11081:5;11070:10;:17::i;:::-;11062:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;11129:15;11138:5;11129:8;:15::i;:::-;11155:28;;:::i;:::-;11186:7;:14;11194:5;11186:14;;;;;;;;;;;11201:1;11186:17;;;;;;;;;;11155:48;;;;;;;;;;;;;;;;;;;;;;;;;;;11223:36;11236:22;11251:6;11236:9;:7;:9::i;:::-;:14;;:22;;;;:::i;:::-;11223:7;:12;;:36;;;;:::i;:::-;11213:46;;11289:7;11269;:14;11277:5;11269:14;;;;;;;;;;;11284:1;11269:17;;;;;;;;;;:27;;;;;;;;;;;;;;;;;;;11322:8;11307:5;:12;11313:5;11307:12;;;;;;;;;;;:23;;;;;;;;;;;;:::i;:::-;;10708:629;;;;;:::o;3228:195::-;3295:7;3327:10;3322:1;:15;;:36;;;;;1230:7;3341:10;:17;;3322:36;3314:68;;;;;;;;;;;;:::i;:::-;;;;;;;;;3412:4;;3399:10;:17;3392:24;;3228:195;;;:::o;2287:602:9:-;2362:16;;:::i;:::-;2428:4;2422:11;2462:2;2456:9;2453:1;2446:20;2514:4;2510:2;2506:13;2500:20;2493:4;2490:1;2486:12;2479:42;2561:2;2555:9;2548:4;2545:1;2541:12;2534:31;2613:4;2609:2;2605:13;2599:20;2592:4;2589:1;2585:12;2578:42;2822:4;2819:1;2813:4;2810:1;2804:4;2797:5;2786:41;2776:2;;2857:1;2854;2847:12;2776:2;2399:484;;;;;:::o;3619:135::-;3696:4;3727:2;:4;;;3719:2;:4;;;:12;:28;;;;;3743:2;:4;;;3735:2;:4;;;:12;3719:28;3712:35;;3619:135;;;;:::o;912:96::-;960:7;1000:1;143:66;986:15;979:22;;912:96;;;:::o;2895:528::-;2961:16;;:::i;:::-;3027:4;3021:11;3061:1;3055:8;3052:1;3045:19;3111:4;3108:1;3104:12;3098:19;3091:4;3088:1;3084:12;3077:41;3152:1;3145:4;3142:1;3138:12;3131:23;3356:4;3353:1;3347:4;3344:1;3338:4;3331:5;3320:41;3310:2;;3391:1;3388;3381:12;3310:2;2998:419;;;;;:::o;3760:219::-;3796:14;;:::i;:::-;3829:143;;;;;;;;3837:66;3829:143;;;;;;3905:66;3829:143;;;;;3822:150;;3760:219;:::o;676:96::-;724:7;143:66;750:1;:15;;;;;;743:22;;676:96;;;:::o;11343:1250:6:-;11621:6;11605:12;;:22;;11597:63;;;;;;;;;;;;:::i;:::-;;;;;;;;;11686:6;11670:12;;:22;;;;;;;;;;;11712:13;11749:1;11738:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;11728:24;;;;;;11712:40;;11770:17;11781:5;11770:10;:17::i;:::-;11762:57;;;;;;;;;;;;:::i;:::-;;;;;;;;;11829:15;11838:5;11829:8;:15::i;:::-;11855:31;;:::i;:::-;11889:7;:14;11897:5;11889:14;;;;;;;;;;;11855:48;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11933:46;11949:29;11964:13;:6;:11;:13::i;:::-;11949:9;:7;:9::i;:::-;:14;;:29;;;;:::i;:::-;11933:7;11941:1;11933:10;;;;;;;;;;;:15;;:46;;;;:::i;:::-;11913:7;:14;11921:5;11913:14;;;;;;;;;;;11928:1;11913:17;;;;;;;;;;:66;;;;;;;;;;;;;;;;;;;12000:3;:10;12004:5;12000:10;;;;;;;;;;;11990:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12107:46;12123:29;12138:13;:6;:11;:13::i;:::-;12123:9;:7;:9::i;:::-;:14;;:29;;;;:::i;:::-;12107:7;12115:1;12107:10;;;;;;;;;;;:15;;:46;;;;:::i;:::-;12094:7;12102:1;12094:10;;;;;;;;;;:59;;;;12163:13;12200:1;12189:13;;;;;;;;:::i;:::-;;;;;;;;;;;;;12179:24;;;;;;12163:40;;12218:9;12213:123;12237:8;:15;;;;12233:1;:19;12213:123;;;12296:5;12281:8;12290:1;12281:11;;;;;;;;;;;;;;;;:20;;12273:52;;;;;;;;;;;;:::i;:::-;;;;;;;;;12254:3;;;;;;;12213:123;;;;12345:8;12359:5;12345:20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12391:8;12376:5;:12;12382:5;12376:12;;;;;;;;;;;:23;;;;;;;;;;;;:::i;:::-;;12418:12;;;;;;;;;;;:23;;;12442:7;12450:1;12442:10;;;;;;;;;;;12454:7;12462:1;12454:10;;;;;;;;;;;12466:1;12469:16;;12487:1;12490:10;12502:5;12418:90;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;12410:134;;;;;;;;;;;;:::i;:::-;;;;;;;;;11343:1250;;;;;;;;:::o;9769:933::-;9821:9;9861:1;9848:9;;:14;9844:198;;;9895:11;;9880:12;:26;;;;;;9876:30;;9844:198;;;9938:1;9925:9;;:14;9921:121;;;9975:11;;9957:15;:29;;;;;;9953:33;;9921:121;;;10013:29;;;;;;;;;;:::i;:::-;;;;;;;;9921:121;9844:198;10079:1;10057:12;:19;10070:5;10057:19;;;;;;;;;;;;:23;10053:534;;;10096:34;;:::i;:::-;:65;;;;;;;;10134:3;:10;10138:5;10134:10;;;;;;;;;;;10096:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10146:7;:14;10154:5;10146:14;;;;;;;;;;;10096:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10191:33;10210:7;10218:1;10210:10;;;;;;;;;;;10221:1;10210:13;;;;;;;;;;;10191:7;10199:1;10191:10;;;;;;;;;;;10202:1;10191:13;;;;;;;;;;;:18;;:33;;;;:::i;:::-;10175:3;:10;10179:5;10175:10;;;;;;;;;;;10186:1;10175:13;;;;;;;;;;:49;;;;;;;;;;;;;;;;;;;10254:33;10273:7;10281:1;10273:10;;;;;;;;;;;10284:1;10273:13;;;;;;;;;;;10254:7;10262:1;10254:10;;;;;;;;;;;10265:1;10254:13;;;;;;;;;;;:18;;:33;;;;:::i;:::-;10238:3;:10;10242:5;10238:10;;;;;;;;;;;10249:1;10238:13;;;;;;;;;;:49;;;;;;;;;;;;;;;;;;;10461:7;:14;10469:5;10461:14;;;;;;;;;;;;10454:21;;;;:::i;:::-;10575:1;10553:12;:19;10566:5;10553:19;;;;;;;;;;;:23;;;;10053:534;;10619:1;10600:16;;:20;10596:100;;;10655:1;10636:16;:20;;;;10677:8;;10670:15;;;;:::i;:::-;10596:100;9769:933;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;:::o;5:146::-;;93:6;80:20;71:29;;105:41;140:5;105:41;:::i;:::-;65:86;;;;:::o;189:782::-;;331:3;324:4;316:6;312:17;308:27;298:2;;349:1;346;339:12;298:2;386:6;373:20;408:105;423:89;505:6;423:89;:::i;:::-;408:105;:::i;:::-;399:114;;530:5;555:6;548:5;541:21;585:4;577:6;573:17;563:27;;607:4;602:3;598:14;591:21;;660:6;707:3;699:4;691:6;687:17;682:3;678:27;675:36;672:2;;;724:1;721;714:12;672:2;749:1;734:231;759:6;756:1;753:13;734:231;;;817:3;839:62;897:3;885:10;839:62;:::i;:::-;834:3;827:75;925:4;920:3;916:14;909:21;;953:4;948:3;944:14;937:21;;791:174;781:1;778;774:9;769:14;;734:231;;;738:14;291:680;;;;;;;:::o;979:128::-;;1060:6;1054:13;1045:22;;1072:30;1096:5;1072:30;:::i;:::-;1039:68;;;;:::o;1114:130::-;;1194:6;1181:20;1172:29;;1206:33;1233:5;1206:33;:::i;:::-;1166:78;;;;:::o;1252:440::-;;1353:3;1346:4;1338:6;1334:17;1330:27;1320:2;;1371:1;1368;1361:12;1320:2;1408:6;1395:20;1430:64;1445:48;1486:6;1445:48;:::i;:::-;1430:64;:::i;:::-;1421:73;;1514:6;1507:5;1500:21;1550:4;1542:6;1538:17;1583:4;1576:5;1572:16;1618:3;1609:6;1604:3;1600:16;1597:25;1594:2;;;1635:1;1632;1625:12;1594:2;1645:41;1679:6;1674:3;1669;1645:41;:::i;:::-;1313:379;;;;;;;:::o;1727:461::-;;1841:4;1829:9;1824:3;1820:19;1816:30;1813:2;;;1859:1;1856;1849:12;1813:2;1877:20;1892:4;1877:20;:::i;:::-;1868:29;;1944:1;1976:49;2021:3;2012:6;2001:9;1997:22;1976:49;:::i;:::-;1969:4;1962:5;1958:16;1951:75;1907:130;2084:2;2117:49;2162:3;2153:6;2142:9;2138:22;2117:49;:::i;:::-;2110:4;2103:5;2099:16;2092:75;2047:131;1807:381;;;;:::o;2195:130::-;;2275:6;2262:20;2253:29;;2287:33;2314:5;2287:33;:::i;:::-;2247:78;;;;:::o;2332:257::-;;2444:2;2432:9;2423:7;2419:23;2415:32;2412:2;;;2460:1;2457;2450:12;2412:2;2495:1;2512:61;2565:7;2556:6;2545:9;2541:22;2512:61;:::i;:::-;2502:71;;2474:105;2406:183;;;;:::o;2596:1320::-;;;;;;2927:3;2915:9;2906:7;2902:23;2898:33;2895:2;;;2944:1;2941;2934:12;2895:2;3007:1;2996:9;2992:17;2979:31;3030:18;3022:6;3019:30;3016:2;;;3062:1;3059;3052:12;3016:2;3082:103;3177:7;3168:6;3157:9;3153:22;3082:103;:::i;:::-;3072:113;;2958:233;3222:2;3240:78;3310:7;3301:6;3290:9;3286:22;3240:78;:::i;:::-;3230:88;;3201:123;3383:2;3372:9;3368:18;3355:32;3407:18;3399:6;3396:30;3393:2;;;3439:1;3436;3429:12;3393:2;3459:103;3554:7;3545:6;3534:9;3530:22;3459:103;:::i;:::-;3449:113;;3334:234;3599:3;3618:78;3688:7;3679:6;3668:9;3664:22;3618:78;:::i;:::-;3608:88;;3578:124;3761:3;3750:9;3746:19;3733:33;3786:18;3778:6;3775:30;3772:2;;;3818:1;3815;3808:12;3772:2;3838:62;3892:7;3883:6;3872:9;3868:22;3838:62;:::i;:::-;3828:72;;3712:194;2889:1027;;;;;;;;:::o;3923:552::-;;;4094:2;4082:9;4073:7;4069:23;4065:32;4062:2;;;4110:1;4107;4100:12;4062:2;4173:1;4162:9;4158:17;4145:31;4196:18;4188:6;4185:30;4182:2;;;4228:1;4225;4218:12;4182:2;4248:103;4343:7;4334:6;4323:9;4319:22;4248:103;:::i;:::-;4238:113;;4124:233;4388:2;4406:53;4451:7;4442:6;4431:9;4427:22;4406:53;:::i;:::-;4396:63;;4367:98;4056:419;;;;;:::o;4482:257::-;;4594:2;4582:9;4573:7;4569:23;4565:32;4562:2;;;4610:1;4607;4600:12;4562:2;4645:1;4662:61;4715:7;4706:6;4695:9;4691:22;4662:61;:::i;:::-;4652:71;;4624:105;4556:183;;;;:::o;4746:241::-;;4850:2;4838:9;4829:7;4825:23;4821:32;4818:2;;;4866:1;4863;4856:12;4818:2;4901:1;4918:53;4963:7;4954:6;4943:9;4939:22;4918:53;:::i;:::-;4908:63;;4880:97;4812:175;;;;:::o;4994:291::-;;5123:2;5111:9;5102:7;5098:23;5094:32;5091:2;;;5139:1;5136;5129:12;5091:2;5174:1;5191:78;5261:7;5252:6;5241:9;5237:22;5191:78;:::i;:::-;5181:88;;5153:122;5085:200;;;;:::o;5292:646::-;;;;5464:3;5452:9;5443:7;5439:23;5435:33;5432:2;;;5481:1;5478;5471:12;5432:2;5516:1;5533:78;5603:7;5594:6;5583:9;5579:22;5533:78;:::i;:::-;5523:88;;5495:122;5648:2;5666:53;5711:7;5702:6;5691:9;5687:22;5666:53;:::i;:::-;5656:63;;5627:98;5784:2;5773:9;5769:18;5756:32;5808:18;5800:6;5797:30;5794:2;;;5840:1;5837;5830:12;5794:2;5860:62;5914:7;5905:6;5894:9;5890:22;5860:62;:::i;:::-;5850:72;;5735:193;5426:512;;;;;:::o;5945:1052::-;;;;;;6185:3;6173:9;6164:7;6160:23;6156:33;6153:2;;;6202:1;6199;6192:12;6153:2;6237:1;6254:78;6324:7;6315:6;6304:9;6300:22;6254:78;:::i;:::-;6244:88;;6216:122;6369:2;6387:53;6432:7;6423:6;6412:9;6408:22;6387:53;:::i;:::-;6377:63;;6348:98;6477:2;6495:78;6565:7;6556:6;6545:9;6541:22;6495:78;:::i;:::-;6485:88;;6456:123;6638:3;6627:9;6623:19;6610:33;6663:18;6655:6;6652:30;6649:2;;;6695:1;6692;6685:12;6649:2;6715:62;6769:7;6760:6;6749:9;6745:22;6715:62;:::i;:::-;6705:72;;6589:194;6842:3;6831:9;6827:19;6814:33;6867:18;6859:6;6856:30;6853:2;;;6899:1;6896;6889:12;6853:2;6919:62;6973:7;6964:6;6953:9;6949:22;6919:62;:::i;:::-;6909:72;;6793:194;6147:850;;;;;;;;:::o;7004:542::-;;;;7167:3;7155:9;7146:7;7142:23;7138:33;7135:2;;;7184:1;7181;7174:12;7135:2;7219:1;7236:78;7306:7;7297:6;7286:9;7282:22;7236:78;:::i;:::-;7226:88;;7198:122;7351:2;7369:53;7414:7;7405:6;7394:9;7390:22;7369:53;:::i;:::-;7359:63;;7330:98;7459:2;7477:53;7522:7;7513:6;7502:9;7498:22;7477:53;:::i;:::-;7467:63;;7438:98;7129:417;;;;;:::o;7553:241::-;;7657:2;7645:9;7636:7;7632:23;7628:32;7625:2;;;7673:1;7670;7663:12;7625:2;7708:1;7725:53;7770:7;7761:6;7750:9;7746:22;7725:53;:::i;:::-;7715:63;;7687:97;7619:175;;;;:::o;7801:366::-;;;7922:2;7910:9;7901:7;7897:23;7893:32;7890:2;;;7938:1;7935;7928:12;7890:2;7973:1;7990:53;8035:7;8026:6;8015:9;8011:22;7990:53;:::i;:::-;7980:63;;7952:97;8080:2;8098:53;8143:7;8134:6;8123:9;8119:22;8098:53;:::i;:::-;8088:63;;8059:98;7884:283;;;;;:::o;8175:365::-;;8358:142;8496:3;8488:6;8358:142;:::i;:::-;8529:4;8524:3;8520:14;8506:28;;8351:189;;;;:::o;8549:273::-;;8686:96;8778:3;8770:6;8686:96;:::i;:::-;8811:4;8806:3;8802:14;8788:28;;8679:143;;;;:::o;8830:142::-;8921:45;8960:5;8921:45;:::i;:::-;8916:3;8909:58;8903:69;;:::o;8979:137::-;9078:32;9104:5;9078:32;:::i;:::-;9073:3;9066:45;9060:56;;:::o;9123:113::-;9206:24;9224:5;9206:24;:::i;:::-;9201:3;9194:37;9188:48;;:::o;9306:1074::-;;9547:102;9643:5;9547:102;:::i;:::-;9662:134;9789:6;9784:3;9662:134;:::i;:::-;9655:141;;9817:104;9915:5;9817:104;:::i;:::-;9941:7;9969:1;9954:404;9979:6;9976:1;9973:13;9954:404;;;10046:6;10040:13;10067:159;10222:3;10207:13;10067:159;:::i;:::-;10060:166;;10243:108;10344:6;10243:108;:::i;:::-;10233:118;;10011:347;10001:1;9998;9994:9;9989:14;;9954:404;;;9958:14;10371:3;10364:10;;9526:854;;;;;;;:::o;10447:840::-;10620:77;10691:5;10620:77;:::i;:::-;10710:99;10802:6;10797:3;10710:99;:::i;:::-;10703:106;;10830:79;10903:5;10830:79;:::i;:::-;10929:7;10957:1;10942:333;10967:6;10964:1;10961:13;10942:333;;;11034:6;11028:13;11055:113;11164:3;11149:13;11055:113;:::i;:::-;11048:120;;11185:83;11261:6;11185:83;:::i;:::-;11175:93;;10999:276;10989:1;10986;10982:9;10977:14;;10942:333;;;10946:14;10599:688;;;;;:::o;11354:860::-;11537:77;11608:5;11537:77;:::i;:::-;11627:109;11729:6;11724:3;11627:109;:::i;:::-;11620:116;;11757:79;11830:5;11757:79;:::i;:::-;11856:7;11884:1;11869:333;11894:6;11891:1;11888:13;11869:333;;;11961:6;11955:13;11982:113;12091:3;12076:13;11982:113;:::i;:::-;11975:120;;12112:83;12188:6;12112:83;:::i;:::-;12102:93;;11926:276;11916:1;11913;11909:9;11904:14;;11869:333;;;11873:14;11516:698;;;;;:::o;12279:890::-;;12474:79;12547:5;12474:79;:::i;:::-;12566:111;12670:6;12665:3;12566:111;:::i;:::-;12559:118;;12698:81;12773:5;12698:81;:::i;:::-;12799:7;12827:1;12812:335;12837:6;12834:1;12831:13;12812:335;;;12904:6;12898:13;12925:113;13034:3;13019:13;12925:113;:::i;:::-;12918:120;;13055:85;13133:6;13055:85;:::i;:::-;13045:95;;12869:278;12859:1;12856;12852:9;12847:14;;12812:335;;;12816:14;13160:3;13153:10;;12453:716;;;;;;;:::o;13177:104::-;13254:21;13269:5;13254:21;:::i;:::-;13249:3;13242:34;13236:45;;:::o;13288:103::-;13361:24;13379:5;13361:24;:::i;:::-;13356:3;13349:37;13343:48;;:::o;13398:343::-;;13508:38;13540:5;13508:38;:::i;:::-;13558:70;13621:6;13616:3;13558:70;:::i;:::-;13551:77;;13633:52;13678:6;13673:3;13666:4;13659:5;13655:16;13633:52;:::i;:::-;13706:29;13728:6;13706:29;:::i;:::-;13701:3;13697:39;13690:46;;13488:253;;;;;:::o;13749:328::-;;13909:67;13973:2;13968:3;13909:67;:::i;:::-;13902:74;;14009:30;14005:1;14000:3;13996:11;13989:51;14068:2;14063:3;14059:12;14052:19;;13895:182;;;:::o;14086:385::-;;14246:67;14310:2;14305:3;14246:67;:::i;:::-;14239:74;;14346:34;14342:1;14337:3;14333:11;14326:55;14415:18;14410:2;14405:3;14401:12;14394:40;14462:2;14457:3;14453:12;14446:19;;14232:239;;;:::o;14480:327::-;;14640:67;14704:2;14699:3;14640:67;:::i;:::-;14633:74;;14740:29;14736:1;14731:3;14727:11;14720:50;14798:2;14793:3;14789:12;14782:19;;14626:181;;;:::o;14816:387::-;;14976:67;15040:2;15035:3;14976:67;:::i;:::-;14969:74;;15076:34;15072:1;15067:3;15063:11;15056:55;15145:20;15140:2;15135:3;15131:12;15124:42;15194:2;15189:3;15185:12;15178:19;;14962:241;;;:::o;15212:391::-;;15372:67;15436:2;15431:3;15372:67;:::i;:::-;15365:74;;15472:34;15468:1;15463:3;15459:11;15452:55;15541:24;15536:2;15531:3;15527:12;15520:46;15594:2;15589:3;15585:12;15578:19;;15358:245;;;:::o;15612:319::-;;15772:67;15836:2;15831:3;15772:67;:::i;:::-;15765:74;;15872:21;15868:1;15863:3;15859:11;15852:42;15922:2;15917:3;15913:12;15906:19;;15758:173;;;:::o;15940:389::-;;16100:67;16164:2;16159:3;16100:67;:::i;:::-;16093:74;;16200:34;16196:1;16191:3;16187:11;16180:55;16269:22;16264:2;16259:3;16255:12;16248:44;16320:2;16315:3;16311:12;16304:19;;16086:243;;;:::o;16338:377::-;;16498:67;16562:2;16557:3;16498:67;:::i;:::-;16491:74;;16598:34;16594:1;16589:3;16585:11;16578:55;16667:10;16662:2;16657:3;16653:12;16646:32;16706:2;16701:3;16697:12;16690:19;;16484:231;;;:::o;16724:324::-;;16884:67;16948:2;16943:3;16884:67;:::i;:::-;16877:74;;16984:26;16980:1;16975:3;16971:11;16964:47;17039:2;17034:3;17030:12;17023:19;;16870:178;;;:::o;17057:331::-;;17217:67;17281:2;17276:3;17217:67;:::i;:::-;17210:74;;17317:33;17313:1;17308:3;17304:11;17297:54;17379:2;17374:3;17370:12;17363:19;;17203:185;;;:::o;17397:383::-;;17557:67;17621:2;17616:3;17557:67;:::i;:::-;17550:74;;17657:34;17653:1;17648:3;17644:11;17637:55;17726:16;17721:2;17716:3;17712:12;17705:38;17771:2;17766:3;17762:12;17755:19;;17543:237;;;:::o;17789:372::-;;17949:67;18013:2;18008:3;17949:67;:::i;:::-;17942:74;;18049:34;18045:1;18040:3;18036:11;18029:55;18118:5;18113:2;18108:3;18104:12;18097:27;18152:2;18147:3;18143:12;18136:19;;17935:226;;;:::o;18170:328::-;;18330:67;18394:2;18389:3;18330:67;:::i;:::-;18323:74;;18430:30;18426:1;18421:3;18417:11;18410:51;18489:2;18484:3;18480:12;18473:19;;18316:182;;;:::o;18507:400::-;;18667:67;18731:2;18726:3;18667:67;:::i;:::-;18660:74;;18767:34;18763:1;18758:3;18754:11;18747:55;18836:33;18831:2;18826:3;18822:12;18815:55;18898:2;18893:3;18889:12;18882:19;;18653:254;;;:::o;18916:327::-;;19076:67;19140:2;19135:3;19076:67;:::i;:::-;19069:74;;19176:29;19172:1;19167:3;19163:11;19156:50;19234:2;19229:3;19225:12;19218:19;;19062:181;;;:::o;19252:319::-;;19412:67;19476:2;19471:3;19412:67;:::i;:::-;19405:74;;19512:21;19508:1;19503:3;19499:11;19492:42;19562:2;19557:3;19553:12;19546:19;;19398:173;;;:::o;19580:329::-;;19740:67;19804:2;19799:3;19740:67;:::i;:::-;19733:74;;19840:31;19836:1;19831:3;19827:11;19820:52;19900:2;19895:3;19891:12;19884:19;;19726:183;;;:::o;19918:319::-;;20078:67;20142:2;20137:3;20078:67;:::i;:::-;20071:74;;20178:21;20174:1;20169:3;20165:11;20158:42;20228:2;20223:3;20219:12;20212:19;;20064:173;;;:::o;20246:396::-;;20406:67;20470:2;20465:3;20406:67;:::i;:::-;20399:74;;20506:34;20502:1;20497:3;20493:11;20486:55;20575:29;20570:2;20565:3;20561:12;20554:51;20633:2;20628:3;20624:12;20617:19;;20392:250;;;:::o;20651:331::-;;20811:67;20875:2;20870:3;20811:67;:::i;:::-;20804:74;;20911:33;20907:1;20902:3;20898:11;20891:54;20973:2;20968:3;20964:12;20957:19;;20797:185;;;:::o;20991:319::-;;21151:67;21215:2;21210:3;21151:67;:::i;:::-;21144:74;;21251:21;21247:1;21242:3;21238:11;21231:42;21301:2;21296:3;21292:12;21285:19;;21137:173;;;:::o;21369:460::-;21502:4;21497:3;21493:14;21582:4;21575:5;21571:16;21565:23;21594:63;21651:4;21646:3;21642:14;21628:12;21594:63;:::i;:::-;21522:141;21733:4;21726:5;21722:16;21716:23;21745:63;21802:4;21797:3;21793:14;21779:12;21745:63;:::i;:::-;21673:141;21475:354;;;:::o;21887:470::-;22030:4;22025:3;22021:14;22110:4;22103:5;22099:16;22093:23;22122:63;22179:4;22174:3;22170:14;22156:12;22122:63;:::i;:::-;22050:141;22261:4;22254:5;22250:16;22244:23;22273:63;22330:4;22325:3;22321:14;22307:12;22273:63;:::i;:::-;22201:141;22003:354;;;:::o;22364:113::-;22447:24;22465:5;22447:24;:::i;:::-;22442:3;22435:37;22429:48;;:::o;22484:254::-;;22627:2;22616:9;22612:18;22604:26;;22641:87;22725:1;22714:9;22710:17;22701:6;22641:87;:::i;:::-;22598:140;;;;:::o;22745:460::-;;22936:2;22925:9;22921:18;22913:26;;22950:79;23026:1;23015:9;23011:17;23002:6;22950:79;:::i;:::-;23040:72;23108:2;23097:9;23093:18;23084:6;23040:72;:::i;:::-;23123;23191:2;23180:9;23176:18;23167:6;23123:72;:::i;:::-;22907:298;;;;;;:::o;23212:349::-;;23375:2;23364:9;23360:18;23352:26;;23389:79;23465:1;23454:9;23450:17;23441:6;23389:79;:::i;:::-;23479:72;23547:2;23536:9;23532:18;23523:6;23479:72;:::i;:::-;23346:215;;;;;:::o;23568:645::-;;23851:3;23840:9;23836:19;23828:27;;23866:71;23934:1;23923:9;23919:17;23910:6;23866:71;:::i;:::-;23948:122;24066:2;24055:9;24051:18;24042:6;23948:122;:::i;:::-;24081;24199:2;24188:9;24184:18;24175:6;24081:122;:::i;:::-;23822:391;;;;;;:::o;24220:562::-;;24493:2;24482:9;24478:18;24470:26;;24543:9;24537:4;24533:20;24529:1;24518:9;24514:17;24507:47;24568:204;24767:4;24758:6;24568:204;:::i;:::-;24560:212;;24464:318;;;;:::o;24789:719::-;;25136:3;25125:9;25121:19;25113:27;;25151:167;25315:1;25304:9;25300:17;25291:6;25151:167;:::i;:::-;25329:169;25493:3;25482:9;25478:19;25469:6;25329:169;:::i;:::-;25107:401;;;;;:::o;25515:470::-;;25742:2;25731:9;25727:18;25719:26;;25792:9;25786:4;25782:20;25778:1;25767:9;25763:17;25756:47;25817:158;25970:4;25961:6;25817:158;:::i;:::-;25809:166;;25713:272;;;;:::o;25992:2280::-;;26833:3;26822:9;26818:19;26810:27;;26884:9;26878:4;26874:20;26870:1;26859:9;26855:17;26848:47;26909:158;27062:4;27053:6;26909:158;:::i;:::-;26901:166;;27115:9;27109:4;27105:20;27100:2;27089:9;27085:18;27078:48;27140:158;27293:4;27284:6;27140:158;:::i;:::-;27132:166;;27346:9;27340:4;27336:20;27331:2;27320:9;27316:18;27309:48;27371:158;27524:4;27515:6;27371:158;:::i;:::-;27363:166;;27540:122;27658:2;27647:9;27643:18;27634:6;27540:122;:::i;:::-;27711:9;27705:4;27701:20;27695:3;27684:9;27680:19;27673:49;27736:158;27889:4;27880:6;27736:158;:::i;:::-;27728:166;;27905:73;27973:3;27962:9;27958:19;27949:6;27905:73;:::i;:::-;27989:123;28107:3;28096:9;28092:19;28083:6;27989:123;:::i;:::-;28161:9;28155:4;28151:20;28145:3;28134:9;28130:19;28123:49;28186:76;28257:4;28248:6;28186:76;:::i;:::-;28178:84;;26804:1468;;;;;;;;;;;:::o;28279:210::-;;28400:2;28389:9;28385:18;28377:26;;28414:65;28476:1;28465:9;28461:17;28452:6;28414:65;:::i;:::-;28371:118;;;;:::o;28496:306::-;;28641:2;28630:9;28626:18;28618:26;;28691:9;28685:4;28681:20;28677:1;28666:9;28662:17;28655:47;28716:76;28787:4;28778:6;28716:76;:::i;:::-;28708:84;;28612:190;;;;:::o;28809:416::-;;29009:2;28998:9;28994:18;28986:26;;29059:9;29053:4;29049:20;29045:1;29034:9;29030:17;29023:47;29084:131;29210:4;29084:131;:::i;:::-;29076:139;;28980:245;;;:::o;29232:416::-;;29432:2;29421:9;29417:18;29409:26;;29482:9;29476:4;29472:20;29468:1;29457:9;29453:17;29446:47;29507:131;29633:4;29507:131;:::i;:::-;29499:139;;29403:245;;;:::o;29655:416::-;;29855:2;29844:9;29840:18;29832:26;;29905:9;29899:4;29895:20;29891:1;29880:9;29876:17;29869:47;29930:131;30056:4;29930:131;:::i;:::-;29922:139;;29826:245;;;:::o;30078:416::-;;30278:2;30267:9;30263:18;30255:26;;30328:9;30322:4;30318:20;30314:1;30303:9;30299:17;30292:47;30353:131;30479:4;30353:131;:::i;:::-;30345:139;;30249:245;;;:::o;30501:416::-;;30701:2;30690:9;30686:18;30678:26;;30751:9;30745:4;30741:20;30737:1;30726:9;30722:17;30715:47;30776:131;30902:4;30776:131;:::i;:::-;30768:139;;30672:245;;;:::o;30924:416::-;;31124:2;31113:9;31109:18;31101:26;;31174:9;31168:4;31164:20;31160:1;31149:9;31145:17;31138:47;31199:131;31325:4;31199:131;:::i;:::-;31191:139;;31095:245;;;:::o;31347:416::-;;31547:2;31536:9;31532:18;31524:26;;31597:9;31591:4;31587:20;31583:1;31572:9;31568:17;31561:47;31622:131;31748:4;31622:131;:::i;:::-;31614:139;;31518:245;;;:::o;31770:416::-;;31970:2;31959:9;31955:18;31947:26;;32020:9;32014:4;32010:20;32006:1;31995:9;31991:17;31984:47;32045:131;32171:4;32045:131;:::i;:::-;32037:139;;31941:245;;;:::o;32193:416::-;;32393:2;32382:9;32378:18;32370:26;;32443:9;32437:4;32433:20;32429:1;32418:9;32414:17;32407:47;32468:131;32594:4;32468:131;:::i;:::-;32460:139;;32364:245;;;:::o;32616:416::-;;32816:2;32805:9;32801:18;32793:26;;32866:9;32860:4;32856:20;32852:1;32841:9;32837:17;32830:47;32891:131;33017:4;32891:131;:::i;:::-;32883:139;;32787:245;;;:::o;33039:416::-;;33239:2;33228:9;33224:18;33216:26;;33289:9;33283:4;33279:20;33275:1;33264:9;33260:17;33253:47;33314:131;33440:4;33314:131;:::i;:::-;33306:139;;33210:245;;;:::o;33462:416::-;;33662:2;33651:9;33647:18;33639:26;;33712:9;33706:4;33702:20;33698:1;33687:9;33683:17;33676:47;33737:131;33863:4;33737:131;:::i;:::-;33729:139;;33633:245;;;:::o;33885:416::-;;34085:2;34074:9;34070:18;34062:26;;34135:9;34129:4;34125:20;34121:1;34110:9;34106:17;34099:47;34160:131;34286:4;34160:131;:::i;:::-;34152:139;;34056:245;;;:::o;34308:416::-;;34508:2;34497:9;34493:18;34485:26;;34558:9;34552:4;34548:20;34544:1;34533:9;34529:17;34522:47;34583:131;34709:4;34583:131;:::i;:::-;34575:139;;34479:245;;;:::o;34731:416::-;;34931:2;34920:9;34916:18;34908:26;;34981:9;34975:4;34971:20;34967:1;34956:9;34952:17;34945:47;35006:131;35132:4;35006:131;:::i;:::-;34998:139;;34902:245;;;:::o;35154:416::-;;35354:2;35343:9;35339:18;35331:26;;35404:9;35398:4;35394:20;35390:1;35379:9;35375:17;35368:47;35429:131;35555:4;35429:131;:::i;:::-;35421:139;;35325:245;;;:::o;35577:416::-;;35777:2;35766:9;35762:18;35754:26;;35827:9;35821:4;35817:20;35813:1;35802:9;35798:17;35791:47;35852:131;35978:4;35852:131;:::i;:::-;35844:139;;35748:245;;;:::o;36000:416::-;;36200:2;36189:9;36185:18;36177:26;;36250:9;36244:4;36240:20;36236:1;36225:9;36221:17;36214:47;36275:131;36401:4;36275:131;:::i;:::-;36267:139;;36171:245;;;:::o;36423:416::-;;36623:2;36612:9;36608:18;36600:26;;36673:9;36667:4;36663:20;36659:1;36648:9;36644:17;36637:47;36698:131;36824:4;36698:131;:::i;:::-;36690:139;;36594:245;;;:::o;36846:416::-;;37046:2;37035:9;37031:18;37023:26;;37096:9;37090:4;37086:20;37082:1;37071:9;37067:17;37060:47;37121:131;37247:4;37121:131;:::i;:::-;37113:139;;37017:245;;;:::o;37269:416::-;;37469:2;37458:9;37454:18;37446:26;;37519:9;37513:4;37509:20;37505:1;37494:9;37490:17;37483:47;37544:131;37670:4;37544:131;:::i;:::-;37536:139;;37440:245;;;:::o;37692:322::-;;37869:2;37858:9;37854:18;37846:26;;37883:121;38001:1;37990:9;37986:17;37977:6;37883:121;:::i;:::-;37840:174;;;;:::o;38021:1394::-;;38542:3;38531:9;38527:19;38519:27;;38557:121;38675:1;38664:9;38660:17;38651:6;38557:121;:::i;:::-;38689:122;38807:2;38796:9;38792:18;38783:6;38689:122;:::i;:::-;38822:123;38940:3;38929:9;38925:19;38916:6;38822:123;:::i;:::-;38956:73;39024:3;39013:9;39009:19;39000:6;38956:73;:::i;:::-;39040:123;39158:3;39147:9;39143:19;39134:6;39040:123;:::i;:::-;39174:81;39250:3;39239:9;39235:19;39226:6;39174:81;:::i;:::-;39304:9;39298:4;39294:20;39288:3;39277:9;39273:19;39266:49;39329:76;39400:4;39391:6;39329:76;:::i;:::-;39321:84;;38513:902;;;;;;;;;;:::o;39422:222::-;;39549:2;39538:9;39534:18;39526:26;;39563:71;39631:1;39620:9;39616:17;39607:6;39563:71;:::i;:::-;39520:124;;;;:::o;39651:256::-;;39713:2;39707:9;39697:19;;39751:4;39743:6;39739:17;39850:6;39838:10;39835:22;39814:18;39802:10;39799:34;39796:62;39793:2;;;39871:1;39868;39861:12;39793:2;39891:10;39887:2;39880:22;39691:216;;;;:::o;39914:329::-;;40098:18;40090:6;40087:30;40084:2;;;40130:1;40127;40120:12;40084:2;40165:4;40157:6;40153:17;40145:25;;40228:4;40222;40218:15;40210:23;;40021:222;;;:::o;40250:321::-;;40393:18;40385:6;40382:30;40379:2;;;40425:1;40422;40415:12;40379:2;40492:4;40488:9;40481:4;40473:6;40469:17;40465:33;40457:41;;40556:4;40550;40546:15;40538:23;;40316:255;;;:::o;40578:199::-;;40712:3;40704:11;;40750:4;40745:3;40741:14;40733:22;;40698:79;;;:::o;40784:122::-;;40893:3;40885:11;;40879:27;;;:::o;40913:176::-;;41024:3;41016:11;;41062:4;41057:3;41053:14;41045:22;;41010:79;;;:::o;41096:185::-;;41253:5;41247:12;41237:22;;41218:63;;;:::o;41288:133::-;;41407:4;41397:14;;41385:36;;;:::o;41428:162::-;;41562:5;41556:12;41546:22;;41527:63;;;:::o;41597:121::-;;41690:5;41684:12;41674:22;;41655:63;;;:::o;41725:156::-;;41871:4;41866:3;41862:14;41854:22;;41848:33;;;:::o;41888:131::-;;42009:4;42004:3;42000:14;41992:22;;41986:33;;;:::o;42026:133::-;;42149:4;42144:3;42140:14;42132:22;;42126:33;;;:::o;42167:226::-;;42345:6;42340:3;42333:19;42382:4;42377:3;42373:14;42358:29;;42326:67;;;;:::o;42402:155::-;;42548:3;42533:18;;42526:31;;;;:::o;42566:165::-;;42722:3;42707:18;;42700:31;;;;:::o;42740:203::-;;42895:6;42890:3;42883:19;42932:4;42927:3;42923:14;42908:29;;42876:67;;;;:::o;42952:162::-;;43066:6;43061:3;43054:19;43103:4;43098:3;43094:14;43079:29;;43047:67;;;;:::o;43123:163::-;;43238:6;43233:3;43226:19;43275:4;43270:3;43266:14;43251:29;;43219:67;;;;:::o;43294:91::-;;43356:24;43374:5;43356:24;:::i;:::-;43345:35;;43339:46;;;:::o;43392:99::-;;43462:24;43480:5;43462:24;:::i;:::-;43451:35;;43445:46;;;:::o;43498:85::-;;43571:5;43564:13;43557:21;43546:32;;43540:43;;;:::o;43590:72::-;;43652:5;43641:16;;43635:27;;;:::o;43669:121::-;;43742:42;43735:5;43731:54;43720:65;;43714:76;;;:::o;43797:72::-;;43859:5;43848:16;;43842:27;;;:::o;43876:129::-;;43963:37;43994:5;43963:37;:::i;:::-;43950:50;;43944:61;;;:::o;44012:121::-;;44091:37;44122:5;44091:37;:::i;:::-;44078:50;;44072:61;;;:::o;44140:108::-;;44219:24;44237:5;44219:24;:::i;:::-;44206:37;;44200:48;;;:::o;44256:145::-;44337:6;44332:3;44327;44314:30;44393:1;44384:6;44379:3;44375:16;44368:27;44307:94;;;:::o;44410:268::-;44475:1;44482:101;44496:6;44493:1;44490:13;44482:101;;;44572:1;44567:3;44563:11;44557:18;44553:1;44548:3;44544:11;44537:39;44518:2;44515:1;44511:10;44506:15;;44482:101;;;44598:6;44595:1;44592:13;44589:2;;;44663:1;44654:6;44649:3;44645:16;44638:27;44589:2;44459:219;;;;:::o;44686:97::-;;44774:2;44770:7;44765:2;44758:5;44754:14;44750:28;44740:38;;44734:49;;;:::o;44791:133::-;44868:32;44894:5;44868:32;:::i;:::-;44861:5;44858:43;44848:2;;44915:1;44912;44905:12;44848:2;44842:82;:::o;44931:111::-;44997:21;45012:5;44997:21;:::i;:::-;44990:5;44987:32;44977:2;;45033:1;45030;45023:12;44977:2;44971:71;:::o;45049:117::-;45118:24;45136:5;45118:24;:::i;:::-;45111:5;45108:35;45098:2;;45157:1;45154;45147:12;45098:2;45092:74;:::o;45173:117::-;45242:24;45260:5;45242:24;:::i;:::-;45235:5;45232:35;45222:2;;45281:1;45278;45271:12;45222:2;45216:74;:::o

Swarm Source

ipfs://56695844caa0f1ebe5998444fb454f3d0114d09e71859029212c139d916547d4
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.