이번 튜토리얼에서는 Python을 사용해 NeoX 블록체인에서 토큰을 배치 전송(batch send)하는 방법을 다룹니다. 예제로 1회 트랜잭션으로 5개의 지갑에 1,000 $NDMEME 토큰을 동시에 전송하는 간단한 스크립트를 만들어 보겠습니다.
배치 전송은 FTWHelpers 컨트랙트의 multiTransfers 함수를 활용합니다.
이제 필요한 정보를 모두 확보했으니, 코딩을 시작해 보겠습니다.
다음은 web3 파이썬 모듈을 import하는 부분입니다:
from web3 import Web3
from eth_account import Account
from eth_account.signers.local import LocalAccount
from web3.middleware import ExtraDataToPOAMiddleware
아래는 이전에 가져온 변수들을 정의하는 부분입니다:
PK = os.environ.get('NEOX_PK') #Our wallet private key
FTW_HELPERS_HASH = "0xDfa53F8deA15CE39A23D57874e03eE0E76425e01"
FTW_HELPERS_ABI = open("ftw_helpers_abi.json").read() #The ABI file for FTWHelpers contract
NDMEME_HASH = "0xE816deE05cf6D0F2a57EB4C489241D8326B5d106"
NDMEME_ABI = open("ndmeme_abi.json").read() #The ABI file for NDMEME contract
NDMEME_AMOUNT = 1000000000000000000000
RECEIVERS = [
"0x32e35665B4bb970c2b9348a6B2b2517D57D8701A",
"0xfE2a5462b3f04c466b7554176050501828aE1103",
"0xdeadc0de9FE6eC6B0B083d617B827F86e4D1EE14",
"0xB5b184b4A5304BE50E45F9489dF9Bce1cfc40F90",
"0x1241f44BFA102ab7386C784959BAe3D0fB923734"
]
RPC_ENDPOINT = "https://mainnet-1.rpc.banelabs.org/"
다음으로 NeoX 체인에 연결할 Web3 객체를 생성합니다:
nonce = w3.eth.get_transaction_count(account.address)
contract = w3.eth.contract(NDMEME_HASH, abi=NDMEME_ABI)
tx = contract.functions.increaseAllowance(FTW_HELPERS_HASH, len(RECEIVERS) * NDMEME_AMOUNT).build_transaction({
'from': account.address,
'nonce': nonce
})
signed_tx = w3.eth.account.sign_transaction(tx, PK)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
tx_result = w3.eth.wait_for_transaction_receipt(tx_hash.hex())
allowance 설정 결과를 출력합니다:
전송 트랜잭션에 사용할 입력값을 준비합니다:
tokens = [NDMEME_HASH] * len(RECEIVERS)
amounts = [NDMEME_AMOUNT] * len(RECEIVERS)
tokens = [Web3.to_checksum_address(x) for x in tokens]
receivers = [Web3.to_checksum_address(x) for x in RECEIVERS]
이제 multiTransfers 함수를 이용해 1회에 5개의 지갑에 토큰을 전송하는 트랜잭션을 빌드합니다:
nonce = w3.eth.get_transaction_count(account.address)
contract = w3.eth.contract(FTW_HELPERS_HASH, abi=FTW_HELPERS_ABI)
tx = contract.functions.multiTransfers(tokens, receivers, amounts).build_transaction({
'from': account.address,
'nonce': nonce
})
signed_tx = w3.eth.account.sign_transaction(tx, PK)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
tx_result = w3.eth.wait_for_transaction_receipt(tx_hash.hex())
전송 결과를 출력합니다:
print(f"Result for transfer transaction: {tx_result}")
최종적으로 전체 스크립트는 다음과 같습니다:
import os
from web3 import Web3
from eth_account import Account
from eth_account.signers.local import LocalAccount
from web3.middleware import ExtraDataToPOAMiddleware
PK = os.environ.get('NEOX_PK') #Our wallet private key
FTW_HELPERS_HASH = "0xDfa53F8deA15CE39A23D57874e03eE0E76425e01"
FTW_HELPERS_ABI = open("ftw_helpers_abi.json").read() #The ABI file for FTWHelpers contract
NDMEME_HASH = "0xE816deE05cf6D0F2a57EB4C489241D8326B5d106"
NDMEME_ABI = open("ndmeme_abi.json").read() #The ABI file for NDMEME contract
NDMEME_AMOUNT = 1000000000000000000000
RECEIVERS = [
"0x32e35665B4bb970c2b9348a6B2b2517D57D8701A",
"0xfE2a5462b3f04c466b7554176050501828aE1103",
"0xdeadc0de9FE6eC6B0B083d617B827F86e4D1EE14",
"0xB5b184b4A5304BE50E45F9489dF9Bce1cfc40F90",
"0x1241f44BFA102ab7386C784959BAe3D0fB923734"
]
RPC_ENDPOINT = "https://mainnet-1.rpc.banelabs.org/"
w3 = Web3(Web3.HTTPProvider(RPC_ENDPOINT))
account: LocalAccount = Account.from_key(PK)
w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
print(f"Your hot wallet address is {account.address}")
nonce = w3.eth.get_transaction_count(account.address)
contract = w3.eth.contract(NDMEME_HASH, abi=NDMEME_ABI)
tx = contract.functions.increaseAllowance(FTW_HELPERS_HASH, len(RECEIVERS) * NDMEME_AMOUNT).build_transaction({
'from': account.address,
'nonce': nonce
})
signed_tx = w3.eth.account.sign_transaction(tx, PK)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
tx_result = w3.eth.wait_for_transaction_receipt(tx_hash.hex())
print(f"Result for increaseAllowance transaction: {tx_result}")
tokens = [NDMEME_HASH] * len(RECEIVERS)
amounts = [NDMEME_AMOUNT] * len(RECEIVERS)
tokens = [Web3.to_checksum_address(x) for x in tokens]
receivers = [Web3.to_checksum_address(x) for x in RECEIVERS]
nonce = w3.eth.get_transaction_count(account.address)
contract = w3.eth.contract(FTW_HELPERS_HASH, abi=FTW_HELPERS_ABI)
tx = contract.functions.multiTransfers(tokens, receivers, amounts).build_transaction({
'from': account.address,
'nonce': nonce
})
signed_tx = w3.eth.account.sign_transaction(tx, PK)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
tx_result = w3.eth.wait_for_transaction_receipt(tx_hash.hex())
print(f"Result for transfer transaction: {tx_result}")
이렇게 여러 지갑을 대상으로 토큰을 전송할 때 여러개의 트랜젝션으로 나눠서 전송하는 것 보다, 하나의 트랜젝션으로 합쳐서 전송했을 때 속도와 비용 측면에서 더 유리합니다.
[
{
"inputs": [
{
"internalType": "address[]",
"name": "tokens",
"type": "address[]"
},
{
"internalType": "address[]",
"name": "receivers",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "amounts",
"type": "uint256[]"
}
],
"name": "multiTransfers",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
[
{
"inputs": [
{
"internalType": "address",
"name": "spender",
"type": "address"
},
{
"internalType": "uint256",
"name": "addedValue",
"type": "uint256"
}
],
"name": "increaseAllowance",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
}
]