TestOptionLiquidation.t.sol
1 pragma solidity >=0.6.0; 2 3 import "truffle/Assert.sol"; 4 import "../../../contracts/utils/MoreMath.sol"; 5 import "../../common/utils/MoreAssert.t.sol"; 6 import "./Base.t.sol"; 7 8 9 contract TestOptionLiquidation is Base { 10 11 function testLiquidationBeforeAllowed() public { 12 13 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 14 depositTokens(address(bob), mu); 15 address _tk = bob.writeOption(CALL, ethInitialPrice, 10 days, pool); 16 17 bob.transferOptions(address(alice), _tk, 1); 18 19 (bool success,) = address(bob).call( 20 abi.encodePacked( 21 bob.liquidateOptions.selector, 22 abi.encode(_tk, address(bob)) 23 ) 24 ); 25 26 Assert.isFalse(success, "liquidate should fail"); 27 } 28 29 function testPartialLiquidationWhenIssuerLacksCollateral() public { 30 31 int step = 40e18; 32 33 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 34 depositTokens(address(bob), mu); 35 address _tk = bob.writeOption(CALL, ethInitialPrice, 10 days, pool); 36 37 bob.transferOptions(address(alice), _tk, 1); 38 39 feed.setPrice(ethInitialPrice + step); 40 41 Assert.equal(bob.calcCollateral(), mu + uint(step), "bob collateral before liquidation"); 42 43 OptionToken tk = OptionToken(_tk); 44 uint v1 = tk.writtenVolume(address(bob)); 45 collateralManager.liquidateOptions(_tk, address(bob)); 46 uint v2 = tk.writtenVolume(address(bob)); 47 48 Assert.isTrue(v1 > v2, "written volume liquidation"); 49 50 MoreAssert.equal(bob.calcCollateral(), bob.balance(), cBase, "bob final collateral"); 51 Assert.equal(alice.calcCollateral(), 0, "alice final collateral"); 52 53 Assert.equal(bob.calcSurplus(), 0, "bob final surplus"); 54 Assert.equal(alice.calcSurplus(), 0, "alice final surplus"); 55 56 Assert.equal(getBookLength(), 2, "book length"); 57 } 58 59 function testMultipleLiquidationsWhenIssuerLacksCollateral() public { 60 61 int step = 20e18; 62 63 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 64 depositTokens(address(bob), mu); 65 address _tk = bob.writeOption(CALL, ethInitialPrice, 10 days, pool); 66 67 bob.transferOptions(address(alice), _tk, 1); 68 69 feed.setPrice(ethInitialPrice + 1 * step); 70 uint v1 = collateralManager.liquidateOptions(_tk, address(bob)); 71 Assert.isTrue(v1 > 0, "liquidation value t1"); 72 Assert.equal(bob.balance(), mu - v1, "bob balance t1"); 73 MoreAssert.equal(bob.calcCollateral(), mu - v1, cBase, "bob collateral t1"); 74 75 feed.setPrice(ethInitialPrice + 2 * step); 76 uint v2 = collateralManager.liquidateOptions(_tk, address(bob)); 77 Assert.isTrue(v2 > 0, "liquidation value t2"); 78 Assert.equal(bob.balance(), mu - v1 - v2, "bob balance t2"); 79 MoreAssert.equal(bob.calcCollateral(), mu - v1 - v2, cBase, "bob collateral t2"); 80 81 feed.setPrice(ethInitialPrice + 3 * step); 82 uint v3 = collateralManager.liquidateOptions(_tk, address(bob)); 83 Assert.isTrue(v3 > 0, "liquidation value t3"); 84 Assert.equal(bob.balance(), mu - v1 - v2 - v3, "bob balance t3"); 85 MoreAssert.equal(bob.calcCollateral(), mu - v1 - v2 - v3, cBase, "bob collateral t3"); 86 87 Assert.equal(getBookLength(), 2, "book length"); 88 } 89 90 function testFullLiquidationsWhenIssuerLacksCollateral() public { 91 92 int step = 100e18; 93 94 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 95 depositTokens(address(bob), mu); 96 address _tk = bob.writeOption(CALL, ethInitialPrice, 10 days, pool); 97 98 bob.transferOptions(address(alice), _tk, 1); 99 100 feed.setPrice(ethInitialPrice + 1 * step); 101 uint v1 = collateralManager.liquidateOptions(_tk, address(bob)); 102 Assert.isTrue(v1 > mu, "liquidation value t1"); 103 Assert.equal(bob.balance(), 0, "bob balance t1"); 104 MoreAssert.equal(bob.calcCollateral(), 0, cBase, "bob collateral t1"); 105 106 Assert.equal(getBookLength(), 1, "book length"); 107 } 108 109 function testLiquidationAtMaturityOTM() public { 110 111 int step = 40e18; 112 113 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 114 depositTokens(address(bob), mu); 115 address _tk = bob.writeOption(CALL, ethInitialPrice, 10 days, pool); 116 117 bob.transferOptions(address(alice), _tk, 1); 118 119 feed.setPrice(ethInitialPrice - step); 120 time.setTimeOffset(10 days); 121 122 Assert.equal(bob.calcCollateral(), 0, "bob collateral before liquidation"); 123 124 collateralManager.liquidateOptions(_tk, address(bob)); 125 126 Assert.equal(bob.calcCollateral(), 0, "bob final collateral"); 127 Assert.equal(alice.calcCollateral(), 0, "alice final collateral"); 128 129 Assert.equal(bob.calcSurplus(), mu, "bob final surplus"); 130 Assert.equal(alice.calcSurplus(), 0, "alice final surplus"); 131 } 132 133 function testLiquidationAtMaturityITM() public { 134 135 int step = 40e18; 136 137 uint mu = MoreMath.sqrtAndMultiply(10, upperVol); 138 depositTokens(address(bob), mu); 139 address _tk = bob.writeOption(PUT, ethInitialPrice, 10 days, pool); 140 141 bob.transferOptions(address(alice), _tk, 1); 142 143 feed.setPrice(ethInitialPrice - step); 144 time.setTimeOffset(10 days); 145 146 uint iv = uint(exchange.calcIntrinsicValue(_tk)); 147 148 Assert.equal(bob.calcCollateral(), iv, "bob collateral before liquidation"); 149 150 collateralManager.liquidateOptions(_tk, address(bob)); 151 152 Assert.equal(iv, uint(step), "intrinsic value"); 153 154 Assert.equal(bob.calcCollateral(), 0, "bob final collateral"); 155 Assert.equal(alice.calcCollateral(), 0, "alice final collateral"); 156 157 Assert.equal(bob.calcSurplus(), mu - iv, "bob final surplus"); 158 Assert.equal(alice.calcSurplus(), 0, "alice final surplus"); 159 } 160 }