Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BNB network support and enhance token handling #566

Merged
merged 12 commits into from
Dec 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions SmartContracts/contracts/dex/ChainbrarySwapFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,39 @@ import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
contract ChainbrarySwapFactory is Ownable, Initializable {
mapping(address => mapping(address => mapping(uint24 => address))) public getPool;
uint24[] public feeTiers;
address public devAddress;

event PoolCreated(address indexed tokenA, address indexed tokenB, uint24 fee, address pool);

constructor() Ownable(_msgSender()) {}

function initialize() external initializer onlyOwner {
feeTiers = [500, 3000, 10000];
devAddress = _msgSender();
}

function createPool(address tokenA, address tokenB, uint24 fee) external returns (address pool) {
require(tokenA != tokenB, "Identical tokens");
require(tokenA != address(0) && tokenB != address(0), "Zero address");
require(getPool[tokenA][tokenB][fee] == address(0), "Pool exists");
require(tokenA != address(0) || tokenB != address(0), "Zero address");
require(
getPool[tokenA][tokenB][fee] == address(0) || getPool[tokenB][tokenA][fee] == address(0),
"Pool exists"
);

// Deploy the Pool contract
Pool newPool = new Pool();

// Initialize the Pool contract
newPool.initialize(tokenA, tokenB, fee);
newPool.initialize(tokenA, tokenB, fee, _msgSender());
pool = address(newPool);

getPool[tokenA][tokenB][fee] = pool;
getPool[tokenB][tokenA][fee] = pool;

emit PoolCreated(tokenA, tokenB, fee, pool);
}

function setDevAddress(address _devAddress) external onlyOwner {
devAddress = _devAddress;
}
}
5 changes: 5 additions & 0 deletions SmartContracts/contracts/dex/ChainbrarySwapRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ contract ChainbrarySwapRouter is Ownable, ReentrancyGuard, Initializable {

event CrossChainSwapInitiated(address indexed sender, address indexed receiver, bytes32 messageId);
event CrossChainSwapReceived(address indexed receiver, bytes32 messageId);
event Received(address sender, uint amount);

constructor() Ownable(_msgSender()) {}

Expand Down Expand Up @@ -193,4 +194,8 @@ contract ChainbrarySwapRouter is Ownable, ReentrancyGuard, Initializable {
function updateCCIPRouter(address _ccipRouter) external onlyOwner {
ccipRouter = _ccipRouter;
}

receive() external payable {
emit Received(_msgSender(), msg.value);
}
}
29 changes: 19 additions & 10 deletions SmartContracts/contracts/dex/Pool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ contract Pool is Ownable, ReentrancyGuard, Initializable {
address public token0;
address public token1;
uint24 public fee; // Fee in hundredths of a bip
address public devAddress;

uint256 public reserve0;
uint256 public reserve1;
Expand All @@ -26,13 +27,19 @@ contract Pool is Ownable, ReentrancyGuard, Initializable {

constructor() Ownable(_msgSender()) {}

function initialize(address _token0, address _token1, uint24 _fee) external initializer onlyOwner {
function initialize(
address _token0,
address _token1,
uint24 _fee,
address _devAddress
) external initializer onlyOwner {
require(_token0 != _token1, "Tokens must be different");
require(_fee > 0 && _fee < 1000000, "Invalid fee");

token0 = _token0;
token1 = _token1;
fee = _fee;
devAddress = _devAddress;
}

function addLiquidity(uint256 amount0, uint256 amount1) external payable nonReentrant {
Expand Down Expand Up @@ -74,16 +81,17 @@ contract Pool is Ownable, ReentrancyGuard, Initializable {

require(userLiquidity0 > 0 && userLiquidity1 > 0, "No liquidity provided by user");

uint256 amount0 = Math.min(userLiquidity0, (liquidity * reserve0) / (reserve0 + reserve1));
uint256 amount1 = Math.min(userLiquidity1, (liquidity * reserve1) / (reserve0 + reserve1));
uint256 totalLiquidity = userLiquidity0 + userLiquidity1;
uint256 amount0 = (liquidity * reserve0) / totalLiquidity;
uint256 amount1 = (liquidity * reserve1) / totalLiquidity;

require(amount0 > 0 && amount1 > 0, "Insufficient liquidity to withdraw");

reserve0 -= amount0;
reserve1 -= amount1;

liquidityProvided0[_msgSender()] -= amount0;
liquidityProvided1[_msgSender()] -= amount1;
liquidityProvided0[_msgSender()] -= (liquidity * userLiquidity0) / totalLiquidity;
liquidityProvided1[_msgSender()] -= (liquidity * userLiquidity1) / totalLiquidity;

if (token0 == address(0)) {
payable(_msgSender()).transfer(amount0);
Expand Down Expand Up @@ -130,23 +138,24 @@ contract Pool is Ownable, ReentrancyGuard, Initializable {
uint256 feeAmount = amountIn - amountInWithFee;
// Transfer the fee to the contract owner
if (tokenIn == address(0)) {
payable(owner()).transfer(feeAmount);
payable(devAddress).transfer(feeAmount);
} else {
IERC20(tokenIn).safeTransfer(owner(), feeAmount);
IERC20(tokenIn).safeTransfer(devAddress, feeAmount);
}

// Update the reserves based on the input and output amounts
if (tokenIn == token0) {
reserve0 += amountIn;
reserve0 += amountInWithFee;
reserve1 -= amountOut;
} else {
reserve1 += amountIn;
reserve1 += amountInWithFee;
reserve0 -= amountOut;
}

// Transfer the output tokens to the recipient
if (tokenOut == address(0)) {
payable(to).transfer(amountOut);
bool success = payable(to).send(amountOut);
require(success, "Transfer failed");
} else {
IERC20(tokenOut).safeTransfer(to, amountOut);
}
Expand Down
18 changes: 13 additions & 5 deletions SmartContracts/test/ChainbrarySwapFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('ChainbrarySwapFactory', function () {
await createPoolTx.wait();

const poolAddress: string = await chainbrarySwapFactoryInstance.getPool(TOKEN_1_ADDRESS, TOKEN_2_ADDRESS, FEE_TIER_1);
expect(poolAddress).to.properAddress;
expect(poolAddress).to.be.properAddress;

// Verify that the pool has been created and stored in the mapping for both token pairs
expect(await chainbrarySwapFactoryInstance.getPool(TOKEN_1_ADDRESS, TOKEN_2_ADDRESS, FEE_TIER_1)).to.equal(poolAddress);
Expand All @@ -66,10 +66,18 @@ describe('ChainbrarySwapFactory', function () {
.to.be.revertedWith('Pool exists');
});

it('should fail to create a pool if one of the token addresses is zero', async () => {
it('should create a pool with a native token', async () => {
const { chainbrarySwapFactoryInstance, owner } = await loadFixture(deployChainbrarySwapFactoryFixture);

await expect(chainbrarySwapFactoryInstance.connect(owner).createPool(ethers.ZeroAddress, TOKEN_2_ADDRESS, FEE_TIER_1))
.to.be.revertedWith('Zero address');
});
// Create pool for TOKEN_1_ADDRESS and ETH with FEE_TIER_1
const createPoolTx: ContractTransactionResponse = await chainbrarySwapFactoryInstance.connect(owner).createPool(TOKEN_1_ADDRESS, ethers.ZeroAddress, FEE_TIER_1);
await createPoolTx.wait();

const poolAddress: string = await chainbrarySwapFactoryInstance.getPool(TOKEN_1_ADDRESS, ethers.ZeroAddress, FEE_TIER_1);
expect(poolAddress).to.properAddress;

// Verify that the pool has been created and stored in the mapping for both token pairs
expect(await chainbrarySwapFactoryInstance.getPool(TOKEN_1_ADDRESS, ethers.ZeroAddress, FEE_TIER_1)).to.equal(poolAddress);
expect(await chainbrarySwapFactoryInstance.getPool(ethers.ZeroAddress, TOKEN_1_ADDRESS, FEE_TIER_1)).to.equal(poolAddress);
})
});
Loading
Loading