Вызов функции смарт-контракта BSC для совершения покупки с помощью Python

Я пытаюсь программно воспроизвести действие покупки соответствии с тем, что в этом контракте NFT на торговой площадке в0x54ac76f9afe0764e6a8ed6c4179730e6c768f01cуказано

Моя цель - иметь возможность воссоздать транзакцию, подобную следующей, с хешем 0xa792fa25a9fcf9346cff4e37a580c96d27d019d646e815dcc8680496fd611adf

Первым делом я вызвал этот хеш в Python с помощью web3, который вернул

      AttributeDict({'blockHash': HexBytes('0x778481abab6360ff6a13c6159743d9289d4edcee64c8fa2d067857fd3d0b673f'), 'blockNumber': 13411584, 'from': '0x292788A70a8e885FF6b0D9A95A4c75366a82930a', 'gas': 328806, 'gasPrice': 5000000000, 'hash': HexBytes('0xa792fa25a9fcf9346cff4e37a580c96d27d019d646e815dcc8680496fd611adf'), 'input': '0xe8e8e872000000000000000000000000b417cc1330076d05a13406310a4ae774f8b5c38300000000000000000000000098eb46cbf76b19824105dfbcfa80ea8ed020c6f4000000000000000000000000bb4cdb9cbd36b01bd1cbaebf2de08d9173bc095c000000000000000000000000000000000000000000000000000013fdffc2431400000000000000000000000000000000000000000000000002df69673c8180000000000000000000000000000000000000000000000000000000000061b5f67900000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000004183c3caefa779647a11d7f6bb55eaa15c08ca2feadd339793fc57d69b094e5f2b1515391276afca3828f7b3d7f22a45c48a6a947f6edeff815d85e6370c93a4721b00000000000000000000000000000000000000000000000000000000000000', 'nonce': 977, 'to': '0x54ac76f9afe0764e6a8Ed6c4179730E6c768F01C', 'transactionIndex': 103, 'value': 0, 'type': '0x0', 'v': 148, 'r': HexBytes('0x980378216da1477e8a5bd65ba5d865814719bfe50a70d53b36a754d36cab9319'), 's': HexBytes('0x69d01eaa1d7711c9f8c30e9976db3fe37bd39c877f9cdded1bfe50255eae4179')})

Чтобы лучше понять, что было внутри ввода, я декодировал ту часть, которая дала

      function called:  matchTransaction
arguments:  {
  "addresses": [
    "0xb417CC1330076D05A13406310A4ae774F8b5c383",
    "0x98eb46CbF76B19824105DfBCfa80EA8ED020c6f4",
    "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c"
  ],
  "values": [
    21981638574868,
    207000000000000000,
    1639315065
  ],
  "signature": "0x83c3caefa779647a11d7f6bb55eaa15c08ca2feadd339793fc57d69b094e5f2b1515391276afca3828f7b3d7f22a45c48a6a947f6edeff815d85e6370c93a4721b"
}

Оттуда у нас есть ABI

      [{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"},{"indexed":false,"internalType":"address","name":"paymentToken","type":"address"},{"indexed":false,"internalType":"address","name":"seller","type":"address"},{"indexed":false,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"MatchTransaction","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"feeToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_messageHash","type":"bytes32"}],"name":"getEthSignedMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_nftAddress","type":"address"},{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"address","name":"_paymentErc20","type":"address"},{"internalType":"uint256","name":"_price","type":"uint256"},{"internalType":"uint256","name":"_saltNonce","type":"uint256"}],"name":"getMessageHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[2]","name":"addresses","type":"address[2]"},{"internalType":"uint256[3]","name":"values","type":"uint256[3]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"ignoreSignature","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[3]","name":"addresses","type":"address[3]"},{"internalType":"uint256[3]","name":"values","type":"uint256[3]"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"matchTransaction","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"paymentTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_ethSignedMessageHash","type":"bytes32"},{"internalType":"bytes","name":"_signature","type":"bytes"}],"name":"recoverSigner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address[]","name":"_removedPaymentTokens","type":"address[]"}],"name":"removePaymentTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeToAddress","type":"address"}],"name":"setFeeToAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_paymentTokens","type":"address[]"}],"name":"setPaymentTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_transactionFee","type":"uint256"}],"name":"setTransactionFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"sig","type":"bytes"}],"name":"splitSignature","outputs":[{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint8","name":"v","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"transactionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"","type":"bytes"}],"name":"usedSignatures","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]

Немного изучив функции рынка, мы можем примерно увидеть, что такое matchTransaction, в файле marketplace.sol.

      function matchTransaction(
        address[3] calldata addresses,
        uint256[3] calldata values,
        bytes calldata signature
    ) external returns (bool) {
        // address[3] [seller_address,nft_address,payment_token_address]
        // uint256[3] [token_id,price,salt_nonce]
        // bytes seller_signature
        require(
            paymentTokens[addresses[2]] == true,
            "Marketplace: invalid payment method"
        );

        require(
            !usedSignatures[signature],
            "Marketplace: signature used. please send another transaction with new signature"
        );

        bytes32 criteriaMessageHash = getMessageHash(
            addresses[1],
            values[0],
            addresses[2],
            values[1],
            values[2]
        );

        bytes32 ethSignedMessageHash = getEthSignedMessageHash(
            criteriaMessageHash
        );

        require(
            recoverSigner(ethSignedMessageHash, signature) == addresses[0],
            "Marketplace: invalid seller signature"
        );

        // check current ownership
        IERC721 nft = IERC721(addresses[1]);
        require(
            nft.ownerOf(values[0]) == addresses[0],
            "Marketplace: seller is not owner of this item now"
        );

        // Check payment approval and buyer balance
        IERC20 paymentContract = IERC20(addresses[2]);
        require(
            paymentContract.balanceOf(_msgSender()) >= values[1],
            "Marketplace: buyer doesn't have enough token to buy this item"
        );
        require(
            paymentContract.allowance(_msgSender(), address(this)) >= values[1],
            "Marketplace: buyer doesn't approve marketplace to spend payment amount"
        );

        // We divide by 10000 to support decimal value such as 4.25% => 425 / 10000
        uint256 fee = transactionFee.mul(values[1]).div(10000);
        uint256 payToSellerAmount = values[1].sub(fee);

        // transfer money to seller
        paymentContract.safeTransferFrom(
            _msgSender(),
            addresses[0],
            payToSellerAmount
        );

        // transfer fee to address
        if (fee > 0) {
            paymentContract.safeTransferFrom(_msgSender(), feeToAddress, fee);
        }

        // transfer item to buyer
        nft.safeTransferFrom(addresses[0], _msgSender(), values[0]);

        usedSignatures[signature] = true;
        // emit sale event
        emitEvent(addresses, values);
        return true;
    }

А также

      // Events
    event MatchTransaction(
        uint256 indexed tokenId,
        address contractAddress,
        uint256 price,
        address paymentToken,
        address seller,
        address buyer,
        uint256 fee
    );

и

      emit MatchTransaction(
            values[0],
            addresses[1],
            values[1],
            addresses[2],
            addresses[0],
            _msgSender(),
            transactionFee
        );

Хорошо, во-первых, я не понимаю разницы между событием и функцией. Я предполагаю, что мне нужно вызвать функцию, но способ ее определения и способ ее вызова в последнем фрагменте отличается от того, что я декодировал, поэтому обо всем по порядку

      import json

from web3 import Web3
from web3.middleware import geth_poa_middleware


bsc='https://bsc-dataseed.binance.org/'
w3=Web3(Web3.HTTPProvider(bsc))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)

marketplace_contract_address='0x54ac76f9afe0764e6a8Ed6c4179730E6c768F01C'
contract_object=w3.eth.contract(address=marketplace_contract_address,abi=abi)

myAddress='0xsjfjjehdhshejdjsjej.....'
nonce=w3.eth.getTransactionCount(myAddress)

current_owner='0x46b1589e796c1102f68e2889a3315e42e600a901'
nft_contract='0x98eb46cbf76b19824105dfbcfa80ea8ed020c6f4'
tokenId=21981638574868
wbnb_contract='0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c'
bnb_price=w3.toWei(0.207,'ether')

salt_nonce=1639315065 #This value is in the website and can be scraped

tx={'nonce':nonce,'from':myAddress,'gas':500000,'gasPrice':5000000000,'to':marketplace_contract_address}

purchase=contract_object.functions.MatchTransaction(here comes the main doubt).buildTransaction(tx)



sign_tx=w3.eth.account.signTransaction(purchase,privatekey)
w3.eth.send_raw_transaction(sign_tx.rawTransaction())

Итак, пока все правильно? Я читал документы и смотрел несколько видеороликов, но все складывается только небольшими частями, поэтому, вероятно, не все так, как должно. Я что-то забыл при создании переменной? Мне нужно включить в tx изменить to и fromадреса? В зависимости от того, что находится внутри входных данных, он может быть уже включен туда

И теперь у меня возникает главное сомнение по поводу всего этого процесса. Как мне перейти к входным данным при вызове функции matchTransaction? Если моя расшифровка верна, должно быть так

      input_data={'addresses':[current_owner,nft_contract,wbnb_contract],'values':[tokenId,bnb_price,salt_nonce],'signature':value_to_be_scraped}

purchase=contract_object.functions.MatchTransaction(input_data).buildTransaction(tx)

Но глядя на marketplace.sol возможно, вам нужно ввести данные без такого словаря, как это сделано в последнем фрагменте кода оттуда

      purchase=contract_object.functions.MatchTransaction(tokenId,nft_contract,bnb_price,wbnb_contract,current_owner,value_to_be_scraped,fee).buildTransaction(tx)

Итак, это главное сомнение можно разделить на 3 части.

1 - Почему входные данные различаются в событии matchTransaction, функции matchTransaction и emit matchTransaction. В чем разница между этими тремя?

2 - Как правильно называть? Я предполагаю, что это функция, поскольку код указывает на нее, но, как я уже сказал, незнание разницы между собой усложняет мне задачу.

3 - Предполагая, что мне нужно воспроизвести аргументы функции, нужно ли мне передавать их в dict, как полученные мной декодированные данные?

Спасибо за любые разъяснения, я знаю, что разместил здесь довольно много текста.

0 ответов

Другие вопросы по тегам