/ test / finance / OptionsExchange / TestCoveredOption.t.sol
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  }