Integrate Web3Auth with the Songbird Blockchain in Flutter
While using the Web3Auth Flutter SDK, you get the private key within the user scope after successful authorization. This private key can be used to retrieve the user's address, and interact with Songbird to make any blockchain calls. We have highlighted a few here for getting you started quickly on that.
Prerequisites
This doc assumes you have already setup your project in Web3Auth Dashboard, and have integrated Web3Auth in your Flutter app. If you haven't done that yet, you can learn how to integrate Web3Auth in your Flutter app.
Installation
To interact with the Ethereum compatible blockchains in Flutter, you can use any
EIP1193
compatible package. Here, we're using
web3dart to demonstrate how to make blockchain calls using it
with Web3Auth.
To install the web3dart
package, you have two options. You can either manually add the package in
the pubspec.yaml
file, or you can use the flutter pub add
command.
- Console
- Pubspec
Add web3dart
using flutter pub add
command.
flutter pub add web3dart
Add web3dart
as a dependency to your pubspec.yaml
.
dependencies:
web3dart: ^2.7.3
Initialize
We'll initialize the Web3Client
with the RPC URL of the network you want to connect to. This
client allows us to interact with the blockchain. To get the public RPC URL, you can checkout
chainlist.org.
import 'package:web3dart/web3dart.dart';
// Please avoid using public RPC URL in production, use services
// like Infura, Quicknode, etc.
final client = Web3Client("YOUR_RPC_URL", Client());
Get Account
Once user has successfully logged in, you can retrieve the user's private key using the getPrivKey
method from Web3AuthFlutter. We'll use this private key to generate the Credentials for the user.
This Credentials object has the user's key pair of private key and public key, and can be used to sign the transactions. Please note, that this assumes that the user has already logged in and the private key is available.
import 'package:web3dart/web3dart.dart';
final privateKey = await Web3AuthFlutter.getPrivKey();
final credentials = EthPrivateKey.fromHex(privateKey);
final address = credentials.address;
Get Balance
To retrieve the native balance of the user, you can use the Web3Client
object we created earlier.
It has getBalance
method which helps to fetch the user's native token balance.
The result we get from Web3Client is in wei, the smallest value. To convert the value to ether, you can divide it with 10^18, where 18 denotes the decimals for wei.
For the simplicity, we'll use a helper function from web3dart package which has the same implementation
// Use the client and address variable from above
final balanceResponse = await client.getBalance(address);
// Convert the balance to ether format, and round off to 4 decimal places.
final balance = balanceResponse.getValueInUnit(EtherUnit.ether).toStringAsFixed(4);
Sign Transaction
To sign a transaction, you can use the Web3Client
object we created earlier. It has
signTransaction
method which helps to sign the transaction for the given key pair, and chain.
The method internally handles the nonce, gas price, and gas limit. If you want to manually set the nonce, gas price, and gas limit, you can override the parameters in the Transaction object.
import 'package:web3dart/web3dart.dart';
// Use client, address, and credentials from previous code snippets
final signature = await client.signTransaction(
credentials,
Transaction(
from: address,
// Replace with the recipient address
to: EthereumAddress.fromHex('0x809D4310d578649D8539e718030EE11e603Ee8f3'),
// Replace with the amount of ETH to send
value: EtherAmount.fromUnitAndValue(EtherUnit.gwei, 50000000), // 0.05 ETH
chainId: null,
fetchChainIdFromNetworkId: true,
),
);
Send Transaction
If you wish to sign, and also broadcast the transaction, you can use the
Web3Client.sendTransaction
method.
This method prepares the transaction, and signs similar to signTransaction
method. The only
difference is, it also broadcasts the transaction to the network, and returns the transaction
receipt.
import 'package:web3dart/web3dart.dart';
// Use client, address, and credentials from previous code snippets
final receipt = await client.sendTransaction(
credentials,
Transaction(
from: address,
to: EthereumAddress.fromHex('0x809D4310d578649D8539e718030EE11e603Ee8f3'),
value: EtherAmount.fromUnitAndValue(EtherUnit.gwei, 50000000), // 0.05 ETH
chainId: null,
fetchChainIdFromNetworkId: true,
),
);
Smart Contract Interactions
With the web3dart library, apart from doing the normal interactions, and transactions, you can also deploy and interact with Smart Contracts.
Firstly, we'll create a new smart contract using Solidity that allows to store a message and update it. The contract will have a constructor that takes an initial message as input, and a function to update the message.
pragma solidity ^0.8.20;
contract HelloWorld {
string public message;
constructor(string memory initMessage) public {
message = initMessage;
}
function update(string memory newMessage) public {
message = newMessage;
}
}
The package don't have a way to compile solidity smart contracts, so we'll need to compile the contract using an online compiler and get the bytecode and abi from there. For this example we'll use Remix IDE to compile the contract.
Please note that the bytecode and abi are different for each network, so you'll need to compile the contract for the network you want to deploy it to.
Once compiled, please copy the bytecode and abi for the future usecases.
final contractAbi = '[{"constant":false,"inputs":[{"name":"newMessage","type":"string"}],"name":"update","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"message","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"initMessage","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]';
final byteCode =
"0x608060405234801561001057600080fd5b506040516104623803806104628339818101604052602081101561003357600080fd5b81019080805164010000000081111561004b57600080fd5b8281019050602081018481111561006157600080fd5b815185600182028301116401000000008211171561007e57600080fd5b5050929190505050806000908051906020019061009c9291906100a3565b5050610148565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100e457805160ff1916838001178555610112565b82800160010185558215610112579182015b828111156101115782518255916020019190600101906100f6565b5b50905061011f9190610123565b5090565b61014591905b80821115610141576000816000905550600101610129565b5090565b90565b61030b806101576000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633d7403a31461003b578063e21f37ce146100f6575b600080fd5b6100f46004803603602081101561005157600080fd5b810190808035906020019064010000000081111561006e57600080fd5b82018360208201111561008057600080fd5b803590602001918460018302840111640100000000831117156100a257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610179565b005b6100fe610193565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561013e578082015181840152602081019050610123565b50505050905090810190601f16801561016b5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b806000908051906020019061018f929190610231565b5050565b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102295780601f106101fe57610100808354040283529160200191610229565b820191906000526020600020905b81548152906001019060200180831161020c57829003601f168201915b505050505081565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061027257805160ff19168380011785556102a0565b828001600101855582156102a0579182015b8281111561029f578251825591602001919060010190610284565b5b5090506102ad91906102b1565b5090565b6102d391905b808211156102cf5760008160009055506001016102b7565b5090565b9056fea265627a7a72305820a58716d2c2342b3cc5028e49842810b98f5c3f2c1591e8c7f3ec916096f6a03264736f6c634300050a0032";
Deploy Contract
Since web3dart package doesn't support deploying contracts directly, we'll use the precompiled smart
contract byteCode to deploy the contract using sendTransaction
method.
// Use the client, address, and credentials from previous code snippets
// Use the bytecode from the previous step
final payload = Uint8List.fromList(utf8.encode(byteCode));
final transaction = Transaction(
// Please make sure to keep the `to` field as `null`
// for deploying the contract
to: null,
from: address,
data: payload,
);
final receipt = await client.sendTransaction(credential, transaction);
Read From Contract
To interact with any smart contract, you need the contract address and the ABI of the contract. The ABI of the contract helps encode the function name and its parameters. Considering ABI as a outline of the contract, which provides contract specifications.
We'll create a DeployedContract
instance with the contract address and ABI. Once created, we can
use it to call the contract function. To interact with the contract, we'll use the call
method
form the Web3Client.
In this sample, we'll read the message from the contract we deployed in the previous step.
import 'package:web3dart/web3dart.dart';
// Use the client, address, contractAbi and credentials from previous code snippets
final contract = DeployedContract(
ContractAbi.fromJson(contractAbi, ''),
"ADDRESS_OF_DEPLOYED_CONTRACT_IN_HEX",
);
final messageFunction = contract.function('message');
final message = await client.call(
contract: contract,
function: messageFunction,
params: [],
);
Write to Contract
Similary, you can write to the contract using the sendTransaction
method of Web3Client. In this
sample, we'll update the message in the contract we deployed previously.
import 'package:web3dart/web3dart.dart';
// Use the client, address, contractAbi and credentials from previous code snippets
final contract = DeployedContract(
ContractAbi.fromJson(contractAbi, ''),
"ADDRESS_OF_DEPLOYED_CONTRACT_IN_HEX",
);
final updateFunction = contract.function('update');
final receipt = await client.sendTransaction(
credentials,
Transaction.callContract(
contract: contract,
function: updateFunction,
parameters: ["YOUR_NEW_MESSAGE"]
)
);