/ test / pools / LinearLiquidityPool / TestPoolTrading.t.sol
TestPoolTrading.t.sol
  1  pragma solidity >=0.6.0;
  2  
  3  import "truffle/Assert.sol";
  4  import "./Base.t.sol";
  5  
  6  contract TestPoolTrading is Base {
  7  
  8      function testBuyOptionsFromPool() public {
  9  
 10          createTraders();
 11  
 12          addSymbol();
 13  
 14          uint cUnit = calcCollateralUnit();
 15  
 16          depositInPool(address(bob), 10 * cUnit);
 17          erc20.issue(address(alice), 5 * cUnit);
 18  
 19          (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, true);
 20          uint volume = 15 * volumeBase / 10;
 21          uint total = buyPrice * volume / volumeBase;
 22  
 23          Assert.equal(erc20.balanceOf(address(alice)), 5 * cUnit, "alice tokens before buying");
 24  
 25          (bool success,) = address(alice).call(
 26              abi.encodePacked(
 27                  alice.buyFromPool.selector,
 28                  abi.encode(symbol, buyPrice, volume)
 29              )
 30          );
 31  
 32  
 33          Assert.equal(erc20.balanceOf(address(alice)), 5 * cUnit - total, "alice tokens after buying");
 34          
 35          uint value = 10 * cUnit + total;
 36          Assert.equal(exchange.balanceOf(address(pool)), value, "pool balance");
 37          Assert.equal(exchange.balanceOf(address(alice)), 0, "alice balance");
 38          
 39          OptionToken tk = OptionToken(symbolAddr);
 40          Assert.equal(tk.balanceOf(address(bob)), 0, "bob options");
 41          Assert.equal(tk.balanceOf(address(alice)), volume, "alice options");
 42          Assert.equal(tk.writtenVolume(address(pool)), volume, "pool written volume");
 43      }
 44  
 45      function testBuyForCheaperPrice() public {
 46  
 47          createTraders();
 48  
 49          addSymbol();
 50  
 51          uint cUnit = calcCollateralUnit();
 52  
 53          depositInPool(address(bob), 10 * cUnit);
 54          erc20.issue(address(alice), 5 * cUnit);
 55  
 56          (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, true);
 57          uint volume = 15 * volumeBase / 10;
 58          
 59          (bool success,) = address(alice).call(
 60              abi.encodePacked(
 61                  alice.buyFromPool.selector,
 62                  abi.encode(symbol, buyPrice - 1, volume)
 63              )
 64          );
 65          
 66          Assert.isFalse(success, "buy cheap should fail");
 67      }
 68  
 69      function testBuyForHigherPrice() public {
 70  
 71          createTraders();
 72  
 73          addSymbol();
 74  
 75          uint cUnit = calcCollateralUnit();
 76  
 77          depositInPool(address(bob), 10 * cUnit);
 78          erc20.issue(address(alice), 5 * cUnit);
 79  
 80          (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, true);
 81          uint volume = 15 * volumeBase / 10;
 82          uint total = buyPrice * volume / volumeBase;
 83          
 84          (bool success,) = address(alice).call(
 85              abi.encodePacked(
 86                  alice.buyFromPool.selector,
 87                  abi.encode(symbol, buyPrice * 2, volume)
 88              )
 89          );
 90          
 91          Assert.isTrue(success, "buy for higher price should succeed");
 92          Assert.equal(erc20.balanceOf(address(alice)), 5 * cUnit - total, "alice tokens after buying");
 93      }
 94  
 95      function testSellOptionsToPool() public {
 96  
 97          createTraders();
 98  
 99          addSymbol();
100  
101          uint cUnit = calcCollateralUnit();
102  
103          depositInPool(address(bob), 10 * cUnit);
104          erc20.issue(address(alice), 5 * cUnit);
105  
106          alice.depositInExchange(5 * cUnit);
107          OptionToken tk = OptionToken(symbolAddr);
108  
109          (uint sellPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, false);
110          uint volume = 2 * volumeBase;
111          uint total = sellPrice * volume / volumeBase;
112  
113          Assert.equal(tk.balanceOf(address(alice)), volume, "alice options before sell");
114          Assert.equal(tk.balanceOf(address(pool)), 0, "pool options before sell");
115          
116          (bool success,) = address(alice).call(
117              abi.encodePacked(
118                  alice.writeOptions.selector,
119                  abi.encode(2, CALL, strike, maturity)
120              )
121          );
122  
123          Assert.equal(tk.balanceOf(address(alice)), 0, "alice options after sell");
124          Assert.equal(tk.balanceOf(address(pool)), volume, "pool options after sell");
125          
126          Assert.equal(exchange.balanceOf(address(pool)), 10 * cUnit - total, "pool balance");
127          Assert.equal(exchange.balanceOf(address(alice)), 5 * cUnit + total, "alice balance");
128      }
129  
130      function testSellForCheapPrice() public {
131  
132          createTraders();
133  
134          addSymbol();
135  
136          uint cUnit = calcCollateralUnit();
137  
138          depositInPool(address(bob), 10 * cUnit);
139          erc20.issue(address(alice), 5 * cUnit);
140  
141          alice.depositInExchange(5 * cUnit);
142  
143          (uint sellPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, false);
144          uint volume = 2 * volumeBase;
145          uint total = sellPrice * volume / volumeBase;
146  
147          (bool success,) = address(alice).call(
148              abi.encodePacked(
149                  alice.writeOptions.selector,
150                  abi.encode(2, CALL, strike, maturity)
151              )
152          );
153  
154          Assert.isTrue(success, "sell cheap should succeed");
155          Assert.equal(exchange.balanceOf(address(alice)), 5 * cUnit + total, "alice balance");
156      }
157  
158      function testSellForHigherPrice() public {
159  
160          createTraders();
161  
162          addSymbol();
163  
164          uint cUnit = calcCollateralUnit();
165  
166          depositInPool(address(bob), 10 * cUnit);
167          erc20.issue(address(alice), 5 * cUnit);
168  
169          alice.depositInExchange(5 * cUnit);
170  
171          (uint sellPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, false);
172          uint volume = 2 * volumeBase;
173  
174          (bool success,) = address(alice).call(
175              abi.encodePacked(
176                  alice.sellToPool.selector,
177                  abi.encode(symbol, sellPrice + 1, volume)
178              )
179          );
180  
181          Assert.isFalse(success, "sell for higher price should fail");
182      }
183  
184      function testBuyFromPoolThenSellBack() public {
185  
186          createTraders();
187  
188          addSymbol();
189  
190          uint cUnit = calcCollateralUnit();
191          uint volume = 15 * volumeBase / 10;
192  
193          depositInPool(address(bob), 10 * cUnit);
194          erc20.issue(address(alice), 5 * cUnit);
195  
196          (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, true);
197  
198          (bool success1,) = address(alice).call(
199              abi.encodePacked(
200                  alice.buyFromPool.selector,
201                  abi.encode(symbol, buyPrice, volume)
202              )
203          );
204          
205          OptionToken tk = OptionToken(symbolAddr);
206          Assert.equal(tk.totalSupply(), volume, "token initial supply");
207          
208          (uint sellPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, false);
209  
210          (bool success2,) = address(alice).call(
211              abi.encodePacked(
212                  alice.sellToPool.selector,
213                  abi.encode(symbol, sellPrice, volume)
214              )
215          );
216  
217          uint diff = (buyPrice - sellPrice) * volume / volumeBase;
218  
219          Assert.equal(alice.balance(), 5 * cUnit - diff, "alice balance");
220          Assert.equal(tk.balanceOf(address(alice)), 0, "alice tokens");
221          Assert.equal(tk.balanceOf(address(pool)), 0, "pool tokens");
222          Assert.equal(tk.writtenVolume(address(pool)), 0, "pool written volume");
223          Assert.equal(tk.totalSupply(), 0, "token final supply");
224      }
225  
226      function testSellToPoolThenBuyBack() public {
227  
228          createTraders();
229  
230          addSymbol();
231  
232          uint cUnit = calcCollateralUnit();
233          uint volume = 2 * volumeBase;
234  
235          depositInPool(address(bob), 10 * cUnit);
236          erc20.issue(address(alice), 5 * cUnit);
237  
238          alice.depositInExchange(2 * cUnit);
239          OptionToken tk = OptionToken(symbolAddr);
240  
241          (uint sellPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, false);
242          
243          (bool success2,) = address(alice).call(
244              abi.encodePacked(
245                  alice.sellToPool.selector,
246                  abi.encode(symbol, sellPrice, volume)
247              )
248          );
249  
250          (uint buyPrice,) = IGovernableLiquidityPool(pool).queryBuy(symbol, true);
251  
252          (bool success1,) = address(alice).call(
253              abi.encodePacked(
254                  alice.buyFromPool.selector,
255                  abi.encode(symbol, buyPrice, volume)
256              )
257          );
258  
259          uint diff = (buyPrice - sellPrice) * volume / volumeBase;
260  
261          Assert.equal(alice.balance(), 5 * cUnit - diff, "alice balance");
262          Assert.equal(tk.balanceOf(address(alice)), volume, "alice tokens");
263          Assert.equal(tk.balanceOf(address(pool)), 0, "pool tokens");
264          Assert.equal(tk.writtenVolume(address(pool)), 0, "pool written volume");
265          Assert.equal(tk.writtenVolume(address(alice)), volume, "alice written volume");
266          Assert.equal(tk.totalSupply(), volume, "token final supply");
267      }
268  }