Skip to content

Commit 9f01f9c

Browse files
Implemented safeguards
1 parent 59320ff commit 9f01f9c

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

contracts/multitoken_dex.tact

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ native mulDiv(a: Int, b: Int, c: Int): Int;
88
@name(fill_zeros)
99
native fillZerosCheckLen(jetton_wallets: map<Address, Address>, want_len: Int): map<Address, Int>;
1010

11-
@name(load_msg_addr)
12-
extends mutates native loadAddress(self: Slice): Address;
13-
// SAFETY: doesn't check if address is std-type
14-
1511

1612

1713
message DexDeploy {
@@ -45,8 +41,7 @@ struct SystemInfo {
4541
owner_address: Address;
4642
}
4743

48-
// swap#4a2663c4 otherJettonMaster:MsgAddressInt = Swap;
49-
// TODO (see below): add also otherJettonMinExpected:(VarUInteger 16)
44+
// swap#4a2663c4 other_jetton_master:MsgAddressInt other_jetton_min_expected:(VarUInteger 16) = Swap;
5045
// the problem is that Tact doesn't support parsing slices as arbitrary structs
5146

5247

@@ -111,19 +106,29 @@ contract MultitokenDex {
111106
if (swap.loadUint(32) != 0x4a2663c4) {
112107
self.transferJettonTo(ctx.sender, msg.sender, received,
113108
msg.query_id, "Unknown operation");
109+
return;
114110
}
115-
// SAFETY: we test whether provided address is among listed jetton masters
116-
// it can fail due to invalid key length, but that's hard to achieve and doesn't harm DEX
117-
let otherJettonMaster: Address = swap.loadAddress();
118-
111+
let other_jetton_master: Address = swap.loadAddress();
112+
let other_jetton_min_expected: Int = swap.loadCoins();
119113

120-
let other_jw: Address = self.jetton_wallets.get(otherJettonMaster)!!;
114+
let other_jw: Address = self.jetton_wallets.get(other_jetton_master)!!;
121115
let old_balance_dst: Int = self.assets.get(other_jw)!!;
116+
if (other_jetton_min_expected >= old_balance_dst) {
117+
self.transferJettonTo(ctx.sender, msg.sender, received,
118+
msg.query_id, "Liquidity pool doesn't have enough funds");
119+
return;
120+
}
121+
// now, other_jetton_min_expected <= old_balance_dst - 1
122122

123123
let swap_value: Int = self.calc_swap(old_balance_src!!, old_balance_dst, received);
124-
125-
// TODO safeguard against slippage: paying attention to otherJettonMinExpected
126-
// TODO safeguard against liquidity pool draining
124+
if (swap_value >= old_balance_dst) { // safeguard against liquidity pool draining
125+
swap_value = old_balance_dst - 1; // still above other_jetton_min_expected, though we still check this next
126+
}
127+
if (swap_value < other_jetton_min_expected) {
128+
self.transferJettonTo(ctx.sender, msg.sender, received,
129+
msg.query_id, "Slippage protection: swap can't give requested count of tokens");
130+
return;
131+
}
127132

128133
self.transferJettonTo(other_jw, msg.sender, swap_value, msg.query_id, "Swap completed");
129134
self.assets.set(ctx.sender, old_balance_src + received);

0 commit comments

Comments
 (0)