//tips
//smart contract
インスタンスに対する関数の実行形式について確認していく。
まずdeploy済みのコントラクトのインスタンスの生成に関しては下記のコードで可能である。
const contract = web3.eth.contract(abi).at(address);
一方で、サンプルのコードでは下記のようにインスタンス生成しないで関数を実行する形やインスタンスに対してmethodsなどを挟むケースも見受けられる。
web3.eth.sendTransaction()
contract.methods.myMethod(…).send(…)
contract.set.sendTransaction
これらの違いがよくわからないので解いていく。
https://web3js.readthedocs.io/en/v1.2.11/web3-eth.html
ドキュメントを見ていくと、web3.ethはメタマスクへの接続に関するものであることがわかってきた。フロントエンドからのコントラクトの実行の際に使う形か。
web3.eth.getAccounts(console.log);
さらに、
web3.eth.Contract
上記を見ていくと、コントラクト内容のcallの内容をweb3が自動でABI callの形にRPC経由で変換してくれるみたい。これは変換の際にRPCが使われているという内容で良いのか少し不安。技術的背景がわかっていればもっとスッキリするだろう。
このjson形態がインスタンスと呼ばれるものとイメージした。
The web3.eth.Contract object makes it easy to interact with smart contracts on the ethereum blockchain. When you create a new contract object you give it the json interface of the respective smart contract and web3 will auto convert all calls into low level ABI calls over RPC for you.
This allows you to interact with smart contracts as if they were JavaScript objects.
新規のコントラクトを生成する際には
new web3.eth.Contract(jsonInterface[, address][, options])
が用いられ、この定義としては
Creates a new contract instance with all its methods and events defined in its json interface object.
json interface objectに定義されたイベントやメソッドを使用できるインスタンス。
このnewの部分はtruffleが代行してくれている形で、truffle-configに設定内容を詰め込んでいる。
このoption部分は理解しておいた方がよく。web3.eth.Contractを用いた場合に下記のようなoptionをとれることからdeploy済みコントラクトへの接続もこれにそうことがわかる。
options - Object (optional): The options of the contract. Some are used as fallbacks for calls and transactions:
from - String: The address transactions should be made from.
gasPrice - String: The gas price in wei to use for transactions.
gas - Number: The maximum gas provided for a transaction (gas limit).
data - String: The byte code of the contract. Used when the contract gets deployed.
var myContract = new web3.eth.Contract([...], '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', {
from: '0x1234567890123456789012345678901234567891', // default from address
gasPrice: '20000000000' // default gas price in wei, 20 gwei in this case
});
const contract = web3.eth.contract(abi).at(address);
もう少し見ていくと
myContract.methods.myMethod([param1[, param2[, ...]]])
methodsの説明もあった。生成したインスタンスに対して、コントラクトに格納された関数やsendなどを呼ぶ関数とのこと。
Creates a transaction object for that method, which then can be called, send, estimated, or ABI encoded.
コントラクトの関数実行後にsendをしなくちゃ関数実行はできないのだっけと疑問に思ったのでそちらも探る。
contract.methods.myMethod(…).send(…)
contract.methods.myMethod(…)後につけられるものは結構あり、これがThe transaction objectという形で返されるので、その後にcall,send,encodeABI:などがつけられる。
Array - arguments: The arguments passed to the method before. They can be changed.
Function - call: Will call the “constant” method and execute its smart contract method in the EVM without sending a transaction (Can’t alter the smart contract state).
Function - send: Will send a transaction to the smart contract and execute its method (Can alter the smart contract state).
Function - estimateGas: Will estimate the gas used when the method would be executed on chain.
Function - encodeABI: Encodes the ABI for this method. This can be send using a transaction, call the method or passing into another smart contracts method as argument.
Sendをみるとわかるようにメソッド内容を実行するための位置付けになっており、確かに自身の.solの中では所有権の移転などのメソッドは組み込まれているがその際の対価請求はopenseaに委ねており、このsendの引数にopensea側での変数を入れることで売買が実行されることがわかる。
関数の実行と支払いを連動させたい場合に使えそう。
一方で関数をdataに打ち込むことで
contract.sendTransaction({data:pwnFuncSig})
という短縮も行うことができそうなことも認識できる。
web3.eth.sendTransaction(transactionObject [, callback])
Sends a transaction to the network.
Methodsの方はtransactionをcreateすることに重点をおき、そちらをcall,sendなどにフォローさせていたが、こちらはsendそのもの。
Dataに渡すものとして、関数が含まれたabiとなる。
data - String: (optional) Either a ABI byte string containing the data of the function call on a contract, or in the case of a contract-creation transaction the initialisation code.
contract.sendTransaction({data:pwnFuncSig})の前文を確認。下記のようにsha3を使ってa ABI byte string の形式にして読み込ませていたよう。これはトリッキーすぎるのであまり使わなくて良さそう。
var pwnFuncSig = web3.utils.sha3(“pwn()”)
contract.sendTransaction({data:pwnFuncSig})
Callbackで使うとするとこのようになるのとこと。
// using the callback
web3.eth.sendTransaction({
from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
data: code // deploying a contracrt
}, function(error, hash){
...
});
この場合のコールバックはどうなるのか。
コールバックとは、呼び出し側の用意した関数などを、呼び出し先の関数に、引数として渡される関数のこと。
お使いの例で言うと、お母さん関数が子供関数に、千円と千円の使い道の指示書(関数)を渡し、お買い物を実行させると、その際の千円の使い道の指示書がコールバック関数となる。
となるとdata: code のコントラクトに対して、function以下の関数を実行させる感じか。
非同期でのpromiseの古いバージョンなのか。
真下にpromiseの例があった。
// using the promise
web3.eth.sendTransaction({
from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
value: '1000000000000000'
})
.then(function(receipt){
...
});
これはわかりやすい。イベントの際にはonが使われていたが、そもそものonの定義はなんだったか朧げなので調べる。
// using the event emitter
web3.eth.sendTransaction({
from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe',
to: '0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe',
value: '1000000000000000'
})
.on('transactionHash', function(hash){
...
})
.on('receipt', function(receipt){
非同期のweb3接続を見ていくとoneceやonで状態ごとのeventを各自しっかり発行しつつ、非同期実行できるよう。
Ethereum as a blockchain has different levels of finality and therefore needs to return multiple “stages” of an action. To cope with requirement we return a “promiEvent” for functions like web3.eth.sendTransaction or contract methods. This “promiEvent” is a promise combined with an event emitter to allow acting on different stages of action on the blockchain, like a transaction.
PromiEvents work like a normal promises with added on, once and off functions. This way developers can watch for additional events like on “receipt” or “transactionHash”.
https://web3js.readthedocs.io/en/v1.2.11/callbacks-promises-events.html
web3.eth.sendTransaction({from: '0x123...', data: '0x432...'})
.once('sending', function(payload){ ... })
.once('sent', function(payload){ ... })
.once('transactionHash', function(hash){ ... })
.once('receipt', function(receipt){ ... })
.on('confirmation', function(confNumber, receipt, latestBlockHash){ ... })
.on('error', function(error){ ... })
.then(function(receipt){
// will be fired once the receipt is mined
});
.on、.once、.offはnode.jsのevent処理のよう。emitで発火するのでonで登録または変数と接続をさせているのか。emitで該当のイベントが発火されたら引数の変数を取得した関数を実行する形になるか。もう少し深掘りしてみる。
https://nodejs.org/api/events.html#emitteroneventname-listener