Ver2.0 ๐ ๋ธ๋ก์ฒด์ธ ๊ธฐ๋ฐ ๋ถ์ฐํ ๊ฑฐ๋์(DEX) ๊ตฌ์ถํ๊ธฐ: ์ค์ํ์ ๊ตด๋ ๋ฅผ ๋ฒ์ด๋ ๊ธ์ต์ ๋ฏธ๋ ๐

๐ ๋ธ๋ก์ฒด์ธ ๊ธฐ๋ฐ ๋ถ์ฐํ ๊ฑฐ๋์(DEX) ๊ตฌ์ถํ๊ธฐ: ์ค์ํ์ ๊ตด๋ ๋ฅผ ๋ฒ์ด๋ ๊ธ์ต์ ๋ฏธ๋ ๐
์๋ ํ์ธ์, ๋ธ๋ก์ฒด์ธ ๋ํ ์ฌ๋ฌ๋ถ! ๐ ์ค๋์ ์ ๋ง ํซํ ์ฃผ์ , ๋ธ๋ก์ฒด์ธ ๊ธฐ๋ฐ ๋ถ์ฐํ ๊ฑฐ๋์(DEX)์ ๋ํด ํจ๊ป ์์๋ณผ๊ฒ์. ์์ฆ ๋ํ์ด(DeFi)๊ฐ ๋์ธ์ธ ๊ฑฐ ๋ค๋ค ์์์ฃ ? ๊ทธ ์ค์ฌ์ DEX๊ฐ ์๋ค๋ ์ฌ์ค! ์ค์ํ ๊ฑฐ๋์์ ์ง๊ฐ ๋งก๊ธฐ๊ณ "์ ์ ๋ฐ ํดํน ๋นํ์ง ๋ง์์ค~" ํ๊ณ ๊ธฐ๋ํ๋ ์๋๋ ์ด์ ๋! ์ฌ๋ฌ๋ถ๋ ์ง์ DEX๋ฅผ ๊ตฌ์ถํด๋ณผ ์ ์๋ค๋ฉด ์ด๋จ๊น์? ใ ใ ใ
์ด ๊ธ์์๋ DEX์ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถํฐ ์์ํด์ ์ค์ ๊ตฌ์ถ ๋ฐฉ๋ฒ๊น์ง ์ด๋ณด์๋ ์ดํดํ ์ ์๊ฒ ์ค๋ช ํด๋๋ฆด๊ฒ์. ์ฝ๋ ์์ ๋ ์์ผ๋ ๋ฐ๋ผ์ค๋ฉด์ "์ ์ด๊ฒ ๋๋ค?" ํ๋ ๊ฒฝํ์ ํจ๊ป ํด๋ด์! ์ฌ๋ฅ๋ท์์๋ ๋ธ๋ก์ฒด์ธ ๊ด๋ จ ์ฌ๋ฅ ๊ฑฐ๋๊ฐ ํ๋ฐํ๋ฐ, ์ด ๊ธ์ ํตํด ์ฌ๋ฌ๋ถ๋ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ์๋ก ๊ฑฐ๋ญ๋ ์ ์์ ๊ฑฐ์์! ๐ฅ
๐ ๋ชฉ์ฐจ
- DEX๋ ๋ฌด์์ธ๊ฐ? ์ค์ํ ๊ฑฐ๋์(CEX)์์ ์ฐจ์ด์
- DEX์ ์๋ ์๋ฆฌ์ ํต์ฌ ๊ธฐ์ ์์
- DEX ๊ตฌ์ถ์ ์ํ ์ค๋น ๋จ๊ณ
- ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐํ๊ธฐ
- ํ๋ก ํธ์๋ ์ธํฐํ์ด์ค ๊ตฌํ
- ์ ๋์ฑ ํ ์ค๊ณ ๋ฐ ๊ตฌํ
- ํ ์คํ ๋ฐ ๋ณด์ ๊ฐ์ฌ
- DEX ์ถ์ ๋ฐ ์ด์ ์ ๋ต
- ๋ฏธ๋ ์ ๋ง ๋ฐ ๋ฐ์ ๋ฐฉํฅ
1. DEX๋ ๋ฌด์์ธ๊ฐ? ์ค์ํ ๊ฑฐ๋์(CEX)์์ ์ฐจ์ด์ ๐ค
DEX๋ Decentralized Exchange์ ์ฝ์๋ก, ์ค๊ฐ์ ์์ด P2P ๋ฐฉ์์ผ๋ก ์ํธํํ๋ฅผ ๊ฑฐ๋ํ ์ ์๋ ํ๋ซํผ์ด์์. ๊ธฐ์กด์ ์ค์ํ ๊ฑฐ๋์(CEX)์๋ ์์ ํ ๋ค๋ฅธ ํจ๋ฌ๋ค์์ธ๋ฐ, ์ด ์ฐจ์ด๋ฅผ ์ฝ๊ฒ ์ดํดํด๋ณด์๋ฉด...
๐ฆ ์ค์ํ ๊ฑฐ๋์(CEX) vs ๐ ๋ถ์ฐํ ๊ฑฐ๋์(DEX)
๐ ์์ฐ ๊ด๋ฆฌ
CEX: "๋ด ์ฝ์ธ์ ๋ด ์ฝ์ธ์ด ์๋๋ค" ใ ใ ใ ๊ฑฐ๋์๊ฐ ์ฌ๋ฌ๋ถ์ ์์ฐ์ ๋ณด๊ดํด์. FTX ์ฌํ ๊ธฐ์ต๋์์ฃ ? ๐ฑ
DEX: "๋ด ์ง๊ฐ์ ์ง์ง ๋ด ๊ฒ!" ์ฌ์ฉ์๊ฐ ์์ ์ ๊ฐ์ธ ์ง๊ฐ์์ ์ง์ ๊ฑฐ๋ํ๋ฏ๋ก ์์ฐ์ ๋ํ ์์ ํ ํต์ ๊ถ์ ๊ฐ์ ธ์.
๐ก๏ธ ๋ณด์
CEX: ์ค์ ์๋ฒ๊ฐ ํดํน ํ๊ฒ์ด ๋ ์ ์์ด์. "๋จ์ผ ์คํจ ์ง์ "์ด๋ผ๋ ์น๋ช ์ ์ธ ์ฝ์ ์ด ์์ฃ .
DEX: ๋ธ๋ก์ฒด์ธ์ ๋ถ์ฐํ๋ ํน์ฑ ๋๋ถ์ ํดํน์ด ํจ์ฌ ์ด๋ ค์์. ์ค๋งํธ ์ปจํธ๋ํธ ์์ฒด์ ์ทจ์ฝ์ ์ ์์ ์ ์์ง๋ง, ์ค์ ์๋ฒ๋ฅผ ๊ณต๊ฒฉํ ์ ์์ด์.
๐ ํฌ๋ช ์ฑ
CEX: "๋ฏฟ์ด์ฃผ์ธ์~" ๋ฐฉ์์ ๋ธ๋๋ฐ์ค ์ด์. ๋ด๋ถ์์ ๋ญ๊ฐ ์ผ์ด๋๋์ง ์ ์ ์์ด์.
DEX: "์ฝ๋๊ฐ ๋ฒ์ด๋ค!" ๋ชจ๋ ๊ฑฐ๋๊ฐ ๋ธ๋ก์ฒด์ธ์ ๊ธฐ๋ก๋๊ณ , ์ค๋งํธ ์ปจํธ๋ํธ ์ฝ๋๋ ๊ณต๊ฐ๋์ด ์์ด์.
๐งพ KYC/AML
CEX: "์ ๋ถ์ฆ ์ฃผ์ธ์~" ๊ท์ ์ค์๋ฅผ ์ํ ์ ์ ํ์ธ ์ ์ฐจ๊ฐ ํ์์์.
DEX: "์ต๋ช ์ฑ ๋ง์ธ!" ๋๋ถ๋ถ์ DEX๋ ์ ์ ํ์ธ ์์ด ์ง๊ฐ ์ฃผ์๋ง์ผ๋ก ๊ฑฐ๋ ๊ฐ๋ฅํด์.
DEX์ ์ธ๊ธฐ๊ฐ ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํ๋ ์ด์ ๋ ๋ฐ๋ก ์ด๋ฐ ํ์ค์ํ, ์์ฐ ์ฃผ๊ถ, ํฌ๋ช ์ฑ ๋๋ฌธ์ด์์. ํนํ 2020๋ ์ดํ DeFi ์ดํ๊ณผ ํจ๊ป Uniswap, SushiSwap, PancakeSwap ๊ฐ์ DEX๋ค์ด ์์ฒญ๋ ์ฑ์ฅ์ ์ด๋ค์ด์. ์ด์ ์ฐ๋ฆฌ๋ ์ด๋ฐ DEX๋ฅผ ๋ง๋ค์ด๋ณผ ์ฐจ๋ก! ๐
2. DEX์ ์๋ ์๋ฆฌ์ ํต์ฌ ๊ธฐ์ ์์ โ๏ธ
DEX๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ๊ถ๊ธํ์์ฃ ? ์ค์ ์๋ฒ ์์ด ์ด๋ป๊ฒ ๊ฑฐ๋๊ฐ ์ด๋ฃจ์ด์ง๊น์? ๊ทธ ๋น๋ฐ์ ์ค๋งํธ ์ปจํธ๋ํธ์ ์๋ํ๋ ๋ง์ผ ๋ฉ์ด์ปค(AMM) ์์คํ ์ ์์ด์!
๐ DEX์ ์ฃผ์ ์๋ ๋ฐฉ์
- ์๋ํ๋ ๋ง์ผ ๋ฉ์ด์ปค(AMM) ๋ชจ๋ธ: ๊ฐ์ฅ ์ธ๊ธฐ ์๋ DEX ๋ชจ๋ธ์ด์์. ์ฃผ๋ฌธ์ฅ(Order Book) ๋์ ์ ๋์ฑ ํ์ ์ฌ์ฉํด ์๋์ผ๋ก ๊ฐ๊ฒฉ์ ๊ฒฐ์ ํด์. x * y = k ๊ณต์(์์ ๊ณฑ ๊ณต์)์ ๊ธฐ๋ฐ์ผ๋ก ํด์.
- ์ฃผ๋ฌธ์ฅ(Order Book) ๋ชจ๋ธ: ์ ํต์ ์ธ ๊ฑฐ๋์์ ๋น์ทํ๊ฒ ๋งค์/๋งค๋ ์ฃผ๋ฌธ์ ๋งค์นญ์ํค๋ ๋ฐฉ์์ด์์. ํ์ง๋ง ์ด ๋ชจ๋ธ์ ๋ธ๋ก์ฒด์ธ์์ ๊ตฌํํ๊ธฐ ๊น๋ค๋ก์์ AMM๋ณด๋ค ๋ ์ธ๊ธฐ ์์ด์.
- ํ์ด๋ธ๋ฆฌ๋ ๋ชจ๋ธ: ์ ๋ ๋ชจ๋ธ์ ์ฅ์ ์ ๊ฒฐํฉํ ๋ฐฉ์์ด์์. ์ต๊ทผ์๋ ์ด๋ฐ ํ์ด๋ธ๋ฆฌ๋ ์ ๊ทผ๋ฒ์ด ๋์ด๋๊ณ ์์ด์.
๐งฉ DEX์ ํต์ฌ ๊ธฐ์ ์์
๐ ์ค๋งํธ ์ปจํธ๋ํธ
DEX์ ์ฌ์ฅ์ด๋ผ๊ณ ํ ์ ์์ด์! ์๋์ผ๋ก ๊ฑฐ๋๋ฅผ ์คํํ๊ณ ์ ๋์ฑ ํ์ ๊ด๋ฆฌํ๋ ์์จ ํ๋ก๊ทธ๋จ์ด์์. ์ด๋๋ฆฌ์์ ๊ฒฝ์ฐ Solidity ์ธ์ด๋ก ์์ฑ๋์ฃ .
๐ง ์ ๋์ฑ ํ
๊ฑฐ๋์ ํ์ํ ํ ํฐ ์์ ๋ณด๊ดํ๋ ์ค๋งํธ ์ปจํธ๋ํธ์์. ์ ๋์ฑ ๊ณต๊ธ์(LP)๋ค์ด ํ ํฐ์ ์์นํ๋ฉด ๊ทธ ๋๊ฐ๋ก LP ํ ํฐ์ ๋ฐ์์.
๐ ํ ํฐ ์ค์ ๋ฉ์ปค๋์ฆ
ํ ํ ํฐ์์ ๋ค๋ฅธ ํ ํฐ์ผ๋ก ๊ตํํ๋ ํต์ฌ ๊ธฐ๋ฅ์ด์์. AMM ๋ชจ๋ธ์์๋ ์์ ๊ณฑ ๊ณต์(x * y = k)์ ์ฌ์ฉํด ๊ฐ๊ฒฉ์ ๊ฒฐ์ ํด์.
๐ ์ง๊ฐ ์ฐ๊ฒฐ
MetaMask, WalletConnect ๊ฐ์ ์น3 ์ง๊ฐ๊ณผ ์ฐ๋ํด ์ฌ์ฉ์๊ฐ ์ง์ ์์ฐ์ ํต์ ํ ์ ์๊ฒ ํด์.
โฝ ๊ฐ์ค๋น ์ต์ ํ
์ด๋๋ฆฌ์ ๊ฐ์ ๋ธ๋ก์ฒด์ธ์์๋ ๊ฑฐ๋ ์์๋ฃ(๊ฐ์ค๋น)๊ฐ ์ค์ํด์. ํจ์จ์ ์ธ ์ปจํธ๋ํธ ์ค๊ณ๋ก ๊ฐ์ค๋น๋ฅผ ์ต์ํํด์ผ ํด์.
์ด๋ฐ ๊ธฐ์ ์์๋ค์ด ๋ชจ์ฌ DEX๋ผ๋ ๋ฉ์ง ์ํ๊ณ๋ฅผ ๋ง๋ค์ด๋ด์. ์ง์ง ์ ๊ธฐํ์ง ์๋์? ์ค์ ์๋ฒ ์์ด๋ ์ด๋ฐ ๋ณต์กํ ๊ธ์ต ์์คํ ์ด ๋์๊ฐ๋ค๋! ๐ฒ ์ด์ ์ฐ๋ฆฌ๋ ์ด๋ฐ DEX๋ฅผ ๋ง๋ค์ด๋ณผ ์ค๋น๊ฐ ๋์ด์!
3. DEX ๊ตฌ์ถ์ ์ํ ์ค๋น ๋จ๊ณ ๐ ๏ธ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก DEX๋ฅผ ๋ง๋ค์ด๋ณผ๊น์? ๊ทธ์ ์ ํ์ํ ์ค๋น๋ฌผ๋ถํฐ ์ฑ๊ฒจ๋ด์! ๋ง์น ์๋ฆฌ ํ๋ก๊ทธ๋จ์์ ์ฌ๋ฃ ์๊ฐํ๋ ๊ฒ์ฒ๋ผ์~ ใ ใ ใ
๐งฐ ๊ฐ๋ฐ ํ๊ฒฝ ์ค์
DEX ๊ฐ๋ฐ์ ์ํ ๊ธฐ๋ณธ ๋๊ตฌ๋ค์ด์์. ์ด๊ฒ๋ค ์์ด๋ ์์๋ ๋ชป ํด์!
- Node.js & npm: ์๋ฐ์คํฌ๋ฆฝํธ ๋ฐํ์ ํ๊ฒฝ๊ณผ ํจํค์ง ๊ด๋ฆฌ์์์.
- Truffle/Hardhat: ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ, ํ ์คํธ, ๋ฐฐํฌ๋ฅผ ์ํ ํ๋ ์์ํฌ์์. ์์ฆ์ Hardhat์ด ๋ ํซํด์! ๐ฅ
- Ganache: ๋ก์ปฌ ์ด๋๋ฆฌ์ ๋ธ๋ก์ฒด์ธ ํ๊ฒฝ์ ์ ๊ณตํด์. ํ ์คํธํ ๋ ์ง์ง ์ ์ฉํด์!
- MetaMask: ๋ธ๋ผ์ฐ์ ์ง๊ฐ ํ์ฅ ํ๋ก๊ทธ๋จ์ด์์. ๊ฐ๋ฐ ์ค์๋ ์ค์ ์ฌ์ฉ์์ฒ๋ผ ํ ์คํธํ ์ ์์ด์.
- Web3.js/ethers.js: ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ด๋๋ฆฌ์ ๋ธ๋ก์ฒด์ธ๊ณผ ์ํธ์์ฉํ ์ ์๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์.
- React/Vue.js: ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ์ํ ์๋ฐ์คํฌ๋ฆฝํธ ํ๋ ์์ํฌ์์.
์ด๋ฐ ๋๊ตฌ๋ค์ ์ค์นํ๋ ๋ฐฉ๋ฒ์ ๊ฐ๋จํด์. ํฐ๋ฏธ๋์์ ๋ค์๊ณผ ๊ฐ์ด ์ ๋ ฅํ๋ฉด ๋ผ์:
// Node.js ์ค์น ํ
npm install -g truffle
npm install -g ganache-cli
npm install web3
// ๋๋ ์ต๊ทผ ํธ๋ ๋์ธ Hardhat ์ฌ์ฉ
npm install --save-dev hardhat
๐ ํ์ํ ์ง์๊ณผ ๊ธฐ์
DEX ๊ฐ๋ฐ์ ๊ฝค ๋ณต์กํด์. ๋ค์ ์ง์๋ค์ด ์์ผ๋ฉด ํจ์ฌ ์์ํ ๊ฑฐ์์:
- ๋ธ๋ก์ฒด์ธ ๊ธฐ์ด ์ดํด: ๋ธ๋ก์ฒด์ธ์ด ์ด๋ป๊ฒ ์๋ํ๋์ง, ํธ๋์ญ์ ์ ์ด๋ป๊ฒ ์ฒ๋ฆฌ๋๋์ง ์์์ผ ํด์.
- Solidity ํ๋ก๊ทธ๋๋ฐ: ์ด๋๋ฆฌ์ ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ ์ธ์ด์์. DEX์ ํต์ฌ ๋ก์ง์ ๊ตฌํํ๋ ๋ฐ ํ์์ ์ด์์.
- JavaScript/TypeScript: ํ๋ก ํธ์๋์ ๋ฐฑ์๋ ๊ฐ๋ฐ์ ํ์ํด์.
- DeFi ํ๋กํ ์ฝ ์ดํด: AMM, ์ ๋์ฑ ํ, ํ ํฐ ์ด์ฝ๋ ธ๋ฏน์ค ๋ฑ์ ๊ฐ๋ ์ ์ดํดํด์ผ ํด์.
- ๋ณด์ ์ง์: ์ค๋งํธ ์ปจํธ๋ํธ ์ทจ์ฝ์ , ๋ฆฌ์ํธ๋ฐ์ ๊ณต๊ฒฉ ๋ฑ ๋ณด์ ์ํ์ ์์์ผ ํด์.
์ด๋ฐ ์ง์์ด ๋ถ์กฑํ๋ค๊ณ ์? ๊ฑฑ์ ๋ง์ธ์! ์ฌ๋ฅ๋ท์์ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ ๊ด๋ จ ์ฌ๋ฅ์ ์ฐพ์๋ณด๋ฉด ๋ง์ ๋์์ ๋ฐ์ ์ ์์ ๊ฑฐ์์. ์ ๋ฌธ๊ฐ๋ค์ ๋ ธํ์ฐ๋ฅผ ๋ฐฐ์ฐ๋ ๊ฒ๋งํผ ํจ์จ์ ์ธ ํ์ต๋ฒ์ ์์ผ๋๊น์! ๐
๐บ๏ธ DEX ์ค๊ณ ๊ณํ ์ธ์ฐ๊ธฐ
๋ฌด์์ ์ฝ๋ฉ๋ถํฐ ์์ํ๋ฉด ์ ๋ผ์! ๋จผ์ ์ด๋ค DEX๋ฅผ ๋ง๋ค์ง ๊ณํ์ ์ธ์๋ด์:
- DEX ์ ํ ์ ํ: AMM ๋ฐฉ์? ์ฃผ๋ฌธ์ฅ ๋ฐฉ์? ํ์ด๋ธ๋ฆฌ๋?
- ์ง์ํ ๋ธ๋ก์ฒด์ธ ๊ฒฐ์ : ์ด๋๋ฆฌ์? BSC? ํด๋ฆฌ๊ณค? ์๋ผ๋?
- ํ ํฐ ํ์ด ์ค์ : ์ด๋ค ํ ํฐ ์๋ค์ ์ง์ํ ์ง ๊ฒฐ์ ํด์.
- ์์๋ฃ ๋ชจ๋ธ ์ค๊ณ: ๊ฑฐ๋ ์์๋ฃ๋ ์ผ๋ง๋ก ํ ์ง, LP์๊ฒ๋ ์ด๋ป๊ฒ ๋ถ๋ฐฐํ ์ง ์ ํด์.
- ๊ฑฐ๋ฒ๋์ค ์์คํ : DAO ํํ๋ก ์ด์ํ ์ง, ๊ฑฐ๋ฒ๋์ค ํ ํฐ์ ๋ฐํํ ์ง ๋ฑ์ ๊ฒฐ์ ํด์.
- ๋ก๋๋งต ์์ฑ: ๊ฐ๋ฐ ๋จ๊ณ์ ์ผ์ ์ ๊ณํํด์.
์ค๋น๊ฐ ๋๋ฌ๋ค๋ฉด, ์ด์ ์ง์ง ๊ฐ๋ฐ์ ์์ํด๋ณผ๊น์? ๋ค์ ์น์ ์์๋ ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ๋ถํฐ ์์ํ ๊ฑฐ์์! ๐
4. ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐํ๊ธฐ ๐ป
๋๋์ด ์ฝ๋ฉ ํ์์ด์์! DEX์ ์ฌ์ฅ์ธ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ๊ฐ๋ฐํด๋ณผ๊ฒ์. ์ฌ๊ธฐ์๋ AMM ๋ฐฉ์์ DEX๋ฅผ ๊ตฌํํ ๊ฑฐ์์. ์๋ํ๋ฉด ์ด ๋ฐฉ์์ด ๊ฐ์ฅ ์ธ๊ธฐ ์๊ณ , ๊ตฌํํ๊ธฐ๋ ์๋์ ์ผ๋ก ์ฝ๊ฑฐ๋ ์!
๐๏ธ ๊ธฐ๋ณธ ๊ตฌ์กฐ ์ค๊ณ
DEX๋ฅผ ์ํ ์ค๋งํธ ์ปจํธ๋ํธ๋ ํฌ๊ฒ ๋ค์๊ณผ ๊ฐ์ ์ปดํฌ๋ํธ๋ก ๊ตฌ์ฑ๋ผ์:
- Factory ์ปจํธ๋ํธ: ์๋ก์ด ํ ํฐ ํ์ด์ ์ ๋์ฑ ํ์ ์์ฑํ๋ ์ปจํธ๋ํธ์์.
- Pair ์ปจํธ๋ํธ: ๋ ํ ํฐ ๊ฐ์ ๊ตํ๊ณผ ์ ๋์ฑ ๊ด๋ฆฌ๋ฅผ ๋ด๋นํ๋ ์ปจํธ๋ํธ์์.
- Router ์ปจํธ๋ํธ: ์ฌ์ฉ์ ์ธํฐํ์ด์ค์ ์ํธ์์ฉํ๋ฉฐ ๋ค์ํ ๊ฑฐ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ ์ปจํธ๋ํธ์์.
- ERC20 ํ ํฐ ์ปจํธ๋ํธ: LP ํ ํฐ ๋ฑ ํ์ํ ํ ํฐ์ ๊ตฌํํ๋ ์ปจํธ๋ํธ์์.
๐ Factory ์ปจํธ๋ํธ ๊ตฌํ
๋จผ์ Factory ์ปจํธ๋ํธ๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์. ์ด ์ปจํธ๋ํธ๋ ์๋ก์ด ํ ํฐ ํ์ด๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํด์:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Pair.sol";
contract Factory {
mapping(address => mapping(address => address)) public getPair;
address[] public allPairs;
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function createPair(address tokenA, address tokenB) external returns (address pair) {
require(tokenA != tokenB, "IDENTICAL_ADDRESSES");
// ํ ํฐ ์ฃผ์ ์ ๋ ฌ (ํญ์ ์์ ์ฃผ์๊ฐ token0)
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
require(token0 != address(0), "ZERO_ADDRESS");
require(getPair[token0][token1] == address(0), "PAIR_EXISTS");
// ์ Pair ์ปจํธ๋ํธ ์์ฑ
bytes memory bytecode = type(Pair).creationCode;
bytes32 salt = keccak256(abi.encodePacked(token0, token1));
assembly {
pair := create2(0, add(bytecode, 32), mload(bytecode), salt)
}
// ์ Pair ์ด๊ธฐํ
Pair(pair).initialize(token0, token1);
// ๋งคํ ์
๋ฐ์ดํธ
getPair[token0][token1] = pair;
getPair[token1][token0] = pair;
allPairs.push(pair);
emit PairCreated(token0, token1, pair, allPairs.length);
return pair;
}
}
์ด ์ฝ๋๋ Uniswap V2์ Factory ์ปจํธ๋ํธ์ ์ ์ฌํด์. create2 opcode๋ฅผ ์ฌ์ฉํด ๊ฒฐ์ ์ ์ธ ์ฃผ์๋ก Pair ์ปจํธ๋ํธ๋ฅผ ์์ฑํ๊ณ ์์ด์. ์ด๋ ๊ฒ ํ๋ฉด ์ด๋ค ํ ํฐ ์์ ์ฃผ์๋ ๋ฏธ๋ฆฌ ๊ณ์ฐํ ์ ์์ด์!
๐ง Pair ์ปจํธ๋ํธ ๊ตฌํ
๋ค์์ Pair ์ปจํธ๋ํธ์์. ์ด ์ปจํธ๋ํธ๋ ์ ๋์ฑ ํ๊ณผ ํ ํฐ ๊ตํ ๋ก์ง์ ๊ตฌํํด์:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/Math.sol";
contract Pair is ERC20 {
using SafeERC20 for IERC20;
address public factory;
address public token0;
address public token1;
uint private reserve0;
uint private reserve1;
uint private constant MINIMUM_LIQUIDITY = 10**3;
constructor() ERC20("MyDEX LP Token", "MDLP") {
factory = msg.sender;
}
function initialize(address _token0, address _token1) external {
require(msg.sender == factory, "FORBIDDEN");
token0 = _token0;
token1 = _token1;
}
function getReserves() public view returns (uint _reserve0, uint _reserve1) {
_reserve0 = reserve0;
_reserve1 = reserve1;
}
// ์ ๋์ฑ ๊ณต๊ธ
function mint(address to) external returns (uint liquidity) {
(uint _reserve0, uint _reserve1) = getReserves();
uint balance0 = IERC20(token0).balanceOf(address(this));
uint balance1 = IERC20(token1).balanceOf(address(this));
uint amount0 = balance0 - _reserve0;
uint amount1 = balance1 - _reserve1;
if (totalSupply() == 0) {
liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
_mint(address(0), MINIMUM_LIQUIDITY); // ์์ํ ์ ๊ธ
} else {
liquidity = Math.min(
(amount0 * totalSupply()) / _reserve0,
(amount1 * totalSupply()) / _reserve1
);
}
require(liquidity > 0, "INSUFFICIENT_LIQUIDITY_MINTED");
_mint(to, liquidity);
_update(balance0, balance1);
return liquidity;
}
// ์ ๋์ฑ ์ ๊ฑฐ
function burn(address to) external returns (uint amount0, uint amount1) {
uint balance0 = IERC20(token0).balanceOf(address(this));
uint balance1 = IERC20(token1).balanceOf(address(this));
uint liquidity = balanceOf(address(this));
amount0 = (liquidity * balance0) / totalSupply();
amount1 = (liquidity * balance1) / totalSupply();
require(amount0 > 0 && amount1 > 0, "INSUFFICIENT_LIQUIDITY_BURNED");
_burn(address(this), liquidity);
IERC20(token0).safeTransfer(to, amount0);
IERC20(token1).safeTransfer(to, amount1);
balance0 = IERC20(token0).balanceOf(address(this));
balance1 = IERC20(token1).balanceOf(address(this));
_update(balance0, balance1);
return (amount0, amount1);
}
// ํ ํฐ ์ค์
function swap(uint amount0Out, uint amount1Out, address to) external {
require(amount0Out > 0 || amount1Out > 0, "INSUFFICIENT_OUTPUT_AMOUNT");
(uint _reserve0, uint _reserve1) = getReserves();
require(amount0Out < _reserve0 && amount1Out < _reserve1, "INSUFFICIENT_LIQUIDITY");
if (amount0Out > 0) IERC20(token0).safeTransfer(to, amount0Out);
if (amount1Out > 0) IERC20(token1).safeTransfer(to, amount1Out);
uint balance0 = IERC20(token0).balanceOf(address(this));
uint balance1 = IERC20(token1).balanceOf(address(this));
uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
require(amount0In > 0 || amount1In > 0, "INSUFFICIENT_INPUT_AMOUNT");
// ์์๋ฃ ๊ณ์ฐ (0.3%)
uint balance0Adjusted = balance0 * 1000 - amount0In * 3;
uint balance1Adjusted = balance1 * 1000 - amount1In * 3;
require(balance0Adjusted * balance1Adjusted >= _reserve0 * _reserve1 * 1000**2, "K");
_update(balance0, balance1);
}
function _update(uint balance0, uint balance1) private {
reserve0 = balance0;
reserve1 = balance1;
}
}
์ด ์ปจํธ๋ํธ๋ AMM์ ํต์ฌ์ธ ์์ ๊ณฑ ๊ณต์(x * y = k)์ ๊ตฌํํ๊ณ ์์ด์. ์ ๋์ฑ ๊ณต๊ธ, ์ ๊ฑฐ, ํ ํฐ ์ค์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ , LP ํ ํฐ๋ ๋ฐํํด์. ์์๋ฃ๋ 0.3%๋ก ์ค์ ํ์ด์.
๐ฃ๏ธ Router ์ปจํธ๋ํธ ๊ตฌํ
๋ง์ง๋ง์ผ๋ก Router ์ปจํธ๋ํธ๋ฅผ ๊ตฌํํด๋ณผ๊ฒ์. ์ด ์ปจํธ๋ํธ๋ ์ฌ์ฉ์ ์นํ์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./Factory.sol";
import "./Pair.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract Router {
using SafeERC20 for IERC20;
address public factory;
constructor(address _factory) {
factory = _factory;
}
// ์ ๋์ฑ ์ถ๊ฐ
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity) {
require(deadline >= block.timestamp, "EXPIRED");
// ํ์ด ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ ๋๋ ์์ฑ
address pair = Factory(factory).getPair(tokenA, tokenB);
if (pair == address(0)) {
pair = Factory(factory).createPair(tokenA, tokenB);
}
// ์ต์ ์ ๊ธ์ก ๊ณ์ฐ
(uint reserveA, uint reserveB) = getReserves(tokenA, tokenB);
if (reserveA == 0 && reserveB == 0) {
(amountA, amountB) = (amountADesired, amountBDesired);
} else {
uint amountBOptimal = quote(amountADesired, reserveA, reserveB);
if (amountBOptimal <= amountBDesired) {
require(amountBOptimal >= amountBMin, "INSUFFICIENT_B_AMOUNT");
(amountA, amountB) = (amountADesired, amountBOptimal);
} else {
uint amountAOptimal = quote(amountBDesired, reserveB, reserveA);
require(amountAOptimal <= amountADesired, "EXCESSIVE_INPUT_AMOUNT");
require(amountAOptimal >= amountAMin, "INSUFFICIENT_A_AMOUNT");
(amountA, amountB) = (amountAOptimal, amountBDesired);
}
}
// ํ ํฐ ์ ์ก
IERC20(tokenA).safeTransferFrom(msg.sender, pair, amountA);
IERC20(tokenB).safeTransferFrom(msg.sender, pair, amountB);
// ์ ๋์ฑ ํ ํฐ ๋ฐํ
liquidity = Pair(pair).mint(to);
return (amountA, amountB, liquidity);
}
// ์ ๋์ฑ ์ ๊ฑฐ
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB) {
require(deadline >= block.timestamp, "EXPIRED");
address pair = Factory(factory).getPair(tokenA, tokenB);
require(pair != address(0), "PAIR_DOES_NOT_EXIST");
// LP ํ ํฐ ์ ์ก
Pair(pair).transferFrom(msg.sender, pair, liquidity);
// ์ ๋์ฑ ์ ๊ฑฐ
(amountA, amountB) = Pair(pair).burn(to);
require(amountA >= amountAMin, "INSUFFICIENT_A_AMOUNT");
require(amountB >= amountBMin, "INSUFFICIENT_B_AMOUNT");
return (amountA, amountB);
}
// ํ ํฐ ์ค์
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts) {
require(deadline >= block.timestamp, "EXPIRED");
require(path.length >= 2, "INVALID_PATH");
amounts = getAmountsOut(amountIn, path);
require(amounts[amounts.length - 1] >= amountOutMin, "INSUFFICIENT_OUTPUT_AMOUNT");
// ์ฒซ ๋ฒ์งธ ํ ํฐ ์ ์ก
IERC20(path[0]).safeTransferFrom(msg.sender, Factory(factory).getPair(path[0], path[1]), amounts[0]);
// ์ค์ ์คํ
_swap(amounts, path, to);
return amounts;
}
// ํฌํผ ํจ์๋ค
function getReserves(address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {
(address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
address pair = Factory(factory).getPair(token0, token1);
if (pair == address(0)) {
return (0, 0);
}
(uint reserve0, uint reserve1) = Pair(pair).getReserves();
(reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0);
}
function quote(uint amountA, uint reserveA, uint reserveB) internal pure returns (uint amountB) {
require(amountA > 0, "INSUFFICIENT_AMOUNT");
require(reserveA > 0 && reserveB > 0, "INSUFFICIENT_LIQUIDITY");
amountB = (amountA * reserveB) / reserveA;
}
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {
require(amountIn > 0, "INSUFFICIENT_INPUT_AMOUNT");
require(reserveIn > 0 && reserveOut > 0, "INSUFFICIENT_LIQUIDITY");
uint amountInWithFee = amountIn * 997; // 0.3% ์์๋ฃ
uint numerator = amountInWithFee * reserveOut;
uint denominator = reserveIn * 1000 + amountInWithFee;
amountOut = numerator / denominator;
}
function getAmountsOut(uint amountIn, address[] memory path) internal view returns (uint[] memory amounts) {
require(path.length >= 2, "INVALID_PATH");
amounts = new uint[](path.length);
amounts[0] = amountIn;
for (uint i = 0; i < path.length - 1; i++) {
(uint reserveIn, uint reserveOut) = getReserves(path[i], path[i + 1]);
amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut);
}
}
function _swap(uint[] memory amounts, address[] memory path, address _to) internal {
for (uint i = 0; i < path.length - 1; i++) {
(address input, address output) = (path[i], path[i + 1]);
(address token0,) = input < output ? (input, output) : (output, input);
uint amountOut = amounts[i + 1];
(uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0));
address to = i < path.length - 2 ? Factory(factory).getPair(output, path[i + 2]) : _to;
Pair(Factory(factory).getPair(input, output)).swap(amount0Out, amount1Out, to);
}
}
}
Router ์ปจํธ๋ํธ๋ ์ฌ์ฉ์ ์นํ์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๊ณ , ๋ณต์กํ ๋ก์ง์ ์ถ์ํํด์. ์ ๋์ฑ ์ถ๊ฐ/์ ๊ฑฐ, ํ ํฐ ์ค์ ๋ฑ์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ฝ๊ฒ ๋ง๋ค์ด์ค์.
์ด๋ ๊ฒ ์ธ ๊ฐ์ง ํต์ฌ ์ปจํธ๋ํธ๋ฅผ ๊ตฌํํ์ด์! ๋ฌผ๋ก ์ค์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋ ๋ง์ ๊ธฐ๋ฅ๊ณผ ๋ณด์ ๊ณ ๋ ค์ฌํญ์ด ํ์ํ๊ฒ ์ง๋ง, ๊ธฐ๋ณธ์ ์ธ DEX์ ๋ผ๋๋ ์ด๋ ๊ฒ ๊ตฌ์ฑ๋ผ์. ๋ค์ ์น์ ์์๋ ์ด ์ค๋งํธ ์ปจํธ๋ํธ์ ์ํธ์์ฉํ ํ๋ก ํธ์๋๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์! ๐จ
5. ํ๋ก ํธ์๋ ์ธํฐํ์ด์ค ๊ตฌํ ๐จ
์ค๋งํธ ์ปจํธ๋ํธ๊ฐ ์ค๋น๋์ผ๋, ์ด์ ์ฌ์ฉ์๋ค์ด ์ค์ ๋ก ์ฌ์ฉํ ์ ์๋ ์น ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค์ด๋ณผ ์ฐจ๋ก์์! ์๋ฌด๋ฆฌ ์ข์ DEX๋ผ๋ ์ฌ์ฉํ๊ธฐ ์ด๋ ค์ฐ๋ฉด ์๋ฌด๋ ์ ์ฐ๊ฒ ์ฃ ? ใ ใ ใ
๐ ๏ธ ๊ธฐ์ ์คํ ์ ํ
DEX ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ์์ฃผ ์ฌ์ฉ๋๋ ๊ธฐ์ ์คํ์ ๋ค์๊ณผ ๊ฐ์์:
- React.js: ์ปดํฌ๋ํธ ๊ธฐ๋ฐ UI ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก, ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ UI ์์๋ฅผ ๋ง๋ค๊ธฐ ์ข์์.
- Web3.js/ethers.js: ์ด๋๋ฆฌ์ ๋ธ๋ก์ฒด์ธ๊ณผ ์ํธ์์ฉํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์.
- Tailwind CSS/Material-UI: ์คํ์ผ๋ง์ ์ํ ํ๋ ์์ํฌ์์.
- Redux/Context API: ์ํ ๊ด๋ฆฌ๋ฅผ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์.
ํ๋ก์ ํธ ์ค์ ์ ๋ค์๊ณผ ๊ฐ์ด ํ ์ ์์ด์:
// React ํ๋ก์ ํธ ์์ฑ
npx create-react-app my-dex-frontend
cd my-dex-frontend
// ํ์ํ ํจํค์ง ์ค์น
npm install ethers @web3-react/core @web3-react/injected-connector
npm install tailwindcss @headlessui/react @heroicons/react
npm install @reduxjs/toolkit react-redux
๐ ์ง๊ฐ ์ฐ๊ฒฐ ๊ตฌํ
DEX์ ์ฒซ ๋จ๊ณ๋ ์ฌ์ฉ์์ ์ง๊ฐ์ ์ฐ๊ฒฐํ๋ ๊ฑฐ์์. MetaMask ๊ฐ์ ์น3 ์ง๊ฐ๊ณผ ์ฐ๋ํด๋ณผ๊ฒ์:
// src/connectors/index.js
import { InjectedConnector } from '@web3-react/injected-connector';
export const injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42, 56, 97] // ์ง์ํ ์ฒด์ธ ID
});
// src/components/WalletConnect.js
import React from 'react';
import { useWeb3React } from '@web3-react/core';
import { injected } from '../connectors';
function WalletConnect() {
const { active, account, activate, deactivate } = useWeb3React();
async function connect() {
try {
await activate(injected);
} catch (ex) {
console.log(ex);
}
}
async function disconnect() {
try {
deactivate();
} catch (ex) {
console.log(ex);
}
}
return (
<div>
{active ? (
<div>
<p>์ฐ๊ฒฐ๋ ๊ณ์ : {account}</p>
<button onClick={disconnect}>์ฐ๊ฒฐ ํด์ </button>
</div>
) : (
<button onClick={connect}>์ง๊ฐ ์ฐ๊ฒฐํ๊ธฐ</button>
)}
</div>
);
}
์ด ์ฝ๋๋ MetaMask ๊ฐ์ ์ง๊ฐ๊ณผ ์ฐ๊ฒฐํ๋ ๊ธฐ๋ณธ์ ์ธ ์ปดํฌ๋ํธ์์. ์ฌ์ฉ์๊ฐ ์ง๊ฐ์ ์ฐ๊ฒฐํ๋ฉด ๊ณ์ ์ฃผ์๋ฅผ ํ์ํ๊ณ , ์ฐ๊ฒฐ ํด์ ๋ฒํผ๋ ์ ๊ณตํด์.
๐ฑ ํ ํฐ ์ค์ ์ธํฐํ์ด์ค
DEX์ ํต์ฌ ๊ธฐ๋ฅ์ธ ํ ํฐ ์ค์ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์:
์ด๋ฐ UI๋ฅผ React ์ปดํฌ๋ํธ๋ก ๊ตฌํํด๋ณผ๊ฒ์:
// src/components/SwapInterface.js
import React, { useState, useEffect } from 'react';
import { useWeb3React } from '@web3-react/core';
import { ethers } from 'ethers';
import RouterABI from '../abis/Router.json';
import ERC20ABI from '../abis/ERC20.json';
const ROUTER_ADDRESS = '0x...'; // ๋ฐฐํฌํ Router ์ปจํธ๋ํธ ์ฃผ์
function SwapInterface() {
const { active, account, library } = useWeb3React();
const [inputAmount, setInputAmount] = useState('');
const [outputAmount, setOutputAmount] = useState('');
const [inputToken, setInputToken] = useState({
address: '0x...', // ETH ์ฃผ์ ๋๋ WETH ์ฃผ์
symbol: 'ETH',
decimals: 18
});
const [outputToken, setOutputToken] = useState({
address: '0x...', // DAI ์ฃผ์
symbol: 'DAI',
decimals: 18
});
// ์ถ๋ ฅ ๊ธ์ก ๊ณ์ฐ
useEffect(() => {
if (inputAmount && active) {
calculateOutputAmount();
}
}, [inputAmount, inputToken, outputToken]);
async function calculateOutputAmount() {
try {
const router = new ethers.Contract(
ROUTER_ADDRESS,
RouterABI,
library.getSigner()
);
const path = [inputToken.address, outputToken.address];
const amountIn = ethers.utils.parseUnits(inputAmount, inputToken.decimals);
const amounts = await router.getAmountsOut(amountIn, path);
const amountOut = ethers.utils.formatUnits(amounts[1], outputToken.decimals);
setOutputAmount(amountOut);
} catch (error) {
console.error('Error calculating output:', error);
}
}
async function handleSwap() {
if (!active || !inputAmount) return;
try {
const router = new ethers.Contract(
ROUTER_ADDRESS,
RouterABI,
library.getSigner()
);
// ์
๋ ฅ ํ ํฐ ์น์ธ
const tokenContract = new ethers.Contract(
inputToken.address,
ERC20ABI,
library.getSigner()
);
const amountIn = ethers.utils.parseUnits(inputAmount, inputToken.decimals);
const amountOutMin = ethers.utils.parseUnits(
(parseFloat(outputAmount) * 0.995).toString(), // 0.5% ์ฌ๋ฆฌํผ์ง ํ์ฉ
outputToken.decimals
);
// ํ ํฐ ์น์ธ
await tokenContract.approve(ROUTER_ADDRESS, amountIn);
// ์ค์ ์คํ
const path = [inputToken.address, outputToken.address];
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20๋ถ
const tx = await router.swapExactTokensForTokens(
amountIn,
amountOutMin,
path,
account,
deadline
);
await tx.wait();
alert('์ค์ ์ฑ๊ณต!');
} catch (error) {
console.error('Swap error:', error);
alert('์ค์ ์คํจ: ' + error.message);
}
}
return (
<div className="swap-container">
<h2>ํ ํฐ ์ค์</h2>
<div className="input-container">
<label>์ง๋ถ:</label>
<input
type="number"
value={inputAmount}
onChange={(e) => setInputAmount(e.target.value)}
placeholder="0.0"
/>
<button>{inputToken.symbol}</button>
</div>
<div className="arrow">โ</div>
<div className="output-container">
<label>๋ฐ๊ธฐ:</label>
<input
type="number"
value={outputAmount}
readOnly
placeholder="0.0"
/>
<button>{outputToken.symbol}</button>
</div>
{inputAmount && outputAmount && (
<div className="rate-info">
<p>1 {inputToken.symbol} = {(outputAmount / inputAmount).toFixed(6)} {outputToken.symbol}</p>
<p>์ฌ๋ฆฌํผ์ง: 0.5%</p>
<p>์์๋ฃ: 0.3%</p>
</div>
)}
<button
className="swap-button"
disabled={!active || !inputAmount}
onClick={handleSwap}
>
{active ? '์ค์ํ๊ธฐ' : '์ง๊ฐ ์ฐ๊ฒฐ ํ์'}
</button>
</div>
);
}
์ด ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์๊ฐ ์ ๋ ฅํ ๊ธ์ก์ ๋ฐ๋ผ ๋ฐ์ ์ ์๋ ํ ํฐ ์์ ๊ณ์ฐํ๊ณ , ์ค์ ๊ธฐ๋ฅ์ ์ ๊ณตํด์. ์ฌ์ฉ์๊ฐ ๊ธ์ก์ ์ ๋ ฅํ๋ฉด Router ์ปจํธ๋ํธ์ getAmountsOut ํจ์๋ฅผ ํธ์ถํด ์ถ๋ ฅ ๊ธ์ก์ ๊ณ์ฐํ๊ณ , ์ค์ ๋ฒํผ์ ๋๋ฅด๋ฉด ์ค์ ๋ก ํ ํฐ์ ๊ตํํด์.
๐ฆ ์ ๋์ฑ ๊ณต๊ธ ์ธํฐํ์ด์ค
DEX์ ๋ ๋ค๋ฅธ ์ค์ํ ๊ธฐ๋ฅ์ธ ์ ๋์ฑ ๊ณต๊ธ ์ธํฐํ์ด์ค๋ ๋ง๋ค์ด๋ณผ๊ฒ์:
// src/components/LiquidityInterface.js
import React, { useState } from 'react';
import { useWeb3React } from '@web3-react/core';
import { ethers } from 'ethers';
import RouterABI from '../abis/Router.json';
import ERC20ABI from '../abis/ERC20.json';
const ROUTER_ADDRESS = '0x...'; // ๋ฐฐํฌํ Router ์ปจํธ๋ํธ ์ฃผ์
function LiquidityInterface() {
const { active, account, library } = useWeb3React();
const [tokenA, setTokenA] = useState({
address: '0x...', // ์ฒซ ๋ฒ์งธ ํ ํฐ ์ฃผ์
symbol: 'ETH',
decimals: 18
});
const [tokenB, setTokenB] = useState({
address: '0x...', // ๋ ๋ฒ์งธ ํ ํฐ ์ฃผ์
symbol: 'DAI',
decimals: 18
});
const [amountA, setAmountA] = useState('');
const [amountB, setAmountB] = useState('');
async function handleAddLiquidity() {
if (!active || !amountA || !amountB) return;
try {
const router = new ethers.Contract(
ROUTER_ADDRESS,
RouterABI,
library.getSigner()
);
// ํ ํฐ ์น์ธ
const tokenAContract = new ethers.Contract(
tokenA.address,
ERC20ABI,
library.getSigner()
);
const tokenBContract = new ethers.Contract(
tokenB.address,
ERC20ABI,
library.getSigner()
);
const amountADesired = ethers.utils.parseUnits(amountA, tokenA.decimals);
const amountBDesired = ethers.utils.parseUnits(amountB, tokenB.decimals);
const amountAMin = amountADesired.mul(95).div(100); // 5% ์ฌ๋ฆฌํผ์ง ํ์ฉ
const amountBMin = amountBDesired.mul(95).div(100);
await tokenAContract.approve(ROUTER_ADDRESS, amountADesired);
await tokenBContract.approve(ROUTER_ADDRESS, amountBDesired);
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20๋ถ
const tx = await router.addLiquidity(
tokenA.address,
tokenB.address,
amountADesired,
amountBDesired,
amountAMin,
amountBMin,
account,
deadline
);
await tx.wait();
alert('์ ๋์ฑ ์ถ๊ฐ ์ฑ๊ณต!');
} catch (error) {
console.error('Add liquidity error:', error);
alert('์ ๋์ฑ ์ถ๊ฐ ์คํจ: ' + error.message);
}
}
return (
<div className="liquidity-container">
<h2>์ ๋์ฑ ๊ณต๊ธ</h2>
<div className="token-input">
<label>{tokenA.symbol} ์๋:</label>
<input
type="number"
value={amountA}
onChange={(e) => setAmountA(e.target.value)}
placeholder="0.0"
/>
</div>
<div className="token-input">
<label>{tokenB.symbol} ์๋:</label>
<input
type="number"
value={amountB}
onChange={(e) => setAmountB(e.target.value)}
placeholder="0.0"
/>
</div>
<button
className="add-liquidity-button"
disabled={!active || !amountA || !amountB}
onClick={handleAddLiquidity}
>
์ ๋์ฑ ๊ณต๊ธํ๊ธฐ
</button>
<p className="info-text">
์ ๋์ฑ์ ๊ณต๊ธํ๋ฉด ํ์ ์ง๋ถ์ ๋ํ๋ด๋ LP ํ ํฐ์ ๋ฐ๊ฒ ๋ฉ๋๋ค.
์ด ํ ํฐ์ ๋ณด์ ํ๋ ๋์ ๊ฑฐ๋ ์์๋ฃ์ ์ผ๋ถ๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค.
</p>
</div>
);
}
์ด ์ปดํฌ๋ํธ๋ ์ฌ์ฉ์๊ฐ ๋ ์ข ๋ฅ์ ํ ํฐ์ DEX์ ๊ณต๊ธํ๊ณ LP ํ ํฐ์ ๋ฐ์ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํด์. ์ ๋์ฑ ๊ณต๊ธ์๋ ๊ฑฐ๋ ์์๋ฃ์ ์ผ๋ถ๋ฅผ ๋ฐ์ ์ ์์ด์!
๐ ๋์๋ณด๋ ๊ตฌํ
๋ง์ง๋ง์ผ๋ก, ์ฌ์ฉ์๊ฐ ์์ ์ ์ ๋์ฑ ํ ์ง๋ถ๊ณผ ์์ต์ ํ์ธํ ์ ์๋ ๋์๋ณด๋๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์:
// src/components/Dashboard.js
import React, { useState, useEffect } from 'react';
import { useWeb3React } from '@web3-react/core';
import { ethers } from 'ethers';
import FactoryABI from '../abis/Factory.json';
import PairABI from '../abis/Pair.json';
const FACTORY_ADDRESS = '0x...'; // ๋ฐฐํฌํ Factory ์ปจํธ๋ํธ ์ฃผ์
function Dashboard() {
const { active, account, library } = useWeb3React();
const [liquidityPositions, setLiquidityPositions] = useState([]);
useEffect(() => {
if (active && account) {
fetchLiquidityPositions();
}
}, [active, account]);
async function fetchLiquidityPositions() {
try {
const factory = new ethers.Contract(
FACTORY_ADDRESS,
FactoryABI,
library
);
// ๋ชจ๋ ํ์ด ๊ฐ์ ธ์ค๊ธฐ
const pairCount = await factory.allPairsLength();
const positions = [];
for (let i = 0; i < pairCount; i++) {
const pairAddress = await factory.allPairs(i);
const pair = new ethers.Contract(
pairAddress,
PairABI,
library
);
// ์ฌ์ฉ์์ LP ํ ํฐ ์์ก ํ์ธ
const balance = await pair.balanceOf(account);
if (balance.gt(0)) {
const totalSupply = await pair.totalSupply();
const token0 = await pair.token0();
const token1 = await pair.token1();
const reserves = await pair.getReserves();
// ์ฌ์ฉ์์ ์ง๋ถ ๊ณ์ฐ
const share = balance.mul(ethers.BigNumber.from(10000)).div(totalSupply);
const sharePercent = share.toNumber() / 100;
// ์ฌ์ฉ์์ ํ ํฐ ์ง๋ถ ๊ณ์ฐ
const token0Amount = reserves[0].mul(balance).div(totalSupply);
const token1Amount = reserves[1].mul(balance).div(totalSupply);
positions.push({
pairAddress,
token0,
token1,
balance: ethers.utils.formatEther(balance),
sharePercent,
token0Amount: ethers.utils.formatUnits(token0Amount, 18), // ํ ํฐ ์์์ ์ ๋ง๊ฒ ์กฐ์ ํ์
token1Amount: ethers.utils.formatUnits(token1Amount, 18)
});
}
}
setLiquidityPositions(positions);
} catch (error) {
console.error('Error fetching positions:', error);
}
}
return (
<div className="dashboard-container">
<h2>๋ด ์ ๋์ฑ ํฌ์ง์
</h2>
{!active && <p>์ง๊ฐ์ ์ฐ๊ฒฐํด์ฃผ์ธ์.</p>}
{active && liquidityPositions.length === 0 && (
<p>์ ๋์ฑ ํฌ์ง์
์ด ์์ต๋๋ค.</p>
)}
{liquidityPositions.map((position, index) => (
<div key={index} className="position-card">
<h3>ํ์ด: {position.token0} - {position.token1}</h3>
<p>LP ํ ํฐ: {position.balance}</p>
<p>ํ ์ง๋ถ: {position.sharePercent}%</p>
<p>์์นํ ํ ํฐ:</p>
<ul>
<li>{position.token0Amount} ํ ํฐ0</li>
<li>{position.token1Amount} ํ ํฐ1</li>
</ul>
<button onClick={() => handleRemoveLiquidity(position)}>
์ ๋์ฑ ์ ๊ฑฐํ๊ธฐ
</button>
</div>
))}
</div>
);
async function handleRemoveLiquidity(position) {
// ์ ๋์ฑ ์ ๊ฑฐ ๋ก์ง ๊ตฌํ
// ...
}
}
์ด ๋์๋ณด๋๋ ์ฌ์ฉ์๊ฐ ๊ณต๊ธํ ๋ชจ๋ ์ ๋์ฑ ํ์ ๋ณด์ฌ์ฃผ๊ณ , ๊ฐ ํ์์์ ์ง๋ถ๊ณผ ์์นํ ํ ํฐ ์์ ํ์ํด์. ๋ํ ์ ๋์ฑ์ ์ ๊ฑฐํ ์ ์๋ ๊ธฐ๋ฅ๋ ์ ๊ณตํด์.
์ด๋ ๊ฒ ํด์ DEX์ ๊ธฐ๋ณธ์ ์ธ ํ๋ก ํธ์๋ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ด์! ๋ฌผ๋ก ์ค์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋ ๋ง์ ๊ธฐ๋ฅ๊ณผ UI/UX ๊ฐ์ ์ด ํ์ํ๊ฒ ์ง๋ง, ๊ธฐ๋ณธ ๋ผ๋๋ ์ด๋ ๊ฒ ๊ตฌ์ฑ๋ผ์. ๋ค์ ์น์ ์์๋ ์ ๋์ฑ ํ ์ค๊ณ์ ๋ํด ๋ ์์ธํ ์์๋ณผ๊ฒ์! ๐ง
6. ์ ๋์ฑ ํ ์ค๊ณ ๋ฐ ๊ตฌํ ๐ง
DEX์ ์ฌ์ฅ์ด๋ผ๊ณ ํ ์ ์๋ ์ ๋์ฑ ํ! ์ด ๋ถ๋ถ์ ์ ๋๋ก ์ค๊ณํ์ง ์์ผ๋ฉด DEX๊ฐ ์ ๋๋ก ์๋ํ์ง ์์์. ์ ๋์ฑ ํ์ AMM ๋ฐฉ์ DEX์ ํต์ฌ ์์๋๊น์! ์ด๋ป๊ฒ ํ๋ฉด ํจ์จ์ ์ด๊ณ ์์ ํ ์ ๋์ฑ ํ์ ๋ง๋ค ์ ์์์ง ์์๋ณผ๊ฒ์. ๐
๐งฎ ์ ๋์ฑ ํ์ ์ํ์ ์๋ฆฌ
AMM ๋ฐฉ์์ DEX์์ ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๋ ๊ณต์์ ์์ ๊ณฑ ๊ณต์(Constant Product Formula)์ด์์:
์ฌ๊ธฐ์:
- x: ํ์ ์๋ ์ฒซ ๋ฒ์งธ ํ ํฐ์ ์
- y: ํ์ ์๋ ๋ ๋ฒ์งธ ํ ํฐ์ ์
- k: ์์ (๊ฑฐ๋ ์ ํ๋ก ๋ณํ์ง ์์)
์ด ๊ณต์์ ๊ฐ๋จํ์ง๋ง ๊ฐ๋ ฅํด์! ์ด ๊ณต์ ๋๋ถ์ ์ค์ํ๋ ์ฃผ๋ฌธ์ฅ ์์ด๋ ์๋์ผ๋ก ๊ฐ๊ฒฉ์ ๊ฒฐ์ ํ ์ ์์ด์. ์๋ฅผ ๋ค์ด๋ณด์๋ฉด:
- ํ์ 100 ETH์ 200,000 DAI๊ฐ ์๋ค๊ณ ๊ฐ์ ํด๋ณผ๊ฒ์. ์ด๋ k = 100 ร 200,000 = 20,000,000์ด์์.
- ๋๊ตฐ๊ฐ 10 ETH๋ฅผ DAI๋ก ๊ตํํ๊ณ ์ถ๋ค๋ฉด, ํ์์๋ ETH๊ฐ ์ฆ๊ฐํ๊ณ DAI๊ฐ ๊ฐ์ํด์.
- ์๋ก์ด ETH ์: 100 + 10 = 110 ETH
- ์๋ก์ด DAI ์์ ๊ณ์ฐํ๋ ค๋ฉด: 110 ร y = 20,000,000, ๋ฐ๋ผ์ y = 20,000,000 รท 110 โ 181,818 DAI
- ๋ฐ๋ผ์ ์ฌ์ฉ์๋ 200,000 - 181,818 = 18,182 DAI๋ฅผ ๋ฐ๊ฒ ๋ผ์.
์ด๋ฐ ๋ฐฉ์์ผ๋ก ํ์ ํฌ๊ธฐ๊ฐ ํด์๋ก, ๊ทธ๋ฆฌ๊ณ ๊ตํํ๋ ค๋ ์์ด ์์์๋ก ๊ฐ๊ฒฉ ์ํฅ(Price Impact)์ด ์์์ ธ์. ์ฆ, ์ ๋์ฑ์ด ๋ง์์๋ก ๋ ํจ์จ์ ์ธ ๊ฑฐ๋๊ฐ ๊ฐ๋ฅํด์ง๋ ๊ฑฐ์ฃ !
๐ ๋ค์ํ ์ ๋์ฑ ํ ๋ชจ๋ธ
์์ ๊ณฑ ๊ณต์ ์ธ์๋ ๋ค์ํ ์ ๋์ฑ ํ ๋ชจ๋ธ์ด ์์ด์:
- ์์ ํฉ ๊ณต์(Constant Sum Formula): x + y = k
์ด ๋ชจ๋ธ์ ๊ฐ๊ฒฉ ๋ณ๋ ์์ด 1:1 ๊ตํ์ ์ ๊ณตํด์. ํ์ง๋ง ๋ฌดํํ ์ ๋์ฑ์ ๊ฐ์ ํ๊ธฐ ๋๋ฌธ์ ์ค์ ๋ก๋ ์ ํ์ ์ผ๋ก ์ฌ์ฉ๋ผ์. - ๊ฐ์ค ์์ ๊ณฑ(Weighted Constant Product): x^wโ ร y^wโ = k
Balancer ๊ฐ์ ํ๋กํ ์ฝ์์ ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก, ํ ํฐ๋ง๋ค ๋ค๋ฅธ ๊ฐ์ค์น๋ฅผ ๋ถ์ฌํ ์ ์์ด์. - ๊ณก์ ๊ธฐ๋ฐ ๋ชจ๋ธ(Curve-based Model): Curve Finance์์ ์ฌ์ฉํ๋ ๋ฐฉ์์ผ๋ก, ์คํ ์ด๋ธ์ฝ์ธ ๊ฐ์ ๋น์ทํ ๊ฐ์น๋ฅผ ๊ฐ์ง ํ ํฐ ๊ฐ์ ๊ตํ์ ์ต์ ํ๋์ด ์์ด์.
- ์ง์ค ์ ๋์ฑ(Concentrated Liquidity): Uniswap V3์์ ๋์ ํ ๋ฐฉ์์ผ๋ก, ์ ๋์ฑ ๊ณต๊ธ์๊ฐ ํน์ ๊ฐ๊ฒฉ ๋ฒ์์๋ง ์ ๋์ฑ์ ์ง์ค์ํฌ ์ ์์ด์.
๐ฐ ์ ๋์ฑ ์ธ์ผํฐ๋ธ ์ค๊ณ
์ ๋์ฑ ํ์ด ์ ์๋ํ๋ ค๋ฉด ์ถฉ๋ถํ ์ ๋์ฑ์ด ํ์ํด์. ๊ทธ๋ฌ๋ ค๋ฉด ์ ๋์ฑ ๊ณต๊ธ์์๊ฒ ์ ์ ํ ์ธ์ผํฐ๋ธ๋ฅผ ์ ๊ณตํด์ผ ํด์:
- ๊ฑฐ๋ ์์๋ฃ ๋ถ๋ฐฐ: ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ธ์ผํฐ๋ธ๋ก, ๊ฑฐ๋ ์์๋ฃ์ ์ผ๋ถ๋ฅผ ์ ๋์ฑ ๊ณต๊ธ์์๊ฒ ๋ถ๋ฐฐํด์. ์ผ๋ฐ์ ์ผ๋ก 0.3%์ ๊ฑฐ๋ ์์๋ฃ ์ค ๋๋ถ๋ถ์ด ์ ๋์ฑ ๊ณต๊ธ์์๊ฒ ๋์๊ฐ์.
- ์ ๋์ฑ ๋ง์ด๋(Liquidity Mining): ์ ๋์ฑ์ ๊ณต๊ธํ๋ ์ฌ์ฉ์์๊ฒ ์ถ๊ฐ๋ก ๊ฑฐ๋ฒ๋์ค ํ ํฐ์ ๋ณด์์ผ๋ก ์ง๊ธํด์. ์ด ๋ฐฉ์์ 2020๋ DeFi ์ฌ๋ฆ์ ์ด๋ ์ฃผ์ ์์ธ์ด์์ด์!
- ๋ถ์คํ ๋ฉ์ปค๋์ฆ(Boosting Mechanism): Curve์ veCRV ์์คํ ์ฒ๋ผ, ๊ฑฐ๋ฒ๋์ค ํ ํฐ์ ์คํ ์ดํนํ๋ฉด ๋ ๋ง์ ๋ณด์์ ๋ฐ์ ์ ์๋ ์์คํ ์ด์์.
- ์ํ๋ฌ๋จผํธ ๋ก์ค ๋ณดํธ(Impermanent Loss Protection): Bancor์ ๊ฐ์ ํ๋กํ ์ฝ์์ ์ ๊ณตํ๋ ๊ธฐ๋ฅ์ผ๋ก, ์ ๋์ฑ ๊ณต๊ธ์ผ๋ก ์ธํ ์์ค์ ๋ณด์ํด์ค์.
๐ ์ ๋์ฑ ํ ๋ชจ๋ํฐ๋ง ๋ฐ ๊ด๋ฆฌ
์ ๋์ฑ ํ์ ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง๊ณผ ๊ด๋ฆฌ๊ฐ ํ์ํด์:
- ์ ๋์ฑ ๊ท ํ ๋ชจ๋ํฐ๋ง: ๋ ํ ํฐ์ ๋น์จ์ด ๋๋ฌด ๋ถ๊ท ํํด์ง๋ฉด ํจ์จ์ ์ธ ๊ฑฐ๋๊ฐ ์ด๋ ค์์ ธ์.
- ์ํ๋ฌ๋จผํธ ๋ก์ค ์ถ์ : ์ ๋์ฑ ๊ณต๊ธ์๊ฐ ์์ ์ ์ ์ฌ์ ์์ค์ ์ถ์ ํ ์ ์์ด์ผ ํด์.
- APY ๊ณ์ฐ: ์ฐ๊ฐ ์์ต๋ฅ ์ ๊ณ์ฐํด ์ ๋์ฑ ๊ณต๊ธ์์๊ฒ ์ ๊ณตํด์ผ ํด์.
- ๋ฆฌ๋ฐธ๋ฐ์ฑ ๋ฉ์ปค๋์ฆ: ํ์ํ ๊ฒฝ์ฐ ํ์ ๊ท ํ์ ๋ง์ถ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํ ์ ์์ด์.
๐ ์ ๋์ฑ ํ ๋ณด์
์ ๋์ฑ ํ์ ๋ง์ ์๊ธ์ด ๋ชจ์ด๋ ๊ณณ์ด๊ธฐ ๋๋ฌธ์ ๋ณด์์ด ๋งค์ฐ ์ค์ํด์:
- ํ๋์๋ก ๊ณต๊ฒฉ ๋ฐฉ์ง: ํ๋์๋ก ์ ์ด์ฉํ ๊ฐ๊ฒฉ ์กฐ์์ ๋ฐฉ์งํ๊ธฐ ์ํ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํด์ผ ํด์.
- ์ค๋ผํด ํ์ฉ: ์ธ๋ถ ๊ฐ๊ฒฉ ์ค๋ผํด์ ํ์ฉํด ๋น์ ์์ ์ธ ๊ฑฐ๋๋ฅผ ๊ฐ์งํ ์ ์์ด์.
- ์ฌ๋ฆฌํผ์ง ์ ํ: ์ฌ์ฉ์๊ฐ ์์๋ณด๋ค ๋๋ฌด ์ ์ ์์ ํ ํฐ์ ๋ฐ์ง ์๋๋ก ์ฌ๋ฆฌํผ์ง ์ ํ์ ์ค์ ํด์ผ ํด์.
- ๊ธด๊ธ ์ ์ง ๊ธฐ๋ฅ: ์ฌ๊ฐํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ํ์ ์ผ์์ ์ผ๋ก ์ค๋จํ ์ ์๋ ๊ธฐ๋ฅ์ด ํ์ํ ์ ์์ด์.
์ ๋์ฑ ํ์ DEX์ ํต์ฌ์ด์์. ์ ์ค๊ณ๋ ์ ๋์ฑ ํ์ ์ฌ์ฉ์์๊ฒ ํจ์จ์ ์ธ ๊ฑฐ๋ ๊ฒฝํ์ ์ ๊ณตํ๊ณ , ์ ๋์ฑ ๊ณต๊ธ์์๊ฒ๋ ์์ ์ ์ธ ์์ต์ ์ ๊ณตํ ์ ์์ด์. ๋ค์ ์น์ ์์๋ DEX์ ํ ์คํ ๊ณผ ๋ณด์ ๊ฐ์ฌ์ ๋ํด ์์๋ณผ๊ฒ์! ๐
7. ํ ์คํ ๋ฐ ๋ณด์ ๊ฐ์ฌ ๐
DEX ๊ฐ๋ฐ์์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ ์ค ํ๋๊ฐ ๋ฐ๋ก ํ ์คํ ๊ณผ ๋ณด์ ๊ฐ์ฌ์์! ํ ๋ฒ์ ๋ฒ๊ทธ๋ ์ทจ์ฝ์ ์ผ๋ก ์๋ฐฑ๋ง ๋ฌ๋ฌ๊ฐ ์ฌ๋ผ์ง ์ ์์ผ๋๊น์. ๊ทธ๋์ ์ฒ ์ ํ ํ ์คํ ๊ณผ ๋ณด์ ๊ฐ์ฌ๋ ํ์์์! ๐ฑ
๐งช ์ค๋งํธ ์ปจํธ๋ํธ ํ ์คํ
์ค๋งํธ ์ปจํธ๋ํธ ํ ์คํ ์ ์ฌ๋ฌ ๋จ๊ณ๋ก ์งํ๋ผ์:
- ๋จ์ ํ ์คํธ(Unit Testing): ๊ฐ ํจ์๊ฐ ์์๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์์. Truffle์ด๋ Hardhat์ ์ฌ์ฉํด ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ ์ ์์ด์:
// test/Pair.test.js
const Pair = artifacts.require("Pair");
const TestERC20 = artifacts.require("TestERC20");
contract("Pair", (accounts) => {
let pair;
let token0;
let token1;
const [owner, user1, user2] = accounts;
beforeEach(async () => {
// ํ
์คํธ์ฉ ํ ํฐ ๋ฐฐํฌ
token0 = await TestERC20.new("Token0", "TK0", web3.utils.toWei("1000000"));
token1 = await TestERC20.new("Token1", "TK1", web3.utils.toWei("1000000"));
// ํ ํฐ ์ฃผ์ ์ ๋ ฌ
const sortedTokens = token0.address < token1.address
? [token0.address, token1.address]
: [token1.address, token0.address];
// Pair ์ปจํธ๋ํธ ๋ฐฐํฌ
pair = await Pair.new();
await pair.initialize(sortedTokens[0], sortedTokens[1]);
// ์ฌ์ฉ์์๊ฒ ํ ํฐ ์ ์ก
await token0.transfer(user1, web3.utils.toWei("1000"));
await token1.transfer(user1, web3.utils.toWei("1000"));
});
it("should add liquidity correctly", async () => {
// ํ ํฐ ์น์ธ
await token0.approve(pair.address, web3.utils.toWei("100"), { from: user1 });
await token1.approve(pair.address, web3.utils.toWei("200"), { from: user1 });
// ํ ํฐ ์ ์ก
await token0.transfer(pair.address, web3.utils.toWei("100"), { from: user1 });
await token1.transfer(pair.address, web3.utils.toWei("200"), { from: user1 });
// ์ ๋์ฑ ๋ฏผํ
await pair.mint(user1, { from: user1 });
// ๊ฒ์ฆ
const liquidity = await pair.balanceOf(user1);
assert(liquidity.gt(0), "Should mint liquidity tokens");
const reserves = await pair.getReserves();
assert.equal(reserves[0].toString(), web3.utils.toWei("100"), "Reserve0 should be correct");
assert.equal(reserves[1].toString(), web3.utils.toWei("200"), "Reserve1 should be correct");
});
it("should swap tokens correctly", async () => {
// ๋จผ์ ์ ๋์ฑ ์ถ๊ฐ
await token0.approve(pair.address, web3.utils.toWei("100"), { from: user1 });
await token1.approve(pair.address, web3.utils.toWei("200"), { from: user1 });
await token0.transfer(pair.address, web3.utils.toWei("100"), { from: user1 });
await token1.transfer(pair.address, web3.utils.toWei("200"), { from: user1 });
await pair.mint(user1, { from: user1 });
// ์ค์์ ์ํ ํ ํฐ ์ ์ก
await token0.transfer(pair.address, web3.utils.toWei("10"), { from: user1 });
// ์ค์ ์คํ
const token1Before = await token1.balanceOf(user2);
await pair.swap(0, web3.utils.toWei("18"), user2, { from: user1 });
const token1After = await token1.balanceOf(user2);
// ๊ฒ์ฆ
const received = token1After.sub(token1Before);
assert.equal(received.toString(), web3.utils.toWei("18"), "Should receive correct amount");
// K ๊ฐ ๊ฒ์ฆ
const reserves = await pair.getReserves();
const k = reserves[0].mul(reserves[1]);
assert(k.gte(web3.utils.toWei("100").mul(web3.utils.toWei("200"))), "K should not decrease");
});
});
- ํตํฉ ํ ์คํธ(Integration Testing): ์ฌ๋ฌ ์ปจํธ๋ํธ๊ฐ ํจ๊ป ์ ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์์. Factory, Pair, Router ์ปจํธ๋ํธ๊ฐ ํจ๊ป ์ ์๋ํ๋์ง ํ ์คํธํด์.
- ์๋๋ฆฌ์ค ํ ์คํธ(Scenario Testing): ์ค์ ์ฌ์ฉ์ ์๋๋ฆฌ์ค๋ฅผ ์๋ฎฌ๋ ์ด์ ํ๋ ํ ์คํธ์์. ์๋ฅผ ๋ค์ด, ์ ๋์ฑ ์ถ๊ฐ โ ํ ํฐ ์ค์ โ ์ ๋์ฑ ์ ๊ฑฐ์ ๊ฐ์ ์ ์ฒด ํ๋ฆ์ ํ ์คํธํด์.
- ์คํธ๋ ์ค ํ ์คํธ(Stress Testing): ๊ทน๋จ์ ์ธ ์ํฉ์์๋ ์์คํ ์ด ์ ์๋ํ๋์ง ํ์ธํ๋ ํ ์คํธ์์. ์๋ฅผ ๋ค์ด, ๋งค์ฐ ํฐ ๊ธ์ก์ ์ค์์ด๋ ์ ๋์ฑ ํ์ด ๊ฑฐ์ ๊ณ ๊ฐ๋ ์ํฉ ๋ฑ์ ํ ์คํธํด์.
- ํผ์ง ํ ์คํธ(Fuzzing Testing): ๋ฌด์์ ์ ๋ ฅ๊ฐ์ผ๋ก ์์คํ ์ ํ ์คํธํด ์์์น ๋ชปํ ๋ฒ๊ทธ๋ฅผ ์ฐพ๋ ๋ฐฉ๋ฒ์ด์์. Echidna๋ Harvey ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํ ์ ์์ด์.
๐ ๋ณด์ ๊ฐ์ฌ
DEX ์ถ์ ์ ์๋ ๋ฐ๋์ ์ ๋ฌธ์ ์ธ ๋ณด์ ๊ฐ์ฌ๋ฅผ ๋ฐ์์ผ ํด์. ๋ณด์ ๊ฐ์ฌ๋ ๋ค์๊ณผ ๊ฐ์ ๋จ๊ณ๋ก ์งํ๋ผ์:
- ์ ์ ๋ถ์(Static Analysis): ์ฝ๋๋ฅผ ์คํํ์ง ์๊ณ ๋ถ์ํ๋ ๋ฐฉ๋ฒ์ด์์. Slither, MythX ๊ฐ์ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด ์๋ํ๋ ๋ถ์์ ์ํํ ์ ์์ด์.
- ์๋ ์ฝ๋ ๋ฆฌ๋ทฐ(Manual Code Review): ๋ณด์ ์ ๋ฌธ๊ฐ๊ฐ ์ง์ ์ฝ๋๋ฅผ ๊ฒํ ํ๋ ๊ณผ์ ์ด์์. ์๋ํ๋ ๋๊ตฌ๋ก๋ ์ฐพ๊ธฐ ์ด๋ ค์ด ๋ณต์กํ ์ทจ์ฝ์ ์ ๋ฐ๊ฒฌํ ์ ์์ด์.
- ํ์ ๊ฒ์ฆ(Formal Verification): ์ํ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํด ์ฝ๋๊ฐ ๋ช ์ธ์ ๋ง๊ฒ ์๋ํจ์ ์ฆ๋ช ํ๋ ๋ฐฉ๋ฒ์ด์์. ๋ณต์กํ์ง๋ง ๋์ ์์ค์ ๋ณด์ฆ์ ์ ๊ณตํด์.
์ฃผ์ ๋ณด์ ๊ฐ์ฌ ์ ์ฒด๋ก๋ OpenZeppelin, CertiK, Trail of Bits, ConsenSys Diligence ๋ฑ์ด ์์ด์. ์ด๋ฐ ์ ๋ฌธ ์ ์ฒด์ ๊ฐ์ฌ๋ฅผ ๋ฐ์ผ๋ฉด ์ฌ์ฉ์๋ค์ ์ ๋ขฐ๋ฅผ ์ป๋ ๋ฐ ํฐ ๋์์ด ๋ผ์!
โ ๏ธ ์ผ๋ฐ์ ์ธ DEX ์ทจ์ฝ์
DEX์์ ์์ฃผ ๋ฐ๊ฒฌ๋๋ ์ทจ์ฝ์ ๋ค์ด์์. ์ด๋ฐ ๋ถ๋ถ๋ค์ ํนํ ์ฃผ์ํด์ผ ํด์:
- ๋ฆฌ์ํธ๋ฐ์ ๊ณต๊ฒฉ(Reentrancy Attack): ์ธ๋ถ ํธ์ถ ์ค์ ์ปจํธ๋ํธ์ ์ํ๊ฐ ๋ณ๊ฒฝ๋๊ธฐ ์ ์ ๋ค์ ์ง์ ํด ๊ณต๊ฒฉํ๋ ๋ฐฉ์์ด์์. ์ด๋๋ฆฌ์์ DAO ํดํน์ ์ฌ์ฉ๋ ์ ๋ช ํ ๊ณต๊ฒฉ ๋ฐฉ์์ด์ฃ .
- ํ๋ก ํธ๋ฌ๋(Front-running): ์ฑ๊ตด์๋ ๋ค๋ฅธ ์ฌ์ฉ์๊ฐ ํธ๋์ญ์ ์ ๊ด์ฐฐํ๊ณ ๋ ๋์ ๊ฐ์ค๋น๋ก ๋จผ์ ์คํ์์ผ ์ด์ต์ ์ทจํ๋ ๊ณต๊ฒฉ์ด์์. DEX์์๋ ํนํ ํฐ ์ค์ ํธ๋์ญ์ ์ ๋ ธ๋ฆฌ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์์.
- ํ๋์๋ก ๊ณต๊ฒฉ(Flash Loan Attack): ๋ด๋ณด ์์ด ๋์ถ๋ฐ์ ๋๋์ ํ ํฐ์ผ๋ก ๊ฐ๊ฒฉ์ ์กฐ์ํ ํ ์ด์ต์ ์ทจํ๋ ๊ณต๊ฒฉ์ด์์.
- ์ ์ ์ค๋ฒํ๋ก/์ธ๋ํ๋ก(Integer Overflow/Underflow): ์ํ์ ์ฐ์ฐ ์ค ๋ณ์์ ๋ฒ์๋ฅผ ๋ฒ์ด๋๋ ๊ฐ์ด ๋ฐ์ํ ๋ ์๊ธฐ๋ ์ทจ์ฝ์ ์ด์์. Solidity 0.8.0 ์ด์์์๋ ์๋์ผ๋ก ์ฒดํฌํด์ฃผ์ง๋ง, ๊ทธ ์ด์ ๋ฒ์ ์์๋ SafeMath ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํด์.
- ์ค๋ผํด ์กฐ์(Oracle Manipulation): ๊ฐ๊ฒฉ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ์ค๋ผํด์ ์กฐ์ํด ๋ถ๋นํ ์ด์ต์ ์ทจํ๋ ๊ณต๊ฒฉ์ด์์.
๐ก๏ธ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก
DEX ๊ฐ๋ฐ ์ ๋ฐ๋ผ์ผ ํ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก๋ค์ด์์:
- Checks-Effects-Interactions ํจํด: ์ธ๋ถ ํธ์ถ ์ ์ ๋ชจ๋ ์ํ ๋ณ๊ฒฝ์ ์๋ฃํด ๋ฆฌ์ํธ๋ฐ์ ๊ณต๊ฒฉ์ ๋ฐฉ์งํด์.
- Pull over Push ํจํด: ์๊ธ์ ์ง์ ์ ์กํ๋ ๋์ ์ฌ์ฉ์๊ฐ ์ธ์ถํ ์ ์๊ฒ ํด์.
- ๊ฐ์ค ์ ํ ์ค์ : ์ธ๋ถ ํธ์ถ ์ ๊ฐ์ค ์ ํ์ ์ค์ ํด DoS ๊ณต๊ฒฉ์ ๋ฐฉ์งํด์.
- ํ์์คํฌํ ์กฐ์ ๋ฐฉ์ง: block.timestamp์ ์์กดํ๋ ๊ฒฝ์ฐ, ์ฝ๊ฐ์ ๋ณ๋์ ํ์ฉํด์ผ ํด์.
- ๊ธด๊ธ ์ ์ง ๊ธฐ๋ฅ: ์ฌ๊ฐํ ์ทจ์ฝ์ ์ด ๋ฐ๊ฒฌ๋์ ๋ ์์คํ ์ ์ผ์ ์ค๋จํ ์ ์๋ ๊ธฐ๋ฅ์ ๊ตฌํํด์.
- ์ ์ง์ ์ถ์: ์ฒ์๋ถํฐ ๋๋์ ์๊ธ์ ๋ค๋ฃจ์ง ์๊ณ , ๋จ๊ณ์ ์ผ๋ก ์ ํ์ ํ์ด๊ฐ๋ฉฐ ์ถ์ํด์.
- ๋ฒ๊ทธ ๋ฐ์ดํฐ ํ๋ก๊ทธ๋จ: ์ทจ์ฝ์ ์ ๋ฐ๊ฒฌํ ์ฌ๋์๊ฒ ๋ณด์์ ์ ๊ณตํด ๋ณด์์ ๊ฐํํด์.
ํ ์คํ ๊ณผ ๋ณด์ ๊ฐ์ฌ๋ DEX ๊ฐ๋ฐ์์ ์ ๋ ์ํํ ํ ์ ์๋ ๋ถ๋ถ์ด์์. ์ฌ์ฉ์์ ์์ฐ์ ๋ค๋ฃจ๋ ๋งํผ, ์ต๋ํ์ ์ฃผ์์ ๋ ธ๋ ฅ์ ๊ธฐ์ธ์ฌ์ผ ํด์. ๋ค์ ์น์ ์์๋ DEX ์ถ์์ ์ด์ ์ ๋ต์ ๋ํด ์์๋ณผ๊ฒ์! ๐
8. DEX ์ถ์ ๋ฐ ์ด์ ์ ๋ต ๐
๋๋์ด DEX ๊ฐ๋ฐ์ด ๊ฑฐ์ ์๋ฃ๋์ด์! ์ด์ ์ฑ๊ณต์ ์ธ ์ถ์์ ์ง์์ ์ธ ์ด์์ ์ํ ์ ๋ต์ ์ธ์๋ณผ ์ฐจ๋ก์์. ์๋ฌด๋ฆฌ ์ข์ DEX๋ผ๋ ์ฌ์ฉ์๊ฐ ์์ผ๋ฉด ์์ฉ์์ผ๋๊น์! ์ด๋ป๊ฒ ํ๋ฉด ๋ง์ ์ฌ์ฉ์์ ์ ๋์ฑ์ ํ๋ณดํ ์ ์์์ง ์์๋ณผ๊ฒ์. ๐
๐ฑ ํ ์คํธ๋ท ๋ฐฐํฌ ๋ฐ ๋ฒ ํ ํ ์คํธ
๋ฉ์ธ๋ท์ ๋ฐ๋ก ์ถ์ํ๊ธฐ ์ ์ ํ ์คํธ๋ท์์ ์ถฉ๋ถํ ํ ์คํธ๋ฅผ ์งํํด์ผ ํด์:
- ํ ์คํธ๋ท ์ ํ: ์ด๋๋ฆฌ์์ Goerli, Sepolia๋ BSC์ ํ ์คํธ๋ท ๋ฑ ๋ชฉํ ๋ธ๋ก์ฒด์ธ์ ํ ์คํธ๋ท์ ์ ํํด์.
- ํ ์คํธ๋ท ๋ฐฐํฌ: ๋ชจ๋ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ํ ์คํธ๋ท์ ๋ฐฐํฌํด์. Hardhat์ด๋ Truffle์ ์ฌ์ฉํ๋ฉด ์ฝ๊ฒ ๋ฐฐํฌํ ์ ์์ด์:
// scripts/deploy.js
async function main() {
// ๊ณ์ ๊ฐ์ ธ์ค๊ธฐ
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
// Factory ๋ฐฐํฌ
const Factory = await ethers.getContractFactory("Factory");
const factory = await Factory.deploy();
await factory.deployed();
console.log("Factory deployed to:", factory.address);
// Router ๋ฐฐํฌ
const Router = await ethers.getContractFactory("Router");
const router = await Router.deploy(factory.address);
await router.deployed();
console.log("Router deployed to:", router.address);
// ๋ฐฐํฌ ์ ๋ณด ์ ์ฅ
const deploymentInfo = {
factory: factory.address,
router: router.address,
network: network.name,
timestamp: new Date().toISOString()
};
fs.writeFileSync(
"deployment.json",
JSON.stringify(deploymentInfo, null, 2)
);
}
main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
- ๋ฒ ํ ํ ์คํฐ ๋ชจ์ง: ์ปค๋ฎค๋ํฐ์์ ๋ฒ ํ ํ ์คํฐ๋ฅผ ๋ชจ์งํด ์ค์ ์ฌ์ฉ์ ํผ๋๋ฐฑ์ ์์งํด์.
- ๋ฒ๊ทธ ์์ ๋ฐ ๊ฐ์ : ๋ฒ ํ ํ ์คํธ์์ ๋ฐ๊ฒฌ๋ ๋ฌธ์ ์ ์ ์์ ํ๊ณ UX๋ฅผ ๊ฐ์ ํด์.
๐ ๋ฉ์ธ๋ท ์ถ์ ์ ๋ต
๋ฉ์ธ๋ท ์ถ์๋ ์ ์คํ๊ฒ ๊ณํํด์ผ ํด์:
- ์ ์ง์ ์ถ์: ์ฒ์๋ถํฐ ๋ชจ๋ ๊ธฐ๋ฅ์ ๊ณต๊ฐํ์ง ์๊ณ , ๋จ๊ณ์ ์ผ๋ก ์ถ์ํด์. ์๋ฅผ ๋ค์ด, ์ฒ์์๋ ์์์ ํ ํฐ ํ์ด๋ง ์ง์ํ๊ณ ์ ์ฐจ ํ์ฅํ ์ ์์ด์.
- ์ ๋์ฑ ํ๋ณด ์ ๋ต: ์ด๊ธฐ ์ ๋์ฑ์ ํ๋ณดํ๊ธฐ ์ํ ์ ๋ต์ด ํ์ํด์. ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ ๊ณ ๋ คํ ์ ์์ด์:
- ํ์ด ์ง์ ์ด๊ธฐ ์ ๋์ฑ ์ ๊ณต
- ์ ๋์ฑ ๋ง์ด๋ ํ๋ก๊ทธ๋จ ์ด์
- ์ ๋ต์ ํํธ๋์ ํ๋ ฅ
- ๊ฑฐ๋ฒ๋์ค ํ ํฐ ์ถ์: DEX์ ๊ฑฐ๋ฒ๋์ค๋ฅผ ์ํ ํ ํฐ์ ์ถ์ํ๋ ๊ฒ๋ ์ข์ ์ ๋ต์ด์์. ์ด ํ ํฐ์ ๋ค์๊ณผ ๊ฐ์ ์ฉ๋๋ก ์ฌ์ฉ๋ ์ ์์ด์:
- ํ๋กํ ์ฝ ๋ณ๊ฒฝ์ ๋ํ ํฌํ
- ์์๋ฃ ์์ต ๋ถ๋ฐฐ
- ์ ๋์ฑ ๋ง์ด๋ ๋ณด์
- ๋ณด์ ๋ชจ๋ํฐ๋ง: ์ถ์ ํ์๋ ์ง์์ ์ธ ๋ณด์ ๋ชจ๋ํฐ๋ง์ด ํ์ํด์. ํนํ ์ด๊ธฐ์๋ ๋ ์ฃผ์ ๊น๊ฒ ๊ด์ฐฐํด์ผ ํด์.
๐ฃ ๋ง์ผํ ๋ฐ ์ปค๋ฎค๋ํฐ ๋น๋ฉ
DEX์ ์ฑ๊ณต์ ์ํด์๋ ํจ๊ณผ์ ์ธ ๋ง์ผํ ๊ณผ ํ๋ฐํ ์ปค๋ฎค๋ํฐ๊ฐ ํ์์์:
- ์์ ๋ฏธ๋์ด ์ ๋ต: Twitter, Discord, Telegram ๋ฑ์ ํ๋ซํผ์ ํ์ฉํด ์ปค๋ฎค๋ํฐ๋ฅผ ๊ตฌ์ถํด์.
- ์ฝํ ์ธ ๋ง์ผํ : ๋ธ๋ก๊ทธ ํฌ์คํธ, ํํ ๋ฆฌ์ผ, ๋น๋์ค ๋ฑ ๊ต์ก ์ฝํ ์ธ ๋ฅผ ์ ์ํด ์ฌ์ฉ์๋ค์๊ฒ ๊ฐ์น๋ฅผ ์ ๊ณตํด์.
- ์ธํ๋ฃจ์ธ์ ํ๋ ฅ: ์ํธํํ ์ธํ๋ฃจ์ธ์์ ํ๋ ฅํด ๋ ๋ง์ ์ฌ์ฉ์์๊ฒ ๋๋ฌํ ์ ์์ด์.
- ์์ด๋๋กญ ๋ฐ ์ธ์ผํฐ๋ธ: ์ด๊ธฐ ์ฌ์ฉ์์๊ฒ ํ ํฐ์ ์์ด๋๋กญํ๊ฑฐ๋ ํน๋ณ ์ธ์ผํฐ๋ธ๋ฅผ ์ ๊ณตํด ์ฌ์ฉ์ ๊ธฐ๋ฐ์ ํ๋ํ ์ ์์ด์.
- DeFi ์ํ๊ณ ํตํฉ: ๋ค๋ฅธ DeFi ํ๋กํ ์ฝ๊ณผ ํตํฉํด ์๋์ง๋ฅผ ์ฐฝ์ถํ ์ ์์ด์. ์๋ฅผ ๋ค์ด, ๋์ถ ํ๋ซํผ์ด๋ ์์ต ๋์ฌ(Yield Farming) ํ๋กํ ์ฝ๊ณผ ํ๋ ฅํ ์ ์์ด์.
๐ ์ฑ๊ณผ ์ธก์ ๋ฐ ๊ฐ์
DEX์ ์ฑ๊ณผ๋ฅผ ์ง์์ ์ผ๋ก ์ธก์ ํ๊ณ ๊ฐ์ ํด์ผ ํด์:
- ํต์ฌ ์งํ ๋ชจ๋ํฐ๋ง: ๋ค์๊ณผ ๊ฐ์ ์งํ๋ฅผ ์ถ์ ํด์ผ ํด์:
- ์ด ์ ๋์ฑ(TVL, Total Value Locked)
- ์ผ์ผ ๊ฑฐ๋๋(Daily Trading Volume)
- ์ผ์ผ ํ์ฑ ์ฌ์ฉ์(DAU, Daily Active Users)
- ์์๋ฃ ์์ต
- ์ ๋์ฑ ํ๋ณ APY
- ์ฌ์ฉ์ ํผ๋๋ฐฑ ์์ง: ์ฌ์ฉ์์ ํผ๋๋ฐฑ์ ์ ๊ทน์ ์ผ๋ก ์์งํ๊ณ ๋ฐ์ํด์.
- A/B ํ ์คํ : UI/UX ๊ฐ์ ์ ์ํด A/B ํ ์คํ ์ ์งํํด์.
- ์ ๊ธฐ์ ์ธ ์ ๋ฐ์ดํธ: ์๋ก์ด ๊ธฐ๋ฅ๊ณผ ๊ฐ์ ์ฌํญ์ ์ ๊ธฐ์ ์ผ๋ก ์ถ์ํด์.
๐๏ธ ๊ท์ ๋์ ์ ๋ต
DEX ์ด์ ์ ๊ท์ ๋ฌธ์ ์๋ ๋๋นํด์ผ ํด์:
- ๋ฒ๋ฅ ์๋ฌธ ๊ตฌํ๊ธฐ: ์ํธํํ ๊ท์ ์ ์ ํตํ ๋ฒ๋ฅ ์ ๋ฌธ๊ฐ์ ์๋ฌธ์ ๊ตฌํด์.
- ๊ท์ ๋ณํ ๋ชจ๋ํฐ๋ง: ์ ์ธ๊ณ ๊ท์ ๋ํฅ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํด์.
- DAO ์ ํ ๊ณ ๋ ค: ์ฅ๊ธฐ์ ์ผ๋ก๋ ํ์ค์ํ ์์จ ์กฐ์ง(DAO)์ผ๋ก ์ ํํด ๊ท์ ๋ฆฌ์คํฌ๋ฅผ ๋ถ์ฐ์ํฌ ์ ์์ด์.
- ์ง์ญ๋ณ ์ ๊ทผ ์ ํ: ํ์ํ ๊ฒฝ์ฐ ํน์ ์ง์ญ์ ์ฌ์ฉ์ ์ ๊ทผ์ ์ ํํ ์ ์๋ ๋ฉ์ปค๋์ฆ์ ๊ตฌํํด์.
DEX์ ์ถ์์ ์ด์์ ๊ฐ๋ฐ๋งํผ์ด๋ ์ค์ํ ๊ณผ์ ์ด์์. ์ง์์ ์ธ ๊ฐ์ ๊ณผ ์ปค๋ฎค๋ํฐ ๋น๋ฉ์ ํตํด ์ฅ๊ธฐ์ ์ธ ์ฑ๊ณต์ ์ด๋ฃฐ ์ ์์ด์. ๋ค์ ์น์ ์์๋ DEX์ ๋ฏธ๋ ์ ๋ง๊ณผ ๋ฐ์ ๋ฐฉํฅ์ ๋ํด ์์๋ณผ๊ฒ์! ๐ฎ
9. ๋ฏธ๋ ์ ๋ง ๋ฐ ๋ฐ์ ๋ฐฉํฅ ๐ฎ
DEX ์์ฅ์ ๊ณ์ํด์ ๋น ๋ฅด๊ฒ ์งํํ๊ณ ์์ด์. ์ง๊ธ DEX๋ฅผ ๊ตฌ์ถํ๋ ๊ฒ์ ๋จ์ํ ํ์ฌ ํธ๋ ๋๋ฅผ ๋ฐ๋ฅด๋ ๊ฒ์ด ์๋๋ผ, ๊ธ์ต์ ๋ฏธ๋๋ฅผ ๋ง๋ค์ด๊ฐ๋ ์ผ์ด๋ผ๊ณ ํ ์ ์์ด์! ์์ผ๋ก DEX๋ ์ด๋ป๊ฒ ๋ฐ์ ํ ์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ค ํ์ ์ ์ธ ๊ธฐ๋ฅ๋ค์ด ๋ฑ์ฅํ ์ง ์ดํด๋ณผ๊ฒ์. ๐
๐ ํฌ๋ก์ค ์ฒด์ธ DEX
ํ์ฌ ๋๋ถ๋ถ์ DEX๋ ๋จ์ผ ๋ธ๋ก์ฒด์ธ์์๋ง ์๋ํด์. ํ์ง๋ง ๋ฏธ๋์๋ ์ฌ๋ฌ ๋ธ๋ก์ฒด์ธ ๊ฐ์ ์ํํ ๊ฑฐ๋๋ฅผ ์ง์ํ๋ ํฌ๋ก์ค ์ฒด์ธ DEX๊ฐ ์ฃผ๋ฅ๊ฐ ๋ ๊ฑฐ์์:
- ์์์ ์ค์(Atomic Swaps): ์๋ก ๋ค๋ฅธ ๋ธ๋ก์ฒด์ธ์ ํ ํฐ์ ์ค๊ฐ์ ์์ด ์ง์ ๊ตํํ๋ ๊ธฐ์ ์ด์์.
- ๋ธ๋ฆฟ์ง ํตํฉ: ๋ค์ํ ๋ธ๋ก์ฒด์ธ ๋ธ๋ฆฟ์ง๋ฅผ ํตํฉํด ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ์ฒด์ธ ๊ฐ์ ์์ฐ์ ์ฝ๊ฒ ์ด๋ํ ์ ์๊ฒ ํด์.
- ๋ ์ด์ด 2 ์๋ฃจ์ : ์ด๋๋ฆฌ์์ Optimism, Arbitrum ๊ฐ์ L2 ์๋ฃจ์ ์ ํตํฉํด ๊ฐ์ค๋น๋ฅผ ์ ๊ฐํ๊ณ ์ฒ๋ฆฌ ์๋๋ฅผ ๋์ฌ์.
๐ค AI ๊ธฐ๋ฐ ๊ฑฐ๋ ๋ฐ ์ ๋์ฑ ๊ด๋ฆฌ
์ธ๊ณต์ง๋ฅ์ DEX์ ๋ค์ํ ์ธก๋ฉด์ ๊ฐ์ ํ ์ ์์ด์:
- ์ต์ ์ ๊ฑฐ๋ ๊ฒฝ๋ก ์ฐพ๊ธฐ: AI๊ฐ ์ฌ๋ฌ DEX์ ํ ํฐ ํ์ด๋ฅผ ๋ถ์ํด ์ต์ ์ ๊ฑฐ๋ ๊ฒฝ๋ก๋ฅผ ์ถ์ฒํด์.
- ๋์ ์์๋ฃ ์กฐ์ : ์์ฅ ์ํฉ์ ๋ฐ๋ผ AI๊ฐ ์๋์ผ๋ก ์์๋ฃ๋ฅผ ์กฐ์ ํด ์ ๋์ฑ์ ์ต์ ํํด์.
- ์ ๋์ฑ ์์ธก: AI๊ฐ ๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํด ๋ฏธ๋ ์ ๋์ฑ ์์๋ฅผ ์์ธกํ๊ณ , ๊ทธ์ ๋ง๊ฒ ์ธ์ผํฐ๋ธ๋ฅผ ์กฐ์ ํด์.
- ์ด์ ๊ฑฐ๋ ๊ฐ์ง: AI๊ฐ ๋น์ ์์ ์ธ ๊ฑฐ๋ ํจํด์ ๊ฐ์งํด ์ ์ฌ์ ์ธ ๊ณต๊ฒฉ์ ์๋ฐฉํด์.
๐ฆ ์ค๋ฌผ ์์ฐ์ ํ ํฐํ
DEX์ ๋ฏธ๋๋ ์ํธํํ๋ฅผ ๋์ด ์ค๋ฌผ ์์ฐ์ ํ ํฐํ(Tokenization)์ ๊ฑฐ๋๋ก ํ์ฅ๋ ๊ฑฐ์์:
- ํ ํฐํ๋ ์ฃผ์: ์ ํต์ ์ธ ์ฃผ์ ์์ฅ์ ์ฃผ์์ ํ ํฐํํด DEX์์ ๊ฑฐ๋ํ ์ ์์ด์.
- ๋ถ๋์ฐ ํ ํฐ: ๋ถ๋์ฐ์ ํ ํฐํํด ์์ก์ผ๋ก๋ ๋ถ๋์ฐ์ ํฌ์ํ ์ ์๊ฒ ํด์.
- ์ํ(Commodities) ํ ํฐ: ๊ธ, ์, ์์ ๊ฐ์ ์ํ์ ํ ํฐํํด 24/7 ๊ฑฐ๋ํ ์ ์๊ฒ ํด์.
- ํ์ ํฌ๋ ๋ง ํ ํฐ: ํ๊ฒฝ ๋ณดํธ๋ฅผ ์ํ ํ์ ํฌ๋ ๋ง์ ํ ํฐํํด ๊ฑฐ๋ํ ์ ์์ด์.
๐ ํ๋ผ์ด๋ฒ์ ๊ฐํ ๊ธฐ์
๋ธ๋ก์ฒด์ธ์ ํฌ๋ช ์ฑ์ ์ฅ์ ์ด์ง๋ง, ๊ธ์ต ๊ฑฐ๋์์๋ ํ๋ผ์ด๋ฒ์๋ ์ค์ํด์. ๋ฏธ๋์ DEX๋ ๋ค์๊ณผ ๊ฐ์ ํ๋ผ์ด๋ฒ์ ๊ธฐ์ ์ ๋์ ํ ๊ฑฐ์์:
- ์ ๋ก ์ง์ ์ฆ๋ช (Zero-Knowledge Proofs): ๊ฑฐ๋ ์ ๋ณด๋ฅผ ๊ณต๊ฐํ์ง ์๊ณ ๋ ๊ฑฐ๋์ ์ ํจ์ฑ์ ์ฆ๋ช ํ ์ ์๋ ๊ธฐ์ ์ด์์.
- ๋น๋ฐ ๊ฑฐ๋(Confidential Transactions): ๊ฑฐ๋ ๊ธ์ก์ ์ํธํํด ์ 3์๊ฐ ๋ณผ ์ ์๊ฒ ํ๋ ๊ธฐ์ ์ด์์.
- ๋ฏน์(Mixer) ํตํฉ: ์ฌ๋ฌ ์ฌ์ฉ์์ ๊ฑฐ๋๋ฅผ ํผํฉํด ๊ฐ๋ณ ๊ฑฐ๋๋ฅผ ์ถ์ ํ๊ธฐ ์ด๋ ต๊ฒ ๋ง๋๋ ๊ธฐ์ ์ด์์.
โก ํ์ฅ์ฑ ํด๊ฒฐ์ฑ
ํ์ฌ DEX์ ๊ฐ์ฅ ํฐ ๊ณผ์ ์ค ํ๋๋ ํ์ฅ์ฑ์ด์์. ๋ฏธ๋์๋ ๋ค์๊ณผ ๊ฐ์ ํด๊ฒฐ์ฑ ์ด ๋์ฑ ๋ฐ์ ํ ๊ฑฐ์์:
- ์ค๋ฉ(Sharding): ๋ธ๋ก์ฒด์ธ์ ์ฌ๋ฌ ์กฐ๊ฐ(์ค๋)์ผ๋ก ๋๋ ๋ณ๋ ฌ ์ฒ๋ฆฌํ๋ ๊ธฐ์ ์ด์์.
- ๋กค์ (Rollups): ์ฌ๋ฌ ํธ๋์ญ์ ์ ๋ฌถ์ด์ ์ฒ๋ฆฌํ ํ ๋ฉ์ธ ์ฒด์ธ์ ํ ๋ฒ์ ๊ธฐ๋กํ๋ ๊ธฐ์ ์ด์์.
- ์ํ ์ฑ๋(State Channels): ๋ธ๋ก์ฒด์ธ ์ธ๋ถ์์ ์ฌ๋ฌ ๊ฑฐ๋๋ฅผ ์ฒ๋ฆฌํ ํ ์ต์ข ๊ฒฐ๊ณผ๋ง ๋ธ๋ก์ฒด์ธ์ ๊ธฐ๋กํ๋ ๊ธฐ์ ์ด์์.
- ํ๋ผ์ฆ๋ง(Plasma): ๋ฉ์ธ ์ฒด์ธ์์ ํ์๋ ์์ ์ฒด์ธ์์ ๊ฑฐ๋๋ฅผ ์ฒ๋ฆฌํ๋ ๊ธฐ์ ์ด์์.
๐ DAO ๊ธฐ๋ฐ ๊ฑฐ๋ฒ๋์ค์ ์งํ
DEX์ ๊ฑฐ๋ฒ๋์ค ๋ชจ๋ธ๋ ๊ณ์ ์งํํ ๊ฑฐ์์:
- ์ก์ฒด ๋ฏผ์ฃผ์ฃผ์(Liquid Democracy): ํฌํ๊ถ์ ๋ค๋ฅธ ์ฌ์ฉ์์๊ฒ ์์ํ ์ ์๋ ์์คํ ์ด์์.
- ์ฟผ๋๋ผํฑ ํฌํ(Quadratic Voting): ํฌํ ๋น์ฉ์ด ํฌํ ์์ ์ ๊ณฑ์ ๋น๋กํ๋ ์์คํ ์ผ๋ก, ์์์ ์๊ฒฌ๋ ๋ฐ์๋ ์ ์๊ฒ ํด์.
- ๋ ์ด์ด๋ ๊ฑฐ๋ฒ๋์ค(Layered Governance): ๋ค์ํ ๊ฒฐ์ ์ฌํญ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฑฐ๋ฒ๋์ค ๋ฉ์ปค๋์ฆ์ ์ ์ฉํ๋ ์์คํ ์ด์์.
- ํํ ์์คํ (Reputation Systems): ๊ณผ๊ฑฐ ๊ธฐ์ฌ๋์ ๋ฐ๋ผ ๊ฑฐ๋ฒ๋์ค ์ํฅ๋ ฅ์ด ๊ฒฐ์ ๋๋ ์์คํ ์ด์์.
๐ DEX ๊ฐ๋ฐ์๋ก์์ ๋ฏธ๋
DEX ๊ฐ๋ฐ์ ๋ธ๋ก์ฒด์ธ ์ฐ์ ์์ ๊ฐ์ฅ ํฅ๋ฏธ๋กญ๊ณ ์์๊ฐ ๋์ ๋ถ์ผ ์ค ํ๋์์. ์ด ๋ถ์ผ์์ ๊ฒฝ๋ ฅ์ ์์ผ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ธฐํ๋ฅผ ์ป์ ์ ์์ด์:
- DeFi ํ๋กํ ์ฝ ๊ฐ๋ฐ์: DEX ์ธ์๋ ๋์ถ, ํ์์ํ, ๋ณดํ ๋ฑ ๋ค์ํ DeFi ํ๋กํ ์ฝ์ ๊ฐ๋ฐํ ์ ์์ด์.
- ๋ธ๋ก์ฒด์ธ ์ํคํ ํธ: ๋ณต์กํ ๋ธ๋ก์ฒด์ธ ์์คํ ์ ์ค๊ณ์ ๊ตฌํ์ ๋ด๋นํ๋ ์ ๋ฌธ๊ฐ๊ฐ ๋ ์ ์์ด์.
- ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ์ฌ์: ๋ค๋ฅธ ํ๋ก์ ํธ์ ์ค๋งํธ ์ปจํธ๋ํธ ๋ณด์์ ๊ฒํ ํ๋ ์ ๋ฌธ๊ฐ๊ฐ ๋ ์ ์์ด์.
- DeFi ์ฐฝ์ ์: ์์ ๋ง์ ํ์ ์ ์ธ DeFi ํ๋ก์ ํธ๋ฅผ ์์ํ ์ ์์ด์.
- ๋ธ๋ก์ฒด์ธ ์ปจ์คํดํธ: ๊ธฐ์ ๋ค์ด ๋ธ๋ก์ฒด์ธ ๊ธฐ์ ์ ๋์ ํ๋ ๊ฒ์ ๋๋ ์ปจ์คํดํธ๊ฐ ๋ ์ ์์ด์.
์ฌ๋ฅ๋ท์์๋ ์ด๋ฐ ๋ธ๋ก์ฒด์ธ ๊ด๋ จ ์ฌ๋ฅ์ ๊ณต์ ํ๊ณ ๊ฑฐ๋ํ ์ ์์ด์. ์ฌ๋ฌ๋ถ์ด DEX ๊ฐ๋ฐ์ ํตํด ์ป์ ์ง์๊ณผ ๊ฒฝํ์ ๋งค์ฐ ๊ฐ์น ์๋ ์ฌ๋ฅ์ด ๋ ์ ์์ด์! ๐
๐ ๊ฒฐ๋ก
DEX๋ ๋จ์ํ ์ํธํํ ๊ฑฐ๋ ํ๋ซํผ์ ๋์ด, ๊ธ์ต์ ๋ฏธ๋๋ฅผ ์ฌ์ ์ํ๋ ํ์ ์ ์ธ ๊ธฐ์ ์ด์์. ์ค์ํ๋ ์ค๊ฐ์ ์์ด๋ ์์ ํ๊ณ ํจ์จ์ ์ธ ๊ธ์ต ์๋น์ค๋ฅผ ์ ๊ณตํ ์ ์๋ค๋ ๊ฒ์ ์ฆ๋ช ํ๊ณ ์์ด์.
์ด ๊ธ์ ํตํด DEX ๊ตฌ์ถ์ ๊ธฐ๋ณธ ์๋ฆฌ๋ถํฐ ์ค์ ๊ตฌํ ๋ฐฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ๋ฏธ๋ ์ ๋ง๊น์ง ์ดํด๋ดค์ด์. ๋ธ๋ก์ฒด์ธ๊ณผ DeFi์ ์ธ๊ณ๋ ๊ณ์ํด์ ๋ฐ์ ํ๊ณ ์์ผ๋ฉฐ, DEX๋ ๊ทธ ์ค์ฌ์ ์์ด์.
์ฌ๋ฌ๋ถ๋ ์ด ํฅ๋ฏธ์ง์งํ ์ฌ์ ์ ๋์ฐธํด๋ณด์ธ์! ์ง์ DEX๋ฅผ ๊ตฌ์ถํ๋ฉฐ ๋ธ๋ก์ฒด์ธ์ ๊ฐ๋ฅ์ฑ์ ํํํ๊ณ , ๊ธ์ต์ ๋ฏธ๋๋ฅผ ํจ๊ป ๋ง๋ค์ด๊ฐ์. ํ์ดํ ! ๐
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.