Skip to content

Commit bc2bf46

Browse files
committed
Add ETH/WETH settlement tests
1 parent 3323a1a commit bc2bf46

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

test/forkMainnet/SignalBuyContract.t.sol

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,263 @@ contract SignalBuyContractTest is BalanceUtil {
942942
userMakerAsset.assertChange(-int256(DEFAULT_ORDER.userTokenAmount.div(2)));
943943
}
944944

945+
/*********************************
946+
* ETH/WETH settlement *
947+
*********************************/
948+
949+
struct ETHandWETHAssetSnapshot {
950+
BalanceSnapshot.Snapshot dealerETHAsset;
951+
BalanceSnapshot.Snapshot dealerWETHAsset;
952+
BalanceSnapshot.Snapshot userETHAsset;
953+
BalanceSnapshot.Snapshot userWETHAsset;
954+
}
955+
ETHandWETHAssetSnapshot assetSnapshots;
956+
957+
function testSettlementETHToETHWithNoFee() public {
958+
SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER;
959+
order.dealerToken = IERC20(LibConstant.ETH_ADDRESS);
960+
order.minDealerTokenAmount = 1e18;
961+
bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712);
962+
963+
SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL;
964+
fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
965+
fill.dealerTokenAmount = order.minDealerTokenAmount;
966+
967+
ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS;
968+
traderParams.dealerTokenAmount = fill.dealerTokenAmount;
969+
traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712);
970+
971+
SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL;
972+
allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
973+
allowFill.fillAmount = traderParams.dealerTokenAmount;
974+
975+
ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS;
976+
crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712);
977+
978+
assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS);
979+
assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth));
980+
assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS);
981+
assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth));
982+
983+
// Case 1: Tx failed due to mismatch msg.value
984+
vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount");
985+
vm.prank(dealer, dealer);
986+
signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount - 1 }(order, orderMakerSig, traderParams, crdParams);
987+
988+
// Case 2: Tx succeeded
989+
vm.expectEmit(true, true, true, true);
990+
emit SignalBuyFilledByTrader(
991+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)),
992+
order.user,
993+
dealer,
994+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)),
995+
DEFAULT_TRADER_PARAMS.recipient,
996+
ISignalBuyContract.FillReceipt(
997+
address(order.userToken),
998+
address(order.dealerToken),
999+
order.userTokenAmount,
1000+
order.minDealerTokenAmount,
1001+
0, // remainingUserTokenAmount should be zero after order fully filled
1002+
0, // tokenlonFee = 0
1003+
0 // dealerStrategyFee = 0
1004+
)
1005+
);
1006+
vm.prank(dealer, dealer);
1007+
signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount }(order, orderMakerSig, traderParams, crdParams);
1008+
1009+
assetSnapshots.dealerETHAsset.assertChange(-int256(order.minDealerTokenAmount));
1010+
assetSnapshots.dealerWETHAsset.assertChange(0);
1011+
assetSnapshots.userETHAsset.assertChange(int256(order.minDealerTokenAmount));
1012+
assetSnapshots.userWETHAsset.assertChange(0);
1013+
}
1014+
1015+
function testSettlementWETHToWETHWithNoFee() public {
1016+
SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER;
1017+
order.dealerToken = weth;
1018+
order.minDealerTokenAmount = 1e18;
1019+
bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712);
1020+
1021+
SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL;
1022+
fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1023+
fill.dealerTokenAmount = order.minDealerTokenAmount;
1024+
1025+
ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS;
1026+
traderParams.dealerTokenAmount = fill.dealerTokenAmount;
1027+
traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712);
1028+
1029+
SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL;
1030+
allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1031+
allowFill.fillAmount = traderParams.dealerTokenAmount;
1032+
1033+
ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS;
1034+
crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712);
1035+
1036+
assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS);
1037+
assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth));
1038+
assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS);
1039+
assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth));
1040+
1041+
// Case 1: Tx failed due to invalid msg.value
1042+
vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount");
1043+
vm.prank(dealer, dealer);
1044+
signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams);
1045+
1046+
// Case 2: Tx succeeded
1047+
vm.expectEmit(true, true, true, true);
1048+
emit SignalBuyFilledByTrader(
1049+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)),
1050+
order.user,
1051+
dealer,
1052+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)),
1053+
DEFAULT_TRADER_PARAMS.recipient,
1054+
ISignalBuyContract.FillReceipt(
1055+
address(order.userToken),
1056+
address(order.dealerToken),
1057+
order.userTokenAmount,
1058+
order.minDealerTokenAmount,
1059+
0, // remainingUserTokenAmount should be zero after order fully filled
1060+
0, // tokenlonFee = 0
1061+
0 // dealerStrategyFee = 0
1062+
)
1063+
);
1064+
vm.prank(dealer, dealer);
1065+
signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams);
1066+
1067+
assetSnapshots.dealerETHAsset.assertChange(0);
1068+
assetSnapshots.dealerWETHAsset.assertChange(-int256(order.minDealerTokenAmount));
1069+
assetSnapshots.userETHAsset.assertChange(0);
1070+
assetSnapshots.userWETHAsset.assertChange(int256(order.minDealerTokenAmount));
1071+
}
1072+
1073+
function testSettlementETHToWETHWithAddedTokenlonFee() public {
1074+
// tokenlonFeeFactor : 10%
1075+
vm.startPrank(owner, owner);
1076+
signalBuyContract.setFactors(1000);
1077+
vm.warp(block.timestamp + signalBuyContract.factorActivateDelay());
1078+
signalBuyContract.activateFactors();
1079+
vm.stopPrank();
1080+
1081+
SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER;
1082+
order.dealerToken = weth;
1083+
order.minDealerTokenAmount = 1e18;
1084+
bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712);
1085+
1086+
SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL;
1087+
fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1088+
// Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio
1089+
// to account for tokenlon fee
1090+
fill.dealerTokenAmount = order.minDealerTokenAmount.mul(115).div(100); // 15% more
1091+
1092+
ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS;
1093+
traderParams.dealerTokenAmount = fill.dealerTokenAmount;
1094+
traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712);
1095+
1096+
SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL;
1097+
allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1098+
allowFill.fillAmount = traderParams.dealerTokenAmount;
1099+
1100+
ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS;
1101+
crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712);
1102+
1103+
assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS);
1104+
assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth));
1105+
assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS);
1106+
assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth));
1107+
1108+
// Case 1: Tx failed due to invalid msg.value
1109+
vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount");
1110+
vm.prank(dealer, dealer);
1111+
signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams);
1112+
1113+
// Case 2: Tx succeeded
1114+
vm.expectEmit(true, true, true, true);
1115+
emit SignalBuyFilledByTrader(
1116+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)),
1117+
order.user,
1118+
dealer,
1119+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)),
1120+
DEFAULT_TRADER_PARAMS.recipient,
1121+
ISignalBuyContract.FillReceipt(
1122+
address(order.userToken),
1123+
address(order.dealerToken),
1124+
order.userTokenAmount,
1125+
fill.dealerTokenAmount,
1126+
0, // remainingUserTokenAmount should be zero after order fully filled
1127+
fill.dealerTokenAmount.div(10), // tokenlonFee = 10% dealerTokenAmount
1128+
0 // dealerStrategyFee = 0
1129+
)
1130+
);
1131+
vm.prank(dealer, dealer);
1132+
signalBuyContract.fillSignalBuy{ value: fill.dealerTokenAmount }(order, orderMakerSig, traderParams, crdParams);
1133+
1134+
assetSnapshots.dealerETHAsset.assertChange(-int256(fill.dealerTokenAmount));
1135+
assetSnapshots.dealerWETHAsset.assertChange(0);
1136+
assetSnapshots.userETHAsset.assertChange(0);
1137+
assetSnapshots.userWETHAsset.assertChange(int256(fill.dealerTokenAmount.mul(9).div(10))); // 10% fee for Tokenlon
1138+
}
1139+
1140+
function testSettlementWETHToETHWithAddedGasFeeAndStrategyFee() public {
1141+
SignalBuyContractLibEIP712.Order memory order = DEFAULT_ORDER;
1142+
order.dealerToken = IERC20(LibConstant.ETH_ADDRESS);
1143+
order.minDealerTokenAmount = 1e18;
1144+
bytes memory orderMakerSig = _signOrder(userPrivateKey, order, SignatureValidator.SignatureType.EIP712);
1145+
1146+
SignalBuyContractLibEIP712.Fill memory fill = DEFAULT_FILL;
1147+
fill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1148+
// Increase dealer token amount so the dealerToken/userToken ratio is better than order's dealerToken/userToken ratio
1149+
// to account for gas fee and dealer strategy fee
1150+
fill.dealerTokenAmount = order.minDealerTokenAmount.mul(11).div(10); // 10% more
1151+
1152+
ISignalBuyContract.TraderParams memory traderParams = DEFAULT_TRADER_PARAMS;
1153+
traderParams.gasFeeFactor = 50; // gasFeeFactor: 0.5%
1154+
traderParams.dealerStrategyFeeFactor = 250; // dealerStrategyFeeFactor: 2.5%
1155+
traderParams.dealerTokenAmount = fill.dealerTokenAmount;
1156+
traderParams.dealerSig = _signFill(dealerPrivateKey, fill, SignatureValidator.SignatureType.EIP712);
1157+
1158+
SignalBuyContractLibEIP712.AllowFill memory allowFill = DEFAULT_ALLOW_FILL;
1159+
allowFill.orderHash = getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order));
1160+
allowFill.fillAmount = traderParams.dealerTokenAmount;
1161+
1162+
ISignalBuyContract.CoordinatorParams memory crdParams = DEFAULT_CRD_PARAMS;
1163+
crdParams.sig = _signAllowFill(coordinatorPrivateKey, allowFill, SignatureValidator.SignatureType.EIP712);
1164+
1165+
assetSnapshots.dealerETHAsset = BalanceSnapshot.take(dealer, LibConstant.ETH_ADDRESS);
1166+
assetSnapshots.dealerWETHAsset = BalanceSnapshot.take(dealer, address(weth));
1167+
assetSnapshots.userETHAsset = BalanceSnapshot.take(user, LibConstant.ETH_ADDRESS);
1168+
assetSnapshots.userWETHAsset = BalanceSnapshot.take(user, address(weth));
1169+
1170+
// Case 1: Tx failed due to invalid msg.value
1171+
vm.expectRevert("SignalBuyContract: mismatch dealer token (ETH) amount");
1172+
vm.prank(dealer, dealer);
1173+
signalBuyContract.fillSignalBuy{ value: 1 }(order, orderMakerSig, traderParams, crdParams);
1174+
1175+
// Case 2: Tx succeeded
1176+
vm.expectEmit(true, true, true, true);
1177+
emit SignalBuyFilledByTrader(
1178+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getOrderStructHash(order)),
1179+
order.user,
1180+
dealer,
1181+
getEIP712Hash(signalBuyContract.EIP712_DOMAIN_SEPARATOR(), SignalBuyContractLibEIP712._getAllowFillStructHash(allowFill)),
1182+
DEFAULT_TRADER_PARAMS.recipient,
1183+
ISignalBuyContract.FillReceipt(
1184+
address(order.userToken),
1185+
address(order.dealerToken),
1186+
order.userTokenAmount,
1187+
fill.dealerTokenAmount,
1188+
0, // remainingUserTokenAmount should be zero after order fully filled
1189+
0, // tokenlonFee = 0
1190+
fill.dealerTokenAmount.mul(3).div(100) // dealerStrategyFee = 0.5% + 2.5% = 3% dealerTokenAmount
1191+
)
1192+
);
1193+
vm.prank(dealer, dealer);
1194+
signalBuyContract.fillSignalBuy(order, orderMakerSig, traderParams, crdParams);
1195+
1196+
assetSnapshots.dealerETHAsset.assertChange(0);
1197+
assetSnapshots.dealerWETHAsset.assertChange(-int256(fill.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy is deducted from dealerTokenAmount directly
1198+
assetSnapshots.userETHAsset.assertChange(int256(fill.dealerTokenAmount.mul(97).div(100))); // 3% fee for SignalBuy
1199+
assetSnapshots.userWETHAsset.assertChange(0);
1200+
}
1201+
9451202
/*********************************
9461203
* cancelSignalBuy *
9471204
*********************************/

0 commit comments

Comments
 (0)