Skip to content

Commit

Permalink
Adds script for calculating rebalance params (#23)
Browse files Browse the repository at this point in the history
* script for calculating rebalance params

* pretty

* add tests

---------

Co-authored-by: Pranav Bhardwaj <[email protected]>
  • Loading branch information
edkim and pblivin0x authored Jan 9, 2024
1 parent 552ec95 commit f55e206
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 23 deletions.
2 changes: 2 additions & 0 deletions .env.default
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
MAINNET_RPC_URL=
RATED_API_URL=
RATED_API_ACCESS_TOKEN=
MOCK_RATED_API=
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"author": "IndexCoop",
"license": "MIT",
"scripts": {
"calculate-target-units": "hardhat run --network mainnet scripts/calculateTargetUnits.ts"
"calculate-target-units": "hardhat run --network mainnet scripts/calculateTargetUnits.ts",
"calculate-rebalance-params": "hardhat run --network mainnet scripts/calculateRebalanceParams.ts"
},
"devDependencies": {
"@nomicfoundation/hardhat-network-helpers": "^1.0.9",
Expand Down
38 changes: 38 additions & 0 deletions scripts/calculateRebalanceParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { AuctionRebalanceProposer } from "../src/auctionRebalanceProposer";
import { eligibleSetTokens } from "../src/addresses";
import { DEFAULT_AUCTION_CONFIG } from "../src/auctionConfig";
import { getEnvVars } from "../src/utils";
import { setupMockRatedApi, getDefaultSigner } from "./utils";

async function main() {
let mockedRatedApi = process.env.MOCK_RATED_API == "true";
if (mockedRatedApi) {
setupMockRatedApi();
}

const proposerSigner = await getDefaultSigner();
const { ratedAccessToken, ratedApiUrl } = getEnvVars();

console.log("Rated API URL: ", mockedRatedApi ? "LOCAL MOCK" : ratedApiUrl);

const dsEthProposer = new AuctionRebalanceProposer(
eligibleSetTokens.dsEth,
ratedAccessToken,
ratedApiUrl,
DEFAULT_AUCTION_CONFIG,
proposerSigner,
);

console.log("Calculating target units for dsEth");
let targetUnits = await dsEthProposer.getTargetUnits();

console.log("Getting rebalance proposal params for dsEth");
const params = await dsEthProposer.getProposeRebalanceParams(targetUnits);

console.log("Propose rebalance params: ", params);
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
19 changes: 5 additions & 14 deletions scripts/calculateTargetUnits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,19 @@ import { eligibleSetTokens } from "../src/addresses";
import { DEFAULT_AUCTION_CONFIG } from "../src/auctionConfig";
import { getEnvVars } from "../src/utils";
import { displayTargetUnits } from "./utils";
import { setupMockRatedApi, getDefaultSigner } from "./utils";

async function main() {
let mockedRatedApi = process.env.MOCK_RATED_API == "true";
if (mockedRatedApi) {
const mockRatedApi = new MockRatedApi(1, 1);
mockRatedApi.mockSummaryEndpoint();
mockRatedApi.mockOperatorsEndpoint();
setupMockRatedApi();
}

console.log("Calculating target units for dsEth");

let proposerSigner = await ethers
.getSigners()
.then((signers) => signers[0]);
const proposerSigner = await getDefaultSigner();
const { ratedAccessToken, ratedApiUrl } = getEnvVars();

console.log("Calculating target units for dsEth");
console.log("Rated API URL: ", mockedRatedApi ? "LOCAL MOCK" : ratedApiUrl);
let block = await ethers.getDefaultProvider().getBlock("latest");
console.log("Current block: ", {
number: block.number,
timestamp: block.timestamp,
hash: block.hash,
});

const dsEthProposer = new AuctionRebalanceProposer(
eligibleSetTokens.dsEth,
Expand Down
26 changes: 25 additions & 1 deletion scripts/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { BigNumber, utils } from "ethers";
import { BigNumber, providers, utils } from "ethers";
import { ethers } from "hardhat";
import { MockRatedApi } from "../test/testUtils";
import { AuctionRebalanceProposer } from "../src/auctionRebalanceProposer";
import { eligibleSetTokens } from "../src/addresses";

export function displayTargetUnits(targetUnits: BigNumber[]) {
console.log("Target Units:");
Expand All @@ -9,3 +13,23 @@ export function displayTargetUnits(targetUnits: BigNumber[]) {
console.log("Swell: " + utils.formatEther(targetUnits[4]));
console.log("Stader: " + utils.formatEther(targetUnits[5]));
}

export function setupMockRatedApi() {
const mockRatedApi = new MockRatedApi(1, 1);
mockRatedApi.mockSummaryEndpoint();
mockRatedApi.mockOperatorsEndpoint();
return mockRatedApi;
}

export async function getDefaultSigner() {
let defaultSigner = await ethers.getSigners().then((signers) => signers[0]);
let provider = defaultSigner.provider as providers.JsonRpcProvider;
let block = await provider.getBlock("latest");
console.log("Current block: ", {
number: block.number,
timestamp: block.timestamp,
hash: block.hash,
});

return defaultSigner;
}
8 changes: 4 additions & 4 deletions src/auctionConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const DEFAULT_AUCTION_CONFIG: AuctionConfig = {
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterAddress: "0x237F7BBe0b358415bE84AB6d279D4338C0d026bB",
quoteAsset: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", // WETH
bucketSize: 300, // 5 minutes
slopeForSellComponents: 0.001, // decrease by 0.1% of market price each bucket
slopeForBuyComponents: 0.0005, // increase by 0.05% of market price each bucket
bucketSize: 600, // 10 minutes
slopeForSellComponents: 0.001, // decrease by 0.001 WETH each bucket
slopeForBuyComponents: 0.0005, // increase by 0.0005 WETH each bucket
shouldLockSetToken: false,
rebalanceDuration: 60 * 60 * 24, // 24 hours
rebalanceDuration: 259200, // 3 days
initialPricePctSellComponents: 1.02, // 2% above market price
initialPricePctBuyComponents: 0.98, // 2% below market price
maxPriceAsPercentOfMarketPrice: 1.02,
Expand Down
6 changes: 3 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { BigNum, ethers } from "ethers";
import { BigNumber, ethers } from "ethers";

export function parseEther(ether: string): BigNum {
export function parseEther(ether: string): BigNumber {
return ethers.utils.parseEther(ether);
}

Expand All @@ -14,7 +14,7 @@ export function parseEther(ether: string): BigNum {
export const toWei = (
valueToConvert: number | string,
power: number = 18,
): BigNum => {
): BigNumber => {
// parseUnits only accepts strings
let value =
typeof valueToConvert === "number"
Expand Down
92 changes: 92 additions & 0 deletions test/proposeRebalance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,5 +228,97 @@ describe("Calculate dsETH auction rebalance params", function () {
expect(targetUnits).to.deep.equal(expectedTargetUnits);
});
});

context("#getProposeRebalanceParams", function () {
const expectedQuoteAsset =
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";

const expectedOldComponents = [
"0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0",
"0xae78736Cd615f374D3085123A210448E74Fc6393",
"0xac3E018457B222d93114458476f3E3416Abbe38F",
"0xf1C9acDc66974dFB6dEcB12aA385b9cD01190E38",
];

const expectedNewComponents = [
"0xf951E335afb289353dc249e82926178EaC7DEd78",
"0xA35b1B31Ce002FBF2058D22F30f95D405200A15b",
];

const expectedOldComponentsAuctionParams = [
{
targetUnit: utils.parseEther("0.183524947187164250"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000e2337a27533a7627f4566878f0000000000000000000000000000000000000000038c5a42e02d16ef8f60ba5c40000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000e2337a27533a7627f4566878f000000000000000000000000000000000000000d954988022c9bcd10de49692500000",
},
{
targetUnit: utils.parseEther("0.137182714490521918"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000d70f6c5da473e6993f13aba414000000000000000000000000000000000000000035f9d4ec55726c12622711fb0000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000d70f6c5da473e6993f13aba41400000000000000000000000000000000000000cea06318b71a05b65fbd90d4dc0000",
},
{
targetUnit: utils.parseEther("0.149549408574172648"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000c546b930ea509d96eda0c452f400000000000000000000000000000000000000003183317db84c73d994fd2e430000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000c546b930ea509d96eda0c452f400000000000000000000000000000000000000bd8a39754584ab7cee5935187c0000",
},
{
targetUnit: utils.parseEther("0.140236634011607713"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000d2607c993077218982d9cbdf5c000000000000000000000000000000000000000034ccec125e7c44a707be31290000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000d2607c993077218982d9cbdf5c00000000000000000000000000000000000000ca2077b651b3b6cf69a41430f40000",
},
];

const expectedNewComponentsAuctionParams = [
{
targetUnit: utils.parseEther("0.143389172227472443"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000c5aed1cff46c3417ec9f3f46da000000000000000000000000000000000000000019d1decccb49b11f56490b664000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cdc0676ff3f33b71b79612d6ce00000000000000000000000000000000000000c5aed1cff46c3417ec9f3f46da0000",
},
{
targetUnit: utils.parseEther("0.223325247302630300"),
priceAdapterName: "BoundedStepwiseLinearPriceAdapter",
priceAdapterConfigData:
"0x0000000000000000000000000000000000c0261076565acf87e2aa029c1800000000000000000000000000000000000000001918d3213835a82ad36ad7970000000000000000000000000000000000000000000000000000000000000000025800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c7fdd270b7eb941544bb65fb4800000000000000000000000000000000000000c0261076565acf87e2aa029c180000",
},
];

it("Should return the correct values", async function () {
const targetUnits = await dsEthProposer.getTargetUnits();

const proposeRebalanceParams =
await dsEthProposer.getProposeRebalanceParams(targetUnits);

expect(proposeRebalanceParams.quoteAsset).to.equal(
expectedQuoteAsset,
);
expect(proposeRebalanceParams.oldComponents).to.deep.equal(
expectedOldComponents,
);
expect(proposeRebalanceParams.newComponents).to.deep.equal(
expectedNewComponents,
);

expect(
proposeRebalanceParams.oldComponentsAuctionParams,
).to.deep.equal(expectedOldComponentsAuctionParams);

expect(
proposeRebalanceParams.newComponentsAuctionParams,
).to.deep.equal(expectedNewComponentsAuctionParams);

expect(proposeRebalanceParams.shouldLockSetToken).to.be.false;
expect(proposeRebalanceParams.rebalanceDuration).to.equal(
259200,
);
expect(proposeRebalanceParams.positionMultiplier).to.deep.equal(
utils.parseEther("0.997957208803707410"),
);
});
});
});
});

0 comments on commit f55e206

Please sign in to comment.