챌린지 3부터는 프로필에 Builder라는 태그가 부착되고 개발자들 풀에 참여해 팀원을 찾거나 서로 정보를 공유하는 커뮤니티에 접근할 수 있게 됩니다.
Checkpoint 0: install
템플릿 프로젝트 파일을 설치해 주겠습니다.
git clone https://github.com/squirtleDevs/scaffold-eth.git challenge-3-single-pool-dex
cd scaffold-eth
git checkout challenge-3-single-pool-dex
yarn install
Checkpoint 1: Environment
리액트, 하드햇 로컬 체인, 배포를 진행해줍니다.
yarn start
yarn chain
yarn deploy
Checkpoint 2: Reserves
만들고 있는 이 Dex는 간단하게 ETH와 Balloons라는 2개의 코인만의 스왑을 할 것입니다.
DEX.sol 에서 유동성을 관리하기 위한 변수를 선언합니다.
uint256 public totalLiquidity;
mapping(address => uint256) liquidity;
초기 상태를 지정하기 위한 init 함수를 작성합니다.
function init(uint256 tokens) public payable returns (uint256) {
require(totalLiquidity == 0, "initialize already initiated");
totalLiquidity = msg.value;
liquidity[msg.sender] = msg.value;
bool sent = token.transferFrom(msg.sender, address(this), tokens);
require(sent, "transaction failed.");
return totalLiquidity;
}
코드를 보면 앞서 선언한 totalLiquidity와 liquidity에 msg.value를 사용하는데 이는 이더리움만을 저장합니다.
Ballons 토큰에 대한 liquidity는 Balloons token 객체가 erc20 인터페이스를 상속하기 때문에. balanceOf로 소유량을 확인할 수 있습니다.
deploy 스크립트를 수정합니다.
// uncomment to init DEX on deploy:
console.log("Approving DEX ("+dex.address+") to take Balloons from main account...")
// If you are going to the testnet make sure your deployer account has enough ETH
await balloons.approve(dex.address,ethers.utils.parseEther('100'));
console.log("INIT exchange...")
await dex.init(""+(3*10**18),{value:ethers.utils.parseEther('3'),gasLimit:200000})
Checkpoint 3: Price
스왑 할 가격을 정하는 price 함수를 작성합니다.
function price(
uint256 xInput,
uint256 xReserves,
uint256 yReserves
) public view returns (uint256 yOutput) {
uint256 xInput_with_fee = xInput.mul(997);
uint256 numerator = xInput_with_fee.mul(yReserves);
uint256 denominator = xReserves.mul(1000).add(xInput_with_fee);
return numerator / denominator;
}
price 함수의 가격 공식은 설명을 참조하시면 됩니다.
Checkpoint 4: Trading
swap을 수행하는 함수를 작성합니다.
function ethToToken() public payable returns (uint256 tokenOutput) {
uint256 token_reserve = token.balanceOf(address(this));
uint256 token_bought = price(msg.value, address(this).balance.sub(msg.value), token_reserve);
require(token.transfer(msg.sender, token_bought));
emit EthToTokenSwap();
return token_bought;
}
function tokenToEth(uint256 tokenInput) public returns (uint256 ethOutput) {
uint256 token_reserve = token.balanceOf((address(this)));
uint256 eth_bought = price(tokenInput, token_reserve, address(this).balance);
(bool sent, ) = msg.sender.call{value: eth_bought}("");
require(sent, "Failed to send user eth.");
require(token.transferFrom(msg.sender, address(this), tokenInput));
emit TokenToEthSwap();
return eth_bought;
}
Checkpoint 5: Liquidity
function deposit() public payable returns (uint256 tokensDeposited) {
uint256 eth_reserve = address(this).balance.sub(msg.value);
uint256 token_reserve = token.balanceOf(address(this));
uint256 token_amount = (msg.value.mul(totalLiquidity)/ eth_reserve).add(1);
uint256 liquidity_minted = msg.value.mul(totalLiquidity) / eth_reserve;
liquidity[msg.sender] = liquidity[msg.sender].add(liquidity_minted);
totalLiquidity = totalLiquidity.add(liquidity_minted);
require(token.transferFrom(msg.sender, address(this), token_amount));
// emit LiquidityProvided();
return liquidity_minted;
}
/**
* @notice allows withdrawal of $BAL and $ETH from liquidity pool
* NOTE: with this current code, the msg caller could end up getting very little back if the liquidity is super low in the pool. I guess they could see that with the UI.
*/
function withdraw(uint256 amount) public returns (uint256 eth_amount, uint256 token_amount) {
uint256 token_reserve = token.balanceOf(address(this));
uint256 eth_amount = amount.mul(address(this).balance) / totalLiquidity;
uint256 token_amount = amount.mul(token_reserve) / totalLiquidity;
liquidity[msg.sender] = liquidity[msg.sender].sub(eth_amount);
totalLiquidity = totalLiquidity.sub(eth_amount);
(bool sent, ) = msg.sender.call{value : eth_amount}("");
require(sent, "Failed to send user eth.");
require(token.transfer(msg.sender, token_amount));
// emit LiquidityRemoved();
return (eth_amount, token_amount);
}
추가적으로 위에 작성한 함수들의 이벤트와 approve 또한 events를 프론트에 표시해주시면 기본 챌린지는 완료입니다.
'블록체인 > 이더리움' 카테고리의 다른 글
ABI란? (0) | 2022.05.21 |
---|---|
트랜잭션 (0) | 2022.05.19 |
[SpeedRunEthereum] Challenge 2 [Token Vendor] (0) | 2022.05.16 |
[SpeedRunEthereum] Challenge 1[Decentralized Staking App] (0) | 2022.05.15 |
[SpeedRunEthereum] Challenge 0[Simple NFT Example] (0) | 2022.05.13 |