【Solidity】トークンの残高を一括で取得する方法を紹介するよ。

トークン残高を一括で取得する方法

昨年は閑散期だった暗号資産・ブロックチェーンも、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を用いて様々な面白いアプリを作ることができます。

それらについても今後紹介していきます。

よかったらシェアしてね!
目次
閉じる