web3.pas is a SDK for creating decentralized Web apps in Embarcadero Delphi.
web3.pas is built upon TMS Web Core, a framework for creating modern web applications in Delphi.
Under the hood, web3.pas is powered by ethers.js — a JavaScript library designed to enable developers to interact with the Ethereum blockchain and the larger Ethereum ecosystem.
Ethers.js gets downloaded at runtime and as such you don’t need to install it. But you do need Delphi Community Edition and TMS Web Core.
Last but not least, you need a browser-based crypto wallet. Please follow the below steps to install MetaMask into your web browser.
- Clone this repo to a directory of your choosing, for example
C:\Projects\web3.pas
- Launch Delphi and start a new TMS Web Core project via File > New > Other > TMS Web > TMS Web Application
- Save your application to a directory of your choosing
- Click on: Project > Add to Project and add
web3.pas
(the unit, not the directory) to your project - Run your application (F9)
- Navigate to https://metamask.io/
- Click on: Get MetaMask
- Follow the instructions and install MetaMask into your web browser
Before you can use web3.pas in your TMS Web Core project, you will need to manually add the following snippet to the <head>
section of your project's HTML document:
<script type="module">
import { ethers } from "https://cdn.jsdelivr.net/npm/ethers@6/dist/ethers.min.js";
window.ethers = ethers;
</script>
Assuming you have added web3
to your uses clause, you can now call into a global singleton named Ethers
:
var
wei: TWei;
begin
wei := Ethers.ParseEther('1.0');
ShowMessage(wei.ToString);
end;
The very first thing needed to begin interacting with the blockchain is connecting to it using a Provider:
var
provider: TJsonRpcProvider;
begin
if not Assigned(Ethereum) then
// If MetaMask is not installed, we use the default provider, which is backed
// by a variety of third-party services (such as Infura).
provider := Ethers.GetDefaultProvider
else
// Connect to the MetaMask EIP-1193 object. This is a standard protocol that
// allows Ethers access to make all read-only requests through MetaMask.
provider := Ethers.BrowserProvider.New(Ethereum);
...
end;
The above snippet will give you read-only access to the blockchain. When requesting write access to the blockchain - such as sending a transaction - MetaMask will show a pop-up to the user asking for permission.
Once you have a Provider, you have a read-only connection to the data on the blockchain. This can be used to query the current account state, fetch historic logs, look up contract code and so on.
// Look up the current block number (i.e. height)
console.log(await(UInt64, provider.GetBlockNumber));
// Get the current balance of an account (by address or ENS name)
balance := await(TWei, provider.GetBalance('vitalik.eth'));
// Since the balance is in wei, you may wish to display it in ether instead.
console.log(Ethers.FormatEther(balance));
// Get the next nonce required to send a transaction
console.log(await(UInt64, provider.GetTransactionCount('vitalik.eth')));
To write to the blockchain you need access to a private key. In most cases, those private keys are not accessible directly to your code, and instead you make requests via a Signer, which dispatches the request to a service (such as MetaMask) which provides strictly gated access and requires feedback to the user to approve or reject operations:
var
provider: TJsonRpcProvider;
signer : TJsonRpcSigner;
begin
signer := nil;
if Assigned(Ethereum) then
begin
// Connect to the MetaMask EIP-1193 object. This is a standard protocol that
// allows Ethers access to make all read-only requests through MetaMask.
provider := Ethers.BrowserProvider.New(Ethereum);
// It also provides an opportunity to request access to write operations, which
// will be performed by the private key that MetaMask manages for the user.
signer := await(TJsonRpcSigner, provider.GetSigner);
end else
// If MetaMask is not installed, we use the default provider, which is backed
// by a variety of third-party services (such as Infura).
// They do not have private keys installed, so they only have read-only access.
provider := Ethers.GetDefaultProvider;
...
end;
Once you have a Signer, you can have MetaMask sign your transaction and broadcast it to the network:
// When sending a transaction, the value is in wei, so ParseEther converts ether to wei.
tx := Transaction(
'0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', // To: vitalik.eth
Ethers.ParseEther('1.0') // Value
);
// Send tx to the network
response := await(TTransactionResponse, signer.SendTransaction(tx));
console.log(response.Hash); // the transaction hash
// Often you may wish to wait until the transaction is mined
receipt := await(TTransactionReceipt, response.Wait);
console.log(receipt.Status); // 1 for success, 0 for failure
The ethers.js documentation covers many of the most common operations that developers require.
Distributed under the GPL-3.0 license.
Commercial support and training is available from Stefan.