import { expect } from 'chai' ; import { ERC20MintableInstance , oTokenInstance , OptionsFactoryInstance } from '../build/types/truffle-types' ; const oToken = artifacts . require ( 'oToken' ) ; const OptionsFactory = artifacts . require ( 'OptionsFactory' ) ; const MockCompoundOracle = artifacts . require ( 'MockCompoundOracle' ) ; const MintableToken = artifacts . require ( 'ERC20Mintable' ) ; const truffleAssert = require ( 'truffle-assertions' ) ; const { BN , time , expectEvent , expectRevert , balance } = require ( '@openzeppelin/test-helpers' ) ; contract ( 'OptionsContract' , accounts => { const creatorAddress = accounts [ 0 ] ; const firstOwnerAddress = accounts [ 1 ] ; const secondOwnerAddress = accounts [ 2 ] ; const thirdOwnerAddress = accounts [ 3 ] ; const nonOwnerAddress = accounts [ 4 ] ; let optionsContracts ; let optionsFactory ; let dai ; before ( 'set up contracts' , async ( ) => { await MockCompoundOracle . deployed ( ) ; dai = await MintableToken . new ( ) ; optionsFactory = await OptionsFactory . deployed ( ) ; await optionsFactory . addAsset ( 'DAI' , dai . address ) ; await optionsFactory . addAsset ( 'USDC' , '0xB5D0545dF2649359B1F91679f64812dc70Bfd547' ) ; const optionsContractResult = await optionsFactory . createOptionsContract ( 'ETH' , - '18' , 'DAI' , - '18' , - '14' , '9' , - '15' , 'USDC' , '1589932800' , '1589932800' , { from : creatorAddress , gas : '4000000' } ) ; const optionsContractAddr = optionsContractResult . logs [ 1 ] . args [ 0 ] ; optionsContracts = await oToken . at ( optionsContractAddr ) ; await optionsContracts . openVault ( { from : creatorAddress , gas : '100000' } ) ; await optionsContracts . openVault ( { from : firstOwnerAddress , gas : '100000' } ) ; let vaultNum = '0' ; let msgValue = '20000000' ; await optionsContracts . addETHCollateral ( creatorAddress , { from : creatorAddress , gas : '100000' , value : msgValue } ) ; vaultNum = '1' ; msgValue = '10000000' ; await optionsContracts . addETHCollateral ( firstOwnerAddress , { from : firstOwnerAddress , gas : '100000' , value : msgValue } ) ; vaultNum = '0' ; let numTokens = '25000' ; optionsContracts . issueOTokens ( numTokens , creatorAddress , { from : creatorAddress , gas : '100000' } ) ; vaultNum = '1' ; numTokens = '10000' ; optionsContracts . issueOTokens ( numTokens , firstOwnerAddress , { from : firstOwnerAddress , gas : '100000' } ) ; const collateral = '15000000' ; const numOptions = ( await optionsContracts . maxOTokensIssuable ( collateral ) ) . toString ( ) ; await optionsContracts . createETHCollateralOption ( numOptions , thirdOwnerAddress , { from : thirdOwnerAddress , value : collateral } ) ; } ) ; describe ( '#exercise() during expiry window' , ( ) => { let initialETH ; let finalETH ; let gasUsed ; let gasPrice ; let txInfo ; it ( 'should be able to call exercise' , async ( ) => { const amtToExercise = '10' ; await optionsContracts . transfer ( secondOwnerAddress , amtToExercise , { from : creatorAddress , gas : '100000' } ) ; const amtPTokens = await optionsContracts . balanceOf ( secondOwnerAddress ) ; expect ( amtPTokens . toString ( ) ) . to . equal ( amtToExercise ) ; const ownerDaiBal = await dai . balanceOf ( secondOwnerAddress ) ; expect ( ownerDaiBal . toString ( ) ) . to . equal ( '0' ) ; await dai . mint ( secondOwnerAddress , '100000' , { from : creatorAddress } ) ; await dai . approve ( optionsContracts . address , '10000000000000000000000' , { from : secondOwnerAddress } ) ; const totalSupplyBefore = new BN ( ( await optionsContracts . totalSupply ( ) ) . toString ( ) ) ; await optionsContracts . approve ( optionsContracts . address , '10000000000000000' , { from : secondOwnerAddress } ) ; initialETH = await balance . current ( secondOwnerAddress ) ; txInfo = await optionsContracts . exercise ( amtToExercise , [ creatorAddress ] , { from : secondOwnerAddress , gas : '1000000' } ) ; const tx = await web3 . eth . getTransaction ( txInfo . tx ) ; finalETH = await balance . current ( secondOwnerAddress ) ; gasUsed = new BN ( txInfo . receipt . gasUsed ) ; gasPrice = new BN ( tx . gasPrice ) ; const expectedEndETHBalance = initialETH . sub ( gasUsed . mul ( gasPrice ) ) . add ( new BN ( 450 ) ) ; expect ( finalETH . toString ( ) ) . to . equal ( expectedEndETHBalance . toString ( ) ) ; const totalSupplyAfter = await optionsContracts . totalSupply ( ) ; expect ( totalSupplyBefore . sub ( new BN ( amtToExercise ) ) . toString ( ) ) . to . equal ( totalSupplyAfter . toString ( ) ) ; expectEvent ( txInfo , 'Exercise' , { amtUnderlyingToPay : new BN ( 100000 ) , amtCollateralToPay : new BN ( 450 ) } ) ; } ) ; it ( 'check that the underlying and oTokens were transferred' , async ( ) => { const amtPTokens = await optionsContracts . balanceOf ( secondOwnerAddress ) ; expect ( amtPTokens . toString ( ) ) . to . equal ( '0' ) ; const ownerDaiBal = await dai . balanceOf ( secondOwnerAddress ) ; expect ( ownerDaiBal . toString ( ) ) . to . equal ( '0' ) ; const contractDaiBal = await dai . balanceOf ( optionsContracts . address ) ; expect ( contractDaiBal . toString ( ) ) . to . equal ( '100000' ) ; } ) ; } ) ; describe ( '#exercise() after expiry window' , ( ) => { it ( 'first person should be able to collect their share of collateral' , async ( ) => { const vaultIndex = '0' ; await time . increaseTo ( 1589932800 ) ; const initialETH = await balance . current ( creatorAddress ) ; const txInfo = await optionsContracts . redeemVaultBalance ( { from : creatorAddress , gas : '1000000' } ) ; const tx = await web3 . eth . getTransaction ( txInfo . tx ) ; const finalETH = await balance . current ( creatorAddress ) ; expectEvent ( txInfo , 'RedeemVaultBalance' , { amtCollateralRedeemed : '19999550' , amtUnderlyingRedeemed : '100000' } ) ; const gasUsed = new BN ( txInfo . receipt . gasUsed ) ; const gasPrice = new BN ( tx . gasPrice ) ; const expectedEndETHBalance = initialETH . sub ( gasUsed . mul ( gasPrice ) ) . add ( new BN ( 19999550 ) ) ; expect ( finalETH . toString ( ) ) . to . equal ( expectedEndETHBalance . toString ( ) ) ; const ownerDaiBal = await dai . balanceOf ( creatorAddress ) ; expect ( ownerDaiBal . toString ( ) ) . to . equal ( '100000' ) ; } ) ; it ( 'only the owner of a vault should be able to collect collateral' , async ( ) => { const vaultIndex = '1' ; await expectRevert ( optionsContracts . redeemVaultBalance ( { from : nonOwnerAddress , gas : '1000000' } ) , 'Vault does not exist' ) ; } ) ; it ( 'once collateral has been collected, should not be able to collect again' ) ; it ( 'the second person should be able to collect their share of collateral' , async ( ) => { const vaultIndex = '1' ; const tx = await optionsContracts . redeemVaultBalance ( { from : firstOwnerAddress , gas : '1000000' } ) ; expectEvent ( tx , 'RedeemVaultBalance' , { amtCollateralRedeemed : '10000000' , amtUnderlyingRedeemed : '0' } ) ; const ownerDaiBal = await dai . balanceOf ( firstOwnerAddress ) ; expect ( ownerDaiBal . toString ( ) ) . to . equal ( '0' ) ; } ) ; } ) ; } ) ;