Skip to content

Commit

Permalink
Dex bootstrap (#181)
Browse files Browse the repository at this point in the history
* impl DEXV2 to support bootstrap

* format

* fix
  • Loading branch information
wangjj9219 authored Sep 12, 2024
1 parent 95e0d85 commit 2b2a8ba
Show file tree
Hide file tree
Showing 18 changed files with 986 additions and 35 deletions.
14 changes: 7 additions & 7 deletions contracts/dex/DEX.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {IDEX} from "./IDEX.sol";
/// @dev This contracts will interact with dex pallet
contract DEX is IDEX {
/// @dev The DEX precompile address.
address private constant PRECOMPILE =
address internal constant PRECOMPILE =
address(0x0000000000000000000000000000000000000405);

/// @inheritdoc IDEX
Expand Down Expand Up @@ -66,7 +66,7 @@ contract DEX is IDEX {
address[] memory path,
uint256 supplyAmount
) public view override returns (uint256) {
for (uint i = 0; i < path.length; i++) {
for (uint256 i = 0; i < path.length; i++) {
require(path[i] != address(0), "DEX: token is zero address");
}
require(supplyAmount != 0, "DEX: supplyAmount is zero");
Expand All @@ -92,7 +92,7 @@ contract DEX is IDEX {
address[] memory path,
uint256 targetAmount
) public view override returns (uint256) {
for (uint i = 0; i < path.length; i++) {
for (uint256 i = 0; i < path.length; i++) {
require(path[i] != address(0), "DEX: token is zero address");
}
require(targetAmount != 0, "DEX: targetAmount is zero");
Expand All @@ -119,7 +119,7 @@ contract DEX is IDEX {
uint256 supplyAmount,
uint256 minTargetAmount
) public override returns (bool) {
for (uint i = 0; i < path.length; i++) {
for (uint256 i = 0; i < path.length; i++) {
require(path[i] != address(0), "DEX: token is zero address");
}
require(supplyAmount != 0, "DEX: supplyAmount is zero");
Expand All @@ -139,7 +139,7 @@ contract DEX is IDEX {
}
}

emit Swaped(
emit Swapped(
msg.sender,
path,
supplyAmount,
Expand All @@ -154,7 +154,7 @@ contract DEX is IDEX {
uint256 targetAmount,
uint256 maxSupplyAmount
) public override returns (bool) {
for (uint i = 0; i < path.length; i++) {
for (uint256 i = 0; i < path.length; i++) {
require(path[i] != address(0), "DEX: token is zero address");
}
require(targetAmount != 0, "DEX: targetAmount is zero");
Expand All @@ -174,7 +174,7 @@ contract DEX is IDEX {
}
}

emit Swaped(
emit Swapped(
msg.sender,
path,
abi.decode(returnData, (uint256)),
Expand Down
175 changes: 175 additions & 0 deletions contracts/dex/DEXV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.0;

import {DEX} from "./DEX.sol";
import {IBootstrap} from "./IBootstrap.sol";

/// @title DEX Predeploy Contract, V2, support bootstrap
/// @author Acala Developers
/// @notice You can use this predeploy contract to call dex pallet
/// @dev This contracts will interact with dex pallet
contract DEXV2 is DEX, IBootstrap {
/// @inheritdoc IBootstrap
function getProvisionPool(
address tokenA,
address tokenB
) public view override returns (uint256, uint256) {
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");

(bool success, bytes memory returnData) = PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getProvisionPool(address,address)",
tokenA,
tokenB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

return abi.decode(returnData, (uint256, uint256));
}

/// @inheritdoc IBootstrap
function getProvisionPoolOf(
address who,
address tokenA,
address tokenB
) public view override returns (uint256, uint256) {
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");

(bool success, bytes memory returnData) = PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getProvisionPoolOf(address,address,address)",
who,
tokenA,
tokenB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

return abi.decode(returnData, (uint256, uint256));
}

/// @inheritdoc IBootstrap
function getInitialShareExchangeRate(
address tokenA,
address tokenB
) public view override returns (uint256, uint256) {
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");

(bool success, bytes memory returnData) = PRECOMPILE.staticcall(
abi.encodeWithSignature(
"getInitialShareExchangeRate(address,address)",
tokenA,
tokenB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

return abi.decode(returnData, (uint256, uint256));
}

/// @inheritdoc IBootstrap
function addProvision(
address tokenA,
address tokenB,
uint256 amountA,
uint256 amountB
) public override returns (bool) {
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");
require(
amountA != 0 || amountB != 0,
"DEX: invalid contribution amount"
);

(bool success, bytes memory returnData) = PRECOMPILE.call(
abi.encodeWithSignature(
"addProvision(address,address,address,uint256,uint256)",
msg.sender,
tokenA,
tokenB,
amountA,
amountB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

emit AddProvision(msg.sender, tokenA, tokenB, amountA, amountB);
return true;
}

/// @inheritdoc IBootstrap
function claimDexShare(
address who,
address tokenA,
address tokenB
) public override returns (bool) {
require(who != address(0), "DEX: who is zero address");
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");

(bool success, bytes memory returnData) = PRECOMPILE.call(
abi.encodeWithSignature(
"claimDexShare(address,address,address)",
who,
tokenA,
tokenB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

emit ClaimShare(who, tokenA, tokenB, abi.decode(returnData, (uint256)));
return true;
}

/// @inheritdoc IBootstrap
function refundProvision(
address who,
address tokenA,
address tokenB
) public override returns (bool) {
require(who != address(0), "DEX: who is zero address");
require(tokenA != address(0), "DEX: tokenA is zero address");
require(tokenB != address(0), "DEX: tokenB is zero address");

(bool success, bytes memory returnData) = PRECOMPILE.call(
abi.encodeWithSignature(
"refundProvision(address,address,address)",
who,
tokenA,
tokenB
)
);
assembly {
if eq(success, 0) {
revert(add(returnData, 0x20), returndatasize())
}
}

return true;
}
}
101 changes: 101 additions & 0 deletions contracts/dex/IBootstrap.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.8.0;

/// @title IBootstrap Predeploy Contract Interface
/// @author Acala Developers
/// @notice You can use this predeploy contract to call the bootstrap functions of dex pallet
/// @dev The interface through which solidity contracts will interact with dex pallet
interface IBootstrap {
/// @notice AddProvision event.
/// @param sender The sender of the transaction.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @param amountA The amount of tokenA contribute to provision pool.
/// @param amountB The amount of tokenB contribute to provision pool.
event AddProvision(
address indexed sender,
address indexed tokenA,
address indexed tokenB,
uint256 amountA,
uint256 amountB
);

/// @notice Claim share event.
/// @param who The owner of the claimed share.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @param amount The amount of claimed share token.
event ClaimShare(
address indexed who,
address indexed tokenA,
address indexed tokenB,
uint256 amount
);

/// @notice Get total provision pool of the tokenA and tokenB.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @return Returns (provision_a, provision_b).
function getProvisionPool(
address tokenA,
address tokenB
) external view returns (uint256, uint256);

/// @notice Get who's provision of the tokenA and tokenB.
/// @param who The contributor.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @return Returns (provision_a, provision_b).
function getProvisionPoolOf(
address who,
address tokenA,
address tokenB
) external view returns (uint256, uint256);

/// @notice Get the initial share exchange rate of the ended provision pool of tokenA and tokenB. 100% = 1**18
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @return Returns (rateA, rateB).
function getInitialShareExchangeRate(
address tokenA,
address tokenB
) external view returns (uint256, uint256);

/// @notice Add provision to the bootstraping trading pair.
/// @dev It'll emit an {AddProvision} event.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @param amountA The amount of tokenA contribute to liquidity pool.
/// @param amountB The amount of tokenB contribute to liquidity pool.
/// @return Returns a boolean value indicating whether the operation succeeded.
function addProvision(
address tokenA,
address tokenB,
uint256 amountA,
uint256 amountB
) external returns (bool);

/// @notice Claim share token of the ended bootstrap trading pair for `who`.
/// @dev It'll emit an {ClaimShare} event.
/// @param who The contributor.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @return Returns a boolean value indicating whether the operation succeeded.
function claimDexShare(
address who,
address tokenA,
address tokenB
) external returns (bool);

/// @notice Refund the contribution token of the aborted bootstrap trading pair for `who`.
/// @param who The contributor.
/// @param tokenA The ERC20 address of the tokenA.
/// @param tokenB The ERC20 address of the tokenB.
/// @return Returns a boolean value indicating whether the operation succeeded.
function refundProvision(
address who,
address tokenA,
address tokenB
) external returns (bool);
}
8 changes: 4 additions & 4 deletions contracts/dex/IDEX.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ pragma solidity ^0.8.0;
/// @notice You can use this predeploy contract to call dex pallet
/// @dev The interface through which solidity contracts will interact with dex pallet
interface IDEX {
/// @notice Swaped event with DEX.
/// @notice Swapped event with DEX.
/// @param sender The sender of the transaction.
/// @param path The trading path of the swap transaction.
/// @param supplyAmount The exact supply amount.
/// @param targetAmount The exact target amount.
event Swaped(
event Swapped(
address indexed sender,
address[] path,
uint256 supplyAmount,
Expand Down Expand Up @@ -82,7 +82,7 @@ interface IDEX {
) external view returns (uint256);

/// @notice Swap with exact supply.
/// @dev It'll emit an {Swaped} event.
/// @dev It'll emit an {Swapped} event.
/// @param path The trading path of the swap transaction.
/// @param supplyAmount The exact gsupply amount.
/// @param minTargetAmount The acceptable minimum target amount.
Expand All @@ -94,7 +94,7 @@ interface IDEX {
) external returns (bool);

/// @notice Swap with exact target.
/// @dev It'll emit an {Swaped} event.
/// @dev It'll emit an {Swapped} event.
/// @param path The trading path of the swap transaction.
/// @param targetAmount The exact target amount.
/// @param maxSupplyAmount The acceptable maximum supply amount.
Expand Down
Loading

0 comments on commit 2b2a8ba

Please sign in to comment.