Create a dApp with StarKey
Create your first Dapp using StarKey wallet, the official wallet of Supra
Setup the project
Start building
Initialize the supraProvider
and state hooks
supraProvider
and state hookssupraProvider
- used to interact with StarKey wallet.
isStarKeyInstalled
- boolean value of StarKey extension installation status
accounts
- Array of connected accounts
networkData
- Chain ID for the connected network
import React, {useEffect, useState} from "react";
import { HexString, TxnBuilderTypes, BCS } from "supra-l1-sdk";
function App() {
let supraProvider: any = typeof window !== "undefined" && (window as any)?.starkey?.supra;
const [isStarkeyInstalled, setIsStarkeyInstalled] = useState<boolean>(!!supraProvider);
const [accounts, setAccounts] = useState<string[]>([]);
const [networkData, setNetworkData] = useState<any>();
return <div></div>;
}
All code from this step forward will be included within the App()
function.
Check for the injected StarKey object
The following code checks for the injected StarKey object every 500ms for up to 5 seconds. If found, the function will update the StarKey installation status and obtain the connected accounts.
const checkForStarkey = () => {
const intervalId = setInterval(() => {
if ((window as any)?.starkey) {
supraProvider = (window as any)?.starkey.supra;
clearInterval(intervalId);
setIsStarkeyInstalled(true);
updateAccounts().then();
}
}, 500);
setTimeout(() => {
clearInterval(intervalId);
}, 5000);
};
useEffect(() => {
checkForStarkey();
}, []);
Get the connected accounts
The following code obtains the connected accounts (if any) and stores them.
const updateAccounts = async () => {
if (supraProvider) {
try {
const response_acc = await supraProvider.account();
if (response_acc.length > 0) {
setAccounts(response_acc);
} else {
setAccounts([]);
}
} catch (e) {
setAccounts([]);
}
getNetworkData().then();
}
};
Initialize additional hooks
The following code will assist in maintaining updated network/account data while also handling events emitted by the injected StarKey object.
useEffect(() => {
if (supraProvider) {
supraProvider.on("accountChanged", (acc: string[]) => {
setAccounts(acc);
});
supraProvider.on("networkChanged", (data: any) => {
setNetworkData(data);
});
supraProvider.on("disconnect", () => {
resetWalletData();
});
}
}, [supraProvider]);
useEffect(() => {
if (accounts) {
getNetworkData().then();
}
}, [accounts]);
Handle wallet connections
The following code will handle the wallet connections, triggered through a button click (which we will setup later) or an emitted event from the StarKey object.
When a wallet is connected, the accounts must be updated. When a wallet is disconnected, we must clear the stored accounts and network data.
const connectWallet = async () => {
const response = await supraProvider.connect();
updateAccounts().then();
};
const disconnectWallet = async () => {
if (supraProvider) {
await supraProvider.disconnect();
}
resetWalletData();
};
const resetWalletData = ()=>{
setAccounts([]);
setNetworkData({});
}
Switch between mainnet and testnet
The following code will be triggered through a button click to prompt the user to switch between mainnet and testnet
const switchToTestnet = async (id:string) => {
if (supraProvider) {
await supraProvider.changeNetwork({chainId:"6"});
await getNetworkData()
}
};
const switchToMainnet = async () => {
if (supraProvider) {
await supraProvider.changeNetwork({chainId:"8"});
await getNetworkData()
}
};
Send a transaction
The following code creates a raw payload that calls the transfer
function of the supra_account
module. Once the raw transaction payload is created, it uses the supraProvider.sendTransaction
function to prompted the connect wallet to sign and submit.
It will transfer 1 supra
to the address 0x8de4158b48633d853186d5fc790718e5821d7d3c4855e06bcd97b105389a7d0f
.
const sendRawTransaction = async () => {
const txExpiryTime = (Math.ceil(Date.now() / 1000) + 30) //30 seconds
/** OptionalTransactionPayloadArgs {
maxGas?: bigint;
gasUnitPrice?: bigint;
txExpiryTime?: bigint;
}*/
const optionalTransactionPayloadArgs = {
txExpiryTime
}
const rawTxPayload = [
accounts[0],
0,
"0000000000000000000000000000000000000000000000000000000000000001",
"supra_account",
"transfer",
[],
[
new HexString("0x8de4158b48633d853186d5fc790718e5821d7d3c4855e06bcd97b105389a7d0f").toUint8Array(),
BCS.bcsSerializeUint64(100000000)
],
optionalTransactionPayloadArgs
];
const data = await supraProvider.createRawTransactionData(rawTxPayload);
if (data) {
const params = {
data: data,
/*from: accounts[0],
to: "",
chainId: networkData.chainId,
value: "100000000",*/
};
const txHash = await supraProvider.sendTransaction(params);
}
};
Create the buttons displayed on the frontend
The following code renders buttons on the frontend that will interact with the above functions.
return <div>
<button onClick={connectWallet}>Connect Wallet</button>
<button onClick={disconnectWallet}>Disconnect Wallet</button>
<p>Connected Account(s): {JSON.stringify(accounts)}</p>
<p>Network Data: {JSON.stringify(networkData)}</p>
<button onClick={switchToTestnet}>Switch to Testnet</button>
<button onClick={switchToMainnet}>Switch to Mainnet</button>
<br></br>
<button onClick={sendRawTransaction}>Send Test Transaction</button>
</div>;
Final code for App.tsx
App.tsx
import React, {useEffect, useState} from "react";
import { HexString, TxnBuilderTypes, BCS } from "supra-l1-sdk";
function App() {
let supraProvider: any = typeof window !== "undefined" && (window as any)?.starkey?.supra;
const [isStarkeyInstalled, setIsStarkeyInstalled] = useState<boolean>(!!supraProvider);
const [accounts, setAccounts] = useState<string[]>([]);
const [networkData, setNetworkData] = useState<any>();
const checkForStarkey = () => {
const intervalId = setInterval(() => {
if ((window as any)?.starkey) {
supraProvider = (window as any)?.starkey.supra;
clearInterval(intervalId);
setIsStarkeyInstalled(true);
updateAccounts().then();
}
}, 500);
setTimeout(() => {
clearInterval(intervalId);
}, 5000);
};
useEffect(() => {
checkForStarkey();
}, []);
const getNetworkData = async () => {
if (supraProvider) {
const data = await supraProvider.getChainId();
console.log(data);
if (data) {
setNetworkData(data)
}
}
};
const updateAccounts = async () => {
if (supraProvider) {
try {
const response_acc = await supraProvider.account();
if (response_acc.length > 0) {
setAccounts(response_acc);
} else {
setAccounts([]);
}
} catch (e) {
setAccounts([]);
}
getNetworkData().then();
}
};
useEffect(() => {
if (supraProvider) {
supraProvider.on("accountChanged", (acc: string[]) => {
setAccounts(acc);
});
supraProvider.on("networkChanged", (data: any) => {
setNetworkData(data);
});
supraProvider.on("disconnect", () => {
resetWalletData();
});
}
}, [supraProvider]);
useEffect(() => {
if (accounts) {
getNetworkData().then();
}
}, [accounts]);
const resetWalletData = ()=>{
setAccounts([]);
setNetworkData({});
}
const connectWallet = async () => {
const response = await supraProvider.connect();
updateAccounts().then();
};
const disconnectWallet = async () => {
if (supraProvider) {
await supraProvider.disconnect();
}
resetWalletData();
};
const switchToTestnet = async () => {
if (supraProvider) {
await supraProvider.changeNetwork({chainId:"6"});
await getNetworkData()
}
};
const switchToMainnet = async () => {
if (supraProvider) {
await supraProvider.changeNetwork({chainId:"8"});
await getNetworkData()
}
};
const sendRawTransaction = async () => {
const txExpiryTime = (Math.ceil(Date.now() / 1000) + 30) //30 seconds
/** OptionalTransactionPayloadArgs {
maxGas?: bigint;
gasUnitPrice?: bigint;
txExpiryTime?: bigint;
}*/
const optionalTransactionPayloadArgs = {
txExpiryTime
}
const rawTxPayload = [
accounts[0],
0,
"0000000000000000000000000000000000000000000000000000000000000001",
"supra_account",
"transfer",
[],
[
new HexString("0x8de4158b48633d853186d5fc790718e5821d7d3c4855e06bcd97b105389a7d0f").toUint8Array(),
BCS.bcsSerializeUint64(100000000)
],
optionalTransactionPayloadArgs
];
const data = await supraProvider.createRawTransactionData(rawTxPayload);
if (data) {
const params = {
data: data,
/*from: accounts[0],
to: "",
chainId: networkData.chainId,
value: "100000000",*/
};
const txHash = await supraProvider.sendTransaction(params);
}
};
return <div>
<button onClick={connectWallet}>Connect Wallet</button>
<button onClick={disconnectWallet}>Disconnect Wallet</button>
<p>Connected Account(s): {JSON.stringify(accounts)}</p>
<p>Network Data: {JSON.stringify(networkData)}</p>
<button onClick={switchToTestnet}>Switch to Testnet</button>
<button onClick={switchToMainnet}>Switch to Mainnet</button>
<br></br>
<button onClick={sendRawTransaction}>Send Test Transaction</button>
</div>;
}
export default App;
Last updated