블록체인 (Block Chain)/이더리움

[브라우니 (Brownie)] 10. 컨트랙트로 작업하기

gsroot 2023. 6. 16. 16:41
728x90
반응형
SMALL

 

계약 배포하기

Brownie가 로드될 때마다 프로젝트를 자동으로 컴파일하고 배포 가능한 각 계약에 대한 ContractContainer 객체를 만듭니다. 이 객체는 개별 배포에 액세스하기 위한 컨테이너로 사용됩니다. 또한 새 계약을 배포하는 데에도 사용됩니다.

>>> Token
[]
>>> type(Token)
<class 'brownie.network.contract.ContractContainer'>
>>> Token.deploy
<ContractConstructor object 'Token.constructor(string _symbol, string _name, uint256 _decimals, uint256 _totalSupply)'>

ContractContainer.deploy 함수는 새로운 스마트 컨트랙트를 배포하는 데 사용됩니다.

>>> Token.deploy
<ContractConstructor object 'Token.constructor(string _symbol, string _name, uint256 _decimals, uint256 _totalSupply)'>

계약 생성자 전달인자 및 거래 매개변수 사전과 함께 호출해야 하며, 이는 from 필드를 포함하는 것이 필요하며 해당 필드는 계약을 배포할 Account를 지정합니다.

>>> Token.deploy("Test Token", "TST", 18, 1e23, {'from': accounts[1]})

Transaction sent: 0x2e3cab83342edda14141714ced002e1326ecd8cded4cd0cf14b2f037b690b976
Transaction confirmed - block: 1   gas spent: 594186
Contract deployed at: 0x5419710735c2D6c3e4db8F30EF2d361F70a4b380
<Token Contract object '0x5419710735c2D6c3e4db8F30EF2d361F70a4b380'>

ContractContainer.deploy를 호출하면 ProjectContract 객체가 반환됩니다. 반환된 객체는 ContractContainer에도 추가됩니다.

>>> t = Token.deploy("Test Token", "TST", 18, 1e23, {'from': accounts[1]})

Transaction sent: 0x2e3cab83342edda14141714ced002e1326ecd8cded4cd0cf14b2f037b690b976
Transaction confirmed - block: 1   gas spent: 594186
Contract deployed at: 0x5419710735c2D6c3e4db8F30EF2d361F70a4b380
<Token Contract object '0x5419710735c2D6c3e4db8F30EF2d361F70a4b380'>

>>> t
<Token Contract object '0x5419710735c2D6c3e4db8F30EF2d361F70a4b380'>
>>> Token
[<Token Contract object '0x5419710735c2D6c3e4db8F30EF2d361F70a4b380'>]

링크되지 않은 라이브러리

컨트랙트가 라이브러리를 필요로 하는 경우, 브라우니는 가장 최근에 배포된 라이브러리에 자동으로 링크합니다. 필요한 라이브러리가 아직 배포되지 않았으면 UndeployedLibrary 예외가 발생합니다.

>>> MetaCoin.deploy({'from': accounts[0]})
  File "brownie/network/contract.py", line 167, in __call__
    f"Contract requires '{library}' library but it has not been deployed yet"
UndeployedLibrary: Contract requires 'ConvertLib' library but it has not been deployed yet

>>> Convert.deploy({'from': accounts[0]})
Transaction sent: 0xff3f5cff35c68a73658ad367850b6fa34783b4d59026520bd61b72b6613d871c
ConvertLib.constructor confirmed - block: 1   gas used: 95101 (48.74%)
ConvertLib deployed at: 0x08c4C7F19200d5636A1665f6048105b0686DFf01
<ConvertLib Contract object '0x08c4C7F19200d5636A1665f6048105b0686DFf01'>

>>> MetaCoin.deploy({'from': accounts[0]})
Transaction sent: 0xd0969b36819337fc3bac27194c1ff0294dd65da8f57c729b5efd7d256b9ecfb3
MetaCoin.constructor confirmed - block: 2   gas used: 231857 (69.87%)
MetaCoin deployed at: 0x8954d0c17F3056A6C98c7A6056C63aBFD3e8FA6f
<MetaCoin Contract object '0x8954d0c17F3056A6C98c7A6056C63aBFD3e8FA6f'>

계약과 상호작용하기

계약을 배포한 후에는 호출과 트랜잭션을 통해 상호작용할 수 있습니다.

  • 트랜잭션은 네트워크에 방송되어 블록체인에 기록됩니다. 실행에는 이더가 필요하며 블록체인의 상태를 변경할 수 있습니다.
  • 호출은 트랜잭션을 방송하지 않고 네트워크에서 코드를 실행하는 데 사용됩니다. 실행에는 비용이 들지 않으며 블록체인의 상태를 변경할 수 없습니다. 호출은 일반적으로 게터 메서드를 사용하여 계약에서 저장소 값을 검색하는 데 사용됩니다.

계약 내의 모든 공개 함수에 대해 호출하거나 트랜잭션을 보낼 수 있습니다. 그러나 코드에 따라 항상 선호되는 방법이 있습니다.

  • Solidity에서 호출 가능한 메서드는 view 또는 pure로 표시됩니다.
  • Vyper에서 호출 가능한 메서드에는 @constant 데코레이터가 포함됩니다.

모든 공개 계약 메서드는 ProjectContract 객체에서 동일한 이름의 클래스 메서드를 통해 사용할 수 있습니다.

>>> Token[0].transfer
<ContractTx object 'transfer(address _to, uint256 _value)'>
>>> Token[0].balanceOf
<ContractCall object 'balanceOf(address _owner)'>

계약 소스에 NatSpec 문서가 포함되어 있으면 ContractCall.info 메소드를 통해 볼 수 있습니다:

>>> Token[0].transfer.info()
transfer(address _to, uint256 _value)
  @dev transfer token for a specified address
  @param _to The address to transfer to.
  @param _value The amount to be transferred.

거래

상태 변경 컨트랙트 메소드는 ContractTx 객체를 통해 호출됩니다. 이 객체는 트랜잭션을 수행하고 TransactionReceipt를 반환합니다.

옵션으로 트랜잭션 매개변수의 딕셔너리를 마지막 인자로 포함할 수 있습니다. 이를 수행하지 않거나 매개변수 내에서 from 값을 지정하지 않으면, 트랜잭션은 컨트랙트를 배포한 동일한 주소에서 전송됩니다.

>>> Token[0].transfer(accounts[1], 1e18, {'from': accounts[0]})

Transaction sent: 0x6e557594e657faf1270235bf4b3f27be7f5a3cb8a9c981cfffb12133cbaa165e
Token.transfer confirmed - block: 4   gas used: 51019 (33.78%)
<Transaction object '0x6e557594e657faf1270235bf4b3f27be7f5a3cb8a9c981cfffb12133cbaa165e'>

거래 없이 컨트랙트 메소드를 호출하려면 ContractTx.call 메소드를 사용하세요.

>>> Token[0].transfer.call(accounts[1], 1e18, {'from': accounts[0]})
True

거래 매개 변수

계약에 대한 거래를 실행할 때, 마지막 입력으로 거래 매개 변수의 dict 를 선택적으로 포함시킬 수 있습니다. 이것은 다음 값을 포함할 수 있습니다:

  • from: 거래를 보내는 계정. 지정하지 않으면, 거래는 계약을 배포한 계정에서 보내집니다.
  • gas_limit: wei 단위로 거래 실행에 대한 가스 제공량입니다. 지정하지 않으면, 가스 제한은 web3.eth.estimate_gas를 사용하여 결정됩니다.
  • gas_buffer: 가스 제한을 자동으로 설정할 때 web3.eth.estimate_gas에 적용되는 배율입니다. gas_limit 및 gas_buffer 는 동시에 지정할 수 없습니다.
  • gas_price: wei 단위로 레거시 거래의 가스 가격입니다. 지정하지 않으면, 가스 가격은 web3.eth.gas_price에 따라 설정됩니다.
  • max_fee: 동적 수수료 거래의 가스 당 최대 수수료입니다. priority_fee: 동적 수수료 거래의 가스 당 최대 우선 순위 수수료입니다.
  • amount: wei 단위로 거래에 포함될 이더의 양입니다.
  • nonce: 거래의 nonce 값입니다. 지정하지 않으면, 보내는 사람의 대기 중인 거래를 고려하여 web3.eth.get_transaction_count에 따라 nonce가 설정됩니다.
  • required_confs: TransactionReceipt가 처리되기 전에 필요한 확인 횟수입니다. 지정하지 않으면, 기본값은 1번의 확인입니다. 0이 지정되면, 즉시 대기 중인 TransactionReceipt를 반환하고, 별도의 스레드에서 확인을 기다립니다.
  • allow_revert: 거래가 예상되는 경우 전파되어야 하는지 여부를 나타내는 부울입니다. 설정되지 않으면, 개발 환경에서 되돌리기 허용, 실제 환경에서는 되돌리기 금지가 기본 동작입니다.

모든 통화 정수 값은 Wei에 의해 변환될 문자열로도 지정할 수 있습니다.

개발 환경에서는 from 필드가 문자열로 지정된 어떤 주소든 사용할 수 있습니다. 이렇게 하면 해당 주소의 개인 키 없이 거래를 브로드캐스트할 수 있습니다. 심지어는 계약에서 거래를 보낼 수도 있습니다!

호출

상태를 변경하지 않는 계약 메서드는 ContractCall 객체를 통해 호출됩니다. 이 객체는 거래를 브로드캐스트하지 않고 계약 메서드를 호출하고 결과를 반환합니다.

>>> Token[0].balanceOf(accounts[0])
1000000000000000000000

거래를 통해 메서드에 액세스하려면 ContractCall.transact을 사용할 수 있습니다.

>>> tx = Token[0].balanceOf.transact(accounts[0])

Transaction sent: 0xe803698b0ade1598c594b2c73ad6a656560a4a4292cc7211b53ffda4a1dbfbe8
Token.balanceOf confirmed - block: 3   gas used: 23222 (18.85%)
<Transaction object '0xe803698b0ade1598c594b2c73ad6a656560a4a4292cc7211b53ffda4a1dbfbe8'>
>>> tx.return_value
1000000000000000000000

프로젝트 외부 컨트랙트

라이브 환경(Live Environment) 또는 개발용 포크(forked development network)에서 작업할 때, 배포된 컨트랙트에 상호작용하기 위해 Contract 객체를 생성할 수 있습니다.

Contract 객체는 프로젝트의 interfaces/ 폴더 내 인터페이스로부터 생성하거나, 블록 익스플로러나 ethPM 레지스트리와 같은 원격 소스에서 정보를 가져와 생성할 수 있습니다.

로컬 인터페이스 사용

InterfaceContainer 객체(별칭 interface)는 프로젝트의 interfaces/ 폴더 내 인터페이스에 대한 접근을 제공합니다.

예를 들어, 인터페이스 이름이 Dai인 컨트랙트에서 Contract 객체를 생성하려면:

>>> interface.Dai
<InterfaceConstructor 'Dai'>

>>> interface.Dai("0x6B175474E89094C44Da98b954EedeAC495271d0F")
<Dai Contract object '0x6B175474E89094C44Da98b954EedeAC495271d0F'>

딕셔너리 형태로 된 ABI에서 인스턴스를 생성하는 Contract.from_abi 클래스 메서드를 사용할 수도 있습니다:

>>> Contract.from_abi("Token", "0x79447c97b6543F6eFBC91613C655977806CB18b0", abi)
<Token Contract object '0x79447c97b6543F6eFBC91613C655977806CB18b0'>

원격 소스에서 가져오기

계약 객체는 원격 소스에서 데이터를 가져와서 생성할 수도 있습니다. 예를 들어, Etherscan에 쿼리를 보내어 객체를 생성하는 데 사용하는 Contract.from_explorer 을 사용하세요:

>>> Contract.from_explorer("0x6b175474e89094c44da98b954eedeac495271d0f")
Fetching source of 0x6B175474E89094C44Da98b954EedeAC495271d0F from api.etherscan.io...
<Dai Contract '0x6B175474E89094C44Da98b954EedeAC495271d0F'>

세션 간 계약 유지

Contract 객체를 만드는 데 사용되는 데이터는 로컬 데이터베이스에 저장되어 세션 간에 지속됩니다. 클래스 메서드를 통해 초기 생성 후, 주소를 사용하여 Contract 객체를 다시 만들 수 있습니다:

>>> Contract("0x6b175474e89094c44da98b954eedeac495271d0f")
<Dai Contract '0x6B175474E89094C44Da98b954EedeAC495271d0F'>

또한, Contract.set_alias를 사용하여 빠른 액세스를 위한 별칭을 만들 수 있습니다. 별칭은 세션 간에도 유지됩니다.

>>> contract = Contract("0x6b175474e89094c44da98b954eedeac495271d0f")
>>> contract.set_alias('dai')

>>> Contract('dai')
<Dai Contract '0x6B175474E89094C44Da98b954EedeAC495271d0F'>

 

728x90
반응형
LIST