昨年は閑散期だった暗号資産・ブロックチェーンも、2019年に入ってまた盛り上がりを見せ始めましたね。
本記事では、EthereumのSmartContractを用いて作成された複数のトークンの残高を一括で取得できる方法を紹介します。
Ethereumでは、SmartContractを用いてトークンを作成することが可能です。
現時点では、EthereumブロックチェーンにおいてERC20ベースのトークンが最も主流となっています。
また、開発言語はEthereum独自のSolidityというJavascriptに似た言語を使っています。
複数のトークンを所有していた場合、それらの残高を一括で取得できたら、一度のクエリで複数のトークンのデータを取得することができるため、パフォーマンスの向上にもなります。
では、詳しく解説していきましょう。
コードの解説
まず、残高を取得したい対象のユーザーアドレス・トークンのコントラクトアドレスの配列を引数としてbalances関数に渡します。
この関数については特別なことはしていませんね。単純にトークンの数分だけfor文を回してユーザーアドレスが持つ残高を1つずつ取得しているだけです。
function balances(address user, address[] tokens) external view returns (uint[]) {
uint[] memory addrBalances = new uint[](tokens.length);
for(uint i = 0; i < tokens.length; i++) {
addrBalances[i] = tokenBalance(user, tokens[i]);
}
return addrBalances;
}
続く、tokenBalance関数にSolidity独自の書き方が出てきます。
まずはソースコードをご覧ください。
function tokenBalance(address user, address token) public view returns (uint) {
// ①トークンアドレスがコントラクトかどうかをチェックする
uint256 tokenCode;
assembly { tokenCode := extcodesize(token) } // contract code size
// ②コントラクトでありかつ、balanceOf関数を持っていること
if (tokenCode > 0 && token.call(bytes4(0x70a08231), user)) {
return Token(token).balanceOf(user);
} else if (token == "0x0000000000000000000000000000000000000000") {
return user.balance;
} else {
return 0;
}
}
①トークンアドレスがコントラクトがどうかをチェックする
まず、トークンのコントラクトアドレスとして渡されたアドレスが、コントラクトであるか確認する必要があります。
コントラクトでないと関数呼ぶ際にエラーが発生してしまうためです。
そのために、assemblyを用いて、extcodesize()関数を呼びます。
この関数により、コントラクトであったらトークンコードが0より大きい値が返ってくることを確認します。
②コントラクトであり、かつbalanceOf関数を持っていること
tokenCodeが0より大きい場合でも、コントラクトがERC20ベースのトークンのコントラクトでない場合があります。
ERC20トークンはbalanceOf関数を実装し、これにより各アドレスのトークン残高を取得できるようになっています。
call関数は、引数に呼び出したい関数名をsha3にかけたものの最初の4byte・その関数の引数を渡します。関数が正常に実行された場合、trueを返します。
これにより、コントラクトでかつERC20に準拠したトークンであることが分かりました。
③トークンの残高の取得
①、②を正常に通って初めて、トークンの残高を取得することができます。
balanceOf関数を呼び出し、残高を取得します。
④Ether残高の取得
トークンの残高のみでなく、Ether残高を取得する方法も実装しました。
これは単純にトークンのアドレスが0x0000000000000000000000000000000000000000の場合、EtherであるとみなしてEtherの残高を取得するようにしました。
address.balanceで取得可能です。
ソースコードの全容
pragma solidity ^0.4.24;
contract Token {
function balanceOf(address) public view returns (uint);
}
contract BalanceChecker {
function tokenBalance(address user, address token) public view returns (uint) {
// check if token is actually a contract
uint256 tokenCode;
assembly { tokenCode := extcodesize(token) } // contract code size
// is it a contract and does it implement balanceOf
if (tokenCode > 0 && token.call(bytes4(0x70a08231), user)) {
return Token(token).balanceOf(user);
} else if (token == "0x0000000000000000000000000000000000000000") {
return user.balance;
} else {
return 0;
}
}
function balances(address user, address[] tokens) external view returns (uint[]) {
uint[] memory addrBalances = new uint[](tokens.length);
for(uint i = 0; i < tokens.length; i++) {
addrBalances[i] = tokenBalance(user, tokens[i]);
}
return addrBalances;
}
}
まとめ
本記事では、EthereumのERC20トークンの残高を一括で取得する方法を紹介しました。
EthereumはSmartContractを用いて様々な面白いアプリを作ることができます。
それらについても今後紹介していきます。