Starkware Component
Here we learn how to sign in to any application using Starknet
Let's add the imports that we will need for our Starknet component to function
Edit Starkware.tsx
import { Payload as SIWPayload, SIWWeb3 } from "@web3auth/sign-in-with-web3";
import { getStarknet } from "get-starknet";
import React, { useState } from "react";
import { starknetKeccak } from "starknet/dist/utils/hash";
import Swal from "sweetalert2";
import styles from "../public/css/starkware.module.css";
import StarkwareLogo from "../public/starknet-logo.png";
const Starkware: React.FC = () => {
return <></>;
};
export default Starkware;
Define the variables that we require
...
const Starkware: React.FC = () => {
const [isConnected, setIsConnected] = useState(false);
const [provider, setProvider] = useState<any>();
const [siwsMessage, setSiwsMessage] = useState<SIWWeb3|null>();
const [sign, setSignature] = useState("");
const [address, setAddress] = useState("");
let typedMessage;
const domain = window.location.host;
const origin = window.location.origin;
let statement = "Sign in with Starkware to the app.";
}
Writing code to detect the current network
const Starkware: React.FC = () => {
...
...
const networkId = () => {
const starknet = getStarknet()
if (!starknet?.isConnected) {
return
}
try {
const { baseUrl } = starknet.provider
if (baseUrl.includes("alpha-mainnet.starknet.io")) {
return "mainnet-alpha"
} else if (baseUrl.includes("alpha4.starknet.io")) {
return "goerli-alpha"
} else if (baseUrl.match(/^https?:\/\/localhost.*/)) {
return "localhost"
}
} catch {}
}
};
Let's write the function to connect the wallet to the app
const Starkware: React.FC = () => {
...
...
async function connectWallet() {
const starknet = await getStarknet()
const[add] = await starknet.enable();
if (add.length > 0) {
setAddress(add);
setIsConnected(true);
setProvider(starknet);
}
}
}
We need to define the function that prompts the wallets to sign the message.
const Starkware: React.FC = () => {
...
...
const signMessage = async (message:string) => {
message = starknetKeccak(message).toString('hex').substring(0, 31);
typedMessage = {
domain: {
name: "Example DApp",
chainId: networkId() === "mainnet-alpha" ? "SN_MAIN" : "SN_GOERLI",
version: "0.0.1",
},
types: {
StarkNetDomain: [
{ name: "name", type: "felt" },
{ name: "chainId", type: "felt" },
{ name: "version", type: "felt" },
],
Message: [{ name: "message", type: "felt" }],
},
primaryType: "Message",
message: {
message,
},
}
return provider.account.signMessage(typedMessage)
}
}
Now we need to write the function that creates the SIWWeb3 Message and perform the signing
const Starkware: React.FC = () => {
...
...
// Generate a message for signing
// The nonce is generated on the server side
async function createStarkwareMessage() {
const payload = new SIWPayload();
payload.domain = domain;
payload.address = address;
payload.uri = origin;
payload.statement = statement;
payload.version = "1";
payload.chainId = 1;
const header = {
t : "eip191"
};
const network = "starkware"
let message = new SIWWeb3({ header, payload, network });
setSiwsMessage(message);
const messageText = message.prepareMessage();
const result = await signMessage(messageText);
setSignature(result.join(','));
}
}
Now we have all the functions that we need. Let's add the jsx code and render the application frontend.
const Starkware: React.FC = () => {
...
...
return (
<>
{isConnected &&
sign == "" &&
<span>
<p className={styles.center}>Sign Transaction</p>
<input className={ styles.publicKey} type="text" id="publicKey" value={address} readOnly/>
</span>
}
{
isConnected != true &&
sign=="" &&
<div>
<div className={styles.logowrapper}>
<img className={styles.starkwarelogo} src={StarkwareLogo} />
</div>
<p className={styles.sign}>Sign in With Starkware</p>
</div>
}
{isConnected &&
sign == "" &&
<div>
<button className={styles.web3auth} id='w3aBtn' onClick={createStarkwareMessage}>Sign-in with Starkware</button>
</div>
}
{isConnected != true &&
sign == "" &&
<button className={styles.web3auth} id='w3aBtn' onClick={connectWallet}>Connect Wallet</button>
}
{
sign &&
<>
<p className={styles.center}>Verify Signature</p>
<input className={styles.signature} type="text" id="signature" value={sign} onChange={ e=> setSignature(e.target.value)} />
<button className={styles.web3auth} id='verify' onClick={e => {
const signature = {
t: "eip191",
s: sign.split(",")
}
const payload = siwsMessage!.payload;
siwsMessage!.verify(payload, signature, provider).then(resp => {
if (resp.success == true) {
Swal.fire("Success","Signature Verified","success")
} else {
Swal.fire("Error",resp.error.type,"error")
}
}).catch(err => {
console.log(err)
Swal.fire("Error",err.error.toString(),"error")
});
}}>Verify</button>
<button className={styles.web3auth} id='verify' onClick={e => {
setSiwsMessage(null);
setSignature("")
}}>Back to Wallet</button>
</>
}
</>
);
}
Full code available here
Let's run the application now :-
npm start