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 }