TestCoveredOption.t.sol
1 pragma solidity >=0.6.0; 2 pragma experimental ABIEncoderV2; 3 4 import "truffle/Assert.sol"; 5 import "../../../contracts/finance/OptionToken.sol"; 6 import "../../../contracts/utils/MoreMath.sol"; 7 import {stdStorage, StdStorage, Test} from "forge-std/Test.sol"; 8 import "./Base.t.sol"; 9 10 contract TestCoveredOption is Base, Test { 11 event LogUint(string, uint); 12 13 function testWriteCoveredCall() public { 14 15 underlying.reset(address(this)); 16 underlying.issue(address(this), underlyingBase); 17 18 address _tk = writeCovered(1, ethInitialPrice, 10 days); 19 20 OptionToken tk = OptionToken(_tk); 21 22 Assert.equal(volumeBase, tk.balanceOf(address(this)), "tk balance"); 23 Assert.equal(volumeBase, tk.writtenVolume(address(this)), "tk writtenVolume"); 24 Assert.equal(0, tk.uncoveredVolume(address(this)), "tk uncoveredVolume"); 25 Assert.equal(0, exchange.calcCollateral(address(this), true), "exchange collateral"); 26 } 27 28 function testBurnCoveredCall() public { 29 30 underlying.reset(address(this)); 31 underlying.issue(address(this), 2 * underlyingBase); 32 33 address _tk = writeCovered(2, ethInitialPrice, 10 days); 34 OptionToken tk = OptionToken(_tk); 35 36 (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(tk.symbol(), true); 37 uint volume = 2 * volumeBase; 38 uint total = buyPrice * volume / volumeBase; 39 40 erc20.issue(address(this), total); 41 erc20.approve(address(pool), total); 42 43 (bool success,) = address(this).call( 44 abi.encodePacked( 45 IGovernableLiquidityPool(pool).buy.selector, 46 abi.encode(symbol, buyPrice, volume, address(erc20)) 47 ) 48 ); 49 50 //tk.burn(volumeBase); 51 52 //assertEq(1, tk.balanceOf(address(this))); 53 54 Assert.equal(volumeBase, tk.balanceOf(address(this)), "tk balance t0"); 55 Assert.equal(volumeBase, tk.writtenVolume(address(this)), "tk writtenVolume t0"); 56 Assert.equal(underlyingBase, underlying.balanceOf(address(this)), "underlying balance t0"); 57 Assert.equal(1, tk.uncoveredVolume(address(this)), "tk uncoveredVolume t0"); 58 Assert.equal(0, exchange.calcCollateral(address(this), true), "exchange collateral t0"); 59 60 //tk.burn(volumeBase); 61 62 Assert.equal(0, tk.balanceOf(address(this)), "tk balance t1"); 63 Assert.equal(0, tk.writtenVolume(address(this)), "tk writtenVolume t1"); 64 Assert.equal(2 * underlyingBase, underlying.balanceOf(address(this)), "underlying balance t1"); 65 Assert.equal(0, tk.uncoveredVolume(address(this)), "tk uncoveredVolume t1"); 66 Assert.equal(0, exchange.calcCollateral(address(this), true), "exchange collateral t1"); 67 } 68 69 function testBurnCollateral() public { 70 71 erc20.reset(address(this)); 72 73 uint ct20 = MoreMath.sqrtAndMultiply(20, upperVol); 74 75 depositTokens(address(this), ct20); 76 77 address _tk1 = exchange.createSymbol( 78 address(feed), 79 PUT, 80 uint(ethInitialPrice), 81 time.getNow() + 20 days 82 ); 83 84 IOptionsExchange.OpenExposureInputs memory oEi; 85 86 oEi.symbols = new string[](1); 87 oEi.volume = new uint[](1); 88 oEi.isShort = new bool[](1); 89 oEi.isCovered = new bool[](1); 90 oEi.poolAddrs = new address[](1); 91 oEi.paymentTokens = new address[](1); 92 93 94 oEi.symbols[0] = IOptionToken(_tk1).symbol(); 95 oEi.volume[0] = volumeBase; 96 oEi.isShort[0] = true; 97 oEi.poolAddrs[0] = pool;//poolAddr; 98 //oEi.isCovered[0] = false; //expoliting default to save gas 99 //oEi.paymentTokens[0] = address(0); //exploiting default to save gas 100 101 102 (bool success,) = address(this).call( 103 abi.encodePacked( 104 exchange.openExposure.selector, 105 abi.encode(oEi, address(this)) 106 ) 107 ); 108 109 Assert.equal(exchange.calcCollateral(address(this), true), ct20, "writer collateral t0"); 110 111 underlying.reset(address(this)); 112 underlying.issue(address(this), 2 * underlyingBase); 113 114 address _tk2 = writeCovered(2, ethInitialPrice, 10 days); 115 116 Assert.equal(exchange.calcCollateral(address(this), true), ct20, "writer collateral t1"); 117 118 //OptionToken(_tk1).burn(volumeBase / 2); 119 120 Assert.equal(exchange.calcCollateral(address(this), true), ct20 / 2, "writer collateral t2"); 121 122 //OptionToken(_tk2).burn(volumeBase); 123 124 Assert.equal(OptionToken(_tk1).balanceOf(address(this)), volumeBase / 2, "balanceOf tk1"); 125 Assert.equal(OptionToken(_tk1).writtenVolume(address(this)), volumeBase / 2, "writtenVolume tk1"); 126 Assert.equal(OptionToken(_tk2).balanceOf(address(this)), volumeBase, "balanceOf tk2"); 127 Assert.equal(OptionToken(_tk2).writtenVolume(address(this)), volumeBase, "writtenVolume tk2"); 128 } 129 130 function testMixedCollateral() public { 131 132 erc20.reset(address(this)); 133 134 uint ct10 = MoreMath.sqrtAndMultiply(10, upperVol); 135 uint ct20 = MoreMath.sqrtAndMultiply(20, upperVol); 136 137 depositTokens(address(this), ct20); 138 139 address _tk1 = exchange.createSymbol( 140 address(feed), 141 PUT, 142 uint(ethInitialPrice), 143 time.getNow() + 20 days 144 ); 145 146 IOptionsExchange.OpenExposureInputs memory oEi; 147 148 oEi.symbols = new string[](1); 149 oEi.volume = new uint[](1); 150 oEi.isShort = new bool[](1); 151 oEi.isCovered = new bool[](1); 152 oEi.poolAddrs = new address[](1); 153 oEi.paymentTokens = new address[](1); 154 155 156 oEi.symbols[0] = IOptionToken(_tk1).symbol(); 157 oEi.volume[0] = volumeBase; 158 oEi.isShort[0] = true; 159 oEi.poolAddrs[0] = pool;//poolAddr; 160 //oEi.isCovered[0] = false; //expoliting default to save gas 161 //oEi.paymentTokens[0] = address(0); //exploiting default to save gas 162 163 164 (bool success,) = address(this).call( 165 abi.encodePacked( 166 exchange.openExposure.selector, 167 abi.encode(oEi, address(this)) 168 ) 169 ); 170 171 Assert.equal(exchange.calcCollateral(address(this), true), ct20, "writer collateral t0"); 172 173 underlying.reset(address(this)); 174 underlying.issue(address(this), 2 * underlyingBase); 175 176 settings.setSwapRouterInfo(router, address(erc20)); 177 settings.setSwapRouterTolerance(105e4, 1e6); 178 179 int step = 40e18; 180 181 address _tk2 = writeCovered(2, ethInitialPrice, 10 days); 182 183 OptionToken tk = OptionToken(_tk2); 184 185 // tk.transfer(address(alice), 2 * volumeBase); 186 187 feed.setPrice(ethInitialPrice + step); 188 time.setTimeOffset(10 days); 189 190 Assert.equal(exchange.calcCollateral(address(this), true), ct10, "writer collateral t1"); 191 192 tk.redeem(pool); 193 194 (bool success1,) = address(this).call( 195 abi.encodePacked( 196 collateralManager.liquidateOptions.selector, 197 abi.encode(_tk2, address(this)) 198 ) 199 ); 200 201 Assert.equal(exchange.calcCollateral(address(this), true), ct10, "writer collateral t2"); 202 203 time.setTimeOffset(20 days); 204 205 206 (bool success2,) = address(this).call( 207 abi.encodePacked( 208 collateralManager.liquidateOptions.selector, 209 abi.encode(_tk1, address(this)) 210 ) 211 ); 212 213 Assert.equal(exchange.calcCollateral(address(this), true), 0, "writer collateral t3"); 214 Assert.equal(exchange.calcSurplus(address(this)), ct20, "writer final surplus"); 215 } 216 217 function writeCovered( 218 uint volume, 219 int strike, 220 uint timeToMaturity 221 ) 222 public 223 returns (address _tk) 224 { 225 ERC20Mock mock = ERC20Mock(UnderlyingFeed(feed).getUnderlyingAddr()); 226 227 uint f = volumeBase; 228 uint d = mock.decimals(); 229 if (d < 18) { 230 f = f / (10 ** (18 - d)); 231 } 232 if (d > 18) { 233 f = f * (10 ** (d - 18)); 234 } 235 236 mock.approve(address(exchange), volume * f); 237 238 _tk = exchange.createSymbol( 239 address(feed), 240 CALL, 241 uint(strike), 242 time.getNow() + timeToMaturity 243 ); 244 245 addSymbol(uint(strike), time.getNow() + timeToMaturity); 246 247 IOptionsExchange.OpenExposureInputs memory oEi; 248 249 oEi.symbols = new string[](1); 250 oEi.volume = new uint[](1); 251 oEi.isShort = new bool[](1); 252 oEi.isCovered = new bool[](1); 253 oEi.poolAddrs = new address[](1); 254 oEi.paymentTokens = new address[](1); 255 256 257 oEi.symbols[0] = IOptionToken(_tk).symbol(); 258 oEi.volume[0] = volume * volumeBase; 259 oEi.isShort[0] = true; 260 oEi.poolAddrs[0] = pool;//poolAddr; 261 oEi.isCovered[0] = true; 262 //oEi.paymentTokens[0] = address(0); //exploiting default to save gas 263 264 (bool success,) = address(this).call( 265 abi.encodePacked( 266 exchange.openExposure.selector, 267 abi.encode(oEi, address(this)) 268 ) 269 ); 270 271 Assert.equal(success,true, "covered option written"); 272 } 273 }