반응형

웹3 및 NFT에서 자주 사용되는 용어 정리

중앙화 거래소(CEX)와 탈중앙화 거래소(DEX)

CEX (Centralized Exchange)

  • 대표 예시: 바이낸스, 업비트
  • 특징: 오더북 기반으로 거래를 처리하며, 장부 정리를 한꺼번에 수행합니다.

DEX (Decentralized Exchange)

  • 대표 예시: 유니스왑, 쥬피터
  • 특징: 스마트 컨트랙트를 활용하여 거래를 처리하며, 자산 보호를 제공하지 않음. 탈중앙화 특성상 보안에 주의가 필요합니다.

Contract Address (CA)

  • 토큰 주소를 의미하며, 특정 토큰의 고유 식별자 역할을 합니다.

상장 관련 용어

TGE (Token Generate Event)

  • 토큰이 발행되는 시점을 의미합니다.

Vesting

  • 토큰의 잠금 기간을 의미하며, 예를 들어 "TGE 60%, 1년 vesting 40%"는 상장 당시 60% 지급 후, 나머지 40%는 1년에 걸쳐 지급됨을 뜻합니다.

에어드랍 관련 용어

Airdrop

  • 특정 요건을 충족한 사용자에게 무료로 신규 코인을 배포하는 행위입니다.

WhiteList (WL)

  • 프로젝트에서 제공하는 우선 청약권을 의미합니다.

Snapshot

  • 특정 시점을 기준으로 조건에 맞는 사용자를 분리하는 행위를 뜻합니다.

Reveal

  • 선판매된 NFT를 고유 특성을 가진 NFT로 변환시키는 작업입니다.

토큰 관련 용어

SWAP

  • DEX에서 토큰 간 교환을 의미합니다.

MCAP (Market Capitalization)

  • 유통 중인 토큰의 시가총액입니다.

TVL (Total Value Locked)

  • 담보 또는 유동성 풀에 잠겨 있는 금액입니다.

FDV (Fully Diluted Valuation)

  • 전체 발행 가능한 토큰의 총 가치입니다.

런치패드, 런치풀, APR

런치패드

  • 신규 코인을 판매하는 방법으로, 공모주 청약과 유사한 방식입니다.

런치풀

  • 예치된 코인에 대해 상장 예정 코인을 이자로 받는 개념입니다.
  • 스테이킹: 기간이 끝날 때까지 인출 불가능.
  • 런치풀: 언제든 인출 가능.

APR (Annual Percentage Rate)

  • 연간 이자율을 의미합니다.

NFT 관련 용어

PFP

  • 프로필 사진(Profile Picture)으로 활용되는 NFT입니다.

Minting

  • NFT를 발행하는 과정을 뜻합니다.

브리딩 (Breeding)

  • NFT 프로젝트에서 새로운 프로젝트를 생성하는 행위로, 펏지 펭귄 → 릴 펏지와 같은 사례가 있습니다.

FP (Floor Price)

  • NFT의 최저가를 의미합니다.

플랫폼별 지갑

  1. 이더리움
    • 메타마스크, 래빗월렛
  2. 솔라나
    • 팬텀, 백팩
  3. 비트코인
    • 엑스버스, 유니삿

블록체인 및 거래 관련 필수 용어

MEV (Maximal Extractable Value)

  • 블록체인 거래에서 선순위 요청을 밀어내고 차익을 얻는 행위로, 일종의 새치기입니다.

슬리피지 (Slippage)

  • 주문 가격과 실제 거래 가격의 차이로, 유동성이 낮은 코인에서 자주 발생합니다.

Mintable

  • 무한 발행이 가능한 코인으로, 추가 발행 가능 여부를 항상 확인해야 합니다.

Conviction

  • 특정 코인에 강한 확신을 가지고 대량 매수하는 행위입니다.

Top Blast

  • 가격이 가장 높은 시점에서 매수하는 것을 의미합니다.

Freeze / 허니팟

  • 매도가 불가능하게 만들어 피해를 입히는 스캠 방식입니다.
반응형
반응형

Layout.tsx

import React, {FC} from "react";
import {Stack, Flex, Box, Text, Button} from '@chakra-ui/react';
import { Link } from "react-router-dom";

const Layout: FC = ({children}) =>{
    return( 
    
    <Stack h="100vh">
        <Flex bg="purple.200" p={4} justifyContent="space-around" alignItems="center">
            <Box>
                <Text fontWeight="bold">h662-Animals</Text>
            </Box>
            <Link to="/">
                <Button size="sm" colorScheme="blue">
                    Main
                </Button>
            </Link>
            <Link to="my-animal">
                <Button size="sm" colorScheme="red">
                    My Animal
                </Button>
            </Link>
            <Link to="sale-animal">
                <Button size="sm" colorScheme="green">
                    Sale Animal
                </Button>
            </Link>
        </Flex>
        <Flex direction="column" h="full" justifyContent="center" alignItems="center">
            {children}
        </Flex>
    </Stack>
    );
}

export default Layout

 

MyAnimalCard.tsx

 

import React , {FC, useState, ChangeEvent} from "react";
import {Box, Text, InputGroup, Input, InputRightAddon, Button} from "@chakra-ui/react"
import AnimalCard from "./AnimalCard";
import { saleAnimalTokenContract, web3 } from "../contracts";

export interface IMyanimalCard{
    animalTokenId : string;
    animalType : string;
    animalPrice : string;
}

interface MyAnimalCardProps extends IMyanimalCard {
    saleStatus:boolean;
    account:string;
}

const MyAnimalCard: FC<MyAnimalCardProps> = ({animalTokenId, animalType, animalPrice, saleStatus, account}) =>{
    const [sellPrice, setSellPrice] = useState<string>("");
    const [myAnimalPrice, setMyAnimalPrice] = useState<string>(animalPrice)

    const onChangeSellPrice = (e: ChangeEvent<HTMLInputElement>) =>{
        setSellPrice(e.target.value);
    }

    const onClickSell = async () =>{
        try{
            if(!account || !saleStatus) return;

            const response = await saleAnimalTokenContract.methods
            .setForSaleAnimalToken(animalTokenId, web3.utils.toWei(sellPrice, "ether"))
            .send({from:account});

            if(response.status) {
                setMyAnimalPrice(web3.utils.toWei(sellPrice, "ether"));
                console.log(response)
            }
        }catch(err){
            console.log(err);
        }
    }

    return(
        <Box textAlign="center" w={150}>
            <AnimalCard animalType={animalType} /><Box  mt={2}>
                {animalPrice === "0" ? (
                <>
                    <InputGroup>
                        <Input type='number' value={sellPrice} onChange={onChangeSellPrice}/>
                        <InputRightAddon children="Matic" />
                    </InputGroup>
                    <Button size="sm" colorScheme="green" mt={2} onClick={onClickSell}>
                        Sell
                    </Button>
                </>) : <Text d="inline-block">{web3.utils.fromWei(myAnimalPrice)} Matic</Text> }
            </Box>
        </Box>
    )
}

export default MyAnimalCard;

함수 설명

  1. onChangeSellPrice = (e: ChangeEvent<HTMLInputElement>)
    • Input 박스 내의 요소가 바뀔때마다 price 를 바꿔준다.
  2. onClickSell
    • 토큰을 판매 등록하는 함수

SaleAnimalCard.tsx

import React, {FC, useState, useEffect} from "react";
import AnimalCard from "./AnimalCard";
import {Box, Text, Button} from "@chakra-ui/react"
import { mintAnimalTokenContract, saleAnimalTokenContract, web3 } from "../contracts";

interface SaleAnimalCardProps{
    animalType:string;
    animalPrice:string;
    animalTokenId: string;
    account:string;
    getOnSaleAnimalTokens: () => Promise<void>;
}

const SaleAnimalCard:FC<SaleAnimalCardProps> =({animalType,animalPrice,animalTokenId, account,getOnSaleAnimalTokens}) =>{
    const [isBuyable, setIsBuyable] = useState<boolean>(false);

    const getAnimalTokenOwner = async () => {
        try{
            const response = await mintAnimalTokenContract.methods.ownerOf(animalTokenId).call();
            
            console.log(response)
            console.log(account);
            setIsBuyable(response.toLocaleLowerCase() === account.toLocaleLowerCase())
        } catch(err){
            console.log(err);
        }   
    } 

    const onClickBuy = async () =>{
        try{
            if(!account) return;
            const response = await saleAnimalTokenContract.methods.purchaseAnimalToken(animalTokenId).send({from: account, value:animalPrice});

            if(response.status){
                getOnSaleAnimalTokens();
            }
        } catch(err){
            console.log(err)
        }
    }

    useEffect(() => {
      
        getAnimalTokenOwner();
    }, [])
    

    return(
        <Box textAlign ="center" w={100}>
            <AnimalCard animalType={animalType} />
            <Box>
                <Text d="inline-block">
                    {web3.utils.fromWei(animalPrice)} Matic
                </Text>
                <Button size="sm" colorScheme="green" m={2} disabled={isBuyable} onClick={onClickBuy}>Buy</Button>
            </Box>
        </Box>
    )
}

export default SaleAnimalCard
반응형
반응형
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "MintAnimalToken.sol";

contract SaleAnimalToken {
    MintAnimalToken public mintAnimalTokenAddress;
    //디플로이 주소값을 담는다.

    constructor (address _mintAnimalTokenAddress) {
        mintAnimalTokenAddress = MintAnimalToken(_mintAnimalTokenAddress);
    }

    mapping(uint256 => uint256) public animalTokenPrices;
    //가격관리 맵핑

    uint256[] public onSaleAnimalTokenArray;
    //FE 에서 사용할 배열. 판매중이 토큰 확인용

    function setForSaleAnimalToken(uint256 _animalTokenId, uint256 _price) public {
        //판매 등록 함수

        address animalTokenOwner = mintAnimalTokenAddress.ownerOf(_animalTokenId);

        require(animalTokenOwner == msg.sender, "Caller is not animal token owner");
        //함수 실행 사람이 토큰의 주인이 맞는지
        require(_price > 0 , "Price is zero or lower");

        require(animalTokenPrices[_animalTokenId] == 0, "This animal token is already on sale.");

        require(mintAnimalTokenAddress.isApprovedForAll(animalTokenOwner, address(this)), "Animal token owner did not approve token.");
        //스마트컨트랙트 판매권한 여부를 확인
        
        animalTokenPrices[_animalTokenId] = _price;

        onSaleAnimalTokenArray.push(_animalTokenId);
    }
}

 

알고리즘

  • MintAnimalToken 장부를 먼저 Deploy 해야한다.
  • Deploy 된 장부의 주소값을 인자로 등록한다.
  • setForSaleAnimalToken 함수
    • 등록할 토큰의 ID 를 가진 주인의 주소를 불러온다.
    • 함수를 실행하는 사람이 msg.sender 가 주인이 맞는지 확인한다.
    • 가격이 0 초과인지 확인한다.
    • 판매등록이 되지 않은 상품인지 확인한다.
    • 해당 장부가 판매등록이 허가가 된 장부인지 확인한다.
    • 배열에 판매등록을 한다.

 

function purchaseAnimalToken(uint256 _animalTokenId) public payable {
        //payble 을 붙여야 matic 이 왔다갔다하는 함수를 실행할 수 있다.

        uint256 price = animalTokenPrices[_animalTokenId];
        address animalTokenOwner = mintAnimalTokenAddress.ownerOf(_animalTokenId);

        require(price > 0, "Animal Token not sale.");
        require(price <= msg.value, "Caller sent lower than price.");
        //함수를 실행할때 보내는 MATIC 의 양이 같거나 큰지 확인
        require(animalTokenOwner != msg.sender, "Caller is animal Token owner");

        payable(animalTokenOwner).transfer(msg.value);
        //가격만큼의 양이 돈의 주인으로 보내진다.

        mintAnimalTokenAddress.safeTransferFrom(animalTokenOwner, msg.sender, _animalTokenId);

        animalTokenPrices[_animalTokenId] = 0;

        for(uint256 i = 0; i<onSaleAnimalTokenArray.length;i++){
            if(animalTokenPrices[onSaleAnimalTokenArray[i]] == 0){
                onSaleAnimalTokenArray[i] = onSaleAnimalTokenArray[onSaleAnimalTokenArray.length -1];
                onSaleAnimalTokenArray.pop();
                //맨뒤랑 바꿔서 맨뒤 삭제
            }
        }
        
        
    }
    //읽기 전용 FE 함수
    //판매중인 리스트 확인용
    function getOnSaleAnimalTokenArrayLength() view public returns (uint256){
            return onSaleAnimalTokenArray.length;
    }

 

알고리즘

  • payable 을 사용해야 구입 판매 함수를 사용할 수 있다.
  • 구매할 토큰의 ID 와 토큰 주인의 주소를 불러온다.
  • 토큰의 판매여부를 확인
  • 구매자가 보낸 금액이 토큰 가격보다 크거나 같은지 확인
  • 구매자가 판매자와 동일한지 확인
  • payable 함수를 이용해 msg.value 에 저장된 금액을 판매자로 송금
  • 판매된 토큰을 배열에서 제거

후기

  • Solidity 언어를 많이 다룰줄 알았는데 아닌것같다. 그래도 대충 하는 법을 익힌듯 해서 얼른 만들어버리고 다른 강의 들어야겠다.

 

전체 알고리즘

MintAnimal Token Deploy
mint 주소를 이용해 Sale 장부 실행
Animal 민팅
Sale 장부 허가
판매 등록후 확인
다른 계정으로 구매후 구매확인

반응형

'BlockChain > Solidity' 카테고리의 다른 글

[zkSync] 간단하게 다뤄보기  (0) 2025.01.11
[DP/NFT] 4. 리액트 세팅  (0) 2022.09.05
[DP/NFT] 2. Minting contract 작성  (0) 2022.09.05
[DP/NFT] 1. Install Solidity & Metamask  (0) 2022.08.25
반응형
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol";

contract MintAnimalToken is ERC721Enumerable {
    constructor() ERC721("h662Animals", "HAS"){}

    mapping(uint256 => uint256) public animalTypes;
    // animalTokenID 입력하면 animalType 이 나오게 맵핑

    function mintAnimalToken() public {
        uint256 animalTokenId = totalSupply() + 1;
        //nft 에 유일한 값을 부여

        //랜덤한 값을 생성
        //Keccak 알고리즘을 사용하기 위해 byte 값이 필요
        //abi.encodePacked 에 세가지 수를 사용하여 겹치지 않는 수 생성
        //5로 나눈 나머지에 1을 더하여 animal type 이 1~5 사이의 값이 생성되도록 함
        uint256 animalType = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender, animalTokenId))) % 5 + 1;

        animalTypes[animalTokenId] = animalType;
        //mapping

        _mint(msg.sender, animalTokenId); // 명령어를 실행하는 사람, 토큰 ID 를 민팅
    }
}

 

알고리즘 요약

  • Keccak 알고리즘을 통해 1~5 랜덤값 생성
  • 맵핑을 통한 ID 별로 types 결정

디버그

  • 컨트랙트이름과 함수이름을 동일하게 짓는 실수는 하지말자
반응형

'BlockChain > Solidity' 카테고리의 다른 글

[zkSync] 간단하게 다뤄보기  (0) 2025.01.11
[DP/NFT] 4. 리액트 세팅  (0) 2022.09.05
[DP/NFT] 3. SaleAnimalToken 작성  (0) 2022.09.05
[DP/NFT] 1. Install Solidity & Metamask  (0) 2022.08.25

+ Recent posts