Skip to content

Commit d3b73da

Browse files
Brechtpddong77wangdongkongliangzhong
authored
[protocol 3.6] Added Chi gas token support (#2162)
* [protocol 3.6] Added Chi gas token support * [protocol 3.6] Feedback * [Loopring 3.6] Improvements * [protocol] Gas token improvements * Chi gastoken improve (#2165) * refactor ChiDiscount * refactor ChiDiscount * fix compilation * more * feedback * fix test Co-authored-by: wangdong <[email protected]> Co-authored-by: kongliangzhong <[email protected]> * Update BatchTransactor.sol * add some comments * more * [protocol3.6] Fix tests Co-authored-by: Daniel Wang <[email protected]> Co-authored-by: wangdong <[email protected]> Co-authored-by: kongliangzhong <[email protected]>
1 parent f4f8ef3 commit d3b73da

File tree

18 files changed

+828
-53
lines changed

18 files changed

+828
-53
lines changed

packages/hebao_v1/contracts/aux/BatchTransactor.sol

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@
33
pragma solidity ^0.7.0;
44
pragma experimental ABIEncoderV2;
55

6-
import "../lib/Claimable.sol";
6+
import "../lib/OwnerManagable.sol";
77
import "../lib/Drainable.sol";
8+
import "./ChiDiscount.sol";
89

910

1011
/// @title BatchTransactor
1112
/// @author Daniel Wang - <[email protected]>
12-
contract BatchTransactor is Drainable, Claimable
13+
contract BatchTransactor is Drainable, ChiDiscount, OwnerManagable
1314
{
15+
address public immutable chiToken;
16+
17+
constructor(address _chiToken)
18+
{
19+
chiToken = _chiToken;
20+
}
1421

1522
function batchTransact(
16-
address target,
17-
bytes[] calldata txs,
18-
uint[] calldata gasLimits
23+
address target,
24+
bytes[] calldata txs,
25+
uint[] calldata gasLimits,
26+
ChiConfig calldata chiConfig
1927
)
2028
external
29+
discountCHI(chiToken, chiConfig)
30+
onlyManager
2131
{
2232
require(target != address(0), "EMPTY_TARGET");
2333
require(txs.length == gasLimits.length, "SIZE_DIFF");
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright 2017 Loopring Technology Limited.
3+
pragma solidity ^0.7.0;
4+
pragma experimental ABIEncoderV2;
5+
6+
import "../thirdparty/chi/IChiToken.sol";
7+
8+
9+
contract ChiDiscount
10+
{
11+
struct ChiConfig
12+
{
13+
address gasTokenVault;
14+
uint maxToBurn;
15+
uint expectedGasRefund; // The amount of gas refunded by the tx itself. Setting this to 0 will work well.
16+
uint calldataCost; // The gas cost for the calldata itself. This is calculated as 16 * msg.data.length
17+
// in the contract when set to 0, but can be calculated perfectly offchain (
18+
// 16 gas for non-zero byte, 4 gas for zero byte).
19+
}
20+
21+
// See:
22+
// - https://github.com/1inch-exchange/1inchProtocol/blob/a7781cf9aa1cc2aaa5ccab0d54ecbae1327ca08f/contracts/OneSplitAudit.sol#L343
23+
// - https://github.com/curvefi/curve-ren-adapter/blob/8c1fbc3fec41ebd79b06984d72ff6ace3198e62d/truffle/contracts/CurveExchangeAdapter.sol#L104
24+
modifier discountCHI(
25+
address chiToken,
26+
ChiConfig calldata config
27+
)
28+
{
29+
uint gasStart = gasleft();
30+
31+
_;
32+
33+
if (chiToken == address(0) || config.maxToBurn == 0) return;
34+
35+
uint gasSpent = 21000 + gasStart - gasleft() + 14154;
36+
gasSpent += (config.calldataCost == 0) ? 16 * msg.data.length : config.calldataCost;
37+
uint gasRefundOffset = (config.expectedGasRefund * 2 > gasSpent) ? gasSpent : config.expectedGasRefund * 2;
38+
uint fullAmountToBurn = (gasSpent - gasRefundOffset) / 41947;
39+
uint amountToBurn = fullAmountToBurn > config.maxToBurn ? config.maxToBurn : fullAmountToBurn;
40+
41+
if (amountToBurn == 0) return;
42+
43+
if (config.gasTokenVault == address(0) || config.gasTokenVault == address(this)) {
44+
IChiToken(chiToken).freeUpTo(amountToBurn);
45+
} else {
46+
IChiToken(chiToken).freeFromUpTo(config.gasTokenVault, amountToBurn);
47+
}
48+
}
49+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
3+
pragma solidity ^0.7.0;
4+
5+
import "../../lib/ERC20.sol";
6+
7+
8+
abstract contract IChiToken is ERC20
9+
{
10+
function free(uint256 value)
11+
external
12+
virtual
13+
returns (uint256);
14+
15+
function freeUpTo(uint256 value)
16+
external
17+
virtual
18+
returns (uint256);
19+
20+
function freeFrom(address from, uint256 value)
21+
external
22+
virtual
23+
returns (uint256);
24+
25+
function freeFromUpTo(address from, uint256 value)
26+
external
27+
virtual
28+
returns (uint256 freed);
29+
}

packages/loopring_v3.js/src/exchange_v3.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ export class ExchangeV3 {
626626

627627
// Get the block data from the transaction data
628628
//const submitBlocksFunctionSignature = "0x8dadd3af"; // submitBlocks
629-
const submitBlocksFunctionSignature = "0xdcb2aa31"; // submitBlocksWithCallbacks
629+
const submitBlocksFunctionSignature = "0x937f369b"; // submitBlocksWithCallbacks
630630

631631
const transaction = await this.web3.eth.getTransaction(
632632
event.transactionHash
@@ -637,6 +637,7 @@ export class ExchangeV3 {
637637
[
638638
"bool",
639639
"bytes",
640+
"bytes",
640641
"bytes"
641642
/*{
642643
"struct CallbackConfig": {

packages/loopring_v3/circuit/Circuits/UniversalCircuit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ class SelectTransactionGadget : public BaseTransactionCircuit
9999
variables.push_back(da);
100100
// std::cout << "da size: " << variables.back().size() << std::endl;
101101
}
102-
publicDataSelects.emplace_back(pb, state.constants, selector, variables, FMT(annotation_prefix, ".publicDataSelects"));
102+
publicDataSelects.emplace_back(
103+
pb, state.constants, selector, variables, FMT(annotation_prefix, ".publicDataSelects"));
103104
}
104105
}
105106

packages/loopring_v3/circuit/Gadgets/MatchingGadgets.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -529,15 +529,19 @@ class SpotPriceAMMGadget : public GadgetT
529529
60,
530530
NUM_BITS_AMOUNT * 2,
531531
FMT(prefix, ".ratio")),
532-
ratioRangeCheck(pb, ratio.result(), NUM_BITS_AMOUNT*2 - 14 /*log2(10000)*/, FMT(prefix, ".ratioRangeCheck")),
532+
ratioRangeCheck(
533+
pb,
534+
ratio.result(),
535+
NUM_BITS_AMOUNT * 2 - 14 /*log2(10000)*/,
536+
FMT(prefix, ".ratioRangeCheck")),
533537
invFeeBips(pb, constants._10000, feeBips, FMT(prefix, ".invFeeBips")),
534538
res(
535539
pb,
536540
constants,
537541
ratio.result(),
538542
constants._10000,
539543
invFeeBips.result(),
540-
NUM_BITS_AMOUNT*2 - 14,
544+
NUM_BITS_AMOUNT * 2 - 14,
541545
14 /*log2(10000)*/,
542546
14 /*log2(10000)*/,
543547
FMT(prefix, ".res"))
@@ -870,7 +874,7 @@ class RequireAMMFillsGadget : public GadgetT
870874
pb,
871875
priceBefore.result(),
872876
priceAfter.result(),
873-
NUM_BITS_AMOUNT*2,
877+
NUM_BITS_AMOUNT * 2,
874878
FMT(prefix, ".priceBefore_leq_priceAfter")),
875879
requirePriceIncreased( //
876880
pb,

packages/loopring_v3/circuit/Gadgets/MathGadgets.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,11 @@ class ArraySelectGadget : public GadgetT
18521852
for (unsigned int i = 0; i < values.size(); i++)
18531853
{
18541854
results.emplace_back(
1855-
pb, selector[i], values[i], (i == 0) ? VariableArrayT(values[0].size(), _constants._0) : results.back().result(), FMT(prefix, ".results"));
1855+
pb,
1856+
selector[i],
1857+
values[i],
1858+
(i == 0) ? VariableArrayT(values[0].size(), _constants._0) : results.back().result(),
1859+
FMT(prefix, ".results"));
18561860
}
18571861
}
18581862

@@ -2239,8 +2243,7 @@ class PowerGadget : public GadgetT
22392243

22402244
for (unsigned int i = 2; i < iterations; i++)
22412245
{
2242-
bn.emplace_back(
2243-
pb, constants.fixedBase, constants.values[i], FMT(prefix, ".bn"));
2246+
bn.emplace_back(pb, constants.fixedBase, constants.values[i], FMT(prefix, ".bn"));
22442247
vn.emplace_back(
22452248
pb,
22462249
constants,

packages/loopring_v3/circuit/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,7 @@ int main(int argc, char **argv)
857857
Loopring::Circuit *circuit = createCircuit(blockType, blockSize, pb);
858858
if (config.swapAB)
859859
{
860-
//pb.constraint_system.swap_AB_if_beneficial();
860+
// pb.constraint_system.swap_AB_if_beneficial();
861861
}
862862
pb.constraint_system.constraints.shrink_to_fit();
863863
pb.values.shrink_to_fit();

packages/loopring_v3/contracts/aux/access/LoopringIOExchangeOwner.sol

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@ import "../../lib/Drainable.sol";
1212
import "../../lib/ERC1271.sol";
1313
import "../../lib/MathUint.sol";
1414
import "../../lib/SignatureUtil.sol";
15+
import "../gas/ChiDiscount.sol";
1516
import "./SelectorBasedAccessManager.sol";
1617
import "./IBlockReceiver.sol";
1718

1819

19-
contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainable
20+
contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ChiDiscount, ERC1271, Drainable
2021
{
2122
using AddressUtil for address;
2223
using AddressUtil for address payable;
@@ -25,8 +26,9 @@ contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainab
2526
using SignatureUtil for bytes32;
2627
using TransactionReader for ExchangeData.Block;
2728

28-
bytes4 private constant SUBMITBLOCKS_SELECTOR = IExchangeV3.submitBlocks.selector;
29-
bool public open;
29+
bytes4 private constant SUBMITBLOCKS_SELECTOR = IExchangeV3.submitBlocks.selector;
30+
bool public open;
31+
address public immutable chiToken;
3032

3133
event SubmitBlocksAccessOpened(bool open);
3234

@@ -50,9 +52,13 @@ contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainab
5052
address[] receivers;
5153
}
5254

53-
constructor(address _exchange)
55+
constructor(
56+
address _exchange,
57+
address _chiToken
58+
)
5459
SelectorBasedAccessManager(_exchange)
5560
{
61+
chiToken = _chiToken;
5662
}
5763

5864
function openAccessToSubmitBlocks(bool _open)
@@ -88,12 +94,17 @@ contract LoopringIOExchangeOwner is SelectorBasedAccessManager, ERC1271, Drainab
8894
return hasAccessTo(drainer, this.drain.selector);
8995
}
9096

97+
/// @dev chiConfig.expectedGasRefund shall be set to numDeposits * 15,000, and
98+
/// chiConfig.calldataCost shall be set to 16 * msg.data.length or calculated
99+
/// perfectly offchain (16 gas for non-zero byte, 4 gas for zero byte).
91100
function submitBlocksWithCallbacks(
92101
bool isDataCompressed,
93102
bytes calldata data,
94-
CallbackConfig calldata config
103+
CallbackConfig calldata config,
104+
ChiConfig calldata chiConfig
95105
)
96106
external
107+
discountCHI(chiToken, chiConfig)
97108
{
98109
if (config.blockCallbacks.length > 0) {
99110
require(config.receivers.length > 0, "MISSING_RECEIVERS");
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// Copyright 2017 Loopring Technology Limited.
3+
pragma solidity ^0.7.0;
4+
pragma experimental ABIEncoderV2;
5+
6+
import "../../thirdparty/chi/IChiToken.sol";
7+
8+
9+
contract ChiDiscount
10+
{
11+
struct ChiConfig
12+
{
13+
address gasTokenVault;
14+
uint maxToBurn;
15+
uint expectedGasRefund; // The amount of gas refunded by the tx itself. Setting this to 0 will work well.
16+
uint calldataCost; // The gas cost for the calldata itself. This is calculated as 16 * msg.data.length
17+
// in the contract when set to 0, but can be calculated perfectly offchain (
18+
// 16 gas for non-zero byte, 4 gas for zero byte).
19+
}
20+
21+
// See:
22+
// - https://github.com/1inch-exchange/1inchProtocol/blob/a7781cf9aa1cc2aaa5ccab0d54ecbae1327ca08f/contracts/OneSplitAudit.sol#L343
23+
// - https://github.com/curvefi/curve-ren-adapter/blob/8c1fbc3fec41ebd79b06984d72ff6ace3198e62d/truffle/contracts/CurveExchangeAdapter.sol#L104
24+
modifier discountCHI(
25+
address chiToken,
26+
ChiConfig calldata config
27+
)
28+
{
29+
uint gasStart = gasleft();
30+
31+
_;
32+
33+
if (chiToken == address(0) || config.maxToBurn == 0) return;
34+
35+
uint gasSpent = 21000 + gasStart - gasleft() + 14154;
36+
gasSpent += (config.calldataCost == 0) ? 16 * msg.data.length : config.calldataCost;
37+
uint gasRefundOffset = (config.expectedGasRefund * 2 > gasSpent) ? gasSpent : config.expectedGasRefund * 2;
38+
uint fullAmountToBurn = (gasSpent - gasRefundOffset) / 41947;
39+
uint amountToBurn = fullAmountToBurn > config.maxToBurn ? config.maxToBurn : fullAmountToBurn;
40+
41+
if (amountToBurn == 0) return;
42+
43+
if (config.gasTokenVault == address(0) || config.gasTokenVault == address(this)) {
44+
IChiToken(chiToken).freeUpTo(amountToBurn);
45+
} else {
46+
IChiToken(chiToken).freeFromUpTo(config.gasTokenVault, amountToBurn);
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)