Skip to content

Commit

Permalink
Fixed minor issue with spot manager (#219)
Browse files Browse the repository at this point in the history
* fixed spot oracle price bug

* deployed spot-usdc mananger
  • Loading branch information
aalavandhan authored Aug 8, 2024
1 parent 654ffc5 commit 1381036
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 34 deletions.
1 change: 1 addition & 0 deletions spot-vaults/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The official mainnet addresses are:
- Bill Broker (SPOT-USDC): [0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB](https://etherscan.io/address/0xA088Aef966CAD7fE0B38e28c2E07590127Ab4ccB)
- SpotAppraiser: [0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c](https://etherscan.io/address/0x965FBFebDA76d9AA11642C1d0074CdF02e546F3c)
- WethWamplManager: [0x6785fa26191eb531c54fd093931f395c4b01b583](https://etherscan.io/address/0x6785fa26191eb531c54fd093931f395c4b01b583)
- UsdcSpotManager: [0x780eB92040bf24cd9BF993505390e88E8ED59935](https://etherscan.io/address/0x780eB92040bf24cd9BF993505390e88E8ED59935)

The official testnet addresses are:

Expand Down
4 changes: 2 additions & 2 deletions spot-vaults/contracts/UsdcSpotManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ contract UsdcSpotManager {
function getSpotUSDPrice() public view returns (uint256) {
uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(VAULT.getTwap());
uint256 ratioX192 = uint256(sqrtPriceX96) * sqrtPriceX96;
uint256 spotPerUsdc = FullMath.mulDiv(ONE, ratioX192, (1 << 192));
return FullMath.mulDiv(spotPerUsdc, ONE_USDC, ONE_SPOT);
uint256 usdcPerSpot = FullMath.mulDiv(ONE, (1 << 192), ratioX192);
return FullMath.mulDiv(usdcPerSpot, ONE_SPOT, ONE_USDC);
}

/// @notice Checks the vault is overweight SPOT, and looking to sell the extra SPOT for USDC.
Expand Down
37 changes: 37 additions & 0 deletions spot-vaults/tasks/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,40 @@ task("deploy:WethWamplManager")
console.log("Skipping verification");
}
});

task("deploy:UsdcSpotManager")
.addParam(
"vault",
"the address of the usdc-spot charm vault",
undefined,
types.string,
false,
)
.addParam(
"spotAppraiser",
"the address of the spot appraiser",
undefined,
types.string,
false,
)
.addParam("verify", "flag to set false for local deployments", true, types.boolean)
.setAction(async function (args: TaskArguments, hre) {
const deployer = (await hre.ethers.getSigners())[0];
console.log("Signer", await deployer.getAddress());

const { vault, spotAppraiser } = args;

const UsdcSpotManager = await hre.ethers.getContractFactory("UsdcSpotManager");
const manager = await UsdcSpotManager.deploy(vault, spotAppraiser);
console.log("usdcSpotManager", manager.target);

if (args.verify) {
await sleep(30);
await hre.run("verify:contract", {
address: manager.target,
constructorArguments: [vault, spotAppraiser],
});
} else {
console.log("Skipping verification");
}
});
41 changes: 40 additions & 1 deletion spot-vaults/tasks/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ task("info:WethWamplManager")
console.log("dataValid:", r[1]);
console.log("isOverweightWampl:", await manager.isOverweightWampl());
console.log("prevDeviation:", pp(await manager.prevDeviation(), managerDecimals));
console.log("amplDeviation:", pp(deviation, managerDecimals));
console.log("deviation:", pp(deviation, managerDecimals));
console.log(
"activeLiqPerc:",
pp(await manager.computeActiveLiqPerc(deviation), managerDecimals),
Expand All @@ -180,3 +180,42 @@ task("info:WethWamplManager")
console.log("rebalanceActive:", rebalanceActive);
console.log("---------------------------------------------------------------");
});

task("info:UsdcSpotManager")
.addPositionalParam(
"address",
"the address of the usdc-spot mananger contract",
undefined,
types.string,
false,
)
.setAction(async function (args: TaskArguments, hre) {
const { address } = args;

const manager = await hre.ethers.getContractAt("UsdcSpotManager", address);
const managerDecimals = await manager.decimals();
console.log("---------------------------------------------------------------");
console.log("UsdcSpotManager:", manager.target);
console.log("owner:", await manager.owner());
console.log("spotAppraiser:", await manager.spotAppraiser());

console.log("---------------------------------------------------------------");
const spotPrice = await manager.getSpotUSDPrice();
console.log("spotPrice:", pp(spotPrice, managerDecimals));

const r = await manager.computeDeviationFactor.staticCall();
const deviation = r[0];
console.log("dataValid:", r[1]);
console.log("isOverweightSpot:", await manager.isOverweightSpot());
console.log("prevDeviation:", pp(await manager.prevDeviation(), managerDecimals));
console.log("deviation:", pp(deviation, managerDecimals));

let rebalanceActive = true;
try {
await manager.rebalance.staticCall();
} catch (e) {
rebalanceActive = false;
}
console.log("rebalanceActive:", rebalanceActive);
console.log("---------------------------------------------------------------");
});
5 changes: 2 additions & 3 deletions spot-vaults/tasks/tools.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { task, types } from "hardhat/config";
import { TaskArguments } from "hardhat/types";

export async function sleep(sleepSec: number) {
await new Promise(resolve => setTimeout(resolve, sleepSec));
}
export const sleep = seconds =>
new Promise(resolve => setTimeout(resolve, seconds * 1000));

task("accounts", "Prints the list of accounts", async (_taskArgs, hre) => {
const accounts = await hre.ethers.getSigners();
Expand Down
56 changes: 28 additions & 28 deletions spot-vaults/test/UsdcSpotManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("UsdcSpotManager", function () {
await mockVault.mockMethod("fullUpper()", [800000]);
await mockVault.mockMethod("baseLower()", [45000]);
await mockVault.mockMethod("baseUpper()", [55000]);
await mockVault.mockMethod("getTwap()", [71000]);
await mockVault.mockMethod("getTwap()", [67200]);
await mockVault.mockMethod("limitThreshold()", [800000]);

const mockPool = new DMock("IUniswapV3Pool");
Expand Down Expand Up @@ -176,7 +176,7 @@ describe("UsdcSpotManager", function () {
const { manager, mockAppraiser } = await loadFixture(setupContracts);
await mockAppraiser.mockMethod("perpPrice()", [priceFP("1.2"), false]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("1.009614109343384160"));
expect(r[0]).to.eq(percFP("1.0057863765655975"));
expect(r[1]).to.eq(false);
});
});
Expand All @@ -186,47 +186,47 @@ describe("UsdcSpotManager", function () {
const { manager, mockAppraiser } = await loadFixture(setupContracts);
await mockAppraiser.mockMethod("usdPrice()", [priceFP("0.8"), false]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("1.009614109343384160"));
expect(r[0]).to.eq(percFP("1.0057863765655975"));
expect(r[1]).to.eq(false);
});
});

it("should return deviation factor", async function () {
const { manager } = await loadFixture(setupContracts);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("1.009614109343384160"));
expect(r[0]).to.eq(percFP("1.0057863765655975"));
expect(r[1]).to.eq(true);
});

it("should return deviation factor", async function () {
const { manager, mockVault } = await loadFixture(setupContracts);
await mockVault.mockMethod("getTwap()", [72500]);
await mockVault.mockMethod("getTwap()", [65800]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("1.172995447264373845"));
expect(r[0]).to.eq(percFP("1.1569216182711425"));
expect(r[1]).to.eq(true);
});

it("should return deviation factor", async function () {
const { manager, mockVault } = await loadFixture(setupContracts);
await mockVault.mockMethod("getTwap()", [70500]);
await mockVault.mockMethod("getTwap()", [67800]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("0.960377048978079093"));
expect(r[0]).to.eq(percFP("0.947216779268338333"));
expect(r[1]).to.eq(true);
});

it("should return deviation factor", async function () {
const { manager, mockAppraiser } = await loadFixture(setupContracts);
await mockAppraiser.mockMethod("perpPrice()", [priceFP("1.5"), true]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("0.807691287474707328"));
expect(r[0]).to.eq(percFP("0.804629101252478"));
expect(r[1]).to.eq(true);
});

it("should return deviation factor", async function () {
const { manager, mockAppraiser } = await loadFixture(setupContracts);
await mockAppraiser.mockMethod("perpPrice()", [priceFP("1"), true]);
const r = await manager.computeDeviationFactor.staticCall();
expect(r[0]).to.eq(percFP("1.211536931212060992"));
expect(r[0]).to.eq(percFP("1.206943651878717"));
expect(r[1]).to.eq(true);
});

Expand Down Expand Up @@ -267,7 +267,7 @@ describe("UsdcSpotManager", function () {
it("should keep limit range", async function () {
const { manager, mockVault } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [72000]);
await mockVault.mockMethod("getTwap()", [66200]);
await mockVault.mockMethod("limitLower()", [40000]);
await mockVault.mockMethod("limitUpper()", [45000]);

Expand All @@ -279,15 +279,15 @@ describe("UsdcSpotManager", function () {
expect(await manager.prevDeviation()).to.eq("0");
expect(await manager.isOverweightSpot()).to.eq(true);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("1.11579057353024426"));
expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833"));
});
});

describe("when overweight usdc", function () {
it("should remove limit range", async function () {
const { manager, mockVault, mockPool } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [72000]);
await mockVault.mockMethod("getTwap()", [66200]);
await mockVault.mockMethod("limitLower()", [73000]);
await mockVault.mockMethod("limitUpper()", [75000]);
await mockPool.mockCall(
Expand All @@ -309,7 +309,7 @@ describe("UsdcSpotManager", function () {
expect(await manager.prevDeviation()).to.eq("0");
expect(await manager.isOverweightSpot()).to.eq(false);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("1.115790573530244260"));
expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833"));
});
});
});
Expand All @@ -319,7 +319,7 @@ describe("UsdcSpotManager", function () {
it("should remove limit range", async function () {
const { manager, mockVault, mockPool } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [72000]);
await mockVault.mockMethod("getTwap()", [66200]);
await mockVault.mockMethod("limitLower()", [40000]);
await mockVault.mockMethod("limitUpper()", [45000]);
await mockVault.mockMethod("period()", [86400]);
Expand All @@ -328,7 +328,7 @@ describe("UsdcSpotManager", function () {
await mockVault.mockMethod("rebalance()", []);
await manager.rebalance();

await mockVault.mockMethod("getTwap()", [70000]);
await mockVault.mockMethod("getTwap()", [67800]);
await mockVault.mockMethod("limitLower()", [60000]);
await mockVault.mockMethod("limitUpper()", [65000]);
await mockPool.mockCall(
Expand All @@ -343,18 +343,18 @@ describe("UsdcSpotManager", function () {
[],
);

expect(await manager.prevDeviation()).to.eq(percFP("1.115790573530244260"));
expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833"));
expect(await manager.isOverweightSpot()).to.eq(true);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("0.913541191300990579"));
expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333"));
});
});

describe("when overweight usdc", function () {
it("should keep limit range", async function () {
const { manager, mockVault } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [72000]);
await mockVault.mockMethod("getTwap()", [66200]);
await mockVault.mockMethod("limitLower()", [40000]);
await mockVault.mockMethod("limitUpper()", [45000]);
await mockVault.mockMethod("period()", [86400]);
Expand All @@ -363,15 +363,15 @@ describe("UsdcSpotManager", function () {
await mockVault.mockMethod("rebalance()", []);
await manager.rebalance();

await mockVault.mockMethod("getTwap()", [70000]);
await mockVault.mockMethod("getTwap()", [67800]);
await mockVault.mockMethod("limitLower()", [75000]);
await mockVault.mockMethod("limitUpper()", [80000]);
await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)");

expect(await manager.prevDeviation()).to.eq(percFP("1.115790573530244260"));
expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833"));
expect(await manager.isOverweightSpot()).to.eq(false);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("0.913541191300990579"));
expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333"));
});
});
});
Expand All @@ -381,7 +381,7 @@ describe("UsdcSpotManager", function () {
it("should not force rebalance", async function () {
const { manager, mockVault, mockPool } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [70500]);
await mockVault.mockMethod("getTwap()", [67800]);
await mockVault.mockMethod("limitLower()", [40000]);
await mockVault.mockMethod("limitUpper()", [45000]);
await mockVault.mockMethod("rebalance()", []);
Expand All @@ -399,7 +399,7 @@ describe("UsdcSpotManager", function () {
expect(await manager.prevDeviation()).to.eq("0");
expect(await manager.isOverweightSpot()).to.eq(true);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("0.960377048978079093"));
expect(await manager.prevDeviation()).to.eq(percFP("0.947216779268338333"));
});
});
});
Expand All @@ -409,7 +409,7 @@ describe("UsdcSpotManager", function () {
it("should not force rebalance", async function () {
const { manager, mockVault, mockPool } = await loadFixture(setupContracts);

await mockVault.mockMethod("getTwap()", [72000]);
await mockVault.mockMethod("getTwap()", [66200]);
await mockVault.mockMethod("limitLower()", [40000]);
await mockVault.mockMethod("limitUpper()", [45000]);
await mockVault.mockMethod("period()", [86400]);
Expand All @@ -423,7 +423,7 @@ describe("UsdcSpotManager", function () {
await mockVault.clearMockCall("period()", []);
await mockVault.clearMockMethod("emergencyBurn(int24,int24,uint128)");

await mockVault.mockMethod("getTwap()", [71500]);
await mockVault.mockMethod("getTwap()", [66800]);
await mockVault.mockMethod("limitLower()", [75000]);
await mockVault.mockMethod("limitUpper()", [80000]);
await mockPool.mockCall(
Expand All @@ -433,10 +433,10 @@ describe("UsdcSpotManager", function () {
);
await mockVault.mockMethod("emergencyBurn(int24,int24,uint128)", []);

expect(await manager.prevDeviation()).to.eq(percFP("1.115790573530244260"));
expect(await manager.prevDeviation()).to.eq(percFP("1.111560295732100833"));
expect(await manager.isOverweightSpot()).to.eq(false);
await expect(manager.rebalance()).not.to.be.reverted;
expect(await manager.prevDeviation()).to.eq(percFP("1.061375478380992817"));
expect(await manager.prevDeviation()).to.eq(percFP("1.0468312037404625"));
});
});
});
Expand Down

0 comments on commit 1381036

Please sign in to comment.