var img = document.createElement('img'); img.src = "https://terradocs.matomo.cloud//piwik.php?idsite=1&rec=1&url=https://docs.terra.money" + location.pathname; img.style = "border:0"; img.alt = "tracker"; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(img,s);
Skip to main content

Signing Bytes

☢️Warning

Wallet-Provider is deprecated. Use Wallet Kit instead.

You can sign arbitrary bytes with Wallet Provider in a React-based web application. This action is useful for verifying account ownership without having to post a transaction to the chain and is commonly used as a form of simple user authentication.

💡tip

Not using React? Use the wallet-controller instead.

The Wallet Provider comes with a useConnectedWallet hook, which lets you trigger actions from a Terra wallet that's connected to the web page. The connectedWallet object includes a .signBytes() method, which prompts the user to sign the data and then returns an object of type SignBytesResult. The returned SignBytesResult object contains the address of the signer and the signed data.

The verifyBytes function then compares the original TEST_BYTES against the signature and public key pairing returned by the SignBytesResult. If verifyBytes returns true, then the account is owned by the connected wallet. Likewise, if verifyBytes returns false, then the account is not owned by the connected wallet. In this way, the owner of the associated wallet is verified without having to produce an on-chain action or pay gas fees.

💡tip

You can see how the verifyBytes function works here.

Wallet Provider also supplies useful error types that can be used with a catch statement to notify the user whether or not the signing was successful:


_96
import {
_96
SignBytesFailed,
_96
SignBytesResult,
_96
Timeout,
_96
useConnectedWallet,
_96
UserDenied,
_96
verifyBytes,
_96
} from '@terra-money/wallet-provider';
_96
import React, { useCallback, useState } from 'react';
_96
_96
const TEST_BYTES = Buffer.from('hello'); // resolves to <Buffer 68 65 6c 6c 6f>
_96
_96
export function SignBytesSample() {
_96
const [txResult, setTxResult] = useState<SignBytesResult | null>(null);
_96
const [txError, setTxError] = useState<string | null>(null);
_96
const [verifyResult, setVerifyResult] = useState<string | null>(null);
_96
const chainID = 'phoenix-1';
_96
_96
const connectedWallet = useConnectedWallet();
_96
_96
const signBytes = useCallback(() => {
_96
if (!connectedWallet) {
_96
return;
_96
}
_96
_96
setTxResult(null);
_96
setTxError(null);
_96
setVerifyResult(null);
_96
_96
connectedWallet
_96
.signBytes(TEST_BYTES)
_96
.then((nextSignBytesResult: SignBytesResult) => {
_96
setTxResult(nextSignBytesResult);
_96
setTxError(null);
_96
_96
const result = verifyBytes(TEST_BYTES, nextSignBytesResult.result);
_96
setVerifyResult(result ? 'Verify OK' : 'Verify failed');
_96
})
_96
.catch((error) => {
_96
setTxResult(null);
_96
setVerifyResult(null);
_96
_96
if (error instanceof UserDenied) {
_96
setTxError('User Denied');
_96
} else if (error instanceof Timeout) {
_96
setTxError('Timeout');
_96
} else if (error instanceof SignBytesFailed) {
_96
setTxError('Sign Bytes Failed');
_96
} else {
_96
setTxError(
_96
'Unknown Error: ' +
_96
(error instanceof Error ? error.message : String(error)),
_96
);
_96
}
_96
});
_96
}, [connectedWallet]);
_96
_96
return (
_96
<div>
_96
<h1>Sign Bytes Sample</h1>
_96
_96
{connectedWallet?.availableSignBytes &&
_96
!txResult &&
_96
!txError &&
_96
!verifyResult && (
_96
<button onClick={() => signBytes()}>
_96
Sign bytes with {connectedWallet.addresses[chainID]}
_96
</button>
_96
)}
_96
_96
{txResult && <pre>{JSON.stringify(txResult, null, 2)}</pre>}
_96
_96
{txError && <pre>{txError}</pre>}
_96
_96
{verifyResult && <pre>{verifyResult}</pre>}
_96
_96
{(!!txResult || !!txError || !!verifyResult) && (
_96
<button
_96
onClick={() => {
_96
setTxResult(null);
_96
setTxError(null);
_96
setVerifyResult(null);
_96
}}
_96
>
_96
Clear result
_96
</button>
_96
)}
_96
_96
{!connectedWallet && <p>Wallet not connected!</p>}
_96
_96
{connectedWallet && !connectedWallet.availableSignBytes && (
_96
<p>This connection does not support signBytes()</p>
_96
)}
_96
</div>
_96
);
_96
}

You can find this code being used in context on GitHub.

You can view a working sandbox example of bytes signing with Station on codesandbox.io.