@dydxfoundation/governance
Version:
dYdX governance smart contracts
254 lines (253 loc) • 11.1 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("ethers/lib/utils");
const types_1 = require("../../../types");
const config_1 = require("../config");
const types_2 = require("../types");
const parsings_1 = require("../utils/parsings");
const methodValidators_1 = require("../validators/methodValidators");
const paramValidators_1 = require("../validators/paramValidators");
const BaseService_1 = __importDefault(require("./BaseService"));
class LiquidityModule extends BaseService_1.default {
constructor(config, erc20Service, hardhatLiquidityModuleAddresses) {
super(config, types_1.LiquidityStakingV1__factory);
this.erc20Service = erc20Service;
this._stakedToken = null;
this._rewardToken = null;
// Get the staking contract address.
const { network } = this.config;
const isHardhatNetwork = network === types_2.Network.hardhat;
if (isHardhatNetwork && !hardhatLiquidityModuleAddresses) {
throw new Error('Must specify staking addresses when on hardhat network');
}
const networkStakingAddresses = isHardhatNetwork
? hardhatLiquidityModuleAddresses
: config_1.liquidityModuleAddresses[network];
this.liquidityModuleAddress = networkStakingAddresses.LIQUIDITY_MODULE_ADDRESS;
}
get contract() {
return this.getContractInstance(this.liquidityModuleAddress);
}
async getStakedToken() {
if (!this._stakedToken) {
this._stakedToken = await this.contract.STAKED_TOKEN();
}
return this._stakedToken;
}
async getRewardToken() {
if (!this._rewardToken) {
this._rewardToken = await this.contract.REWARDS_TOKEN();
}
return this._rewardToken;
}
async stake(user, amount, onBehalfOf, gasLimit) {
const txs = [];
const { approve } = this.erc20Service;
const stakedToken = await this.getStakedToken();
const stakedTokenDecimals = config_1.USDC_TOKEN_DECIMALS;
const convertedAmount = (0, parsings_1.parseNumberToString)(amount, stakedTokenDecimals);
const allowance = (0, parsings_1.parseNumberToEthersBigNumber)(await this.allowance(user), stakedTokenDecimals);
if (allowance.lt(convertedAmount)) {
// user has an approval value for spender of less than `convertedAmount`
const approveTx = approve(stakedToken, user, this.liquidityModuleAddress, config_1.DEFAULT_APPROVE_AMOUNT);
txs.push(approveTx);
}
let txCallback;
if (onBehalfOf) {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.stakeFor(onBehalfOf, convertedAmount),
from: user,
gasLimit,
});
}
else {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.stake(convertedAmount),
from: user,
gasLimit,
});
}
txs.push({
tx: txCallback,
txType: types_2.eEthereumTxType.LIQUIDITY_MODULE_ACTION,
gas: this.generateTxPriceEstimation(txs, txCallback),
});
return txs;
}
async withdrawStake(user, amount, recipient) {
let convertedAmount;
if (amount === '-1') {
convertedAmount = config_1.MAX_UINT_AMOUNT;
}
else {
convertedAmount = (0, parsings_1.parseNumberToString)(amount, config_1.USDC_TOKEN_DECIMALS);
}
let txCallback;
if (convertedAmount === config_1.MAX_UINT_AMOUNT) {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.withdrawMaxStake(recipient || user),
from: user,
gasSurplus: 20,
});
}
else {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.withdrawStake(recipient || user, convertedAmount),
from: user,
gasSurplus: 20,
});
}
return [
{
tx: txCallback,
txType: types_2.eEthereumTxType.LIQUIDITY_MODULE_ACTION,
gas: this.generateTxPriceEstimation([], txCallback),
},
];
}
async withdrawDebt(user, amount, recipient) {
let convertedAmount;
if (amount === '-1') {
convertedAmount = config_1.MAX_UINT_AMOUNT;
}
else {
convertedAmount = (0, parsings_1.parseNumberToString)(amount, config_1.USDC_TOKEN_DECIMALS);
}
let txCallback;
if (convertedAmount === config_1.MAX_UINT_AMOUNT) {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.withdrawMaxDebt(recipient || user),
from: user,
gasSurplus: 20,
});
}
else {
txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.withdrawDebt(recipient || user, convertedAmount),
from: user,
gasSurplus: 20,
});
}
return [
{
tx: txCallback,
txType: types_2.eEthereumTxType.LIQUIDITY_MODULE_ACTION,
gas: this.generateTxPriceEstimation([], txCallback),
},
];
}
async requestWithdrawal(user, amount) {
const convertedAmount = (0, parsings_1.parseNumberToString)(amount, config_1.USDC_TOKEN_DECIMALS);
const txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.requestWithdrawal(convertedAmount),
from: user,
gasSurplus: 20,
});
return [
{
tx: txCallback,
txType: types_2.eEthereumTxType.LIQUIDITY_MODULE_ACTION,
gas: this.generateTxPriceEstimation([], txCallback),
},
];
}
async claimRewards(user, recipient) {
const txCallback = this.generateTxCallback({
rawTxMethod: () => this.contract.populateTransaction.claimRewards(recipient || user),
from: user,
gasSurplus: 20,
});
return [
{
tx: txCallback,
txType: types_2.eEthereumTxType.LIQUIDITY_MODULE_ACTION,
gas: this.generateTxPriceEstimation([], txCallback),
},
];
}
async getTotalStake() {
const currentActiveBalance = await this.contract.getTotalActiveBalanceCurrentEpoch();
return (0, utils_1.formatUnits)(currentActiveBalance, config_1.USDC_TOKEN_DECIMALS);
}
async getRewardsPerSecond() {
const rewardsPerSecond = await this.contract.getRewardsPerSecond();
return (0, utils_1.formatUnits)(rewardsPerSecond, config_1.DYDX_TOKEN_DECIMALS);
}
async allowance(user) {
return this.erc20Service.allowance(await this.getStakedToken(), user, this.liquidityModuleAddress);
}
async getUserStake(user) {
return this.erc20Service.balanceOf(this.liquidityModuleAddress, user);
}
async getUserBalanceOfStakedToken(user) {
const stakedTokenAddress = await this.getStakedToken();
return this.erc20Service.balanceOf(stakedTokenAddress, user);
}
async getUserStakeAvailableToWithdraw(user) {
const userStakeAvailableToWithdraw = await this.contract.getStakeAvailableToWithdraw(user);
return (0, utils_1.formatUnits)(userStakeAvailableToWithdraw, config_1.USDC_TOKEN_DECIMALS);
}
async getUserStakePendingWithdraw(user) {
const [currentEpochInactive, nextEpochInactive,] = await Promise.all([
this.contract.getInactiveBalanceCurrentEpoch(user),
this.contract.getInactiveBalanceNextEpoch(user),
]);
const userStakePendingWithdrawal = nextEpochInactive.sub(currentEpochInactive);
return (0, utils_1.formatUnits)(userStakePendingWithdrawal, config_1.USDC_TOKEN_DECIMALS);
}
async getUserUnclaimedRewards(user) {
const userUnclaimedRewards = await this.contract.callStatic.claimRewards(user, { from: user });
return (0, utils_1.formatUnits)(userUnclaimedRewards, config_1.DYDX_TOKEN_DECIMALS);
}
async getTimeRemainingInCurrentEpoch() {
return this.contract.getTimeRemainingInCurrentEpoch();
}
async getLengthOfBlackoutWindow() {
return this.contract.getBlackoutWindow();
}
}
__decorate([
methodValidators_1.StakingValidator,
__param(0, (0, paramValidators_1.IsEthAddress)()),
__param(1, (0, paramValidators_1.IsPositiveAmount)()),
__param(2, paramValidators_1.Optional),
__param(2, (0, paramValidators_1.IsEthAddress)())
], LiquidityModule.prototype, "stake", null);
__decorate([
methodValidators_1.StakingValidator,
__param(0, (0, paramValidators_1.IsEthAddress)()),
__param(1, (0, paramValidators_1.IsPositiveOrMinusOneAmount)()),
__param(2, paramValidators_1.Optional),
__param(2, (0, paramValidators_1.IsEthAddress)())
], LiquidityModule.prototype, "withdrawStake", null);
__decorate([
methodValidators_1.StakingValidator,
__param(0, (0, paramValidators_1.IsEthAddress)()),
__param(1, (0, paramValidators_1.IsPositiveOrMinusOneAmount)()),
__param(2, paramValidators_1.Optional),
__param(2, (0, paramValidators_1.IsEthAddress)())
], LiquidityModule.prototype, "withdrawDebt", null);
__decorate([
methodValidators_1.StakingValidator,
__param(0, (0, paramValidators_1.IsEthAddress)()),
__param(1, (0, paramValidators_1.IsPositiveAmount)())
], LiquidityModule.prototype, "requestWithdrawal", null);
__decorate([
methodValidators_1.StakingValidator,
__param(0, (0, paramValidators_1.IsEthAddress)()),
__param(1, paramValidators_1.Optional),
__param(1, (0, paramValidators_1.IsEthAddress)())
], LiquidityModule.prototype, "claimRewards", null);
exports.default = LiquidityModule;