Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spot-contracts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This repository is a collection of smart contracts that implement the SPOT perpe
The official mainnet addresses are:

- SPOT ERC-20 Token: [0xC1f33e0cf7e40a67375007104B929E49a581bafE](https://etherscan.io/address/0xC1f33e0cf7e40a67375007104B929E49a581bafE)
- Bond issuer: [0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2](https://etherscan.io/address/0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2)
- Bond issuer: [0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66](https://etherscan.io/address/0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66)
- Router: [0x38f600e08540178719BF656e6B43FC15A529c393](https://etherscan.io/address/0x38f600e08540178719BF656e6B43FC15A529c393)

## Install
Expand Down
4 changes: 3 additions & 1 deletion spot-contracts/contracts/BondIssuer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ contract BondIssuer is IBondIssuer, OwnableUpgradeable {
}

// Set to the timestamp of the most recent issue window start
lastIssueWindowTimestamp = block.timestamp - (block.timestamp % minIssueTimeIntervalSec) + issueWindowOffsetSec;
lastIssueWindowTimestamp =
block.timestamp -
((block.timestamp - issueWindowOffsetSec) % minIssueTimeIntervalSec);

IBondController bond = IBondController(
bondFactory.createBond(collateral, trancheRatios, lastIssueWindowTimestamp + maxMaturityDuration)
Expand Down
2 changes: 1 addition & 1 deletion spot-contracts/deployments/mainnet.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"ampl": "0xD46bA6D942050d489DBd938a2C909A5d5039A161",
"bondFactory": "0x72799FFD1F4CCF92eA2b1eE0CADa16a5461c4d96",
"bondIssuer": "0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2",
"bondIssuer": "0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66",
"spot": "0xC1f33e0cf7e40a67375007104B929E49a581bafE",
"proxyAdmin": "0x2978B4103985A6668CE345555b0febdE64Fb092F",
"router": "0x38f600e08540178719BF656e6B43FC15A529c393"
Expand Down
10 changes: 7 additions & 3 deletions spot-contracts/tasks/mainnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ yarn hardhat --network mainnet deploy:BondIssuer \
--tranche-ratios "[200,800]"

yarn hardhat --network mainnet deploy:PerpetualTranche \
--bond-issuer-address "0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2" \
--bond-issuer-address "0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66" \
--collateral-token-address "0xD46bA6D942050d489DBd938a2C909A5d5039A161" \
--name "SPOT" \
--symbol "SPOT" \
Expand All @@ -27,7 +27,7 @@ yarn hardhat --network mainnet deploy:Router

########################################################################
## Transfer ownership
yarn hardhat --network mainnet transferOwnership "0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2" \
yarn hardhat --network mainnet transferOwnership "0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66" \
--new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662"

yarn hardhat --network mainnet transferOwnership "0xFF732cA9EFc95E853FBD71a5c61647cd0C0898a3" \
Expand All @@ -42,6 +42,7 @@ yarn hardhat --network mainnet transferOwnership "0xC1f33e0cf7e40a67375007104B92
yarn hardhat --network mainnet transferOwnership "0x2978B4103985A6668CE345555b0febdE64Fb092F" \
--new-owner-address "0x57981B1EaFe4b18EC97f8B10859B40207b364662"


########################################################################
## OPS
yarn hardhat --network mainnet ops:info 0xC1f33e0cf7e40a67375007104B929E49a581bafE
Expand All @@ -62,6 +63,9 @@ yarn hardhat --network mainnet ops:redeem \
yarn hardhat --network mainnet ops:redeemTranches \
--bond-issuer-address 0x9443b779d4AedF97d2B93D7CDa5fA0BB6312DfF2

yarn hardhat --network mainnet ops:redeemTranches \
--bond-issuer-address 0xD64FA63dc5E8fcB743457E47E4d522E11Ff1AD66

yarn hardhat --network mainnet ops:trancheAndRollover \
--router-address 0x38f600e08540178719BF656e6B43FC15A529c393 \
--perp-address 0xC1f33e0cf7e40a67375007104B929E49a581bafE \
Expand All @@ -70,4 +74,4 @@ yarn hardhat --network mainnet ops:trancheAndRollover \
########################################################################
## upgrade

yarn hardhat --network mainnet prepare_upgrade:perp:mainnet 0xC1f33e0cf7e40a67375007104B929E49a581bafE
yarn hardhat --network mainnet prepare_upgrade:perp:mainnet 0xC1f33e0cf7e40a67375007104B929E49a581bafE
80 changes: 64 additions & 16 deletions spot-contracts/test/BondIssuer.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { expect } from "chai";
import { ethers } from "hardhat";
import { ethers, network } from "hardhat";
import { Contract, Signer } from "ethers";

import { TimeHelpers, setupBondFactory } from "./helpers";

const START_TIME = 2499998400;
const mockTime = (x: number) => START_TIME + x;

let bondFactory: Contract, token: Contract, issuer: Contract, deployer: Signer, otherUser: Signer;
describe("BondIssuer", function () {
beforeEach(async function () {
Expand All @@ -16,15 +19,20 @@ describe("BondIssuer", function () {
await token.init("Test token", "TEST");
const BondIssuer = await ethers.getContractFactory("BondIssuer");
issuer = await BondIssuer.deploy(bondFactory.address, token.address);
await issuer.init(86400, [200, 300, 500], 3600, 120);
await issuer.init(86400, [200, 300, 500], 3600, 900);
await TimeHelpers.setNextBlockTimestamp(mockTime(0));
});

afterEach(async function () {
await network.provider.send("hardhat_reset");
});

describe("#setup", function () {
it("should set storage parameters", async function () {
expect(await issuer.owner()).to.eq(await deployer.getAddress());
expect(await issuer.bondFactory()).to.eq(bondFactory.address);
expect(await issuer.minIssueTimeIntervalSec()).to.eq(3600);
expect(await issuer.issueWindowOffsetSec()).to.eq(120);
expect(await issuer.issueWindowOffsetSec()).to.eq(900);
expect(await issuer.maxMaturityDuration()).to.eq(86400);
expect(await issuer.collateral()).to.eq(token.address);
expect(await issuer.trancheRatios(0)).to.eq(200);
Expand Down Expand Up @@ -94,7 +102,7 @@ describe("BondIssuer", function () {
describe("#issue", function () {
describe("when sufficient time has passed", function () {
it("should issue a new bond", async function () {
await TimeHelpers.setNextBlockTimestamp(2499998400);
await TimeHelpers.setNextBlockTimestamp(mockTime(901));
const tx = await issuer.issue();
const txR = await tx.wait();
const bondIssuedEvent = txR.events[txR.events.length - 1];
Expand All @@ -103,34 +111,74 @@ describe("BondIssuer", function () {
expect(tx).to.emit(issuer, "BondIssued");
expect(await issuer.isInstance(bond)).to.eq(true);
expect(await issuer.callStatic.getLatestBond()).to.eq(bond);
expect(await issuer.lastIssueWindowTimestamp()).to.eq(2499998520);
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));

expect(await issuer.issuedCount()).to.eq(1);
expect(await issuer.issuedBondAt(0)).to.eq(bond);
await expect(issuer.issuedBondAt(1)).to.be.reverted;

await TimeHelpers.setNextBlockTimestamp(2500002120);
await TimeHelpers.setNextBlockTimestamp(mockTime(4495));
await expect(issuer.issue()).not.to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));

await TimeHelpers.setNextBlockTimestamp(mockTime(4501));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(2500002120);
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(4500));

expect(await issuer.issuedCount()).to.eq(2);
await expect(issuer.issuedBondAt(1)).to.not.be.reverted;

await TimeHelpers.setNextBlockTimestamp(mockTime(4505));
await expect(issuer.issue()).not.to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(4500));
});
});

describe("when sufficient time has not passed", function () {
it("should not issue a new bond", async function () {
await TimeHelpers.setNextBlockTimestamp(2500005720);
describe("for various elapsed times lastIssueWindowTimestamp", function () {
beforeEach(async function () {
expect(await issuer.lastIssueWindowTimestamp()).to.eq("0");
});

it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(3500));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.issuedCount()).to.eq(1);
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));
});

await TimeHelpers.setNextBlockTimestamp(2500009310);
await expect(issuer.issue()).not.to.emit(issuer, "BondIssued");
expect(await issuer.issuedCount()).to.eq(1);
it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(3595));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));
});

await TimeHelpers.setNextBlockTimestamp(2500009320);
it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(3600));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.issuedCount()).to.eq(2);
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));
});

it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(4495));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(900));
});

it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(4500));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(4500));
});

it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(4501));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(4500));
});

it("should should snap down", async function () {
await TimeHelpers.setNextBlockTimestamp(mockTime(4600));
await expect(issuer.issue()).to.emit(issuer, "BondIssued");
expect(await issuer.lastIssueWindowTimestamp()).to.eq(mockTime(4500));
});
});
});
Expand Down