Skip to main content

Integrate Web3Auth with the Skale 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 Skale 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.

Add web3dart using flutter pub add command.

flutter pub add web3dart

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"]
)
);