[Ethereum] 아비트라지를 위한 여정 12편 - ABI

0xDave·2022년 11월 21일
0

Ethereum

목록 보기
62/112

🚨 주의: 검증된 컨트랙트가 아닌 ABI와 상호작용하는 것은 매우 위험합니다. 절대 추천하지 않으며 항상 DYOR 하시기 바랍니다.


Brownie에서 Contract.from_explorer() 컨트랙트를 불러올 때 가끔 안 될 때가 있다. 원인은 explorer에 컨트랙트의 소스코드가 공개되지 않았기 때문이다. 소스코드를 볼 수 없는 컨트랙트와 상호작용은 위험하기 때문에 이를 방지하는 것일 수 있다. 특히 지금까지 예로 들었던 아발란체 메인넷이 아닌 다른 체인에서 컨트랙트를 불러올 때 이런 경우가 종종 있다.


⛓ ABI


이럴 때는 ABI를 통해 컨트랙트와 상호작용 할 수 있다. 하지만 이는 매우 위험하며, 트랜잭션을 요청하는 순간 지갑의 모든 자산이 탈취당할 수 있다. 따라서 이러한 위험을 인지해야 한다. sSPELL의 컨트랙트는 아비트럼 네트워크에서 검증된 상태다. 하지만 SPELL은 검증되지 않았기 때문에 Brownie에서 사용하려면 ABI를 활용해야 한다. ABI는 low level language 단위의 API 개념이라 할 수 있다. ABI를 활용해서 컨트랙트 내의 함수를 호출하거나 데이터를 얻을 수 있다. 아래는 ERC-20의 표준 ABI다. 각 항목을 자세히 보면 함수의 이름과 파라미터, 리턴값과 선언된 형태 등을 알 수 있다.


[
    {
        "constant": true,
        "inputs": [],
        "name": "name",
        "outputs": [
            {
                "name": "",
                "type": "string"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "name": "_spender",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "approve",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "totalSupply",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "name": "_from",
                "type": "address"
            },
            {
                "name": "_to",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "transferFrom",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "decimals",
        "outputs": [
            {
                "name": "",
                "type": "uint8"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            {
                "name": "_owner",
                "type": "address"
            }
        ],
        "name": "balanceOf",
        "outputs": [
            {
                "name": "balance",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [],
        "name": "symbol",
        "outputs": [
            {
                "name": "",
                "type": "string"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "constant": false,
        "inputs": [
            {
                "name": "_to",
                "type": "address"
            },
            {
                "name": "_value",
                "type": "uint256"
            }
        ],
        "name": "transfer",
        "outputs": [
            {
                "name": "",
                "type": "bool"
            }
        ],
        "payable": false,
        "stateMutability": "nonpayable",
        "type": "function"
    },
    {
        "constant": true,
        "inputs": [
            {
                "name": "_owner",
                "type": "address"
            },
            {
                "name": "_spender",
                "type": "address"
            }
        ],
        "name": "allowance",
        "outputs": [
            {
                "name": "",
                "type": "uint256"
            }
        ],
        "payable": false,
        "stateMutability": "view",
        "type": "function"
    },
    {
        "payable": true,
        "stateMutability": "payable",
        "type": "fallback"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "name": "owner",
                "type": "address"
            },
            {
                "indexed": true,
                "name": "spender",
                "type": "address"
            },
            {
                "indexed": false,
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Approval",
        "type": "event"
    },
    {
        "anonymous": false,
        "inputs": [
            {
                "indexed": true,
                "name": "from",
                "type": "address"
            },
            {
                "indexed": true,
                "name": "to",
                "type": "address"
            },
            {
                "indexed": false,
                "name": "value",
                "type": "uint256"
            }
        ],
        "name": "Transfer",
        "type": "event"
    }
]

🍪 Brownie에서 가져오기


아비트럼 네트워크에 접속

$ brownie console --network arbitrum-main

json을 임포트하고 ERC-20 ABI를 가져온다.

>>> import json
>>> ERC20_ABI = json.loads("""[ABI 복붙]""")

Contract.from_abi를 이용해서 해당 컨트랙트를 변수에 담는다.

>>> spell = Contract.from_abi(name="SPELL Token", address="0x3e6648c5a70a150a88bce65f4ad4d506fe15d2af", abi=ERC20_ABI)

이제 기존에 컨트랙트를 이용했던 것처럼 그대로 이용할 수 있다!

>>> spell.name()
'Spell Token'
>>> spell.symbol()
'SPELL'
>>> spell.decimals()
18
profile
Just BUIDL :)

0개의 댓글