From 1917470ad25dd8f1f6a50ee9d4472bd39caa57cb Mon Sep 17 00:00:00 2001 From: ramy Date: Sun, 27 Jun 2021 00:29:36 -0400 Subject: [PATCH 1/2] Added test to for expire call. --- test/contracts/LSP.spec.ts | 66 +++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/test/contracts/LSP.spec.ts b/test/contracts/LSP.spec.ts index df17718..37ce500 100644 --- a/test/contracts/LSP.spec.ts +++ b/test/contracts/LSP.spec.ts @@ -33,6 +33,7 @@ describe("LSP", function () { const collateralPerPair = ethers.utils.parseUnits("1") const tokensToKeep = tokensToCreate.sub(tokensToTransfer) const tokensToRedeem = ethers.utils.parseUnits("1") + const tokensToSettle = ethers.utils.parseUnits("1") beforeAll(async () => { namedAccounts = await getNamedAccounts() @@ -257,7 +258,7 @@ describe("LSP", function () { ) expect(syntheticBalanceDeployer).toEqBN(tokensToKeep) }) - it("Sponsor can redeem remaining tokens", async function () { + it("Sponsor can redeem some tokens", async function () { // Transaction parameters const transactionOptions = { gasPrice: gasprice * 1000000000, // gasprice arg * 1 GWEI @@ -293,4 +294,67 @@ describe("LSP", function () { const expectedCollateralBalance = oldCollateralBalance.add(tokensToRedeem) expect(newCollateralBalance).toEqBN(expectedCollateralBalance) }) + it("Should change state to ExpiredPriceRequested after expire", async function () { + // Check that sponsor still has enough L / S Tokens + const syntheticBalances = await contracts.LSP.getPositionTokens( + namedAccounts.deployer + ) + expect(syntheticBalances[0]).toBeGteBN(tokensToSettle) + expect(syntheticBalances[1]).toBeGteBN(tokensToSettle) + + // Check contract state + const ContractState = { + Open: 0, + ExpiredPriceRequested: 1, + ExpiredPriceReceived: 2, + } + + let contractState: number = await contracts.LSP.contractState() + + expect(contractState).toEqual(ContractState.Open) + + // fast forward 350 seconds + await ethers.provider.send("evm_increaseTime", [350]) + await ethers.provider.send("evm_mine", []) + + // expire the contract + const expireTx = await contracts.LSP.expire() + + await expireTx.wait() + contractState = await contracts.LSP.contractState() + + expect(contractState).toEqual(ContractState.ExpiredPriceRequested) + }) + + it("Should change the contract state after calling expire", async function () { + // Check that sponsor still has enough L / S Tokens + const syntheticBalances = await contracts.LSP.getPositionTokens( + namedAccounts.deployer + ) + expect(syntheticBalances[0]).toBeGteBN(tokensToSettle) + expect(syntheticBalances[1]).toBeGteBN(tokensToSettle) + + // Check contract state + const ContractState = { + Open: 0, + ExpiredPriceRequested: 1, + ExpiredPriceReceived: 2, + } + + let contractState: number = await contracts.LSP.contractState() + + expect(contractState).toEqual(ContractState.Open) + + // fast forward 350 seconds + await ethers.provider.send("evm_increaseTime", [350]) + await ethers.provider.send("evm_mine", []) + + // expire the contract + const expireTx = await contracts.LSP.expire() + + await expireTx.wait() + contractState = await contracts.LSP.contractState() + + expect(contractState).toEqual(ContractState.ExpiredPriceRequested) + }) }) From a0bf55546b853f470a2ab1c120d49c6ec397935a Mon Sep 17 00:00:00 2001 From: ramy Date: Sun, 27 Jun 2021 01:40:41 -0400 Subject: [PATCH 2/2] Added stronger types to help with auto complete. Added information about OptimisticOracle. --- abis/OptomisticOracle.json | 28 ++++++++++++++++++++++++++++ hardhat.config.ts | 25 ++++++++++++++----------- test/contracts/LSP.spec.ts | 29 ++++++++++++++++++++--------- 3 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 abis/OptomisticOracle.json diff --git a/abis/OptomisticOracle.json b/abis/OptomisticOracle.json new file mode 100644 index 0000000..82250b4 --- /dev/null +++ b/abis/OptomisticOracle.json @@ -0,0 +1,28 @@ +[ + "constructor(uint256 _liveness, address _finderAddress, address _timerAddress)", + "event DisputePrice(address indexed requester, address indexed proposer, address indexed disputer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice)", + "event ProposePrice(address indexed requester, address indexed proposer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice, uint256 expirationTimestamp, address currency)", + "event RequestPrice(address indexed requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData, address currency, uint256 reward, uint256 finalFee)", + "event Settle(address indexed requester, address indexed proposer, address indexed disputer, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 price, uint256 payout)", + "function ancillaryBytesLimit() view returns (uint256)", + "function defaultLiveness() view returns (uint256)", + "function disputePrice(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) returns (uint256 totalBond)", + "function disputePriceFor(address disputer, address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) returns (uint256 totalBond)", + "function finder() view returns (address)", + "function getCurrentTime() view returns (uint256)", + "function getRequest(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) view returns (tuple(address proposer, address disputer, address currency, bool settled, bool refundOnDispute, int256 proposedPrice, int256 resolvedPrice, uint256 expirationTime, uint256 reward, uint256 finalFee, uint256 bond, uint256 customLiveness))", + "function getState(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) view returns (uint8)", + "function hasPrice(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) view returns (bool)", + "function proposePrice(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice) returns (uint256 totalBond)", + "function proposePriceFor(address proposer, address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData, int256 proposedPrice) returns (uint256 totalBond)", + "function requestPrice(bytes32 identifier, uint256 timestamp, bytes ancillaryData, address currency, uint256 reward) returns (uint256 totalBond)", + "function requests(bytes32) view returns (address proposer, address disputer, address currency, bool settled, bool refundOnDispute, int256 proposedPrice, int256 resolvedPrice, uint256 expirationTime, uint256 reward, uint256 finalFee, uint256 bond, uint256 customLiveness)", + "function setBond(bytes32 identifier, uint256 timestamp, bytes ancillaryData, uint256 bond) returns (uint256 totalBond)", + "function setCurrentTime(uint256 time)", + "function setCustomLiveness(bytes32 identifier, uint256 timestamp, bytes ancillaryData, uint256 customLiveness)", + "function setRefundOnDispute(bytes32 identifier, uint256 timestamp, bytes ancillaryData)", + "function settle(address requester, bytes32 identifier, uint256 timestamp, bytes ancillaryData) returns (uint256 payout)", + "function settleAndGetPrice(bytes32 identifier, uint256 timestamp, bytes ancillaryData) returns (int256)", + "function stampAncillaryData(bytes ancillaryData, address requester) pure returns (bytes)", + "function timerAddress() view returns (address)" +] \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index 5ca1d4c..6db669e 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -58,9 +58,10 @@ task( "convert", "Convert all json abis to human readable format", async (_, { ethers }) => { - const path = "~/abis/" + const path = "./abis/" const files = await readdir(path) for (const file of files) { + if (file === "index.ts") continue const jsonBuffer = await readFile(path.concat(file)) const jsonAbi = JSON.parse(jsonBuffer.toString()) const iface = new ethers.utils.Interface(jsonAbi) @@ -220,11 +221,12 @@ task("launch", "Launch all configured LSP contracts") // Get Collateral Contract instance if not present already if (!(contractConfiguration.collateralToken in contracts)) { - contracts[contractConfiguration.collateralToken] = - await ethers.getContractAt( - abis[contractConfiguration.collateralToken], - collateralTokenAddress - ) + contracts[ + contractConfiguration.collateralToken + ] = await ethers.getContractAt( + abis[contractConfiguration.collateralToken], + collateralTokenAddress + ) } // Create and Approve collateral for the proposer reward @@ -289,11 +291,12 @@ task("launch", "Launch all configured LSP contracts") // Configure Financial ProductLibrary // Get Financial Product Library instance if not present already if (!(contractConfiguration.financialProductLibrary in contracts)) { - contracts[contractConfiguration.financialProductLibrary] = - await ethers.getContractAt( - abis[contractConfiguration.financialProductLibrary], - financialProductLibraryAddress - ) + contracts[ + contractConfiguration.financialProductLibrary + ] = await ethers.getContractAt( + abis[contractConfiguration.financialProductLibrary], + financialProductLibraryAddress + ) } // Set Parameters diff --git a/test/contracts/LSP.spec.ts b/test/contracts/LSP.spec.ts index 37ce500..879f0ea 100644 --- a/test/contracts/LSP.spec.ts +++ b/test/contracts/LSP.spec.ts @@ -2,7 +2,7 @@ * @jest-environment node */ -import { ethers, getNamedAccounts } from "hardhat" +import { config, ethers, getNamedAccounts } from "hardhat" import { waffleJest } from "@ethereum-waffle/jest" import { Address } from "hardhat-deploy/dist/types" import { BigNumber, Contract } from "ethers" @@ -10,20 +10,25 @@ import WETHAbi from "~/abis/WETH.json" import LSPABI from "~/abis/LSP.json" import LSPCreatorABI from "~/abis/LSPCreator.json" import ERC20ABI from "~/abis/ERC20.json" +import OptimisticOracle from "~/abis/OptomisticOracle.json" import LinearLongShortPairABI from "~/abis/LinearLongShortPairFinancialProductLibrary.json" jest.setTimeout(40000) expect.extend(waffleJest) describe("LSP", function () { - const addresses: Record = { + const addresses = { WETH: "0xd0a1e359811322d97991e03f863a0c30c2cf029c", LSPCreator: "0x4C68829DBD07FEbB250B90f5624d4a5C30BBeC2c", LinearLongShortPairFinancialProductLibrary: "0x46b541E0fE2E817340A1A88740607329fF5ED279", + OptimisticOracle: "0xB1d3A89333BBC3F5e98A991d6d4C1910802986BC", + LSP: "", + longToken: "", + shortToken: "", } - const contracts: Record = {} - let namedAccounts: Record + let contracts: Record + let namedAccounts: Record const gasprice = 50 const prepaidProposerReward = ethers.utils.parseUnits("0.01") @@ -86,7 +91,7 @@ describe("LSP", function () { const approvePromise = new Promise((resolve) => { contracts.WETH.once( - contracts.WETH.filters.Approval(null, addresses.EMP), + contracts.WETH.filters.Approval(null, addresses.LSP), (_1, _2, allowance) => { expect(allowance).toEqBN(prepaidProposerReward) resolve() @@ -335,10 +340,10 @@ describe("LSP", function () { expect(syntheticBalances[1]).toBeGteBN(tokensToSettle) // Check contract state - const ContractState = { - Open: 0, - ExpiredPriceRequested: 1, - ExpiredPriceReceived: 2, + enum ContractState { + Open, + ExpiredPriceRequested, + ExpiredPriceReceived, } let contractState: number = await contracts.LSP.contractState() @@ -357,4 +362,10 @@ describe("LSP", function () { expect(contractState).toEqual(ContractState.ExpiredPriceRequested) }) + it("Should settle tokens after receiving expired price. ", async () => { + contracts.OptimisticOracle = await ethers.getContractAt( + OptimisticOracle, + addresses.OptimisticOracle + ) + }) })