{
  "address": "0x77D3d884FeA1E389150a26D4569b20ebA284A86d",
  "abi": [
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_token",
          "type": "address"
        },
        {
          "internalType": "string",
          "name": "_name",
          "type": "string"
        },
        {
          "internalType": "string",
          "name": "_symbol",
          "type": "string"
        },
        {
          "internalType": "uint256",
          "name": "_interval",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "_maxDuration",
          "type": "uint256"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "constructor"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "provider",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "discount",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "penaltyRate",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        }
      ],
      "name": "Cancel",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "provider",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "discount",
          "type": "uint256"
        },
        {
          "indexed": true,
          "internalType": "uint256",
          "name": "unlockTime",
          "type": "uint256"
        },
        {
          "indexed": true,
          "internalType": "int128",
          "name": "_type",
          "type": "int128"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        }
      ],
      "name": "Deposit",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "provider",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "discount",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        }
      ],
      "name": "Migrate",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "previousOwner",
          "type": "address"
        },
        {
          "indexed": true,
          "internalType": "address",
          "name": "newOwner",
          "type": "address"
        }
      ],
      "name": "OwnershipTransferred",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "account",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "bool",
          "name": "isDelegate",
          "type": "bool"
        }
      ],
      "name": "SetDelegate",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "account",
          "type": "address"
        }
      ],
      "name": "SetMigrator",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "prevSupply",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "supply",
          "type": "uint256"
        }
      ],
      "name": "Supply",
      "type": "event"
    },
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "provider",
          "type": "address"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "value",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "discount",
          "type": "uint256"
        },
        {
          "indexed": false,
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        }
      ],
      "name": "Withdraw",
      "type": "event"
    },
    {
      "inputs": [],
      "name": "CRETE_LOCK_TYPE",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "DEPOSIT_FOR_TYPE",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "INCREASE_LOCK_AMOUNT",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "INCREASE_UNLOCK_TIME",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_t",
          "type": "uint256"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "balanceOf",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_block",
          "type": "uint256"
        }
      ],
      "name": "balanceOfAt",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "cancel",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "checkpoint",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "_value",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "_duration",
          "type": "uint256"
        }
      ],
      "name": "createLock",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_value",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "_discount",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "_duration",
          "type": "uint256"
        }
      ],
      "name": "createLockFor",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "decimals",
      "outputs": [
        {
          "internalType": "uint8",
          "name": "",
          "type": "uint8"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "delegateAt",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "delegateLength",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_value",
          "type": "uint256"
        }
      ],
      "name": "depositFor",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "epoch",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_idx",
          "type": "uint256"
        }
      ],
      "name": "getCheckpointTime",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "addr",
          "type": "address"
        }
      ],
      "name": "getLastUserSlope",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "_value",
          "type": "uint256"
        }
      ],
      "name": "increaseAmount",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_addr",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "_value",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "_discount",
          "type": "uint256"
        }
      ],
      "name": "increaseAmountFor",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "_duration",
          "type": "uint256"
        }
      ],
      "name": "increaseUnlockTime",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "interval",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "name": "isDelegate",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "name": "locked",
      "outputs": [
        {
          "internalType": "int128",
          "name": "amount",
          "type": "int128"
        },
        {
          "internalType": "int128",
          "name": "discount",
          "type": "int128"
        },
        {
          "internalType": "uint256",
          "name": "start",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "end",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "maxDuration",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "migrate",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "name": "migrated",
      "outputs": [
        {
          "internalType": "bool",
          "name": "",
          "type": "bool"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "migrator",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "name",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "owner",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "pointHistory",
      "outputs": [
        {
          "internalType": "int128",
          "name": "bias",
          "type": "int128"
        },
        {
          "internalType": "int128",
          "name": "slope",
          "type": "int128"
        },
        {
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "blk",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "renounceOwnership",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "account",
          "type": "address"
        },
        {
          "internalType": "bool",
          "name": "_isDelegate",
          "type": "bool"
        }
      ],
      "name": "setDelegate",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_migrator",
          "type": "address"
        }
      ],
      "name": "setMigrator",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "slopeChanges",
      "outputs": [
        {
          "internalType": "int128",
          "name": "",
          "type": "int128"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "supply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "symbol",
      "outputs": [
        {
          "internalType": "string",
          "name": "",
          "type": "string"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "token",
      "outputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "totalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "t",
          "type": "uint256"
        }
      ],
      "name": "totalSupply",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "uint256",
          "name": "_block",
          "type": "uint256"
        }
      ],
      "name": "totalSupplyAt",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "newOwner",
          "type": "address"
        }
      ],
      "name": "transferOwnership",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "_addr",
          "type": "address"
        }
      ],
      "name": "unlockTime",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        }
      ],
      "name": "userPointEpoch",
      "outputs": [
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "",
          "type": "address"
        },
        {
          "internalType": "uint256",
          "name": "",
          "type": "uint256"
        }
      ],
      "name": "userPointHistory",
      "outputs": [
        {
          "internalType": "int128",
          "name": "bias",
          "type": "int128"
        },
        {
          "internalType": "int128",
          "name": "slope",
          "type": "int128"
        },
        {
          "internalType": "uint256",
          "name": "ts",
          "type": "uint256"
        },
        {
          "internalType": "uint256",
          "name": "blk",
          "type": "uint256"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [],
      "name": "withdraw",
      "outputs": [],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ],
  "transactionHash": "0x1064f0b310cd50cc56773b40a85f7746c3da04bc1ba84fb59ca4d3ee90fc47bd",
  "receipt": {
    "to": null,
    "from": "0x5b8C253517b6Bd003369173109693B01cb6841B5",
    "contractAddress": "0x77D3d884FeA1E389150a26D4569b20ebA284A86d",
    "transactionIndex": 229,
    "gasUsed": "3430744",
    "logsBloom": "0x00000000000000000100000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000020400000000000000000008000000000000000000000000000000000000000000000",
    "blockHash": "0x4680ddf4f5057c612e1a6528d2ac10e7f6999df0e039e026664c954423f69ea3",
    "transactionHash": "0x1064f0b310cd50cc56773b40a85f7746c3da04bc1ba84fb59ca4d3ee90fc47bd",
    "logs": [
      {
        "transactionIndex": 229,
        "blockNumber": 14903250,
        "transactionHash": "0x1064f0b310cd50cc56773b40a85f7746c3da04bc1ba84fb59ca4d3ee90fc47bd",
        "address": "0x77D3d884FeA1E389150a26D4569b20ebA284A86d",
        "topics": [
          "0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0",
          "0x0000000000000000000000000000000000000000000000000000000000000000",
          "0x0000000000000000000000005b8c253517b6bd003369173109693b01cb6841b5"
        ],
        "data": "0x",
        "logIndex": 413,
        "blockHash": "0x4680ddf4f5057c612e1a6528d2ac10e7f6999df0e039e026664c954423f69ea3"
      }
    ],
    "blockNumber": 14903250,
    "cumulativeGasUsed": "29476925",
    "status": 1,
    "byzantium": true
  },
  "args": [
    "0xf474E526ADe9aD2CC2B66ffCE528B1A51B91FCdC",
    "Voting-escrowed LEVX",
    "THANO$",
    259200,
    62985600
  ],
  "solcInputHash": "e47e3caa7a97fd9ed213c8c8516f216a",
  "metadata": "{\"compiler\":{\"version\":\"0.8.14+commit.80d49f37\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_token\",\"type\":\"address\"},{\"internalType\":\"string\",\"name\":\"_name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"_symbol\",\"type\":\"string\"},{\"internalType\":\"uint256\",\"name\":\"_interval\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_maxDuration\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"discount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"penaltyRate\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"Cancel\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"discount\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"unlockTime\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"int128\",\"name\":\"_type\",\"type\":\"int128\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"Deposit\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"discount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"Migrate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"bool\",\"name\":\"isDelegate\",\"type\":\"bool\"}],\"name\":\"SetDelegate\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"SetMigrator\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"prevSupply\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"supply\",\"type\":\"uint256\"}],\"name\":\"Supply\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"provider\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"discount\",\"type\":\"uint256\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"}],\"name\":\"Withdraw\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"CRETE_LOCK_TYPE\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"DEPOSIT_FOR_TYPE\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCREASE_LOCK_AMOUNT\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"INCREASE_UNLOCK_TIME\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_t\",\"type\":\"uint256\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_block\",\"type\":\"uint256\"}],\"name\":\"balanceOfAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"cancel\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"checkpoint\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"createLock\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_discount\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"createLockFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"delegateAt\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"delegateLength\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"depositFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"epoch\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_idx\",\"type\":\"uint256\"}],\"name\":\"getCheckpointTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getLastUserSlope\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"increaseAmount\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_discount\",\"type\":\"uint256\"}],\"name\":\"increaseAmountFor\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_duration\",\"type\":\"uint256\"}],\"name\":\"increaseUnlockTime\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"interval\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"isDelegate\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"locked\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"amount\",\"type\":\"int128\"},{\"internalType\":\"int128\",\"name\":\"discount\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"start\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"end\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"maxDuration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"migrated\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"migrator\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"pointHistory\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"bias\",\"type\":\"int128\"},{\"internalType\":\"int128\",\"name\":\"slope\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blk\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"_isDelegate\",\"type\":\"bool\"}],\"name\":\"setDelegate\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_migrator\",\"type\":\"address\"}],\"name\":\"setMigrator\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"slopeChanges\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"\",\"type\":\"int128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"supply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"token\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"t\",\"type\":\"uint256\"}],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_block\",\"type\":\"uint256\"}],\"name\":\"totalSupplyAt\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_addr\",\"type\":\"address\"}],\"name\":\"unlockTime\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"name\":\"userPointEpoch\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"userPointHistory\",\"outputs\":[{\"internalType\":\"int128\",\"name\":\"bias\",\"type\":\"int128\"},{\"internalType\":\"int128\",\"name\":\"slope\",\"type\":\"int128\"},{\"internalType\":\"uint256\",\"name\":\"ts\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"blk\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdraw\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"LevX (team@levx.io)\",\"details\":\"Vote weight decays linearly over time. Lock time cannot be      more than `MAXTIME`.Ported from vyper (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)\",\"kind\":\"dev\",\"methods\":{\"balanceOf(address,uint256)\":{\"details\":\"Adheres to the ERC20 `balanceOf` interface for Aragon compatibility\",\"params\":{\"_t\":\"Epoch time to return voting power at\",\"addr\":\"User wallet address\"},\"returns\":{\"_0\":\"User voting power\"}},\"balanceOfAt(address,uint256)\":{\"details\":\"Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime\",\"params\":{\"_block\":\"Block to calculate the voting power at\",\"addr\":\"User's wallet address\"},\"returns\":{\"_0\":\"Voting power\"}},\"cancel()\":{\"details\":\"Only possible if the lock exists\"},\"createLock(uint256,uint256)\":{\"params\":{\"_duration\":\"Epoch time until tokens unlock from now\",\"_value\":\"Amount to deposit\"}},\"createLockFor(address,uint256,uint256,uint256)\":{\"details\":\"Only delegates can creat a lock for someone else\",\"params\":{\"_addr\":\"User's wallet address\",\"_discount\":\"Amount to get discounted out of _value\",\"_duration\":\"Epoch time until tokens unlock from now\",\"_value\":\"Amount to add to user's lock\"}},\"depositFor(address,uint256)\":{\"details\":\"Anyone (even a smart contract) can deposit for someone else, but      cannot extend their locktime and deposit for a brand new user\",\"params\":{\"_addr\":\"User's wallet address\",\"_value\":\"Amount to add to user's lock\"}},\"getCheckpointTime(address,uint256)\":{\"params\":{\"_addr\":\"User wallet address\",\"_idx\":\"User epoch number\"},\"returns\":{\"_0\":\"Epoch time of the checkpoint\"}},\"getLastUserSlope(address)\":{\"params\":{\"addr\":\"Address of the user wallet\"},\"returns\":{\"_0\":\"Value of the slope\"}},\"increaseAmount(uint256)\":{\"params\":{\"_value\":\"Amount of tokens to deposit and add to the lock\"}},\"increaseAmountFor(address,uint256,uint256)\":{\"params\":{\"_addr\":\"User's wallet address\",\"_discount\":\"Amount to get discounted out of _value\",\"_value\":\"Amount of tokens to deposit and add to the lock\"}},\"increaseUnlockTime(uint256)\":{\"params\":{\"_duration\":\"Increased epoch time for unlocking\"}},\"owner()\":{\"details\":\"Returns the address of the current owner.\"},\"renounceOwnership()\":{\"details\":\"Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner.\"},\"totalSupply(uint256)\":{\"details\":\"Adheres to the ERC20 `totalSupply` interface for Aragon compatibility\",\"returns\":{\"_0\":\"Total voting power\"}},\"totalSupplyAt(uint256)\":{\"params\":{\"_block\":\"Block to calculate the total voting power at\"},\"returns\":{\"_0\":\"Total voting power at `_block`\"}},\"transferOwnership(address)\":{\"details\":\"Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner.\"},\"unlockTime(address)\":{\"params\":{\"_addr\":\"User wallet\"},\"returns\":{\"_0\":\"Epoch time of the lock end\"}},\"withdraw()\":{\"details\":\"Only possible if the lock has expired\"}},\"title\":\"Voting Escrow\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"balanceOf(address,uint256)\":{\"notice\":\"Get the current voting power for `msg.sender`\"},\"balanceOfAt(address,uint256)\":{\"notice\":\"Measure voting power of `addr` at block height `_block`\"},\"cancel()\":{\"notice\":\"Cancel the existing lock of `msg.sender` with penalty\"},\"checkpoint()\":{\"notice\":\"Record global data to checkpoint\"},\"createLock(uint256,uint256)\":{\"notice\":\"Deposit `_value` tokens for `msg.sender` and lock for `_duration`\"},\"createLockFor(address,uint256,uint256,uint256)\":{\"notice\":\"Deposit `_value` tokens with `_discount` for `_addr` and lock for `_duration`\"},\"depositFor(address,uint256)\":{\"notice\":\"Deposit `_value` tokens for `_addr` and add to the lock\"},\"getCheckpointTime(address,uint256)\":{\"notice\":\"Get the timestamp for checkpoint `_idx` for `_addr`\"},\"getLastUserSlope(address)\":{\"notice\":\"Get the most recently recorded rate of voting power decrease for `addr`\"},\"increaseAmount(uint256)\":{\"notice\":\"Deposit `_value` additional tokens for `msg.sender`          without modifying the unlock time\"},\"increaseAmountFor(address,uint256,uint256)\":{\"notice\":\"Deposit `_value` additional tokens for `msg.sender`          without modifying the unlock time\"},\"increaseUnlockTime(uint256)\":{\"notice\":\"Extend the unlock time for `msg.sender` to `_duration`\"},\"totalSupply(uint256)\":{\"notice\":\"Calculate total voting power\"},\"totalSupplyAt(uint256)\":{\"notice\":\"Calculate total voting power at some point in the past\"},\"unlockTime(address)\":{\"notice\":\"Get timestamp when `_addr`'s lock finishes\"},\"withdraw()\":{\"notice\":\"Withdraw all tokens for `msg.sender`\"}},\"notice\":\"Votes have a weight depending on time, so that users are         committed to the future of (whatever they are voting for)\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/VotingEscrow.sol\":\"VotingEscrow\"},\"evmVersion\":\"london\",\"libraries\":{\":__CACHE_BREAKER__\":\"0x00000000d41867734bbee4c6863d9255b2b06ac1\"},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@openzeppelin/contracts/access/Ownable.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (access/Ownable.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../utils/Context.sol\\\";\\n\\n/**\\n * @dev Contract module which provides a basic access control mechanism, where\\n * there is an account (an owner) that can be granted exclusive access to\\n * specific functions.\\n *\\n * By default, the owner account will be the one that deploys the contract. This\\n * can later be changed with {transferOwnership}.\\n *\\n * This module is used through inheritance. It will make available the modifier\\n * `onlyOwner`, which can be applied to your functions to restrict their use to\\n * the owner.\\n */\\nabstract contract Ownable is Context {\\n    address private _owner;\\n\\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\\n\\n    /**\\n     * @dev Initializes the contract setting the deployer as the initial owner.\\n     */\\n    constructor() {\\n        _transferOwnership(_msgSender());\\n    }\\n\\n    /**\\n     * @dev Returns the address of the current owner.\\n     */\\n    function owner() public view virtual returns (address) {\\n        return _owner;\\n    }\\n\\n    /**\\n     * @dev Throws if called by any account other than the owner.\\n     */\\n    modifier onlyOwner() {\\n        require(owner() == _msgSender(), \\\"Ownable: caller is not the owner\\\");\\n        _;\\n    }\\n\\n    /**\\n     * @dev Leaves the contract without owner. It will not be possible to call\\n     * `onlyOwner` functions anymore. Can only be called by the current owner.\\n     *\\n     * NOTE: Renouncing ownership will leave the contract without an owner,\\n     * thereby removing any functionality that is only available to the owner.\\n     */\\n    function renounceOwnership() public virtual onlyOwner {\\n        _transferOwnership(address(0));\\n    }\\n\\n    /**\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n     * Can only be called by the current owner.\\n     */\\n    function transferOwnership(address newOwner) public virtual onlyOwner {\\n        require(newOwner != address(0), \\\"Ownable: new owner is the zero address\\\");\\n        _transferOwnership(newOwner);\\n    }\\n\\n    /**\\n     * @dev Transfers ownership of the contract to a new account (`newOwner`).\\n     * Internal function without access restriction.\\n     */\\n    function _transferOwnership(address newOwner) internal virtual {\\n        address oldOwner = _owner;\\n        _owner = newOwner;\\n        emit OwnershipTransferred(oldOwner, newOwner);\\n    }\\n}\\n\",\"keccak256\":\"0x24e0364e503a9bbde94c715d26573a76f14cd2a202d45f96f52134ab806b67b9\",\"license\":\"MIT\"},\"@openzeppelin/contracts/security/ReentrancyGuard.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Contract module that helps prevent reentrant calls to a function.\\n *\\n * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier\\n * available, which can be applied to functions to make sure there are no nested\\n * (reentrant) calls to them.\\n *\\n * Note that because there is a single `nonReentrant` guard, functions marked as\\n * `nonReentrant` may not call one another. This can be worked around by making\\n * those functions `private`, and then adding `external` `nonReentrant` entry\\n * points to them.\\n *\\n * TIP: If you would like to learn more about reentrancy and alternative ways\\n * to protect against it, check out our blog post\\n * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].\\n */\\nabstract contract ReentrancyGuard {\\n    // Booleans are more expensive than uint256 or any type that takes up a full\\n    // word because each write operation emits an extra SLOAD to first read the\\n    // slot's contents, replace the bits taken up by the boolean, and then write\\n    // back. This is the compiler's defense against contract upgrades and\\n    // pointer aliasing, and it cannot be disabled.\\n\\n    // The values being non-zero value makes deployment a bit more expensive,\\n    // but in exchange the refund on every call to nonReentrant will be lower in\\n    // amount. Since refunds are capped to a percentage of the total\\n    // transaction's gas, it is best to keep them low in cases like this one, to\\n    // increase the likelihood of the full refund coming into effect.\\n    uint256 private constant _NOT_ENTERED = 1;\\n    uint256 private constant _ENTERED = 2;\\n\\n    uint256 private _status;\\n\\n    constructor() {\\n        _status = _NOT_ENTERED;\\n    }\\n\\n    /**\\n     * @dev Prevents a contract from calling itself, directly or indirectly.\\n     * Calling a `nonReentrant` function from another `nonReentrant`\\n     * function is not supported. It is possible to prevent this from happening\\n     * by making the `nonReentrant` function external, and making it call a\\n     * `private` function that does the actual work.\\n     */\\n    modifier nonReentrant() {\\n        // On the first call to nonReentrant, _notEntered will be true\\n        require(_status != _ENTERED, \\\"ReentrancyGuard: reentrant call\\\");\\n\\n        // Any calls to nonReentrant after this point will fail\\n        _status = _ENTERED;\\n\\n        _;\\n\\n        // By storing the original value once again, a refund is triggered (see\\n        // https://eips.ethereum.org/EIPS/eip-2200)\\n        _status = _NOT_ENTERED;\\n    }\\n}\\n\",\"keccak256\":\"0x0e9621f60b2faabe65549f7ed0f24e8853a45c1b7990d47e8160e523683f3935\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Interface of the ERC20 standard as defined in the EIP.\\n */\\ninterface IERC20 {\\n    /**\\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\\n     * another (`to`).\\n     *\\n     * Note that `value` may be zero.\\n     */\\n    event Transfer(address indexed from, address indexed to, uint256 value);\\n\\n    /**\\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\\n     * a call to {approve}. `value` is the new allowance.\\n     */\\n    event Approval(address indexed owner, address indexed spender, uint256 value);\\n\\n    /**\\n     * @dev Returns the amount of tokens in existence.\\n     */\\n    function totalSupply() external view returns (uint256);\\n\\n    /**\\n     * @dev Returns the amount of tokens owned by `account`.\\n     */\\n    function balanceOf(address account) external view returns (uint256);\\n\\n    /**\\n     * @dev Moves `amount` tokens from the caller's account to `to`.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transfer(address to, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Returns the remaining number of tokens that `spender` will be\\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\\n     * zero by default.\\n     *\\n     * This value changes when {approve} or {transferFrom} are called.\\n     */\\n    function allowance(address owner, address spender) external view returns (uint256);\\n\\n    /**\\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\\n     * that someone may use both the old and the new allowance by unfortunate\\n     * transaction ordering. One possible solution to mitigate this race\\n     * condition is to first reduce the spender's allowance to 0 and set the\\n     * desired value afterwards:\\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\\n     *\\n     * Emits an {Approval} event.\\n     */\\n    function approve(address spender, uint256 amount) external returns (bool);\\n\\n    /**\\n     * @dev Moves `amount` tokens from `from` to `to` using the\\n     * allowance mechanism. `amount` is then deducted from the caller's\\n     * allowance.\\n     *\\n     * Returns a boolean value indicating whether the operation succeeded.\\n     *\\n     * Emits a {Transfer} event.\\n     */\\n    function transferFrom(\\n        address from,\\n        address to,\\n        uint256 amount\\n    ) external returns (bool);\\n}\\n\",\"keccak256\":\"0x9750c6b834f7b43000631af5cc30001c5f547b3ceb3635488f140f60e897ea6b\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\n\\n/**\\n * @dev Interface for the optional metadata functions from the ERC20 standard.\\n *\\n * _Available since v4.1._\\n */\\ninterface IERC20Metadata is IERC20 {\\n    /**\\n     * @dev Returns the name of the token.\\n     */\\n    function name() external view returns (string memory);\\n\\n    /**\\n     * @dev Returns the symbol of the token.\\n     */\\n    function symbol() external view returns (string memory);\\n\\n    /**\\n     * @dev Returns the decimals places of the token.\\n     */\\n    function decimals() external view returns (uint8);\\n}\\n\",\"keccak256\":\"0x8de418a5503946cabe331f35fe242d3201a73f67f77aaeb7110acb1f30423aca\",\"license\":\"MIT\"},\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)\\n\\npragma solidity ^0.8.0;\\n\\nimport \\\"../IERC20.sol\\\";\\nimport \\\"../../../utils/Address.sol\\\";\\n\\n/**\\n * @title SafeERC20\\n * @dev Wrappers around ERC20 operations that throw on failure (when the token\\n * contract returns false). Tokens that return no value (and instead revert or\\n * throw on failure) are also supported, non-reverting calls are assumed to be\\n * successful.\\n * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,\\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\\n */\\nlibrary SafeERC20 {\\n    using Address for address;\\n\\n    function safeTransfer(\\n        IERC20 token,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));\\n    }\\n\\n    function safeTransferFrom(\\n        IERC20 token,\\n        address from,\\n        address to,\\n        uint256 value\\n    ) internal {\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));\\n    }\\n\\n    /**\\n     * @dev Deprecated. This function has issues similar to the ones found in\\n     * {IERC20-approve}, and its usage is discouraged.\\n     *\\n     * Whenever possible, use {safeIncreaseAllowance} and\\n     * {safeDecreaseAllowance} instead.\\n     */\\n    function safeApprove(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        // safeApprove should only be called when setting an initial allowance,\\n        // or when resetting it to zero. To increase and decrease it, use\\n        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'\\n        require(\\n            (value == 0) || (token.allowance(address(this), spender) == 0),\\n            \\\"SafeERC20: approve from non-zero to non-zero allowance\\\"\\n        );\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));\\n    }\\n\\n    function safeIncreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        uint256 newAllowance = token.allowance(address(this), spender) + value;\\n        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n    }\\n\\n    function safeDecreaseAllowance(\\n        IERC20 token,\\n        address spender,\\n        uint256 value\\n    ) internal {\\n        unchecked {\\n            uint256 oldAllowance = token.allowance(address(this), spender);\\n            require(oldAllowance >= value, \\\"SafeERC20: decreased allowance below zero\\\");\\n            uint256 newAllowance = oldAllowance - value;\\n            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));\\n        }\\n    }\\n\\n    /**\\n     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement\\n     * on the return value: the return value is optional (but if data is returned, it must not be false).\\n     * @param token The token targeted by the call.\\n     * @param data The call data (encoded using abi.encode or one of its variants).\\n     */\\n    function _callOptionalReturn(IERC20 token, bytes memory data) private {\\n        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since\\n        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that\\n        // the target address contains contract code and also asserts for success in the low-level call.\\n\\n        bytes memory returndata = address(token).functionCall(data, \\\"SafeERC20: low-level call failed\\\");\\n        if (returndata.length > 0) {\\n            // Return data is optional\\n            require(abi.decode(returndata, (bool)), \\\"SafeERC20: ERC20 operation did not succeed\\\");\\n        }\\n    }\\n}\\n\",\"keccak256\":\"0xc3d946432c0ddbb1f846a0d3985be71299df331b91d06732152117f62f0be2b5\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Address.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)\\n\\npragma solidity ^0.8.1;\\n\\n/**\\n * @dev Collection of functions related to the address type\\n */\\nlibrary Address {\\n    /**\\n     * @dev Returns true if `account` is a contract.\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * It is unsafe to assume that an address for which this function returns\\n     * false is an externally-owned account (EOA) and not a contract.\\n     *\\n     * Among others, `isContract` will return false for the following\\n     * types of addresses:\\n     *\\n     *  - an externally-owned account\\n     *  - a contract in construction\\n     *  - an address where a contract will be created\\n     *  - an address where a contract lived, but was destroyed\\n     * ====\\n     *\\n     * [IMPORTANT]\\n     * ====\\n     * You shouldn't rely on `isContract` to protect against flash loan attacks!\\n     *\\n     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\\n     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\\n     * constructor.\\n     * ====\\n     */\\n    function isContract(address account) internal view returns (bool) {\\n        // This method relies on extcodesize/address.code.length, which returns 0\\n        // for contracts in construction, since the code is only stored at the end\\n        // of the constructor execution.\\n\\n        return account.code.length > 0;\\n    }\\n\\n    /**\\n     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\\n     * `recipient`, forwarding all available gas and reverting on errors.\\n     *\\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\\n     * imposed by `transfer`, making them unable to receive funds via\\n     * `transfer`. {sendValue} removes this limitation.\\n     *\\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\\n     *\\n     * IMPORTANT: because control is transferred to `recipient`, care must be\\n     * taken to not create reentrancy vulnerabilities. Consider using\\n     * {ReentrancyGuard} or the\\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\\n     */\\n    function sendValue(address payable recipient, uint256 amount) internal {\\n        require(address(this).balance >= amount, \\\"Address: insufficient balance\\\");\\n\\n        (bool success, ) = recipient.call{value: amount}(\\\"\\\");\\n        require(success, \\\"Address: unable to send value, recipient may have reverted\\\");\\n    }\\n\\n    /**\\n     * @dev Performs a Solidity function call using a low level `call`. A\\n     * plain `call` is an unsafe replacement for a function call: use this\\n     * function instead.\\n     *\\n     * If `target` reverts with a revert reason, it is bubbled up by this\\n     * function (like regular Solidity function calls).\\n     *\\n     * Returns the raw returned data. To convert to the expected return value,\\n     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\\n     *\\n     * Requirements:\\n     *\\n     * - `target` must be a contract.\\n     * - calling `target` with `data` must not revert.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionCall(target, data, \\\"Address: low-level call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\\n     * `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, 0, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but also transferring `value` wei to `target`.\\n     *\\n     * Requirements:\\n     *\\n     * - the calling contract must have an ETH balance of at least `value`.\\n     * - the called Solidity function must be `payable`.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value\\n    ) internal returns (bytes memory) {\\n        return functionCallWithValue(target, data, value, \\\"Address: low-level call with value failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\\n     * with `errorMessage` as a fallback revert reason when `target` reverts.\\n     *\\n     * _Available since v3.1._\\n     */\\n    function functionCallWithValue(\\n        address target,\\n        bytes memory data,\\n        uint256 value,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(address(this).balance >= value, \\\"Address: insufficient balance for call\\\");\\n        require(isContract(target), \\\"Address: call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.call{value: value}(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\\n        return functionStaticCall(target, data, \\\"Address: low-level static call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a static call.\\n     *\\n     * _Available since v3.3._\\n     */\\n    function functionStaticCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal view returns (bytes memory) {\\n        require(isContract(target), \\\"Address: static call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.staticcall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {\\n        return functionDelegateCall(target, data, \\\"Address: low-level delegate call failed\\\");\\n    }\\n\\n    /**\\n     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\\n     * but performing a delegate call.\\n     *\\n     * _Available since v3.4._\\n     */\\n    function functionDelegateCall(\\n        address target,\\n        bytes memory data,\\n        string memory errorMessage\\n    ) internal returns (bytes memory) {\\n        require(isContract(target), \\\"Address: delegate call to non-contract\\\");\\n\\n        (bool success, bytes memory returndata) = target.delegatecall(data);\\n        return verifyCallResult(success, returndata, errorMessage);\\n    }\\n\\n    /**\\n     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\\n     * revert reason using the provided one.\\n     *\\n     * _Available since v4.3._\\n     */\\n    function verifyCallResult(\\n        bool success,\\n        bytes memory returndata,\\n        string memory errorMessage\\n    ) internal pure returns (bytes memory) {\\n        if (success) {\\n            return returndata;\\n        } else {\\n            // Look for revert reason and bubble it up if present\\n            if (returndata.length > 0) {\\n                // The easiest way to bubble the revert reason is using memory via assembly\\n\\n                assembly {\\n                    let returndata_size := mload(returndata)\\n                    revert(add(32, returndata), returndata_size)\\n                }\\n            } else {\\n                revert(errorMessage);\\n            }\\n        }\\n    }\\n}\\n\",\"keccak256\":\"0x2ccf9d2313a313d41a791505f2b5abfdc62191b5d4334f7f7a82691c088a1c87\",\"license\":\"MIT\"},\"@openzeppelin/contracts/utils/Context.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\\n\\npragma solidity ^0.8.0;\\n\\n/**\\n * @dev Provides information about the current execution context, including the\\n * sender of the transaction and its data. While these are generally available\\n * via msg.sender and msg.data, they should not be accessed in such a direct\\n * manner, since when dealing with meta-transactions the account sending and\\n * paying for execution may not be the actual sender (as far as an application\\n * is concerned).\\n *\\n * This contract is only required for intermediate, library-like contracts.\\n */\\nabstract contract Context {\\n    function _msgSender() internal view virtual returns (address) {\\n        return msg.sender;\\n    }\\n\\n    function _msgData() internal view virtual returns (bytes calldata) {\\n        return msg.data;\\n    }\\n}\\n\",\"keccak256\":\"0xe2e337e6dde9ef6b680e07338c493ebea1b5fd09b43424112868e9cc1706bca7\",\"license\":\"MIT\"},\"contracts/VotingEscrow.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.14;\\n\\nimport \\\"@openzeppelin/contracts/access/Ownable.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\\\";\\nimport \\\"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\\\";\\nimport \\\"@openzeppelin/contracts/security/ReentrancyGuard.sol\\\";\\nimport \\\"./interfaces/IVotingEscrow.sol\\\";\\nimport \\\"./interfaces/IVotingEscrowMigrator.sol\\\";\\nimport \\\"./interfaces/IVotingEscrowDelegate.sol\\\";\\nimport \\\"./libraries/Integers.sol\\\";\\n\\n/**\\n * @title Voting Escrow\\n * @author LevX (team@levx.io)\\n * @notice Votes have a weight depending on time, so that users are\\n *         committed to the future of (whatever they are voting for)\\n * @dev Vote weight decays linearly over time. Lock time cannot be\\n *      more than `MAXTIME`.\\n * @dev Ported from vyper (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)\\n */\\n\\n// Voting escrow to have time-weighted votes\\n// Votes have a weight depending on time, so that users are committed\\n// to the future of (whatever they are voting for).\\n// The weight in this implementation is linear, and lock cannot be more than maxtime:\\n// w ^\\n// 1 +        /\\n//   |      /\\n//   |    /\\n//   |  /\\n//   |/\\n// 0 +--------+------> time\\n//       maxtime\\n\\ncontract VotingEscrow is Ownable, ReentrancyGuard, IVotingEscrow {\\n    using SafeERC20 for IERC20;\\n    using Integers for int128;\\n    using Integers for uint256;\\n\\n    struct Point {\\n        int128 bias;\\n        int128 slope; // - dweight / dt\\n        uint256 ts;\\n        uint256 blk; // block\\n    }\\n\\n    struct LockedBalance {\\n        int128 amount;\\n        int128 discount;\\n        uint256 start;\\n        uint256 end;\\n    }\\n\\n    int128 public constant DEPOSIT_FOR_TYPE = 0;\\n    int128 public constant CRETE_LOCK_TYPE = 1;\\n    int128 public constant INCREASE_LOCK_AMOUNT = 2;\\n    int128 public constant INCREASE_UNLOCK_TIME = 3;\\n    uint256 internal constant MULTIPLIER = 1e18;\\n\\n    uint256 public immutable override interval;\\n    uint256 public immutable override maxDuration;\\n    address public immutable override token;\\n    string public override name;\\n    string public override symbol;\\n    uint8 public immutable override decimals;\\n\\n    address public override migrator;\\n    mapping(address => bool) public override isDelegate;\\n\\n    uint256 public override supply;\\n    mapping(address => bool) public override migrated;\\n    mapping(address => address[]) public override delegateAt;\\n    mapping(address => LockedBalance) public override locked;\\n    uint256 public override epoch;\\n\\n    mapping(uint256 => Point) public override pointHistory; // epoch -> unsigned point\\n    mapping(address => mapping(uint256 => Point)) public override userPointHistory; // user -> Point[user_epoch]\\n    mapping(address => uint256) public override userPointEpoch;\\n    mapping(uint256 => int128) public override slopeChanges; // time -> signed slope change\\n\\n    constructor(\\n        address _token,\\n        string memory _name,\\n        string memory _symbol,\\n        uint256 _interval,\\n        uint256 _maxDuration\\n    ) {\\n        token = _token;\\n        name = _name;\\n        symbol = _symbol;\\n        decimals = IERC20Metadata(_token).decimals();\\n\\n        interval = _interval;\\n        maxDuration = (_maxDuration / _interval) * _interval; // rounded down to a multiple of interval\\n\\n        pointHistory[0].blk = block.number;\\n        pointHistory[0].ts = block.timestamp;\\n    }\\n\\n    modifier beforeMigrated(address addr) {\\n        require(!migrated[addr], \\\"VE: LOCK_MIGRATED\\\");\\n        _;\\n    }\\n\\n    modifier onlyDelegate {\\n        require(isDelegate[msg.sender], \\\"VE: NOT_DELEGATE\\\");\\n        _;\\n    }\\n\\n    /**\\n     * @notice Check if the call is from an EOA or a whitelisted smart contract, revert if not\\n     */\\n    modifier authorized {\\n        if (msg.sender != tx.origin) {\\n            require(isDelegate[msg.sender], \\\"VE: CONTRACT_NOT_DELEGATE\\\");\\n        }\\n        _;\\n    }\\n\\n    function delegateLength(address addr) external view returns (uint256) {\\n        return delegateAt[addr].length;\\n    }\\n\\n    /**\\n     * @notice Get the most recently recorded rate of voting power decrease for `addr`\\n     * @param addr Address of the user wallet\\n     * @return Value of the slope\\n     */\\n    function getLastUserSlope(address addr) external view override returns (int128) {\\n        uint256 uepoch = userPointEpoch[addr];\\n        return userPointHistory[addr][uepoch].slope;\\n    }\\n\\n    /**\\n     * @notice Get the timestamp for checkpoint `_idx` for `_addr`\\n     * @param _addr User wallet address\\n     * @param _idx User epoch number\\n     * @return Epoch time of the checkpoint\\n     */\\n    function getCheckpointTime(address _addr, uint256 _idx) external view override returns (uint256) {\\n        return userPointHistory[_addr][_idx].ts;\\n    }\\n\\n    /**\\n     * @notice Get timestamp when `_addr`'s lock finishes\\n     * @param _addr User wallet\\n     * @return Epoch time of the lock end\\n     */\\n    function unlockTime(address _addr) external view override returns (uint256) {\\n        return locked[_addr].end;\\n    }\\n\\n    function setMigrator(address _migrator) external override onlyOwner {\\n        require(migrator == address(0), \\\"VE: MIGRATOR_SET\\\");\\n\\n        migrator = _migrator;\\n\\n        emit SetMigrator(_migrator);\\n    }\\n\\n    function setDelegate(address account, bool _isDelegate) external override onlyOwner {\\n        isDelegate[account] = _isDelegate;\\n\\n        emit SetDelegate(account, _isDelegate);\\n    }\\n\\n    /**\\n     * @notice Record global and per-user data to checkpoint\\n     * @param addr User's wallet address. No user checkpoint if 0x0\\n     * @param old_locked Pevious locked amount / end lock time for the user\\n     * @param new_locked New locked amount / end lock time for the user\\n     */\\n    function _checkpoint(\\n        address addr,\\n        LockedBalance memory old_locked,\\n        LockedBalance memory new_locked\\n    ) internal {\\n        Point memory u_old;\\n        Point memory u_new;\\n        int128 old_dslope;\\n        int128 new_dslope;\\n        uint256 _epoch = epoch;\\n\\n        if (addr != address(0)) {\\n            // Calculate slopes and biases\\n            // Kept at zero when they have to\\n            if (old_locked.end > block.timestamp && old_locked.amount > 0) {\\n                u_old.slope = old_locked.amount / maxDuration.toInt128();\\n                u_old.bias = u_old.slope * (old_locked.end - block.timestamp).toInt128();\\n            }\\n            if (new_locked.end > block.timestamp && new_locked.amount > 0) {\\n                u_new.slope = new_locked.amount / maxDuration.toInt128();\\n                u_new.bias = u_new.slope * (new_locked.end - block.timestamp).toInt128();\\n            }\\n\\n            // Read values of scheduled changes in the slope\\n            // old_locked.end can be in the past and in the future\\n            // new_locked.end can ONLY by in the FUTURE unless everything expired: than zeros\\n            old_dslope = slopeChanges[old_locked.end];\\n            if (new_locked.end != 0) {\\n                if (new_locked.end == old_locked.end) new_dslope = old_dslope;\\n                else new_dslope = slopeChanges[new_locked.end];\\n            }\\n        }\\n\\n        Point memory last_point = Point({bias: 0, slope: 0, ts: block.timestamp, blk: block.number});\\n        if (_epoch > 0) last_point = pointHistory[_epoch];\\n        uint256 last_checkpoint = last_point.ts;\\n        // initial_last_point is used for extrapolation to calculate block number\\n        // (approximately, for *At methods) and save them\\n        // as we cannot figure that out exactly from inside the contract\\n        Point memory initial_last_point = Point(last_point.bias, last_point.slope, last_point.ts, last_point.blk);\\n        uint256 block_slope; // dblock/dt\\n        if (block.timestamp > last_point.ts)\\n            block_slope = (MULTIPLIER * (block.number - last_point.blk)) / (block.timestamp - last_point.ts);\\n        // If last point is already recorded in this block, slope=0\\n        // But that's ok b/c we know the block in such case\\n\\n        {\\n            // Go over weeks to fill history and calculate what the current point is\\n            uint256 t_i = (last_checkpoint / interval) * interval;\\n            for (uint256 i; i < 255; i++) {\\n                // Hopefully it won't happen that this won't get used in 5 years!\\n                // If it does, users will be able to withdraw but vote weight will be broken\\n                t_i += interval;\\n                int128 d_slope;\\n                if (t_i > block.timestamp) t_i = block.timestamp;\\n                else d_slope = slopeChanges[t_i];\\n                last_point.bias -= last_point.slope * (t_i - last_checkpoint).toInt128();\\n                last_point.slope += d_slope;\\n                if (last_point.bias < 0)\\n                    // This can happen\\n                    last_point.bias = 0;\\n                if (last_point.slope < 0)\\n                    // This cannot happen - just in case\\n                    last_point.slope = 0;\\n                last_checkpoint = t_i;\\n                last_point.ts = t_i;\\n                last_point.blk = initial_last_point.blk + (block_slope * (t_i - initial_last_point.ts)) / MULTIPLIER;\\n                _epoch += 1;\\n                if (t_i == block.timestamp) {\\n                    last_point.blk = block.number;\\n                    break;\\n                } else pointHistory[_epoch] = last_point;\\n            }\\n        }\\n\\n        epoch = _epoch;\\n        // Now point_history is filled until t=now\\n\\n        if (addr != address(0)) {\\n            // If last point was in this block, the slope change has been applied already\\n            // But in such case we have 0 slope(s)\\n            last_point.slope += (u_new.slope - u_old.slope);\\n            last_point.bias += (u_new.bias - u_old.bias);\\n            if (last_point.slope < 0) last_point.slope = 0;\\n            if (last_point.bias < 0) last_point.bias = 0;\\n        }\\n\\n        // Record the changed point into history\\n        pointHistory[_epoch] = last_point;\\n\\n        if (addr != address(0)) {\\n            // Schedule the slope changes (slope is going down)\\n            // We subtract new_user_slope from [new_locked.end]\\n            // and add old_user_slope to [old_locked.end]\\n            if (old_locked.end > block.timestamp) {\\n                // old_dslope was <something> - u_old.slope, so we cancel that\\n                old_dslope += u_old.slope;\\n                if (new_locked.end == old_locked.end) old_dslope -= u_new.slope; // It was a new deposit, not extension\\n                slopeChanges[old_locked.end] = old_dslope;\\n            }\\n\\n            if (new_locked.end > block.timestamp) {\\n                if (new_locked.end > old_locked.end) {\\n                    new_dslope -= u_new.slope; // old slope disappeared at this point\\n                    slopeChanges[new_locked.end] = new_dslope;\\n                }\\n                // else: we recorded it already in old_dslope\\n            }\\n\\n            // Now handle user history\\n            uint256 user_epoch = userPointEpoch[addr] + 1;\\n\\n            userPointEpoch[addr] = user_epoch;\\n            u_new.ts = block.timestamp;\\n            u_new.blk = block.number;\\n            userPointHistory[addr][user_epoch] = u_new;\\n        }\\n    }\\n\\n    /**\\n     * @notice Deposit and lock tokens for a user\\n     * @param _addr User's wallet address\\n     * @param _value Amount to deposit\\n     * @param _discount Amount to get discounted out of _value\\n     * @param unlock_time New time when to unlock the tokens, or 0 if unchanged\\n     * @param locked_balance Previous locked amount / timestamp\\n     */\\n    function _depositFor(\\n        address _addr,\\n        uint256 _value,\\n        uint256 _discount,\\n        uint256 unlock_time,\\n        LockedBalance memory locked_balance,\\n        int128 _type\\n    ) internal {\\n        LockedBalance memory _locked = locked_balance;\\n        uint256 supply_before = supply;\\n\\n        supply = supply_before + _value;\\n        LockedBalance memory old_locked;\\n        (old_locked.amount, old_locked.discount, old_locked.start, old_locked.end) = (\\n            _locked.amount,\\n            _locked.discount,\\n            _locked.start,\\n            _locked.end\\n        );\\n        // Adding to existing lock, or if a lock is expired - creating a new one\\n        _locked.amount += (_value).toInt128();\\n        if (_discount != 0) _locked.discount += _discount.toInt128();\\n        if (unlock_time != 0) {\\n            if (_locked.start == 0) _locked.start = block.timestamp;\\n            _locked.end = unlock_time;\\n        }\\n        locked[_addr] = _locked;\\n\\n        // Possibilities:\\n        // Both old_locked.end could be current or expired (>/< block.timestamp)\\n        // value == 0 (extend lock) or value > 0 (add to lock or extend lock)\\n        // _locked.end > block.timestamp (always)\\n        _checkpoint(_addr, old_locked, _locked);\\n\\n        if (_value > _discount) {\\n            IERC20(token).safeTransferFrom(_addr, address(this), _value - _discount);\\n        }\\n\\n        emit Deposit(_addr, _value, _discount, _locked.end, _type, block.timestamp);\\n        emit Supply(supply_before, supply_before + _value);\\n    }\\n\\n    function _pushDelegate(address addr, address delegate) internal {\\n        bool found;\\n        address[] storage delegates = delegateAt[addr];\\n        for (uint256 i; i < delegates.length; ) {\\n            if (delegates[i] == delegate) found = true;\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n        if (!found) delegateAt[addr].push(delegate);\\n    }\\n\\n    /**\\n     * @notice Record global data to checkpoint\\n     */\\n    function checkpoint() external override {\\n        _checkpoint(address(0), LockedBalance(0, 0, 0, 0), LockedBalance(0, 0, 0, 0));\\n    }\\n\\n    /**\\n     * @notice Deposit `_value` tokens for `_addr` and add to the lock\\n     * @dev Anyone (even a smart contract) can deposit for someone else, but\\n     *      cannot extend their locktime and deposit for a brand new user\\n     * @param _addr User's wallet address\\n     * @param _value Amount to add to user's lock\\n     */\\n    function depositFor(address _addr, uint256 _value) external override nonReentrant beforeMigrated(_addr) {\\n        LockedBalance memory _locked = locked[_addr];\\n\\n        require(_value > 0, \\\"VE: INVALID_VALUE\\\");\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n\\n        _depositFor(_addr, _value, 0, 0, _locked, DEPOSIT_FOR_TYPE);\\n    }\\n\\n    /**\\n     * @notice Deposit `_value` tokens with `_discount` for `_addr` and lock for `_duration`\\n     * @dev Only delegates can creat a lock for someone else\\n     * @param _addr User's wallet address\\n     * @param _value Amount to add to user's lock\\n     * @param _discount Amount to get discounted out of _value\\n     * @param _duration Epoch time until tokens unlock from now\\n     */\\n    function createLockFor(\\n        address _addr,\\n        uint256 _value,\\n        uint256 _discount,\\n        uint256 _duration\\n    ) external override nonReentrant onlyDelegate beforeMigrated(_addr) {\\n        _pushDelegate(_addr, msg.sender);\\n\\n        uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\\n        LockedBalance memory _locked = locked[_addr];\\n\\n        require(_value > 0, \\\"VE: INVALID_VALUE\\\");\\n        require(_value >= _discount, \\\"VE: DISCOUNT_TOO_HIGH\\\");\\n        require(_locked.amount == 0, \\\"VE: EXISTING_LOCK_FOUND\\\");\\n        require(unlock_time > block.timestamp, \\\"VE: UNLOCK_TIME_TOO_EARLY\\\");\\n        require(unlock_time <= block.timestamp + maxDuration, \\\"VE: UNLOCK_TIME_TOO_LATE\\\");\\n\\n        _depositFor(_addr, _value, _discount, unlock_time, _locked, CRETE_LOCK_TYPE);\\n    }\\n\\n    /**\\n     * @notice Deposit `_value` tokens for `msg.sender` and lock for `_duration`\\n     * @param _value Amount to deposit\\n     * @param _duration Epoch time until tokens unlock from now\\n     */\\n    function createLock(uint256 _value, uint256 _duration)\\n        external\\n        override\\n        nonReentrant\\n        authorized\\n        beforeMigrated(msg.sender)\\n    {\\n        uint256 unlock_time = ((block.timestamp + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\\n        LockedBalance memory _locked = locked[msg.sender];\\n\\n        require(_value > 0, \\\"VE: INVALID_VALUE\\\");\\n        require(_locked.amount == 0, \\\"VE: EXISTING_LOCK_FOUND\\\");\\n        require(unlock_time > block.timestamp, \\\"VE: UNLOCK_TIME_TOO_EARLY\\\");\\n        require(unlock_time <= block.timestamp + maxDuration, \\\"VE: UNLOCK_TIME_TOO_LATE\\\");\\n\\n        _depositFor(msg.sender, _value, 0, unlock_time, _locked, CRETE_LOCK_TYPE);\\n    }\\n\\n    /**\\n     * @notice Deposit `_value` additional tokens for `msg.sender`\\n     *          without modifying the unlock time\\n     * @param _addr User's wallet address\\n     * @param _value Amount of tokens to deposit and add to the lock\\n     * @param _discount Amount to get discounted out of _value\\n     */\\n    function increaseAmountFor(\\n        address _addr,\\n        uint256 _value,\\n        uint256 _discount\\n    ) external override nonReentrant onlyDelegate beforeMigrated(_addr) {\\n        _pushDelegate(_addr, msg.sender);\\n\\n        LockedBalance memory _locked = locked[_addr];\\n\\n        require(_value > 0, \\\"VE: INVALID_VALUE\\\");\\n        require(_value >= _discount, \\\"VE: DISCOUNT_TOO_HIGH\\\");\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n\\n        _depositFor(_addr, _value, _discount, 0, _locked, INCREASE_LOCK_AMOUNT);\\n    }\\n\\n    /**\\n     * @notice Deposit `_value` additional tokens for `msg.sender`\\n     *          without modifying the unlock time\\n     * @param _value Amount of tokens to deposit and add to the lock\\n     */\\n    function increaseAmount(uint256 _value) external override nonReentrant authorized beforeMigrated(msg.sender) {\\n        LockedBalance memory _locked = locked[msg.sender];\\n\\n        require(_value > 0, \\\"VE: INVALID_VALUE\\\");\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n\\n        _depositFor(msg.sender, _value, 0, 0, _locked, INCREASE_LOCK_AMOUNT);\\n    }\\n\\n    /**\\n     * @notice Extend the unlock time for `msg.sender` to `_duration`\\n     * @param _duration Increased epoch time for unlocking\\n     */\\n    function increaseUnlockTime(uint256 _duration)\\n        external\\n        override\\n        nonReentrant\\n        authorized\\n        beforeMigrated(msg.sender)\\n    {\\n        LockedBalance memory _locked = locked[msg.sender];\\n        uint256 unlock_time = ((_locked.end + _duration) / interval) * interval; // Locktime is rounded down to a multiple of interval\\n\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.discount == 0, \\\"VE: LOCK_DISCOUNTED\\\");\\n        require(unlock_time >= _locked.end + interval, \\\"VE: UNLOCK_TIME_TOO_EARLY\\\");\\n        require(unlock_time <= block.timestamp + maxDuration, \\\"VE: UNLOCK_TIME_TOO_LATE\\\");\\n\\n        _depositFor(msg.sender, 0, 0, unlock_time, _locked, INCREASE_UNLOCK_TIME);\\n    }\\n\\n    /**\\n     * @notice Cancel the existing lock of `msg.sender` with penalty\\n     * @dev Only possible if the lock exists\\n     */\\n    function cancel() external override nonReentrant {\\n        LockedBalance memory _locked = locked[msg.sender];\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n\\n        uint256 penaltyRate = _penaltyRate(_locked.start, _locked.end);\\n        uint256 supply_before = _clear(_locked, penaltyRate);\\n\\n        uint256 value = _locked.amount.toUint256();\\n        uint256 discount = _locked.discount.toUint256();\\n\\n        IERC20(token).safeTransfer(msg.sender, ((value - discount) * (1e18 - penaltyRate)) / 1e18);\\n\\n        emit Cancel(msg.sender, value, discount, penaltyRate, block.timestamp);\\n        emit Supply(supply_before, supply_before - value);\\n    }\\n\\n    function _penaltyRate(uint256 start, uint256 end) internal view returns (uint256 penalty) {\\n        penalty = (1e18 * (end - block.timestamp)) / (end - start);\\n        if (penalty < 1e18 / 2) penalty = 1e18 / 2;\\n    }\\n\\n    /**\\n     * @notice Withdraw all tokens for `msg.sender`\\n     * @dev Only possible if the lock has expired\\n     */\\n    function withdraw() external override nonReentrant {\\n        LockedBalance memory _locked = locked[msg.sender];\\n        require(block.timestamp >= _locked.end, \\\"VE: LOCK_NOT_EXPIRED\\\");\\n\\n        uint256 supply_before = _clear(_locked, 0);\\n\\n        uint256 value = _locked.amount.toUint256();\\n        uint256 discount = _locked.discount.toUint256();\\n\\n        if (value > discount) {\\n            IERC20(token).safeTransfer(msg.sender, value - discount);\\n        }\\n\\n        emit Withdraw(msg.sender, value, discount, block.timestamp);\\n        emit Supply(supply_before, supply_before - value);\\n    }\\n\\n    function migrate() external override nonReentrant beforeMigrated(msg.sender) {\\n        require(migrator != address(0), \\\"VE: MIGRATOR_NOT_SET\\\");\\n\\n        LockedBalance memory _locked = locked[msg.sender];\\n        require(_locked.amount > 0, \\\"VE: LOCK_NOT_FOUND\\\");\\n        require(_locked.end > block.timestamp, \\\"VE: LOCK_EXPIRED\\\");\\n\\n        address[] memory delegates = delegateAt[msg.sender];\\n        uint256 supply_before = _clear(_locked, 0);\\n\\n        uint256 value = _locked.amount.toUint256();\\n        uint256 discount = _locked.discount.toUint256();\\n\\n        IVotingEscrowMigrator(migrator).migrate(\\n            msg.sender,\\n            _locked.amount,\\n            _locked.discount,\\n            _locked.start,\\n            _locked.end,\\n            delegates\\n        );\\n        migrated[msg.sender] = true;\\n\\n        if (value > discount) {\\n            IERC20(token).safeTransfer(migrator, value - discount);\\n        }\\n\\n        emit Migrate(msg.sender, value, discount, block.timestamp);\\n        emit Supply(supply_before, supply_before - value);\\n    }\\n\\n    function _clear(LockedBalance memory _locked, uint256 penaltyRate) internal returns (uint256 supply_before) {\\n        uint256 value = _locked.amount.toUint256();\\n\\n        locked[msg.sender] = LockedBalance(0, 0, 0, 0);\\n        supply_before = supply;\\n        supply = supply_before - value;\\n\\n        // old_locked can have either expired <= timestamp or zero end\\n        // _locked has only 0 end\\n        // Both can have >= 0 amount\\n        _checkpoint(msg.sender, _locked, LockedBalance(0, 0, 0, 0));\\n\\n        address[] storage delegates = delegateAt[msg.sender];\\n        for (uint256 i; i < delegates.length; ) {\\n            IVotingEscrowDelegate(delegates[i]).withdraw(msg.sender, penaltyRate);\\n            unchecked {\\n                ++i;\\n            }\\n        }\\n        delete delegateAt[msg.sender];\\n    }\\n\\n    // The following ERC20/minime-compatible methods are not real balanceOf and supply!\\n    // They measure the weights for the purpose of voting, so they don't represent\\n    // real coins.\\n\\n    /**\\n     * @notice Binary search to estimate timestamp for block number\\n     * @param _block Block to find\\n     * @param max_epoch Don't go beyond this epoch\\n     * @return Approximate timestamp for block\\n     */\\n    function _findBlockEpoch(uint256 _block, uint256 max_epoch) internal view returns (uint256) {\\n        uint256 _min;\\n        uint256 _max = max_epoch;\\n        for (uint256 i; i < 128; i++) {\\n            if (_min >= _max) break;\\n            uint256 _mid = (_min + _max + 1) / 2;\\n            if (pointHistory[_mid].blk <= _block) _min = _mid;\\n            else _max = _mid - 1;\\n        }\\n        return _min;\\n    }\\n\\n    function balanceOf(address addr) public view override returns (uint256) {\\n        return balanceOf(addr, block.timestamp);\\n    }\\n\\n    /**\\n     * @notice Get the current voting power for `msg.sender`\\n     * @dev Adheres to the ERC20 `balanceOf` interface for Aragon compatibility\\n     * @param addr User wallet address\\n     * @param _t Epoch time to return voting power at\\n     * @return User voting power\\n     */\\n    function balanceOf(address addr, uint256 _t) public view override returns (uint256) {\\n        uint256 _epoch = userPointEpoch[addr];\\n        if (_epoch == 0) return 0;\\n        else {\\n            Point memory last_point = userPointHistory[addr][_epoch];\\n            last_point.bias -= last_point.slope * (_t - last_point.ts).toInt128();\\n            if (last_point.bias < 0) last_point.bias = 0;\\n            return last_point.bias.toUint256();\\n        }\\n    }\\n\\n    /**\\n     * @notice Measure voting power of `addr` at block height `_block`\\n     * @dev Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime\\n     * @param addr User's wallet address\\n     * @param _block Block to calculate the voting power at\\n     * @return Voting power\\n     */\\n    function balanceOfAt(address addr, uint256 _block) external view override returns (uint256) {\\n        // Copying and pasting totalSupply code because Vyper cannot pass by\\n        // reference yet\\n        require(_block <= block.number);\\n\\n        // Binary search\\n        uint256 _min;\\n        uint256 _max = userPointEpoch[addr];\\n        for (uint256 i; i < 128; i++) {\\n            if (_min >= _max) break;\\n            uint256 _mid = (_min + _max + 1) / 2;\\n            if (userPointHistory[addr][_mid].blk <= _block) _min = _mid;\\n            else _max = _mid - 1;\\n        }\\n\\n        Point memory upoint = userPointHistory[addr][_min];\\n\\n        uint256 max_epoch = epoch;\\n        uint256 _epoch = _findBlockEpoch(_block, max_epoch);\\n        Point memory point_0 = pointHistory[_epoch];\\n        uint256 d_block;\\n        uint256 d_t;\\n        if (_epoch < max_epoch) {\\n            Point memory point_1 = pointHistory[_epoch + 1];\\n            d_block = point_1.blk - point_0.blk;\\n            d_t = point_1.ts - point_0.ts;\\n        } else {\\n            d_block = block.number - point_0.blk;\\n            d_t = block.timestamp - point_0.ts;\\n        }\\n        uint256 block_time = point_0.ts;\\n        if (d_block != 0) block_time += ((d_t * (_block - point_0.blk)) / d_block);\\n\\n        upoint.bias -= upoint.slope * (block_time - upoint.ts).toInt128();\\n        if (upoint.bias >= 0) return upoint.bias.toUint256();\\n        else return 0;\\n    }\\n\\n    /**\\n     * @notice Calculate total voting power at some point in the past\\n     * @param point The point (bias/slope) to start search from\\n     * @param t Time to calculate the total voting power at\\n     * @return Total voting power at that time\\n     */\\n    function _supplyAt(Point memory point, uint256 t) internal view returns (uint256) {\\n        Point memory last_point = point;\\n        uint256 t_i = (last_point.ts / interval) * interval;\\n        for (uint256 i; i < 255; i++) {\\n            t_i += interval;\\n            int128 d_slope;\\n            if (t_i > t) t_i = t;\\n            else d_slope = slopeChanges[t_i];\\n            last_point.bias -= last_point.slope * (t_i - last_point.ts).toInt128();\\n            if (t_i == t) break;\\n            last_point.slope += d_slope;\\n            last_point.ts = t_i;\\n        }\\n\\n        if (last_point.bias < 0) last_point.bias = 0;\\n        return last_point.bias.toUint256();\\n    }\\n\\n    function totalSupply() public view override returns (uint256) {\\n        return totalSupply(block.timestamp);\\n    }\\n\\n    /**\\n     * @notice Calculate total voting power\\n     * @dev Adheres to the ERC20 `totalSupply` interface for Aragon compatibility\\n     * @return Total voting power\\n     */\\n    function totalSupply(uint256 t) public view override returns (uint256) {\\n        uint256 _epoch = epoch;\\n        Point memory last_point = pointHistory[_epoch];\\n        return _supplyAt(last_point, t);\\n    }\\n\\n    /**\\n     * @notice Calculate total voting power at some point in the past\\n     * @param _block Block to calculate the total voting power at\\n     * @return Total voting power at `_block`\\n     */\\n    function totalSupplyAt(uint256 _block) external view override returns (uint256) {\\n        require(_block <= block.number);\\n        uint256 _epoch = epoch;\\n        uint256 target_epoch = _findBlockEpoch(_block, _epoch);\\n\\n        Point memory point = pointHistory[target_epoch];\\n        uint256 dt;\\n        if (target_epoch < _epoch) {\\n            Point memory point_next = pointHistory[target_epoch + 1];\\n            if (point.blk != point_next.blk)\\n                dt = ((_block - point.blk) * (point_next.ts - point.ts)) / (point_next.blk - point.blk);\\n        } else if (point.blk != block.number)\\n            dt = ((_block - point.blk) * (block.timestamp - point.ts)) / (block.number - point.blk);\\n        // Now dt contains info on how far are we beyond point\\n\\n        return _supplyAt(point, point.ts + dt);\\n    }\\n}\\n\",\"keccak256\":\"0x48a5b84c2cf5815941b71bec71d85fde3383bcec3827a0bd1b9e53a56133cbc7\",\"license\":\"UNLICENSED\"},\"contracts/interfaces/IVotingEscrow.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.0;\\n\\ninterface IVotingEscrow {\\n    event SetMigrator(address indexed account);\\n    event SetDelegate(address indexed account, bool isDelegate);\\n    event Deposit(\\n        address indexed provider,\\n        uint256 value,\\n        uint256 discount,\\n        uint256 indexed unlockTime,\\n        int128 indexed _type,\\n        uint256 ts\\n    );\\n    event Cancel(address indexed provider, uint256 value, uint256 discount, uint256 penaltyRate, uint256 ts);\\n    event Withdraw(address indexed provider, uint256 value, uint256 discount, uint256 ts);\\n    event Migrate(address indexed provider, uint256 value, uint256 discount, uint256 ts);\\n    event Supply(uint256 prevSupply, uint256 supply);\\n\\n    function interval() external view returns (uint256);\\n\\n    function maxDuration() external view returns (uint256);\\n\\n    function token() external view returns (address);\\n\\n    function name() external view returns (string memory);\\n\\n    function symbol() external view returns (string memory);\\n\\n    function decimals() external view returns (uint8);\\n\\n    function migrator() external view returns (address);\\n\\n    function isDelegate(address account) external view returns (bool);\\n\\n    function supply() external view returns (uint256);\\n\\n    function migrated(address account) external view returns (bool);\\n\\n    function delegateAt(address account, uint256 index) external view returns (address);\\n\\n    function locked(address account)\\n        external\\n        view\\n        returns (\\n            int128 amount,\\n            int128 discount,\\n            uint256 start,\\n            uint256 end\\n        );\\n\\n    function epoch() external view returns (uint256);\\n\\n    function pointHistory(uint256 epoch)\\n        external\\n        view\\n        returns (\\n            int128 bias,\\n            int128 slope,\\n            uint256 ts,\\n            uint256 blk\\n        );\\n\\n    function userPointHistory(address account, uint256 epoch)\\n        external\\n        view\\n        returns (\\n            int128 bias,\\n            int128 slope,\\n            uint256 ts,\\n            uint256 blk\\n        );\\n\\n    function userPointEpoch(address account) external view returns (uint256);\\n\\n    function slopeChanges(uint256 epoch) external view returns (int128);\\n\\n    function delegateLength(address addr) external view returns (uint256);\\n\\n    function getLastUserSlope(address addr) external view returns (int128);\\n\\n    function getCheckpointTime(address _addr, uint256 _idx) external view returns (uint256);\\n\\n    function unlockTime(address _addr) external view returns (uint256);\\n\\n    function setMigrator(address _migrator) external;\\n\\n    function setDelegate(address account, bool _isDelegate) external;\\n\\n    function checkpoint() external;\\n\\n    function depositFor(address _addr, uint256 _value) external;\\n\\n    function createLockFor(\\n        address _addr,\\n        uint256 _value,\\n        uint256 _discount,\\n        uint256 _duration\\n    ) external;\\n\\n    function createLock(uint256 _value, uint256 _duration) external;\\n\\n    function increaseAmountFor(\\n        address _addr,\\n        uint256 _value,\\n        uint256 _discount\\n    ) external;\\n\\n    function increaseAmount(uint256 _value) external;\\n\\n    function increaseUnlockTime(uint256 _duration) external;\\n\\n    function cancel() external;\\n\\n    function withdraw() external;\\n\\n    function migrate() external;\\n\\n    function balanceOf(address addr) external view returns (uint256);\\n\\n    function balanceOf(address addr, uint256 _t) external view returns (uint256);\\n\\n    function balanceOfAt(address addr, uint256 _block) external view returns (uint256);\\n\\n    function totalSupply() external view returns (uint256);\\n\\n    function totalSupply(uint256 t) external view returns (uint256);\\n\\n    function totalSupplyAt(uint256 _block) external view returns (uint256);\\n}\\n\",\"keccak256\":\"0x3ac00d3de6b34a0c5cb777b5e9477af3982061f7e9021848dc662508f1cf0f1b\",\"license\":\"UNLICENSED\"},\"contracts/interfaces/IVotingEscrowDelegate.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.0;\\n\\ninterface IVotingEscrowDelegate {\\n    event Withdraw(address indexed addr, uint256 amount, uint256 penaltyRate);\\n\\n    function withdraw(address addr, uint256 penaltyRate) external;\\n}\\n\",\"keccak256\":\"0x6ba70000f8e426991d384d100a94596b815599f7698c49a95ffac88fbebab8a1\",\"license\":\"UNLICENSED\"},\"contracts/interfaces/IVotingEscrowMigrator.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.0;\\n\\ninterface IVotingEscrowMigrator {\\n    function migrate(\\n        address account,\\n        int128 amount,\\n        int128 discount,\\n        uint256 start,\\n        uint256 end,\\n        address[] calldata delegates\\n    ) external;\\n}\\n\",\"keccak256\":\"0xfa001d759be1d07823598ae2b590d6a2cb8e57e4c68f22468471c39480f9e97d\",\"license\":\"UNLICENSED\"},\"contracts/libraries/Integers.sol\":{\"content\":\"// SPDX-License-Identifier: UNLICENSED\\npragma solidity ^0.8.14;\\n\\nlibrary Integers {\\n    function toInt128(uint256 u) internal pure returns (int128) {\\n        return int128(int256(u));\\n    }\\n\\n    function toUint256(int128 i) internal pure returns (uint256) {\\n        return uint256(uint128(i));\\n    }\\n}\\n\",\"keccak256\":\"0x200ed6ff23c8df3b451d7446ed31f4f8f6fdf781118435d8a185c919d0065570\",\"license\":\"UNLICENSED\"}},\"version\":1}",
  "bytecode": "0x6101006040523480156200001257600080fd5b5060405162003f6938038062003f69833981016040819052620000359162000326565b620000403362000163565b600180556001600160a01b03851660c052835162000066906002906020870190620001b3565b5082516200007c906003906020860190620001b3565b50846001600160a01b031663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015620000bc573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000e29190620003c3565b60ff1660e052608082905281620000fa8183620003ef565b62000106919062000412565b60a0525050600080525050600b60205250437fdf7de25b7f1fd6d0b5205f0e18f1f35bd7b8d84cce336588d184533ce43a6f7855427fdf7de25b7f1fd6d0b5205f0e18f1f35bd7b8d84cce336588d184533ce43a6f77556200047c565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b828054620001c19062000440565b90600052602060002090601f016020900481019282620001e5576000855562000230565b82601f106200020057805160ff191683800117855562000230565b8280016001018555821562000230579182015b828111156200023057825182559160200191906001019062000213565b506200023e92915062000242565b5090565b5b808211156200023e576000815560010162000243565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200028157600080fd5b81516001600160401b03808211156200029e576200029e62000259565b604051601f8301601f19908116603f01168101908282118183101715620002c957620002c962000259565b81604052838152602092508683858801011115620002e657600080fd5b600091505b838210156200030a5785820183015181830184015290820190620002eb565b838211156200031c5760008385830101525b9695505050505050565b600080600080600060a086880312156200033f57600080fd5b85516001600160a01b03811681146200035757600080fd5b60208701519095506001600160401b03808211156200037557600080fd5b6200038389838a016200026f565b955060408801519150808211156200039a57600080fd5b50620003a9888289016200026f565b606088015160809098015196999598509695949350505050565b600060208284031215620003d657600080fd5b815160ff81168114620003e857600080fd5b9392505050565b6000826200040d57634e487b7160e01b600052601260045260246000fd5b500490565b60008160001904831182151516156200043b57634e487b7160e01b600052601160045260246000fd5b500290565b600181811c908216806200045557607f821691505b6020821081036200047657634e487b7160e01b600052602260045260246000fd5b50919050565b60805160a05160c05160e051613a4362000526600039600061034d01526000818161077401528181610d71015261237b01526000818161046b015281816113be01528181611cb701528181611efa0152818161297d01526129fa01526000818161059f015281816112920152818161136c01528181611b4c01528181611de0015281816126f7015281816127180152818161276301528181612bb50152612bfb0152613a436000f3fe608060405234801561001057600080fd5b50600436106102895760003560e01c806381fc83bb1161015c578063a9a8d391116100ce578063ea8a1af011610087578063ea8a1af0146106e3578063f2fde38b146106eb578063f3a6d608146106fe578063f52a36f714610744578063f56d21f014610767578063fc0c546a1461076f57600080fd5b8063a9a8d3911461062b578063b52c05fe1461063e578063bd85b03914610651578063c2c4c5c114610664578063cbf9fe5f1461066c578063e620f4fd146106aa57600080fd5b8063947a36fb11610120578063947a36fb1461059a57806395d89b41146105c1578063981b24d0146105c957806399742dc6146105dc578063a2cc7140146105ef578063a6db822b1461061857600080fd5b806381fc83bb1461051a5780638ad4c4471461053a5780638da5cb5b146105785780638fd3ab8014610589578063900cf0cf1461059157600080fd5b80633ccfd60b1161020057806370a08231116101b957806370a082311461048d578063715018a6146104a057806376b467b7146104a85780637b39ecd5146104d45780637c616fe6146104dc5780637cd07e47146104ef57600080fd5b80633ccfd60b1461040d5780634a994eef146104155780634ba0a5ee146104285780634d144a011461044b5780634ee2cd7e146104535780636db5c8fd1461046657600080fd5b806318160ddd1161025257806318160ddd1461031a57806323cf3118146103225780632f4f21e214610335578063313ce5671461034857806334d901a4146103815780633a0af6bf146103f257600080fd5b8062fdd58e1461028e578063047fc9aa146102b457806306fdde03146102bd57806307779627146102d257806315456eba14610305575b600080fd5b6102a161029c366004613382565b610796565b6040519081526020015b60405180910390f35b6102a160065481565b6102c561087c565b6040516102ab91906133d8565b6102f56102e036600461340b565b60056020526000908152604090205460ff1681565b60405190151581526020016102ab565b610318610313366004613426565b61090a565b005b6102a1610a6c565b61031861033036600461340b565b610a7c565b610318610343366004613382565b610b3c565b61036f7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ab565b6103ca61038f366004613382565b600c602090815260009283526040808420909152908252902080546001820154600290920154600f82810b93600160801b909304900b919084565b60408051600f95860b81529390940b60208401529282015260608101919091526080016102ab565b6103fa600281565b604051600f9190910b81526020016102ab565b610318610c74565b61031861042336600461344d565b610e16565b6102f561043636600461340b565b60076020526000908152604090205460ff1681565b6103fa600081565b6102a1610461366004613382565b610e9f565b6102a17f000000000000000000000000000000000000000000000000000000000000000081565b6102a161049b36600461340b565b611173565b61031861117f565b6102a16104b636600461340b565b6001600160a01b031660009081526009602052604090206002015490565b6103fa600381565b6103186104ea366004613426565b6111b5565b600454610502906001600160a01b031681565b6040516001600160a01b0390911681526020016102ab565b6102a161052836600461340b565b600d6020526000908152604090205481565b6103ca610548366004613426565b600b60205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6000546001600160a01b0316610502565b610318611412565b6102a1600a5481565b6102a17f000000000000000000000000000000000000000000000000000000000000000081565b6102c5611701565b6102a16105d7366004613426565b61170e565b6103186105ea366004613484565b6118ad565b6102a16105fd36600461340b565b6001600160a01b031660009081526008602052604090205490565b6103186106263660046134b7565b611a8a565b610502610639366004613382565b611d17565b61031861064c3660046134f0565b611d4f565b6102a161065f366004613426565b611f4e565b610318611fae565b6103ca61067a36600461340b565b600960205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6102a16106b8366004613382565b6001600160a01b03919091166000908152600c60209081526040808320938352929052206001015490565b61031861200e565b6103186106f936600461340b565b6121b6565b6103fa61070c36600461340b565b6001600160a01b03166000908152600d6020908152604080832054600c8352818420908452909152902054600160801b9004600f0b90565b6103fa610752366004613426565b600e60205260009081526040902054600f0b81565b6103fa600181565b6105027f000000000000000000000000000000000000000000000000000000000000000081565b6001600160a01b0382166000908152600d60205260408120548082036107c0576000915050610876565b6001600160a01b0384166000908152600c6020908152604080832084845282529182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282018390526002015460608201529061082c906108299086613528565b90565b816020015161083b919061353f565b8151829061084a9083906135d4565b600f90810b90915282516000910b1215905061086557600081525b80516001600160801b03165b925050505b92915050565b6002805461088990613624565b80601f01602080910402602001604051908101604052809291908181526020018280546108b590613624565b80156109025780601f106108d757610100808354040283529160200191610902565b820191906000526020600020905b8154815290600101906020018083116108e557829003601f168201915b505050505081565b6002600154036109355760405162461bcd60e51b815260040161092c9061365e565b60405180910390fd5b6002600155333214610970573360009081526005602052604090205460ff166109705760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff16156109a05760405162461bcd60e51b815260040161092c906136cc565b3360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015282610a095760405162461bcd60e51b815260040161092c906136f7565b60008160000151600f0b13610a305760405162461bcd60e51b815260040161092c90613722565b42816060015111610a535760405162461bcd60e51b815260040161092c9061374e565b610a633384600080856002612251565b50506001805550565b6000610a7742611f4e565b905090565b6000546001600160a01b03163314610aa65760405162461bcd60e51b815260040161092c90613778565b6004546001600160a01b031615610af25760405162461bcd60e51b815260206004820152601060248201526f15914e88135251d4905513d497d4d15560821b604482015260640161092c565b600480546001600160a01b0319166001600160a01b0383169081179091556040517ff40543f3e605deae7fbca26db18ff1de07eda2925d68655836eae4c167444e3290600090a250565b600260015403610b5e5760405162461bcd60e51b815260040161092c9061365e565b60026001556001600160a01b038216600090815260076020526040902054829060ff1615610b9e5760405162461bcd60e51b815260040161092c906136cc565b6001600160a01b03831660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015282610c105760405162461bcd60e51b815260040161092c906136f7565b60008160000151600f0b13610c375760405162461bcd60e51b815260040161092c90613722565b42816060015111610c5a5760405162461bcd60e51b815260040161092c9061374e565b610c6a8484600080856000612251565b5050600180555050565b600260015403610c965760405162461bcd60e51b815260040161092c9061365e565b600260018181553360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252928301549181019190915291015460608201819052421015610d2d5760405162461bcd60e51b815260206004820152601460248201527315914e881313d0d2d7d393d517d156141254915160621b604482015260640161092c565b6000610d3a82600061243f565b825160208401519192506001600160801b03908116911680821115610d9857610d9833610d678385613528565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906125ad565b60408051838152602081018390524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a26000805160206139ee83398151915283610df48482613528565b6040805192835260208301919091520160405180910390a15050600180555050565b6000546001600160a01b03163314610e405760405162461bcd60e51b815260040161092c90613778565b6001600160a01b038216600081815260056020908152604091829020805460ff191685151590811790915591519182527f615a0bea5d49872b4b6680f2760a723460414907bfdf270030fd08ebca2bd23e910160405180910390a25050565b600043821115610eae57600080fd5b6001600160a01b0383166000908152600d6020526040812054815b6080811015610f565781831015610f565760006002610ee884866137ad565b610ef39060016137ad565b610efd91906137db565b6001600160a01b0388166000908152600c602090815260408083208484529091529020600201549091508610610f3557809350610f43565b610f40600182613528565b92505b5080610f4e816137ef565b915050610ec9565b506001600160a01b0385166000908152600c60209081526040808320858452825280832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152600a549091610fc08783612615565b6000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250808484101561109f576000600b816110248760016137ad565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528601519192506110819190613528565b9250836040015181604001516110979190613528565b9150506110c3565b60608301516110ae9043613528565b91508260400151426110c09190613528565b90505b60408301518215611100578284606001518c6110df9190613528565b6110e99084613808565b6110f391906137db565b6110fd90826137ad565b90505b6111138760400151826108299190613528565b8760200151611122919061353f565b875188906111319083906135d4565b600f90810b90915288516000910b1290506111615786516001600160801b03169950505050505050505050610876565b60009950505050505050505050610876565b60006108768242610796565b6000546001600160a01b031633146111a95760405162461bcd60e51b815260040161092c90613778565b6111b3600061269d565b565b6002600154036111d75760405162461bcd60e51b815260040161092c9061365e565b6002600155333214611212573360009081526005602052604090205460ff166112125760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff16156112425760405162461bcd60e51b815260040161092c906136cc565b33600090815260096020908152604080832081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606082018190529091907f00000000000000000000000000000000000000000000000000000000000000009081906112bf9087906137ad565b6112c991906137db565b6112d39190613808565b9050428260600151116112f85760405162461bcd60e51b815260040161092c9061374e565b60008260000151600f0b1361131f5760405162461bcd60e51b815260040161092c90613722565b6020820151600f0b1561136a5760405162461bcd60e51b815260206004820152601360248201527215914e881313d0d2d7d11254d0d3d553951151606a1b604482015260640161092c565b7f0000000000000000000000000000000000000000000000000000000000000000826060015161139a91906137ad565b8110156113b95760405162461bcd60e51b815260040161092c90613827565b6113e37f0000000000000000000000000000000000000000000000000000000000000000426137ad565b8111156114025760405162461bcd60e51b815260040161092c9061385e565b610c6a3360008084866003612251565b6002600154036114345760405162461bcd60e51b815260040161092c9061365e565b60026001553360008181526007602052604090205460ff16156114695760405162461bcd60e51b815260040161092c906136cc565b6004546001600160a01b03166114b85760405162461bcd60e51b815260206004820152601460248201527315914e88135251d4905513d497d393d517d4d15560621b604482015260640161092c565b33600090815260096020908152604080832081516080810183528154600f81810b808452600160801b909204900b9482019490945260018201549281019290925260020154606082015291126115205760405162461bcd60e51b815260040161092c90613722565b428160600151116115435760405162461bcd60e51b815260040161092c9061374e565b336000908152600860209081526040808320805482518185028101850190935280835291929091908301828280156115a457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611586575b5050505050905060006115b883600061243f565b835160208501516004805460408089015160608a0151915163111c7ff160e11b81529697506001600160801b0380871697908616966001600160a01b0390941695632238ffe2956116139533959094929390918d9101613895565b600060405180830381600087803b15801561162d57600080fd5b505af1158015611641573d6000803e3d6000fd5b5050336000908152600760205260409020805460ff1916600117905550508082111561168157600454611681906001600160a01b0316610d678385613528565b60408051838152602081018390524281830152905133917fc47a839c70aa320457c80c5abd38ce8b516c72e37be119b7962f67f1f8eb7ac2919081900360600190a26000805160206139ee833981519152836116dd8482613528565b6040805192835260208301919091520160405180910390a150506001805550505050565b6003805461088990613624565b60004382111561171d57600080fd5b600a54600061172c8483612615565b6000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508383101561183b576000600b8161178f8660016137ad565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528501519192501461183557826060015181606001516117fb9190613528565b8360400151826040015161180f9190613528565b606085015161181e908a613528565b6118289190613808565b61183291906137db565b91505b5061188a565b4382606001511461188a5760608201516118559043613528565b60408301516118649042613528565b60608401516118739089613528565b61187d9190613808565b61188791906137db565b90505b6118a38282846040015161189e91906137ad565b6126ed565b9695505050505050565b6002600154036118cf5760405162461bcd60e51b815260040161092c9061365e565b60026001553360009081526005602052604090205460ff166119265760405162461bcd60e51b815260206004820152601060248201526f56453a204e4f545f44454c454741544560801b604482015260640161092c565b6001600160a01b038316600090815260076020526040902054839060ff16156119615760405162461bcd60e51b815260040161092c906136cc565b61196b843361284c565b6001600160a01b03841660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002909101546060820152836119dd5760405162461bcd60e51b815260040161092c906136f7565b82841015611a255760405162461bcd60e51b81526020600482015260156024820152740ac8a74408892a6869eaa9ca8bea89e9ebe90928e9605b1b604482015260640161092c565b60008160000151600f0b13611a4c5760405162461bcd60e51b815260040161092c90613722565b42816060015111611a6f5760405162461bcd60e51b815260040161092c9061374e565b611a7f8585856000856002612251565b505060018055505050565b600260015403611aac5760405162461bcd60e51b815260040161092c9061365e565b60026001553360009081526005602052604090205460ff16611b035760405162461bcd60e51b815260206004820152601060248201526f56453a204e4f545f44454c454741544560801b604482015260640161092c565b6001600160a01b038416600090815260076020526040902054849060ff1615611b3e5760405162461bcd60e51b815260040161092c906136cc565b611b48853361284c565b60007f000000000000000000000000000000000000000000000000000000000000000080611b7685426137ad565b611b8091906137db565b611b8a9190613808565b6001600160a01b03871660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015290915085611bff5760405162461bcd60e51b815260040161092c906136f7565b84861015611c475760405162461bcd60e51b81526020600482015260156024820152740ac8a74408892a6869eaa9ca8bea89e9ebe90928e9605b1b604482015260640161092c565b8051600f0b15611c935760405162461bcd60e51b815260206004820152601760248201527615914e8811561254d5125391d7d313d0d2d7d193d55391604a1b604482015260640161092c565b428211611cb25760405162461bcd60e51b815260040161092c90613827565b611cdc7f0000000000000000000000000000000000000000000000000000000000000000426137ad565b821115611cfb5760405162461bcd60e51b815260040161092c9061385e565b611d0a87878785856001612251565b5050600180555050505050565b60086020528160005260406000208181548110611d3357600080fd5b6000918252602090912001546001600160a01b03169150829050565b600260015403611d715760405162461bcd60e51b815260040161092c9061365e565b6002600155333214611dac573360009081526005602052604090205460ff16611dac5760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff1615611ddc5760405162461bcd60e51b815260040161092c906136cc565b60007f000000000000000000000000000000000000000000000000000000000000000080611e0a85426137ad565b611e1491906137db565b611e1e9190613808565b3360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015290915084611e8a5760405162461bcd60e51b815260040161092c906136f7565b8051600f0b15611ed65760405162461bcd60e51b815260206004820152601760248201527615914e8811561254d5125391d7d313d0d2d7d193d55391604a1b604482015260640161092c565b428211611ef55760405162461bcd60e51b815260040161092c90613827565b611f1f7f0000000000000000000000000000000000000000000000000000000000000000426137ad565b821115611f3e5760405162461bcd60e51b815260040161092c9061385e565b611a7f3386600085856001612251565b600a546000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152909190611fa681856126ed565b949350505050565b6111b3600060405180608001604052806000600f0b81526020016000600f0b815260200160008152602001600081525060405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152506128fd565b6002600154036120305760405162461bcd60e51b815260040161092c9061365e565b6002600181815533600090815260096020908152604080832081516080810183528154600f81810b808452600160801b909204900b94820194909452948101549185019190915290930154606083015290911361209f5760405162461bcd60e51b815260040161092c90613722565b428160600151116120c25760405162461bcd60e51b815260040161092c9061374e565b60006120d682604001518360600151613053565b905060006120e4838361243f565b835160208501519192506001600160801b03908116911661213033670de0b6b3a76400006121128782613528565b61211c8587613528565b6121269190613808565b610d6791906137db565b604080518381526020810183905290810185905242606082015233907f10de281942f9db9a7f40110d5f1d818f2ab6f7e182a6d5c0727c6804c17b84bf9060800160405180910390a26000805160206139ee833981519152836121938482613528565b6040805192835260208301919091520160405180910390a1505060018055505050565b6000546001600160a01b031633146121e05760405162461bcd60e51b815260040161092c90613778565b6001600160a01b0381166122455760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092c565b61224e8161269d565b50565b600654829061226087826137ad565b60065560408051608081018252600080825260208083018281528385018381526060808601948552885193890151968901519089015190945292909252600f93840b90915290910b815287835184906122ba908390613911565b600f0b90525086156122df5786836020018181516122d89190613911565b600f0b9052505b85156123005782604001516000036122f8574260408401525b606083018690525b6001600160a01b0389166000908152600960209081526040918290208551918601516001600160801b03908116600160801b029216919091178155908401516001820155606084015160029091015561235a8982856128fd565b868811156123a3576123a389306123718a8c613528565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169291906130a7565b83600f0b83606001518a6001600160a01b03167f082ff60aeac04e11bcd706f6c38626b5c4323c459c49c07581cc1837b37800db8b8b426040516123fa939291909283526020830191909152604082015260600190565b60405180910390a46000805160206139ee8339815191528261241c8a826137ad565b6040805192835260208301919091520160405180910390a1505050505050505050565b8151604080516080810182526000808252602080830182815283850183815260608501848152338552600990935294909220925191516001600160801b03928316600160801b9184169190910217835592516001830155915160029091015560065491166124ad8183613528565b6006819055506124e8338560405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152506128fd565b336000908152600860205260408120905b815481101561258c5781818154811061251457612514613960565b60009182526020909120015460405163f3fef3a360e01b8152336004820152602481018790526001600160a01b039091169063f3fef3a390604401600060405180830381600087803b15801561256957600080fd5b505af115801561257d573d6000803e3d6000fd5b505050508060010190506124f9565b503360009081526008602052604081206125a591613334565b505092915050565b6040516001600160a01b03831660248201526044810182905261261090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526130df565b505050565b60008082815b60808110156126935781831015612693576000600261263a84866137ad565b6126459060016137ad565b61264f91906137db565b6000818152600b6020526040902060020154909150871061267257809350612680565b61267d600182613528565b92505b508061268b816137ef565b91505061261b565b5090949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008083905060007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836040015161274691906137db565b6127509190613808565b905060005b60ff811015612826576127887f0000000000000000000000000000000000000000000000000000000000000000836137ad565b915060008583111561279c578592506127b0565b506000828152600e6020526040902054600f0b5b6127c38460400151846108299190613528565b84602001516127d2919061353f565b845185906127e19083906135d4565b600f0b9052508583036127f45750612826565b80846020018181516128069190613911565b600f0b90525050604083018290528061281e816137ef565b915050612755565b5060008260000151600f0b121561283c57600082525b81516001600160801b0316610871565b6001600160a01b0382166000908152600860205260408120815b81548110156128b257836001600160a01b031682828154811061288b5761288b613960565b6000918252602090912001546001600160a01b0316036128aa57600192505b600101612866565b50816128f7576001600160a01b0384811660009081526008602090815260408220805460018101825590835291200180546001600160a01b0319169185169190911790555b50505050565b604080516080810182526000808252602082018190529181018290526060810191909152604080516080810182526000808252602082018190529181018290526060810191909152600a5460009081906001600160a01b03881615612aad57428760600151118015612976575060008760000151600f0b135b156129d9577f000000000000000000000000000000000000000000000000000000000000000087516129a89190613976565b600f0b602086015260608701516129c490610829904290613528565b85602001516129d3919061353f565b600f0b85525b4286606001511180156129f3575060008660000151600f0b135b15612a56577f00000000000000000000000000000000000000000000000000000000000000008651612a259190613976565b600f0b60208501526060860151612a4190610829904290613528565b8460200151612a50919061353f565b600f0b84525b6060808801516000908152600e602052604090205490870151600f9190910b935015612aad578660600151866060015103612a9357829150612aad565b60608601516000908152600e6020526040902054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612b2257506000818152600b602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b600081604001519050600060405180608001604052808460000151600f0b81526020018460200151600f0b8152602001846040015181526020018460600151815250905060008360400151421115612bb1576040840151612b839042613528565b6060850151612b929043613528565b612ba490670de0b6b3a7640000613808565b612bae91906137db565b90505b60007f0000000000000000000000000000000000000000000000000000000000000000612bde81866137db565b612be89190613808565b905060005b60ff811015612d8457612c207f0000000000000000000000000000000000000000000000000000000000000000836137ad565b9150600042831115612c3457429250612c48565b506000828152600e6020526040902054600f0b5b612c556108298785613528565b8760200151612c64919061353f565b87518890612c739083906135d4565b600f0b905250602087018051829190612c8d908390613911565b600f90810b90915288516000910b12159050612ca857600087525b60008760200151600f0b1215612cc057600060208801525b60408088018490528501519295508592670de0b6b3a764000090612ce49085613528565b612cee9086613808565b612cf891906137db565b8560600151612d0791906137ad565b6060880152612d176001896137ad565b9750428303612d2c5750436060870152612d84565b6000888152600b60209081526040918290208951918a01516001600160801b03908116600160801b02921691909117815590880151600182015560608801516002909101555080612d7c816137ef565b915050612bed565b5050600a8590556001600160a01b038c1615612e185788602001518860200151612dae91906135d4565b84602001818151612dbf9190613911565b600f0b90525088518851612dd391906135d4565b84518590612de2908390613911565b600f90810b90915260208601516000910b12159050612e0357600060208501525b60008460000151600f0b1215612e1857600084525b6000858152600b60209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101556001600160a01b038c161561304557428b606001511115612ed7576020890151612e879088613911565b96508a606001518a6060015103612eaa576020880151612ea790886135d4565b96505b60608b01516000908152600e6020526040902080546001600160801b0319166001600160801b0389161790555b428a606001511115612f31578a606001518a606001511115612f31576020880151612f0290876135d4565b60608b01516000908152600e6020526040902080546001600160801b0319166001600160801b03831617905595505b6001600160a01b038c166000908152600d6020526040812054612f559060016137ad565b905080600d60008f6001600160a01b03166001600160a01b0316815260200190815260200160002081905550428960400181815250504389606001818152505088600c60008f6001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506040820151816001015560608201518160020155905050505b505050505050505050505050565b600061305f8383613528565b6130694284613528565b61307b90670de0b6b3a7640000613808565b61308591906137db565b90506706f05b59d3b2000081101561087657506706f05b59d3b2000092915050565b6040516001600160a01b03808516602483015283166044820152606481018290526128f79085906323b872dd60e01b906084016125d9565b6000613134826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131b19092919063ffffffff16565b805190915015612610578080602001905181019061315291906139b4565b6126105760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161092c565b60606131c084846000856131ca565b90505b9392505050565b60608247101561322b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161092c565b6001600160a01b0385163b6132825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161092c565b600080866001600160a01b0316858760405161329e91906139d1565b60006040518083038185875af1925050503d80600081146132db576040519150601f19603f3d011682016040523d82523d6000602084013e6132e0565b606091505b50915091506132f08282866132fb565b979650505050505050565b6060831561330a5750816131c3565b82511561331a5782518084602001fd5b8160405162461bcd60e51b815260040161092c91906133d8565b508054600082559060005260206000209081019061224e91905b80821115613362576000815560010161334e565b5090565b80356001600160a01b038116811461337d57600080fd5b919050565b6000806040838503121561339557600080fd5b61339e83613366565b946020939093013593505050565b60005b838110156133c75781810151838201526020016133af565b838111156128f75750506000910152565b60208152600082518060208401526133f78160408501602087016133ac565b601f01601f19169190910160400192915050565b60006020828403121561341d57600080fd5b6131c382613366565b60006020828403121561343857600080fd5b5035919050565b801515811461224e57600080fd5b6000806040838503121561346057600080fd5b61346983613366565b915060208301356134798161343f565b809150509250929050565b60008060006060848603121561349957600080fd5b6134a284613366565b95602085013595506040909401359392505050565b600080600080608085870312156134cd57600080fd5b6134d685613366565b966020860135965060408601359560600135945092505050565b6000806040838503121561350357600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b60008282101561353a5761353a613512565b500390565b600081600f0b83600f0b60016001607f1b0360008213600084138383048511828216161561356f5761356f613512565b60016001607f1b0319600085128281168783058712161561359257613592613512565b600087129250858205871284841616156135ae576135ae613512565b858505871281841616156135c4576135c4613512565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156135ff576135ff613512565b8160016001607f1b0301831381161561361a5761361a613512565b5090039392505050565b600181811c9082168061363857607f821691505b60208210810361365857634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526019908201527f56453a20434f4e54524143545f4e4f545f44454c454741544500000000000000604082015260600190565b60208082526011908201527015914e881313d0d2d7d35251d490551151607a1b604082015260600190565b60208082526011908201527056453a20494e56414c49445f56414c554560781b604082015260600190565b60208082526012908201527115914e881313d0d2d7d393d517d193d5539160721b604082015260600190565b60208082526010908201526f15914e881313d0d2d7d156141254915160821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600082198211156137c0576137c0613512565b500190565b634e487b7160e01b600052601260045260246000fd5b6000826137ea576137ea6137c5565b500490565b60006001820161380157613801613512565b5060010190565b600081600019048311821515161561382257613822613512565b500290565b60208082526019908201527f56453a20554e4c4f434b5f54494d455f544f4f5f4541524c5900000000000000604082015260600190565b60208082526018908201527f56453a20554e4c4f434b5f54494d455f544f4f5f4c4154450000000000000000604082015260600190565b600060c0820160018060a01b03808a168452602089600f0b8186015288600f0b604086015287606086015286608086015260c060a086015282865180855260e087019150828801945060005b818110156138ff5785518516835294830194918301916001016138e1565b50909c9b505050505050505050505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561393b5761393b613512565b8260016001607f1b031903821281161561395757613957613512565b50019392505050565b634e487b7160e01b600052603260045260246000fd5b600081600f0b83600f0b8061398d5761398d6137c5565b60016001607f1b03198214600019821416156139ab576139ab613512565b90059392505050565b6000602082840312156139c657600080fd5b81516131c38161343f565b600082516139e38184602087016133ac565b919091019291505056fe5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5ca2646970667358221220d93557040f0abd30cf05470177525239087785ed86cd63c6fcc15afdc8540df864736f6c634300080e0033",
  "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106102895760003560e01c806381fc83bb1161015c578063a9a8d391116100ce578063ea8a1af011610087578063ea8a1af0146106e3578063f2fde38b146106eb578063f3a6d608146106fe578063f52a36f714610744578063f56d21f014610767578063fc0c546a1461076f57600080fd5b8063a9a8d3911461062b578063b52c05fe1461063e578063bd85b03914610651578063c2c4c5c114610664578063cbf9fe5f1461066c578063e620f4fd146106aa57600080fd5b8063947a36fb11610120578063947a36fb1461059a57806395d89b41146105c1578063981b24d0146105c957806399742dc6146105dc578063a2cc7140146105ef578063a6db822b1461061857600080fd5b806381fc83bb1461051a5780638ad4c4471461053a5780638da5cb5b146105785780638fd3ab8014610589578063900cf0cf1461059157600080fd5b80633ccfd60b1161020057806370a08231116101b957806370a082311461048d578063715018a6146104a057806376b467b7146104a85780637b39ecd5146104d45780637c616fe6146104dc5780637cd07e47146104ef57600080fd5b80633ccfd60b1461040d5780634a994eef146104155780634ba0a5ee146104285780634d144a011461044b5780634ee2cd7e146104535780636db5c8fd1461046657600080fd5b806318160ddd1161025257806318160ddd1461031a57806323cf3118146103225780632f4f21e214610335578063313ce5671461034857806334d901a4146103815780633a0af6bf146103f257600080fd5b8062fdd58e1461028e578063047fc9aa146102b457806306fdde03146102bd57806307779627146102d257806315456eba14610305575b600080fd5b6102a161029c366004613382565b610796565b6040519081526020015b60405180910390f35b6102a160065481565b6102c561087c565b6040516102ab91906133d8565b6102f56102e036600461340b565b60056020526000908152604090205460ff1681565b60405190151581526020016102ab565b610318610313366004613426565b61090a565b005b6102a1610a6c565b61031861033036600461340b565b610a7c565b610318610343366004613382565b610b3c565b61036f7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016102ab565b6103ca61038f366004613382565b600c602090815260009283526040808420909152908252902080546001820154600290920154600f82810b93600160801b909304900b919084565b60408051600f95860b81529390940b60208401529282015260608101919091526080016102ab565b6103fa600281565b604051600f9190910b81526020016102ab565b610318610c74565b61031861042336600461344d565b610e16565b6102f561043636600461340b565b60076020526000908152604090205460ff1681565b6103fa600081565b6102a1610461366004613382565b610e9f565b6102a17f000000000000000000000000000000000000000000000000000000000000000081565b6102a161049b36600461340b565b611173565b61031861117f565b6102a16104b636600461340b565b6001600160a01b031660009081526009602052604090206002015490565b6103fa600381565b6103186104ea366004613426565b6111b5565b600454610502906001600160a01b031681565b6040516001600160a01b0390911681526020016102ab565b6102a161052836600461340b565b600d6020526000908152604090205481565b6103ca610548366004613426565b600b60205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6000546001600160a01b0316610502565b610318611412565b6102a1600a5481565b6102a17f000000000000000000000000000000000000000000000000000000000000000081565b6102c5611701565b6102a16105d7366004613426565b61170e565b6103186105ea366004613484565b6118ad565b6102a16105fd36600461340b565b6001600160a01b031660009081526008602052604090205490565b6103186106263660046134b7565b611a8a565b610502610639366004613382565b611d17565b61031861064c3660046134f0565b611d4f565b6102a161065f366004613426565b611f4e565b610318611fae565b6103ca61067a36600461340b565b600960205260009081526040902080546001820154600290920154600f82810b93600160801b909304900b919084565b6102a16106b8366004613382565b6001600160a01b03919091166000908152600c60209081526040808320938352929052206001015490565b61031861200e565b6103186106f936600461340b565b6121b6565b6103fa61070c36600461340b565b6001600160a01b03166000908152600d6020908152604080832054600c8352818420908452909152902054600160801b9004600f0b90565b6103fa610752366004613426565b600e60205260009081526040902054600f0b81565b6103fa600181565b6105027f000000000000000000000000000000000000000000000000000000000000000081565b6001600160a01b0382166000908152600d60205260408120548082036107c0576000915050610876565b6001600160a01b0384166000908152600c6020908152604080832084845282529182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282018390526002015460608201529061082c906108299086613528565b90565b816020015161083b919061353f565b8151829061084a9083906135d4565b600f90810b90915282516000910b1215905061086557600081525b80516001600160801b03165b925050505b92915050565b6002805461088990613624565b80601f01602080910402602001604051908101604052809291908181526020018280546108b590613624565b80156109025780601f106108d757610100808354040283529160200191610902565b820191906000526020600020905b8154815290600101906020018083116108e557829003601f168201915b505050505081565b6002600154036109355760405162461bcd60e51b815260040161092c9061365e565b60405180910390fd5b6002600155333214610970573360009081526005602052604090205460ff166109705760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff16156109a05760405162461bcd60e51b815260040161092c906136cc565b3360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015282610a095760405162461bcd60e51b815260040161092c906136f7565b60008160000151600f0b13610a305760405162461bcd60e51b815260040161092c90613722565b42816060015111610a535760405162461bcd60e51b815260040161092c9061374e565b610a633384600080856002612251565b50506001805550565b6000610a7742611f4e565b905090565b6000546001600160a01b03163314610aa65760405162461bcd60e51b815260040161092c90613778565b6004546001600160a01b031615610af25760405162461bcd60e51b815260206004820152601060248201526f15914e88135251d4905513d497d4d15560821b604482015260640161092c565b600480546001600160a01b0319166001600160a01b0383169081179091556040517ff40543f3e605deae7fbca26db18ff1de07eda2925d68655836eae4c167444e3290600090a250565b600260015403610b5e5760405162461bcd60e51b815260040161092c9061365e565b60026001556001600160a01b038216600090815260076020526040902054829060ff1615610b9e5760405162461bcd60e51b815260040161092c906136cc565b6001600160a01b03831660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015282610c105760405162461bcd60e51b815260040161092c906136f7565b60008160000151600f0b13610c375760405162461bcd60e51b815260040161092c90613722565b42816060015111610c5a5760405162461bcd60e51b815260040161092c9061374e565b610c6a8484600080856000612251565b5050600180555050565b600260015403610c965760405162461bcd60e51b815260040161092c9061365e565b600260018181553360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252928301549181019190915291015460608201819052421015610d2d5760405162461bcd60e51b815260206004820152601460248201527315914e881313d0d2d7d393d517d156141254915160621b604482015260640161092c565b6000610d3a82600061243f565b825160208401519192506001600160801b03908116911680821115610d9857610d9833610d678385613528565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001691906125ad565b60408051838152602081018390524281830152905133917f02f25270a4d87bea75db541cdfe559334a275b4a233520ed6c0a2429667cca94919081900360600190a26000805160206139ee83398151915283610df48482613528565b6040805192835260208301919091520160405180910390a15050600180555050565b6000546001600160a01b03163314610e405760405162461bcd60e51b815260040161092c90613778565b6001600160a01b038216600081815260056020908152604091829020805460ff191685151590811790915591519182527f615a0bea5d49872b4b6680f2760a723460414907bfdf270030fd08ebca2bd23e910160405180910390a25050565b600043821115610eae57600080fd5b6001600160a01b0383166000908152600d6020526040812054815b6080811015610f565781831015610f565760006002610ee884866137ad565b610ef39060016137ad565b610efd91906137db565b6001600160a01b0388166000908152600c602090815260408083208484529091529020600201549091508610610f3557809350610f43565b610f40600182613528565b92505b5080610f4e816137ef565b915050610ec9565b506001600160a01b0385166000908152600c60209081526040808320858452825280832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152600a549091610fc08783612615565b6000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152919250808484101561109f576000600b816110248760016137ad565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528601519192506110819190613528565b9250836040015181604001516110979190613528565b9150506110c3565b60608301516110ae9043613528565b91508260400151426110c09190613528565b90505b60408301518215611100578284606001518c6110df9190613528565b6110e99084613808565b6110f391906137db565b6110fd90826137ad565b90505b6111138760400151826108299190613528565b8760200151611122919061353f565b875188906111319083906135d4565b600f90810b90915288516000910b1290506111615786516001600160801b03169950505050505050505050610876565b60009950505050505050505050610876565b60006108768242610796565b6000546001600160a01b031633146111a95760405162461bcd60e51b815260040161092c90613778565b6111b3600061269d565b565b6002600154036111d75760405162461bcd60e51b815260040161092c9061365e565b6002600155333214611212573360009081526005602052604090205460ff166112125760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff16156112425760405162461bcd60e51b815260040161092c906136cc565b33600090815260096020908152604080832081516080810183528154600f81810b8352600160801b909104900b9381019390935260018101549183019190915260020154606082018190529091907f00000000000000000000000000000000000000000000000000000000000000009081906112bf9087906137ad565b6112c991906137db565b6112d39190613808565b9050428260600151116112f85760405162461bcd60e51b815260040161092c9061374e565b60008260000151600f0b1361131f5760405162461bcd60e51b815260040161092c90613722565b6020820151600f0b1561136a5760405162461bcd60e51b815260206004820152601360248201527215914e881313d0d2d7d11254d0d3d553951151606a1b604482015260640161092c565b7f0000000000000000000000000000000000000000000000000000000000000000826060015161139a91906137ad565b8110156113b95760405162461bcd60e51b815260040161092c90613827565b6113e37f0000000000000000000000000000000000000000000000000000000000000000426137ad565b8111156114025760405162461bcd60e51b815260040161092c9061385e565b610c6a3360008084866003612251565b6002600154036114345760405162461bcd60e51b815260040161092c9061365e565b60026001553360008181526007602052604090205460ff16156114695760405162461bcd60e51b815260040161092c906136cc565b6004546001600160a01b03166114b85760405162461bcd60e51b815260206004820152601460248201527315914e88135251d4905513d497d393d517d4d15560621b604482015260640161092c565b33600090815260096020908152604080832081516080810183528154600f81810b808452600160801b909204900b9482019490945260018201549281019290925260020154606082015291126115205760405162461bcd60e51b815260040161092c90613722565b428160600151116115435760405162461bcd60e51b815260040161092c9061374e565b336000908152600860209081526040808320805482518185028101850190935280835291929091908301828280156115a457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611586575b5050505050905060006115b883600061243f565b835160208501516004805460408089015160608a0151915163111c7ff160e11b81529697506001600160801b0380871697908616966001600160a01b0390941695632238ffe2956116139533959094929390918d9101613895565b600060405180830381600087803b15801561162d57600080fd5b505af1158015611641573d6000803e3d6000fd5b5050336000908152600760205260409020805460ff1916600117905550508082111561168157600454611681906001600160a01b0316610d678385613528565b60408051838152602081018390524281830152905133917fc47a839c70aa320457c80c5abd38ce8b516c72e37be119b7962f67f1f8eb7ac2919081900360600190a26000805160206139ee833981519152836116dd8482613528565b6040805192835260208301919091520160405180910390a150506001805550505050565b6003805461088990613624565b60004382111561171d57600080fd5b600a54600061172c8483612615565b6000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608201529192508383101561183b576000600b8161178f8660016137ad565b8152602080820192909252604090810160002081516080810183528154600f81810b8352600160801b909104900b938101939093526001810154918301919091526002015460608083018290528501519192501461183557826060015181606001516117fb9190613528565b8360400151826040015161180f9190613528565b606085015161181e908a613528565b6118289190613808565b61183291906137db565b91505b5061188a565b4382606001511461188a5760608201516118559043613528565b60408301516118649042613528565b60608401516118739089613528565b61187d9190613808565b61188791906137db565b90505b6118a38282846040015161189e91906137ad565b6126ed565b9695505050505050565b6002600154036118cf5760405162461bcd60e51b815260040161092c9061365e565b60026001553360009081526005602052604090205460ff166119265760405162461bcd60e51b815260206004820152601060248201526f56453a204e4f545f44454c454741544560801b604482015260640161092c565b6001600160a01b038316600090815260076020526040902054839060ff16156119615760405162461bcd60e51b815260040161092c906136cc565b61196b843361284c565b6001600160a01b03841660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b928101929092526001810154928201929092526002909101546060820152836119dd5760405162461bcd60e51b815260040161092c906136f7565b82841015611a255760405162461bcd60e51b81526020600482015260156024820152740ac8a74408892a6869eaa9ca8bea89e9ebe90928e9605b1b604482015260640161092c565b60008160000151600f0b13611a4c5760405162461bcd60e51b815260040161092c90613722565b42816060015111611a6f5760405162461bcd60e51b815260040161092c9061374e565b611a7f8585856000856002612251565b505060018055505050565b600260015403611aac5760405162461bcd60e51b815260040161092c9061365e565b60026001553360009081526005602052604090205460ff16611b035760405162461bcd60e51b815260206004820152601060248201526f56453a204e4f545f44454c454741544560801b604482015260640161092c565b6001600160a01b038416600090815260076020526040902054849060ff1615611b3e5760405162461bcd60e51b815260040161092c906136cc565b611b48853361284c565b60007f000000000000000000000000000000000000000000000000000000000000000080611b7685426137ad565b611b8091906137db565b611b8a9190613808565b6001600160a01b03871660009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015290915085611bff5760405162461bcd60e51b815260040161092c906136f7565b84861015611c475760405162461bcd60e51b81526020600482015260156024820152740ac8a74408892a6869eaa9ca8bea89e9ebe90928e9605b1b604482015260640161092c565b8051600f0b15611c935760405162461bcd60e51b815260206004820152601760248201527615914e8811561254d5125391d7d313d0d2d7d193d55391604a1b604482015260640161092c565b428211611cb25760405162461bcd60e51b815260040161092c90613827565b611cdc7f0000000000000000000000000000000000000000000000000000000000000000426137ad565b821115611cfb5760405162461bcd60e51b815260040161092c9061385e565b611d0a87878785856001612251565b5050600180555050505050565b60086020528160005260406000208181548110611d3357600080fd5b6000918252602090912001546001600160a01b03169150829050565b600260015403611d715760405162461bcd60e51b815260040161092c9061365e565b6002600155333214611dac573360009081526005602052604090205460ff16611dac5760405162461bcd60e51b815260040161092c90613695565b3360008181526007602052604090205460ff1615611ddc5760405162461bcd60e51b815260040161092c906136cc565b60007f000000000000000000000000000000000000000000000000000000000000000080611e0a85426137ad565b611e1491906137db565b611e1e9190613808565b3360009081526009602090815260409182902082516080810184528154600f81810b8352600160801b909104900b92810192909252600181015492820192909252600290910154606082015290915084611e8a5760405162461bcd60e51b815260040161092c906136f7565b8051600f0b15611ed65760405162461bcd60e51b815260206004820152601760248201527615914e8811561254d5125391d7d313d0d2d7d193d55391604a1b604482015260640161092c565b428211611ef55760405162461bcd60e51b815260040161092c90613827565b611f1f7f0000000000000000000000000000000000000000000000000000000000000000426137ad565b821115611f3e5760405162461bcd60e51b815260040161092c9061385e565b611a7f3386600085856001612251565b600a546000818152600b6020908152604080832081516080810183528154600f81810b8352600160801b909104900b93810193909352600181015491830191909152600201546060820152909190611fa681856126ed565b949350505050565b6111b3600060405180608001604052806000600f0b81526020016000600f0b815260200160008152602001600081525060405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152506128fd565b6002600154036120305760405162461bcd60e51b815260040161092c9061365e565b6002600181815533600090815260096020908152604080832081516080810183528154600f81810b808452600160801b909204900b94820194909452948101549185019190915290930154606083015290911361209f5760405162461bcd60e51b815260040161092c90613722565b428160600151116120c25760405162461bcd60e51b815260040161092c9061374e565b60006120d682604001518360600151613053565b905060006120e4838361243f565b835160208501519192506001600160801b03908116911661213033670de0b6b3a76400006121128782613528565b61211c8587613528565b6121269190613808565b610d6791906137db565b604080518381526020810183905290810185905242606082015233907f10de281942f9db9a7f40110d5f1d818f2ab6f7e182a6d5c0727c6804c17b84bf9060800160405180910390a26000805160206139ee833981519152836121938482613528565b6040805192835260208301919091520160405180910390a1505060018055505050565b6000546001600160a01b031633146121e05760405162461bcd60e51b815260040161092c90613778565b6001600160a01b0381166122455760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161092c565b61224e8161269d565b50565b600654829061226087826137ad565b60065560408051608081018252600080825260208083018281528385018381526060808601948552885193890151968901519089015190945292909252600f93840b90915290910b815287835184906122ba908390613911565b600f0b90525086156122df5786836020018181516122d89190613911565b600f0b9052505b85156123005782604001516000036122f8574260408401525b606083018690525b6001600160a01b0389166000908152600960209081526040918290208551918601516001600160801b03908116600160801b029216919091178155908401516001820155606084015160029091015561235a8982856128fd565b868811156123a3576123a389306123718a8c613528565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169291906130a7565b83600f0b83606001518a6001600160a01b03167f082ff60aeac04e11bcd706f6c38626b5c4323c459c49c07581cc1837b37800db8b8b426040516123fa939291909283526020830191909152604082015260600190565b60405180910390a46000805160206139ee8339815191528261241c8a826137ad565b6040805192835260208301919091520160405180910390a1505050505050505050565b8151604080516080810182526000808252602080830182815283850183815260608501848152338552600990935294909220925191516001600160801b03928316600160801b9184169190910217835592516001830155915160029091015560065491166124ad8183613528565b6006819055506124e8338560405180608001604052806000600f0b81526020016000600f0b81526020016000815260200160008152506128fd565b336000908152600860205260408120905b815481101561258c5781818154811061251457612514613960565b60009182526020909120015460405163f3fef3a360e01b8152336004820152602481018790526001600160a01b039091169063f3fef3a390604401600060405180830381600087803b15801561256957600080fd5b505af115801561257d573d6000803e3d6000fd5b505050508060010190506124f9565b503360009081526008602052604081206125a591613334565b505092915050565b6040516001600160a01b03831660248201526044810182905261261090849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526130df565b505050565b60008082815b60808110156126935781831015612693576000600261263a84866137ad565b6126459060016137ad565b61264f91906137db565b6000818152600b6020526040902060020154909150871061267257809350612680565b61267d600182613528565b92505b508061268b816137ef565b91505061261b565b5090949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60008083905060007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000836040015161274691906137db565b6127509190613808565b905060005b60ff811015612826576127887f0000000000000000000000000000000000000000000000000000000000000000836137ad565b915060008583111561279c578592506127b0565b506000828152600e6020526040902054600f0b5b6127c38460400151846108299190613528565b84602001516127d2919061353f565b845185906127e19083906135d4565b600f0b9052508583036127f45750612826565b80846020018181516128069190613911565b600f0b90525050604083018290528061281e816137ef565b915050612755565b5060008260000151600f0b121561283c57600082525b81516001600160801b0316610871565b6001600160a01b0382166000908152600860205260408120815b81548110156128b257836001600160a01b031682828154811061288b5761288b613960565b6000918252602090912001546001600160a01b0316036128aa57600192505b600101612866565b50816128f7576001600160a01b0384811660009081526008602090815260408220805460018101825590835291200180546001600160a01b0319169185169190911790555b50505050565b604080516080810182526000808252602082018190529181018290526060810191909152604080516080810182526000808252602082018190529181018290526060810191909152600a5460009081906001600160a01b03881615612aad57428760600151118015612976575060008760000151600f0b135b156129d9577f000000000000000000000000000000000000000000000000000000000000000087516129a89190613976565b600f0b602086015260608701516129c490610829904290613528565b85602001516129d3919061353f565b600f0b85525b4286606001511180156129f3575060008660000151600f0b135b15612a56577f00000000000000000000000000000000000000000000000000000000000000008651612a259190613976565b600f0b60208501526060860151612a4190610829904290613528565b8460200151612a50919061353f565b600f0b84525b6060808801516000908152600e602052604090205490870151600f9190910b935015612aad578660600151866060015103612a9357829150612aad565b60608601516000908152600e6020526040902054600f0b91505b604080516080810182526000808252602082015242918101919091524360608201528115612b2257506000818152600b602090815260409182902082516080810184528154600f81810b8352600160801b909104900b9281019290925260018101549282019290925260029091015460608201525b600081604001519050600060405180608001604052808460000151600f0b81526020018460200151600f0b8152602001846040015181526020018460600151815250905060008360400151421115612bb1576040840151612b839042613528565b6060850151612b929043613528565b612ba490670de0b6b3a7640000613808565b612bae91906137db565b90505b60007f0000000000000000000000000000000000000000000000000000000000000000612bde81866137db565b612be89190613808565b905060005b60ff811015612d8457612c207f0000000000000000000000000000000000000000000000000000000000000000836137ad565b9150600042831115612c3457429250612c48565b506000828152600e6020526040902054600f0b5b612c556108298785613528565b8760200151612c64919061353f565b87518890612c739083906135d4565b600f0b905250602087018051829190612c8d908390613911565b600f90810b90915288516000910b12159050612ca857600087525b60008760200151600f0b1215612cc057600060208801525b60408088018490528501519295508592670de0b6b3a764000090612ce49085613528565b612cee9086613808565b612cf891906137db565b8560600151612d0791906137ad565b6060880152612d176001896137ad565b9750428303612d2c5750436060870152612d84565b6000888152600b60209081526040918290208951918a01516001600160801b03908116600160801b02921691909117815590880151600182015560608801516002909101555080612d7c816137ef565b915050612bed565b5050600a8590556001600160a01b038c1615612e185788602001518860200151612dae91906135d4565b84602001818151612dbf9190613911565b600f0b90525088518851612dd391906135d4565b84518590612de2908390613911565b600f90810b90915260208601516000910b12159050612e0357600060208501525b60008460000151600f0b1215612e1857600084525b6000858152600b60209081526040918290208651918701516001600160801b03908116600160801b02921691909117815590850151600182015560608501516002909101556001600160a01b038c161561304557428b606001511115612ed7576020890151612e879088613911565b96508a606001518a6060015103612eaa576020880151612ea790886135d4565b96505b60608b01516000908152600e6020526040902080546001600160801b0319166001600160801b0389161790555b428a606001511115612f31578a606001518a606001511115612f31576020880151612f0290876135d4565b60608b01516000908152600e6020526040902080546001600160801b0319166001600160801b03831617905595505b6001600160a01b038c166000908152600d6020526040812054612f559060016137ad565b905080600d60008f6001600160a01b03166001600160a01b0316815260200190815260200160002081905550428960400181815250504389606001818152505088600c60008f6001600160a01b03166001600160a01b03168152602001908152602001600020600083815260200190815260200160002060008201518160000160006101000a8154816001600160801b030219169083600f0b6001600160801b0316021790555060208201518160000160106101000a8154816001600160801b030219169083600f0b6001600160801b031602179055506040820151816001015560608201518160020155905050505b505050505050505050505050565b600061305f8383613528565b6130694284613528565b61307b90670de0b6b3a7640000613808565b61308591906137db565b90506706f05b59d3b2000081101561087657506706f05b59d3b2000092915050565b6040516001600160a01b03808516602483015283166044820152606481018290526128f79085906323b872dd60e01b906084016125d9565b6000613134826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166131b19092919063ffffffff16565b805190915015612610578080602001905181019061315291906139b4565b6126105760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b606482015260840161092c565b60606131c084846000856131ca565b90505b9392505050565b60608247101561322b5760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b606482015260840161092c565b6001600160a01b0385163b6132825760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161092c565b600080866001600160a01b0316858760405161329e91906139d1565b60006040518083038185875af1925050503d80600081146132db576040519150601f19603f3d011682016040523d82523d6000602084013e6132e0565b606091505b50915091506132f08282866132fb565b979650505050505050565b6060831561330a5750816131c3565b82511561331a5782518084602001fd5b8160405162461bcd60e51b815260040161092c91906133d8565b508054600082559060005260206000209081019061224e91905b80821115613362576000815560010161334e565b5090565b80356001600160a01b038116811461337d57600080fd5b919050565b6000806040838503121561339557600080fd5b61339e83613366565b946020939093013593505050565b60005b838110156133c75781810151838201526020016133af565b838111156128f75750506000910152565b60208152600082518060208401526133f78160408501602087016133ac565b601f01601f19169190910160400192915050565b60006020828403121561341d57600080fd5b6131c382613366565b60006020828403121561343857600080fd5b5035919050565b801515811461224e57600080fd5b6000806040838503121561346057600080fd5b61346983613366565b915060208301356134798161343f565b809150509250929050565b60008060006060848603121561349957600080fd5b6134a284613366565b95602085013595506040909401359392505050565b600080600080608085870312156134cd57600080fd5b6134d685613366565b966020860135965060408601359560600135945092505050565b6000806040838503121561350357600080fd5b50508035926020909101359150565b634e487b7160e01b600052601160045260246000fd5b60008282101561353a5761353a613512565b500390565b600081600f0b83600f0b60016001607f1b0360008213600084138383048511828216161561356f5761356f613512565b60016001607f1b0319600085128281168783058712161561359257613592613512565b600087129250858205871284841616156135ae576135ae613512565b858505871281841616156135c4576135c4613512565b5050509290910295945050505050565b600081600f0b83600f0b600081128160016001607f1b0319018312811516156135ff576135ff613512565b8160016001607f1b0301831381161561361a5761361a613512565b5090039392505050565b600181811c9082168061363857607f821691505b60208210810361365857634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60208082526019908201527f56453a20434f4e54524143545f4e4f545f44454c454741544500000000000000604082015260600190565b60208082526011908201527015914e881313d0d2d7d35251d490551151607a1b604082015260600190565b60208082526011908201527056453a20494e56414c49445f56414c554560781b604082015260600190565b60208082526012908201527115914e881313d0d2d7d393d517d193d5539160721b604082015260600190565b60208082526010908201526f15914e881313d0d2d7d156141254915160821b604082015260600190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b600082198211156137c0576137c0613512565b500190565b634e487b7160e01b600052601260045260246000fd5b6000826137ea576137ea6137c5565b500490565b60006001820161380157613801613512565b5060010190565b600081600019048311821515161561382257613822613512565b500290565b60208082526019908201527f56453a20554e4c4f434b5f54494d455f544f4f5f4541524c5900000000000000604082015260600190565b60208082526018908201527f56453a20554e4c4f434b5f54494d455f544f4f5f4c4154450000000000000000604082015260600190565b600060c0820160018060a01b03808a168452602089600f0b8186015288600f0b604086015287606086015286608086015260c060a086015282865180855260e087019150828801945060005b818110156138ff5785518516835294830194918301916001016138e1565b50909c9b505050505050505050505050565b600081600f0b83600f0b600082128260016001607f1b030382138115161561393b5761393b613512565b8260016001607f1b031903821281161561395757613957613512565b50019392505050565b634e487b7160e01b600052603260045260246000fd5b600081600f0b83600f0b8061398d5761398d6137c5565b60016001607f1b03198214600019821416156139ab576139ab613512565b90059392505050565b6000602082840312156139c657600080fd5b81516131c38161343f565b600082516139e38184602087016133ac565b919091019291505056fe5e2aa66efd74cce82b21852e317e5490d9ecc9e6bb953ae24d90851258cc2f5ca2646970667358221220d93557040f0abd30cf05470177525239087785ed86cd63c6fcc15afdc8540df864736f6c634300080e0033",
  "devdoc": {
    "author": "LevX (team@levx.io)",
    "details": "Vote weight decays linearly over time. Lock time cannot be      more than `MAXTIME`.Ported from vyper (https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/VotingEscrow.vy)",
    "kind": "dev",
    "methods": {
      "balanceOf(address,uint256)": {
        "details": "Adheres to the ERC20 `balanceOf` interface for Aragon compatibility",
        "params": {
          "_t": "Epoch time to return voting power at",
          "addr": "User wallet address"
        },
        "returns": {
          "_0": "User voting power"
        }
      },
      "balanceOfAt(address,uint256)": {
        "details": "Adheres to MiniMe `balanceOfAt` interface: https://github.com/Giveth/minime",
        "params": {
          "_block": "Block to calculate the voting power at",
          "addr": "User's wallet address"
        },
        "returns": {
          "_0": "Voting power"
        }
      },
      "cancel()": {
        "details": "Only possible if the lock exists"
      },
      "createLock(uint256,uint256)": {
        "params": {
          "_duration": "Epoch time until tokens unlock from now",
          "_value": "Amount to deposit"
        }
      },
      "createLockFor(address,uint256,uint256,uint256)": {
        "details": "Only delegates can creat a lock for someone else",
        "params": {
          "_addr": "User's wallet address",
          "_discount": "Amount to get discounted out of _value",
          "_duration": "Epoch time until tokens unlock from now",
          "_value": "Amount to add to user's lock"
        }
      },
      "depositFor(address,uint256)": {
        "details": "Anyone (even a smart contract) can deposit for someone else, but      cannot extend their locktime and deposit for a brand new user",
        "params": {
          "_addr": "User's wallet address",
          "_value": "Amount to add to user's lock"
        }
      },
      "getCheckpointTime(address,uint256)": {
        "params": {
          "_addr": "User wallet address",
          "_idx": "User epoch number"
        },
        "returns": {
          "_0": "Epoch time of the checkpoint"
        }
      },
      "getLastUserSlope(address)": {
        "params": {
          "addr": "Address of the user wallet"
        },
        "returns": {
          "_0": "Value of the slope"
        }
      },
      "increaseAmount(uint256)": {
        "params": {
          "_value": "Amount of tokens to deposit and add to the lock"
        }
      },
      "increaseAmountFor(address,uint256,uint256)": {
        "params": {
          "_addr": "User's wallet address",
          "_discount": "Amount to get discounted out of _value",
          "_value": "Amount of tokens to deposit and add to the lock"
        }
      },
      "increaseUnlockTime(uint256)": {
        "params": {
          "_duration": "Increased epoch time for unlocking"
        }
      },
      "owner()": {
        "details": "Returns the address of the current owner."
      },
      "renounceOwnership()": {
        "details": "Leaves the contract without owner. It will not be possible to call `onlyOwner` functions anymore. Can only be called by the current owner. NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner."
      },
      "totalSupply(uint256)": {
        "details": "Adheres to the ERC20 `totalSupply` interface for Aragon compatibility",
        "returns": {
          "_0": "Total voting power"
        }
      },
      "totalSupplyAt(uint256)": {
        "params": {
          "_block": "Block to calculate the total voting power at"
        },
        "returns": {
          "_0": "Total voting power at `_block`"
        }
      },
      "transferOwnership(address)": {
        "details": "Transfers ownership of the contract to a new account (`newOwner`). Can only be called by the current owner."
      },
      "unlockTime(address)": {
        "params": {
          "_addr": "User wallet"
        },
        "returns": {
          "_0": "Epoch time of the lock end"
        }
      },
      "withdraw()": {
        "details": "Only possible if the lock has expired"
      }
    },
    "title": "Voting Escrow",
    "version": 1
  },
  "userdoc": {
    "kind": "user",
    "methods": {
      "balanceOf(address,uint256)": {
        "notice": "Get the current voting power for `msg.sender`"
      },
      "balanceOfAt(address,uint256)": {
        "notice": "Measure voting power of `addr` at block height `_block`"
      },
      "cancel()": {
        "notice": "Cancel the existing lock of `msg.sender` with penalty"
      },
      "checkpoint()": {
        "notice": "Record global data to checkpoint"
      },
      "createLock(uint256,uint256)": {
        "notice": "Deposit `_value` tokens for `msg.sender` and lock for `_duration`"
      },
      "createLockFor(address,uint256,uint256,uint256)": {
        "notice": "Deposit `_value` tokens with `_discount` for `_addr` and lock for `_duration`"
      },
      "depositFor(address,uint256)": {
        "notice": "Deposit `_value` tokens for `_addr` and add to the lock"
      },
      "getCheckpointTime(address,uint256)": {
        "notice": "Get the timestamp for checkpoint `_idx` for `_addr`"
      },
      "getLastUserSlope(address)": {
        "notice": "Get the most recently recorded rate of voting power decrease for `addr`"
      },
      "increaseAmount(uint256)": {
        "notice": "Deposit `_value` additional tokens for `msg.sender`          without modifying the unlock time"
      },
      "increaseAmountFor(address,uint256,uint256)": {
        "notice": "Deposit `_value` additional tokens for `msg.sender`          without modifying the unlock time"
      },
      "increaseUnlockTime(uint256)": {
        "notice": "Extend the unlock time for `msg.sender` to `_duration`"
      },
      "totalSupply(uint256)": {
        "notice": "Calculate total voting power"
      },
      "totalSupplyAt(uint256)": {
        "notice": "Calculate total voting power at some point in the past"
      },
      "unlockTime(address)": {
        "notice": "Get timestamp when `_addr`'s lock finishes"
      },
      "withdraw()": {
        "notice": "Withdraw all tokens for `msg.sender`"
      }
    },
    "notice": "Votes have a weight depending on time, so that users are         committed to the future of (whatever they are voting for)",
    "version": 1
  },
  "storageLayout": {
    "storage": [
      {
        "astId": 7,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "_owner",
        "offset": 0,
        "slot": "0",
        "type": "t_address"
      },
      {
        "astId": 115,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "_status",
        "offset": 0,
        "slot": "1",
        "type": "t_uint256"
      },
      {
        "astId": 3158,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "name",
        "offset": 0,
        "slot": "2",
        "type": "t_string_storage"
      },
      {
        "astId": 3161,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "symbol",
        "offset": 0,
        "slot": "3",
        "type": "t_string_storage"
      },
      {
        "astId": 3167,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "migrator",
        "offset": 0,
        "slot": "4",
        "type": "t_address"
      },
      {
        "astId": 3172,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "isDelegate",
        "offset": 0,
        "slot": "5",
        "type": "t_mapping(t_address,t_bool)"
      },
      {
        "astId": 3175,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "supply",
        "offset": 0,
        "slot": "6",
        "type": "t_uint256"
      },
      {
        "astId": 3180,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "migrated",
        "offset": 0,
        "slot": "7",
        "type": "t_mapping(t_address,t_bool)"
      },
      {
        "astId": 3186,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "delegateAt",
        "offset": 0,
        "slot": "8",
        "type": "t_mapping(t_address,t_array(t_address)dyn_storage)"
      },
      {
        "astId": 3192,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "locked",
        "offset": 0,
        "slot": "9",
        "type": "t_mapping(t_address,t_struct(LockedBalance)3131_storage)"
      },
      {
        "astId": 3195,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "epoch",
        "offset": 0,
        "slot": "10",
        "type": "t_uint256"
      },
      {
        "astId": 3201,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "pointHistory",
        "offset": 0,
        "slot": "11",
        "type": "t_mapping(t_uint256,t_struct(Point)3122_storage)"
      },
      {
        "astId": 3209,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "userPointHistory",
        "offset": 0,
        "slot": "12",
        "type": "t_mapping(t_address,t_mapping(t_uint256,t_struct(Point)3122_storage))"
      },
      {
        "astId": 3214,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "userPointEpoch",
        "offset": 0,
        "slot": "13",
        "type": "t_mapping(t_address,t_uint256)"
      },
      {
        "astId": 3219,
        "contract": "contracts/VotingEscrow.sol:VotingEscrow",
        "label": "slopeChanges",
        "offset": 0,
        "slot": "14",
        "type": "t_mapping(t_uint256,t_int128)"
      }
    ],
    "types": {
      "t_address": {
        "encoding": "inplace",
        "label": "address",
        "numberOfBytes": "20"
      },
      "t_array(t_address)dyn_storage": {
        "base": "t_address",
        "encoding": "dynamic_array",
        "label": "address[]",
        "numberOfBytes": "32"
      },
      "t_bool": {
        "encoding": "inplace",
        "label": "bool",
        "numberOfBytes": "1"
      },
      "t_int128": {
        "encoding": "inplace",
        "label": "int128",
        "numberOfBytes": "16"
      },
      "t_mapping(t_address,t_array(t_address)dyn_storage)": {
        "encoding": "mapping",
        "key": "t_address",
        "label": "mapping(address => address[])",
        "numberOfBytes": "32",
        "value": "t_array(t_address)dyn_storage"
      },
      "t_mapping(t_address,t_bool)": {
        "encoding": "mapping",
        "key": "t_address",
        "label": "mapping(address => bool)",
        "numberOfBytes": "32",
        "value": "t_bool"
      },
      "t_mapping(t_address,t_mapping(t_uint256,t_struct(Point)3122_storage))": {
        "encoding": "mapping",
        "key": "t_address",
        "label": "mapping(address => mapping(uint256 => struct VotingEscrow.Point))",
        "numberOfBytes": "32",
        "value": "t_mapping(t_uint256,t_struct(Point)3122_storage)"
      },
      "t_mapping(t_address,t_struct(LockedBalance)3131_storage)": {
        "encoding": "mapping",
        "key": "t_address",
        "label": "mapping(address => struct VotingEscrow.LockedBalance)",
        "numberOfBytes": "32",
        "value": "t_struct(LockedBalance)3131_storage"
      },
      "t_mapping(t_address,t_uint256)": {
        "encoding": "mapping",
        "key": "t_address",
        "label": "mapping(address => uint256)",
        "numberOfBytes": "32",
        "value": "t_uint256"
      },
      "t_mapping(t_uint256,t_int128)": {
        "encoding": "mapping",
        "key": "t_uint256",
        "label": "mapping(uint256 => int128)",
        "numberOfBytes": "32",
        "value": "t_int128"
      },
      "t_mapping(t_uint256,t_struct(Point)3122_storage)": {
        "encoding": "mapping",
        "key": "t_uint256",
        "label": "mapping(uint256 => struct VotingEscrow.Point)",
        "numberOfBytes": "32",
        "value": "t_struct(Point)3122_storage"
      },
      "t_string_storage": {
        "encoding": "bytes",
        "label": "string",
        "numberOfBytes": "32"
      },
      "t_struct(LockedBalance)3131_storage": {
        "encoding": "inplace",
        "label": "struct VotingEscrow.LockedBalance",
        "members": [
          {
            "astId": 3124,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "amount",
            "offset": 0,
            "slot": "0",
            "type": "t_int128"
          },
          {
            "astId": 3126,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "discount",
            "offset": 16,
            "slot": "0",
            "type": "t_int128"
          },
          {
            "astId": 3128,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "start",
            "offset": 0,
            "slot": "1",
            "type": "t_uint256"
          },
          {
            "astId": 3130,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "end",
            "offset": 0,
            "slot": "2",
            "type": "t_uint256"
          }
        ],
        "numberOfBytes": "96"
      },
      "t_struct(Point)3122_storage": {
        "encoding": "inplace",
        "label": "struct VotingEscrow.Point",
        "members": [
          {
            "astId": 3115,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "bias",
            "offset": 0,
            "slot": "0",
            "type": "t_int128"
          },
          {
            "astId": 3117,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "slope",
            "offset": 16,
            "slot": "0",
            "type": "t_int128"
          },
          {
            "astId": 3119,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "ts",
            "offset": 0,
            "slot": "1",
            "type": "t_uint256"
          },
          {
            "astId": 3121,
            "contract": "contracts/VotingEscrow.sol:VotingEscrow",
            "label": "blk",
            "offset": 0,
            "slot": "2",
            "type": "t_uint256"
          }
        ],
        "numberOfBytes": "96"
      },
      "t_uint256": {
        "encoding": "inplace",
        "label": "uint256",
        "numberOfBytes": "32"
      }
    }
  }
}