Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: tezos-provider with all Beacon operations #19

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ Catalogue of various wallet and dapp examples implementing WalletConnect's **SDK

**Wallets:**

- [React Wallet (Sign v1 + v2)](https://github.com/WalletConnect/web-examples/tree/main/advanced/wallets/react-wallet-v2) ([Demo](https://react-wallet.walletconnect.com/))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why remove this comment?


**dApps:**

- [React dApp (with standalone client) - v2](https://github.com/WalletConnect/web-examples/tree/main/advanced/dapps/react-dapp-v2) ([Demo](https://react-app.walletconnect.com/))
- [React dApp (with EthereumProvider + Ethers.js) - v2](https://github.com/WalletConnect/web-examples/tree/main/advanced/dapps/react-dapp-v2-with-ethers) ([Demo](https://react-dapp-v2-with-ethers.vercel.app/))
- [React dApp (with EthereumProvider + web3.js) - v2](https://github.com/WalletConnect/web-examples/tree/main/advanced/dapps/react-dapp-v2-with-web3js) ([Demo](https://react-dapp-v2-with-web3js.vercel.app/))
- [React dApp (with TezosProvider) - v2](https://github.com/WalletConnect/web-examples/tree/main/dapps/tezos-provider)

### Auth API

Expand Down
246 changes: 129 additions & 117 deletions dapps/tezos-provider/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { WalletConnectModal } from "@walletconnect/modal";
import { useState } from "react";
import { TEZOS_ACTIONS, DEFAULT_TEZOS_METHODS } from "./utils/samples";
import { SAMPLES, SAMPLE_KINDS } from "./utils/samples";
import TezosProvider, { formatTezosBalance, getChainId, TezosChainDataMainnet, TezosChainDataTestnet } from "./utils/tezos-provider";
import { PartialTezosTransactionOperation, TezosBallotOperation } from "@airgap/beacon-types";

const projectId = import.meta.env.VITE_PROJECT_ID;

Expand All @@ -25,38 +24,49 @@ const provider: TezosProvider = await TezosProvider.init({

const App = () => {
const [isConnected, setIsConnected] = useState(false);
const [lastKind, setLastKind] = useState<any>(null);
const [result, setResult] = useState<any>(null);
const [description, setDescription] = useState<any>(null);
const [contractAddress, setContractAddress] = useState("");
const [balance, setBalance] = useState("");

console.log("Provider", provider);

// 3. handle display_uri event and open modal
if (provider.signer) {
provider.signer.on("display_uri", async (uri: string) => {
console.log("event display_uri", uri);
await modal.openModal({
uri,
const subscribe = async () => {
if (provider.signer) {
console.log("Subscribing to events...");
provider.signer.on("display_uri", async (uri: string) => {
console.log("event display_uri", uri);
await modal.openModal({
uri,
});
});
});

provider.signer.on("session_ping", ({ id, topic }: { id: string; topic: string }) => {
console.log("Session Ping:", id, topic);
});
provider.signer.on("session_ping", ({ id, topic }: { id: string; topic: string }) => {
console.log("Event session_ping:", id, topic);
});

provider.signer.on("session_event", ({ event, chainId }: { event: any; chainId: string }) => {
console.log("Session Event:", event, chainId);
});
provider.signer.on("session_event", ({ event, chainId }: { event: any; chainId: string }) => {
console.log("Event session_event:", event, chainId);
});

provider.signer.on("session_update", ({ topic, params }: { topic: string; params: any }) => {
console.log("Session Update:", topic, params);
});
provider.signer.on("session_update", ({ topic, params }: { topic: string; params: any }) => {
console.log("Event session_update:", topic, params);
});

provider.signer.on("session_delete", ({ id, topic }: { id: string; topic: string }) => {
console.log("Session Delete:", id, topic);
});
}
provider.signer.on("session_delete", ({ id, topic }: { id: string; topic: string }) => {
console.log("Event session_delete:", id, topic);
});

provider.signer.on("connect", ({ id, topic }: { id: string; topic: string }) => {
console.log("Event connect:", id, topic);
});

provider.signer.on("disconnect", ({ id, topic }: { id: string; topic: string }) => {
console.log("Event disconnect:", id, topic);
setIsConnected(false);
});
}
};

const getBalance = async () => {
if (provider) {
Expand All @@ -67,7 +77,10 @@ const App = () => {

// 4. handle connect event
const connect = async () => {
window.localStorage.removeItem('walletconnect');
console.log("Connecting...");
try {
await subscribe();
await provider.connect({chains: [TezosChainDataTestnet, TezosChainDataMainnet]});
setIsConnected(true);
console.log("Connected successfully. Provider", provider);
Expand All @@ -82,37 +95,42 @@ const App = () => {

// 5. handle disconnect event
const disconnect = async () => {
console.log("Disconnecting...");
if (provider.signer) {
await provider.signer.disconnect();
}
window.localStorage.removeItem('walletconnect');
setIsConnected(false);
setResult(null); // Clear result on disconnect
};

// 6. handle operations
const handleOp = async (method: string) => {
const handleOp = async (kind: SAMPLE_KINDS) => {
if (!provider) return;

setLastKind(kind);
setResult("Waiting for response from the Wallet...");

try {
let res = null;
switch (method) {
case "tezos_getAccounts":
switch (kind) {
case SAMPLE_KINDS.GET_ACCOUNTS:
res = await provider.tezosGetAccounts();
break;
case "tezos_sign":
case SAMPLE_KINDS.SIGN:
res = await provider.tezosSign("05010000004254");
break;
case "tezos_send_transaction":
res = await provider.tezosSendTransaction(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_TRANSACTION]);
case SAMPLE_KINDS.SEND_TRANSACTION:
res = await provider.tezosSendTransaction(SAMPLES[SAMPLE_KINDS.SEND_TRANSACTION]);
break;
case "tezos_send_delegation":
res = await provider.tezosSendDelegation(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_DELEGATION]);
case SAMPLE_KINDS.SEND_DELEGATION:
res = await provider.tezosSendDelegation(SAMPLES[SAMPLE_KINDS.SEND_DELEGATION]);
break;
case "tezos_send_undelegation":
case SAMPLE_KINDS.SEND_UNDELEGATION:
res = await provider.tezosSendUndelegation();
break;
case "tezos_send_origination":
res = await provider.tezosSendOrigination(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_ORGINATION]);
case SAMPLE_KINDS.SEND_ORGINATION:
res = await provider.tezosSendOrigination(SAMPLES[SAMPLE_KINDS.SEND_ORGINATION]);
const contractAddressList = await provider.getContractAddress(res.hash);
if (contractAddressList.length > 0) {
setContractAddress(contractAddressList[0]);
Expand All @@ -121,86 +139,79 @@ const App = () => {
console.error("TezosRpc could not find contract address in origination operation.");
}
break;
case "tezos_send_contract_call":
const contract_call: PartialTezosTransactionOperation = {
...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_CONTRACT_CALL],
case SAMPLE_KINDS.SEND_CONTRACT_CALL:
res = await provider.tezosSendContractCall({
...SAMPLES[SAMPLE_KINDS.SEND_CONTRACT_CALL],
destination: contractAddress,
};
res = await provider.tezosSendContractCall(contract_call);
});
break;
case "tezos_send_stake":
res = await provider.tezosSendStake(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_STAKE]);
case SAMPLE_KINDS.SEND_STAKE:
res = await provider.tezosSendStake(SAMPLES[SAMPLE_KINDS.SEND_STAKE]);
break;
case "tezos_send_unstake":
res = await provider.tezosSendUnstake(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_UNSTAKE]);
case SAMPLE_KINDS.SEND_UNSTAKE:
res = await provider.tezosSendUnstake(SAMPLES[SAMPLE_KINDS.SEND_UNSTAKE]);
break;
case "tezos_send_finalize":
res = await provider.tezosSendFinalizeUnstake(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_FINALIZE]);
case SAMPLE_KINDS.SEND_FINALIZE:
res = await provider.tezosSendFinalizeUnstake(SAMPLES[SAMPLE_KINDS.SEND_FINALIZE]);
break;
case "tezos_send_ballot":
const proposal = await provider.getCurrentProposal() || "[no proposal in progress]";
const ballot : TezosBallotOperation = {
...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_BALLOT],
proposal: proposal
};
res = await provider.tezosSendBallot(ballot);
case SAMPLE_KINDS.SEND_INCREASE_PAID_STORAGE:
res = await provider.tezosSendIncreasePaidStorage({
...SAMPLES[SAMPLE_KINDS.SEND_INCREASE_PAID_STORAGE],
destination: contractAddress,
});
break;

default:
throw new Error(`Unsupported method ${method}`);
throw new Error(`App: Unsupported kind ${kind}`);
}
setLastKind(kind);
setResult(res);
await getBalance();
} catch (error) {
if (error instanceof Error) {
console.error(`Error sending ${method}:`, error.name, error.message);
console.error(`Error sending ${kind}:`, error.name, error.message);
setResult([error.name, error.message]);
} else {
console.error(`Error sending ${method}:`, error);
console.error(`Error sending ${kind}:`, error);
setResult(error);
}

}
};

const describe = (method: string) => {
switch (method) {
case "tezos_send_transaction":
setDescription(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_TRANSACTION]);
const describe = (kind: SAMPLE_KINDS) => {
switch (kind) {
case SAMPLE_KINDS.SEND_TRANSACTION:
setDescription(SAMPLES[kind]);
break;
case "tezos_send_delegation":
setDescription(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_DELEGATION]);
case SAMPLE_KINDS.SEND_DELEGATION:
setDescription(SAMPLES[kind]);
break;
case "tezos_send_undelegation":
setDescription(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_UNDELEGATION]);
case SAMPLE_KINDS.SEND_UNDELEGATION:
setDescription(SAMPLES[kind]);
break;
case "tezos_send_origination":
setDescription(TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_ORGINATION]);
case SAMPLE_KINDS.SEND_ORGINATION:
setDescription(SAMPLES[kind]);
break;
case "tezos_send_contract_call":
const contract_call = {
...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_CONTRACT_CALL],
destination: contractAddress
? contractAddress
: "[click Origination to get contract address]",
};
setDescription(contract_call);
case SAMPLE_KINDS.SEND_CONTRACT_CALL:
setDescription({
...SAMPLES[kind],
destination: contractAddress ? contractAddress : "[click Origination to get contract address]",
});
break;
case "tezos_send_stake":
setDescription({...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_STAKE], destination: provider.address});
case SAMPLE_KINDS.SEND_STAKE:
setDescription({...SAMPLES[kind], destination: provider.address});
break;
case "tezos_send_unstake":
setDescription({...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_UNSTAKE], destination: provider.address});
case SAMPLE_KINDS.SEND_UNSTAKE:
setDescription({...SAMPLES[kind], destination: provider.address});
break;
case "tezos_send_finalize":
setDescription({...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_FINALIZE], destination: provider.address});
case SAMPLE_KINDS.SEND_FINALIZE:
setDescription({...SAMPLES[kind], destination: provider.address});
break;
case "tezos_send_ballot":
const ballot = {
...TEZOS_ACTIONS[DEFAULT_TEZOS_METHODS.TEZOS_SEND_BALLOT],
source: provider.address,
};
setDescription(ballot);
case SAMPLE_KINDS.SEND_INCREASE_PAID_STORAGE:
setDescription({
...SAMPLES[kind],
destination: contractAddress ? contractAddress : "[click Origination to get contract address]",
});
break;
default:
setDescription("No description available");
Expand All @@ -210,7 +221,7 @@ const App = () => {
const describeClear = () => {
setDescription(undefined);
};

return (
<div className="App">
<h1>TezosProvider</h1>
Expand All @@ -229,36 +240,37 @@ const App = () => {
<b>Balance: </b>
{balance}
</p>
<div className="btn-container">
<button onClick={() => handleOp("tezos_getAccounts")} onMouseEnter={describeClear}>Get Accounts</button>
<button onClick={() => handleOp("tezos_sign")} onMouseEnter={describeClear}>Sign</button>
<button onClick={disconnect} onMouseEnter={describeClear}>Disconnect</button>
</div>
<div className="btn-container">
<button onClick={() => handleOp("tezos_send_transaction")} onMouseEnter={() => describe("tezos_send_transaction")}>Send Transaction</button>
<button onClick={() => handleOp("tezos_send_delegation")} onMouseEnter={() => describe("tezos_send_delegation")}>Delegate</button>
<button onClick={() => handleOp("tezos_send_undelegation")} onMouseEnter={() => describe("tezos_send_undelegation")}>Undelegate</button>
<button onClick={() => handleOp("tezos_send_origination")} onMouseEnter={() => describe("tezos_send_origination")}>Originate</button>
<button onClick={() => handleOp("tezos_send_contract_call")} onMouseEnter={() => describe("tezos_send_contract_call")}>Contract call</button>
</div>
<div className="btn-container">
<button onClick={() => handleOp("tezos_send_stake")} onMouseEnter={() => describe("tezos_send_stake")}>Stake</button>
<button onClick={() => handleOp("tezos_send_unstake")} onMouseEnter={() => describe("tezos_send_unstake")}>Unstake</button>
<button onClick={() => handleOp("tezos_send_finalize")} onMouseEnter={() => describe("tezos_send_finalize")}>Finalize</button>
<button onClick={() => handleOp("tezos_send_ballot")} onMouseEnter={() => describe("tezos_send_ballot")}>Ballot</button>
<div className="layout-container">
<div className="btn-container">
<button onClick={disconnect} onMouseEnter={describeClear}>Disconnect</button>
<button onClick={() => handleOp(SAMPLE_KINDS.GET_ACCOUNTS)} onMouseEnter={describeClear}>Get Accounts</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SIGN)} onMouseEnter={describeClear}>Sign</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_TRANSACTION)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_TRANSACTION)}>Send Transaction</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_DELEGATION)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_DELEGATION)}>Delegate</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_UNDELEGATION)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_UNDELEGATION)}>Undelegate</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_ORGINATION)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_ORGINATION)}>Originate</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_CONTRACT_CALL)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_CONTRACT_CALL)}>Contract call</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_STAKE)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_STAKE)}>Stake</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_UNSTAKE)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_UNSTAKE)}>Unstake</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_FINALIZE)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_FINALIZE)}>Finalize</button>
<button onClick={() => handleOp(SAMPLE_KINDS.SEND_INCREASE_PAID_STORAGE)} onMouseEnter={() => describe(SAMPLE_KINDS.SEND_INCREASE_PAID_STORAGE)}>Increase paid storage</button>
</div>
<div className="result-column">
{result && (
<>
<p>Result of the last operation:</p>
<pre>{lastKind}</pre>
<pre>{JSON.stringify(result, null, 2)}</pre>
</>
)}
{description && (
<>
<p>Operation:</p>
<pre>{JSON.stringify(description, null, 2)}</pre>
</>
)}
</div>
</div>
{result && (
<>
<p>Result of the last operation:</p>
<pre>{JSON.stringify(result, null, 2)}</pre>
</>
)}
{description && (
<>
<p>Operation:</p>
<pre>{JSON.stringify(description, null, 2)}</pre>
</>
)}
</>
) : (
<>
Expand Down
Loading