Issue #863

We will check USDC token balance on Solana testnet.

Firstly, we will use https://usdcfaucet.com/ to airdrop some USDC tokens into our wallet. Secondly, we check USDC token mint address on testnet cluster using Solana Explorer

https://explorer.solana.com/address/CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp?cluster=testnet

Then we make an RPC call to POST https://api.testnet.solana.comhttps://api.testnet.solana.com using method getTokenAccountsByOwner, passing our wallet address and the token mint address

{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
        "53THxwqa9qF3cn46wHVKbGMM8hUpZDJE5jS3T1qVL5bc",
        {
            "mint": "CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp"
        },
        {
            "encoding": "jsonParsed"
        }
    ]
}

The response looks like below. Notice the unit of amount and uiAmount

{
  "jsonrpc": "2.0",
  "result": {
    "context": {
      "slot": 117004636
    },
    "value": [
      {
        "account": {
          "data": {
            "parsed": {
              "info": {
                "isNative": false,
                "mint": "CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp",
                "owner": "53THxwqa9qF3cn46wHVKbGMM8hUpZDJE5jS3T1qVL5bc",
                "state": "initialized",
                "tokenAmount": {
                  "amount": "2000000",
                  "decimals": 6,
                  "uiAmount": 2.0,
                  "uiAmountString": "2"
                }
              },
              "type": "account"
            },
            "program": "spl-token",
            "space": 165
          },
          "executable": false,
          "lamports": 2039280,
          "owner": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
          "rentEpoch": 283
        },
        "pubkey": "AwZsZP6YSDAJQR88eFwJNWxDGy64FpT3SRZssGJYmMDU"
      }
    ]
  },
  "id": 1
}

Here is how to parse it in Swift

func fetchBalance(for address: Wallet.Address) async throws -> Double {
    let requestJson: [String: Any] = [
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getTokenAccountsByOwner",
        "params": [
            address,
            [
                "mint": "CpMah17kQEL2wqyMKt3mZBdTnZbkbfx4nqmQMFDP5vwp"
            ],
            [
                "encoding": "jsonParsed"
            ]
        ]
    ]

    let body = try JSONSerialization.data(
        withJSONObject: requestJson,
        options: []
    )

    let data = try await URLSession.shared.asyncData(
        with: URL(string: "https://api.testnet.solana.com")!,
        method: .post,
        body: body
    )

    let responseJson = try JSONSerialization.jsonObject(with: data, options: [])

    guard
        let json = responseJson as? JSONDictionary,
        let result = json["result"] as? JSONDictionary,
        let value = result["value"] as? JSONArray,
        let value1 = value.first,
        let account = value1["account"] as? JSONDictionary,
        let data = account["data"] as? JSONDictionary,
        let parsed = data["parsed"] as? JSONDictionary,
        let info = parsed["info"] as? JSONDictionary,
        let tokenAmount = info["tokenAmount"] as? JSONDictionary,
        let uiAmount = tokenAmount["uiAmount"] as? Double
    else { return 0 }

    return uiAmount
}

Read more