UNPKG

@dydxfoundation/governance

Version:
238 lines (237 loc) 14.2 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const units_1 = require("@ethersproject/units"); const bignumber_js_1 = __importDefault(require("bignumber.js")); const ethereum_multicall_1 = require("ethereum-multicall"); const ethers_1 = require("ethers"); const Multicall2_json_1 = __importDefault(require("../../../abi/contracts/dependencies/makerdao/multicall2.sol/Multicall2.json")); const DydxToken_json_1 = __importDefault(require("../../../abi/contracts/governance/token/DydxToken.sol/DydxToken.json")); const LiquidityStakingV1_json_1 = __importDefault(require("../../../abi/contracts/liquidity/v1/LiquidityStakingV1.sol/LiquidityStakingV1.json")); const SafetyModuleV1_json_1 = __importDefault(require("../../../abi/contracts/safety/v1/SafetyModuleV1.sol/SafetyModuleV1.json")); const types_1 = require("../../../types"); const config_1 = require("../config"); const types_2 = require("../types"); const BaseService_1 = __importDefault(require("./BaseService")); class DydxTokenService extends BaseService_1.default { constructor(config, erc20Service, safetyModule, liquidityModule, merkleDistributor, hardhatTokenAddresses, hardhatTreasuryAddresses, hardhatMulticallAddress) { super(config, types_1.DydxToken__factory); this.decimalsOf = () => { return config_1.DYDX_TOKEN_DECIMALS; }; this.totalSupply = async () => { return this.erc20Service.totalSupply(this.tokenAddress); }; this.balanceOf = async (user) => { return this.erc20Service.balanceOf(this.tokenAddress, user); }; this.distributedToday = async () => { var _a, _b, _c, _d; const contractCallContext = [ { reference: 'token', contractAddress: this.tokenAddress, abi: DydxToken_json_1.default, calls: [ { reference: 'transferRestriction', methodName: '_transfersRestrictedBefore', methodParameters: [], }, ], }, { reference: 'safetyModule', contractAddress: this.safetyModule.contract.address, abi: SafetyModuleV1_json_1.default, calls: [ { reference: 'rewardsPerSecond', methodName: 'getRewardsPerSecond', methodParameters: [], }, ], }, { reference: 'liquidityModule', contractAddress: this.liquidityModule.contract.address, abi: LiquidityStakingV1_json_1.default, calls: [ { reference: 'rewardsPerSecond', methodName: 'getRewardsPerSecond', methodParameters: [], }, ], }, { reference: 'multicall', contractAddress: this._multicallData.multicallAddress, abi: Multicall2_json_1.default, calls: [ { reference: 'timeLatest', methodName: 'getCurrentBlockTimestamp', methodParameters: [], }, ], }, ]; const [multiRes, rootUpdatedMetadata,] = await Promise.all([ this._multicallData.multicall.call(contractCallContext), this.merkleDistributor.getRootUpdatedMetadata(), ]); const tokenReturnContext = multiRes.results.token.callsReturnContext; const multicallReturnContext = multiRes.results.multicall.callsReturnContext; const transferRestriction = ethers_1.BigNumber.from((_a = tokenReturnContext.find(c => c.reference === 'transferRestriction')) === null || _a === void 0 ? void 0 : _a.returnValues[0].hex); const currentTimestamp = ethers_1.BigNumber.from((_b = multicallReturnContext.find(c => c.reference === 'timeLatest')) === null || _b === void 0 ? void 0 : _b.returnValues[0].hex); if (currentTimestamp.lt(transferRestriction)) { // Distributed today is 0 during transfer restriction return '0.0'; } const safetyModuleReturnContext = multiRes.results.safetyModule.callsReturnContext; const liquidityModuleReturnContext = multiRes.results.liquidityModule.callsReturnContext; const safetyModuleRewardsPerSecond = (0, units_1.formatEther)(ethers_1.BigNumber.from((_c = safetyModuleReturnContext.find(c => c.reference === 'rewardsPerSecond')) === null || _c === void 0 ? void 0 : _c.returnValues[0].hex)); const liquidityModuleRewardsPerSecond = (0, units_1.formatEther)(ethers_1.BigNumber.from((_d = liquidityModuleReturnContext.find(c => c.reference === 'rewardsPerSecond')) === null || _d === void 0 ? void 0 : _d.returnValues[0].hex)); // the earliest rewards can become liquid is after the transfer restriction period const lastClaimableMerkleRewardsTimestamp = Math.max(transferRestriction.toNumber(), rootUpdatedMetadata.lastRootUpdatedTimestamp); let dailyMerkleDistributorRewards = new bignumber_js_1.default(0); const secondsSinceClaimableMerkleRewards = currentTimestamp.sub(lastClaimableMerkleRewardsTimestamp); if (rootUpdatedMetadata.numRootUpdates > 0 && secondsSinceClaimableMerkleRewards.lte(config_1.ONE_DAY_SECONDS.toNumber())) { dailyMerkleDistributorRewards = new bignumber_js_1.default(config_1.MERKLE_DISTRIBUTOR_REWARDS_PER_EPOCH); if (rootUpdatedMetadata.numRootUpdates === 1) { // The first root update includes retroactive rewards dailyMerkleDistributorRewards = dailyMerkleDistributorRewards.plus(config_1.RETROACTIVE_MINING_REWARDS); } } const dailySafetyRewards = new bignumber_js_1.default(safetyModuleRewardsPerSecond) .multipliedBy(config_1.ONE_DAY_SECONDS.toNumber()); let dailyLiquidityRewards = new bignumber_js_1.default(liquidityModuleRewardsPerSecond) .multipliedBy(config_1.ONE_DAY_SECONDS.toNumber()); const secondsSinceTransferRestrictionEnd = currentTimestamp.sub(transferRestriction); if (secondsSinceTransferRestrictionEnd.lte(config_1.ONE_DAY_SECONDS.toNumber())) { // within one day of transfer restriction end, previous 36 days of liquidity module rewards // become liquid const preTransferRestrictionLiquidityStakingRewards = new bignumber_js_1.default(liquidityModuleRewardsPerSecond) .multipliedBy(config_1.ONE_DAY_SECONDS.toNumber()) .multipliedBy(36); dailyLiquidityRewards = dailyLiquidityRewards.plus(preTransferRestrictionLiquidityStakingRewards); } const distributedToday = dailySafetyRewards .plus(dailyLiquidityRewards) .plus(dailyMerkleDistributorRewards) .toFixed(); return distributedToday; }; this.circulatingSupply = async () => { var _a, _b, _c, _d, _e, _f, _g; const contractCallContext = [ { reference: 'token', contractAddress: this.tokenAddress, abi: DydxToken_json_1.default, calls: [ { reference: 'transferRestriction', methodName: '_transfersRestrictedBefore', methodParameters: [], }, { reference: 'totalSupply', methodName: 'totalSupply', methodParameters: [], }, { reference: 'rewardsTreasuryBalance', methodName: 'balanceOf', methodParameters: [this.treasuryAddresses.REWARDS_TREASURY_ADDRESS], }, { reference: 'rewardsTreasuryVesterBalance', methodName: 'balanceOf', methodParameters: [this.treasuryAddresses.REWARDS_TREASURY_VESTER_ADDRESS], }, { reference: 'communityTreasuryBalance', methodName: 'balanceOf', methodParameters: [this.treasuryAddresses.COMMUNITY_TREASURY_ADDRESS], }, { reference: 'communityTreasuryVesterBalance', methodName: 'balanceOf', methodParameters: [this.treasuryAddresses.COMMUNITY_TREASURY_VESTER_ADDRESS], }, ], }, { reference: 'multicall', contractAddress: this._multicallData.multicallAddress, abi: Multicall2_json_1.default, calls: [ { reference: 'timeLatest', methodName: 'getCurrentBlockTimestamp', methodParameters: [], }, ], }, ]; const multiRes = await this._multicallData.multicall.call(contractCallContext); const tokenReturnContext = multiRes.results.token.callsReturnContext; const multicallReturnContext = multiRes.results.multicall.callsReturnContext; const transferRestriction = ethers_1.BigNumber.from((_a = tokenReturnContext.find(c => c.reference === 'transferRestriction')) === null || _a === void 0 ? void 0 : _a.returnValues[0].hex); const totalSupply = ethers_1.BigNumber.from((_b = tokenReturnContext.find(c => c.reference === 'totalSupply')) === null || _b === void 0 ? void 0 : _b.returnValues[0].hex); const rewardsTreasuryBalance = ethers_1.BigNumber.from((_c = tokenReturnContext.find(c => c.reference === 'rewardsTreasuryBalance')) === null || _c === void 0 ? void 0 : _c.returnValues[0].hex); const rewardsTreasuryVesterBalance = ethers_1.BigNumber.from((_d = tokenReturnContext.find(c => c.reference === 'rewardsTreasuryVesterBalance')) === null || _d === void 0 ? void 0 : _d.returnValues[0].hex); const communityTreasuryBalance = ethers_1.BigNumber.from((_e = tokenReturnContext.find(c => c.reference === 'communityTreasuryBalance')) === null || _e === void 0 ? void 0 : _e.returnValues[0].hex); const communityTreasuryVesterBalance = ethers_1.BigNumber.from((_f = tokenReturnContext.find(c => c.reference === 'communityTreasuryVesterBalance')) === null || _f === void 0 ? void 0 : _f.returnValues[0].hex); const currentTimestamp = ethers_1.BigNumber.from((_g = multicallReturnContext.find(c => c.reference === 'timeLatest')) === null || _g === void 0 ? void 0 : _g.returnValues[0].hex); if (currentTimestamp.lt(transferRestriction)) { // Circulating supply is 0 before transfer restriction end return '0.0'; } // circulatingSupply = total supply - illiquid supply // We consider all tokens owned by the treasuries + treasury vesters to be illiquid // supply since it would require a governance vote + sufficient time for vesting to move the funds. const circulatingSupplyWei = totalSupply .sub((0, units_1.parseEther)(config_1.LOCKED_ALLOCATION)) .sub(rewardsTreasuryBalance) .sub(rewardsTreasuryVesterBalance) .sub(communityTreasuryBalance) .sub(communityTreasuryVesterBalance); return (0, units_1.formatEther)(circulatingSupplyWei); }; this.erc20Service = erc20Service; const { network } = this.config; const isHardhatNetwork = network === types_2.Network.hardhat; if (isHardhatNetwork && (!hardhatTokenAddresses || !hardhatTreasuryAddresses || !hardhatMulticallAddress)) { throw new Error('Must specify token, treasury, and multicall addresses when on hardhat network'); } const tokenAddresses = isHardhatNetwork ? hardhatTokenAddresses : config_1.dydxTokenAddresses[network]; this.tokenAddress = tokenAddresses.TOKEN_ADDRESS; this.treasuryAddresses = isHardhatNetwork ? hardhatTreasuryAddresses : config_1.dydxTreasuryAddresses[network]; this.safetyModule = safetyModule; this.liquidityModule = liquidityModule; this.merkleDistributor = merkleDistributor; const multicallAddress = isHardhatNetwork ? hardhatMulticallAddress : config_1.multicallAddresses[network]; const multicall = new ethereum_multicall_1.Multicall({ multicallCustomContractAddress: multicallAddress.MULTICALL_ADDRESS, ethersProvider: this.config.provider, }); this._multicallData = { multicall, multicallAddress: multicallAddress.MULTICALL_ADDRESS, }; } get contract() { return this.getContractInstance(this.tokenAddress); } } exports.default = DydxTokenService;