Skip to content

Commit

Permalink
feat: add wallet rpc examples
Browse files Browse the repository at this point in the history
  • Loading branch information
krzysu committed Oct 29, 2024
1 parent f3a81e1 commit d4b9b00
Show file tree
Hide file tree
Showing 18 changed files with 391 additions and 102 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"lint:plugin": "cd packages/web3-plugin-wallet-rpc && yarn lint",
"lint:example": "cd packages/example-react-app && yarn lint",
"format": "prettier --write .",
"start:example": "cd packages/example-react-app && yarn start"
"start:example": "yarn build && cd packages/example-react-app && yarn start"
},
"devDependencies": {
"prettier": "^3.3.3"
Expand Down
47 changes: 0 additions & 47 deletions packages/example-react-app/src/AccountDetail.tsx

This file was deleted.

22 changes: 16 additions & 6 deletions packages/example-react-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { useContext, useEffect, useState } from 'react';
import type { ProviderChainId, providers } from 'web3';

import { Accounts } from './components/Accounts';
import { ProviderButton } from './components/ProviderButton';
import { AccountProvider } from './web3/AccountContext';
import { type IWeb3Context, Web3Context } from './web3/Web3Context';

import Accounts from './Accounts';
import ProviderButton from './ProviderButton';
import WalletRpcPlugComponent from './WalletRpcPlugComponent';
import { SwitchEthereumChain } from './wallet-components/SwitchEthereumChain';
import { AddEthereumChain } from './wallet-components/AddEthereumChain';
import { WatchAsset } from './wallet-components/WatchAsset';
import { Permissions } from './wallet-components/Permissions';

function App() {
const web3Context: IWeb3Context = useContext(Web3Context);
Expand Down Expand Up @@ -74,14 +76,22 @@ function App() {
})}
</>
) : null}

<h2>Network Details</h2>
<div>Chain ID: {`${chainId}`}</div>
<div>Network ID: {`${networkId}`}</div>

<AccountProvider>
<Accounts></Accounts>
<Accounts />
</AccountProvider>

<WalletRpcPlugComponent></WalletRpcPlugComponent>
<h2>Wallet RPC Methods</h2>
<div>
<AddEthereumChain />
<SwitchEthereumChain />
<WatchAsset />
<Permissions />
</div>
</>
)}
<br />
Expand Down
18 changes: 0 additions & 18 deletions packages/example-react-app/src/ProviderButton.tsx

This file was deleted.

19 changes: 0 additions & 19 deletions packages/example-react-app/src/WalletRpcPlugComponent.tsx

This file was deleted.

44 changes: 44 additions & 0 deletions packages/example-react-app/src/components/AccountDetail.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { type MutableRefObject, useContext, useEffect, useRef, useState } from 'react';

import { type IWeb3Context, Web3Context } from '../web3/Web3Context';

export function AccountDetail({ address }: { address: string }) {
const web3Context: IWeb3Context = useContext(Web3Context);

const [balance, setBalance] = useState<number>(NaN);
const subscriptionId: MutableRefObject<string | undefined> = useRef(undefined);

async function updateBalance(): Promise<void> {
const newBalance = await web3Context.web3.eth.getBalance(address);

setBalance(parseFloat(web3Context.web3.utils.fromWei(newBalance, 'ether')));
}

useEffect(() => {
async function subscribeToNewBlockHeaders() {
const newBlockSubscription =
await web3Context.web3.eth.subscribe('newBlockHeaders');

subscriptionId.current = newBlockSubscription.id;

newBlockSubscription.on('data', () => {
void updateBalance();
});
}

void subscribeToNewBlockHeaders();

return () => {
void web3Context.web3.eth.subscriptionManager.unsubscribe(
({ id }) => subscriptionId.current === id,
);
};
});

return (
<>
<div>{address}</div>
<div>Balance in native token: {`${balance}`}</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
import { useContext } from 'react';
import { AccountContext, type IAccountContext } from './web3/AccountContext';
import AccountDetail from './AccountDetail';

function Accounts() {
import { AccountContext, type IAccountContext } from '../web3/AccountContext';

import { AccountDetail } from './AccountDetail';

export function Accounts() {
const accountContext: IAccountContext = useContext(AccountContext);

return (
<>
<h2>Accounts</h2>
<div>
{accountContext.selectedAccount === undefined ? (
<button onClick={accountContext.requestAccounts}>Connect Accounts</button>
<button type="button" onClick={accountContext.requestAccounts}>
Connect Accounts
</button>
) : (
<>
<h3>Selected Account</h3>
<AccountDetail address={accountContext.selectedAccount}></AccountDetail>
<AccountDetail address={accountContext.selectedAccount} />
{accountContext.accounts.length > 1 ? (
<>
<h3>Other Accounts</h3>
{accountContext.accounts.slice(1).map((account: string) => (
<AccountDetail address={account} key={account}></AccountDetail>
<AccountDetail address={account} key={account} />
))}
</>
) : null}
Expand All @@ -29,5 +33,3 @@ function Accounts() {
</>
);
}

export default Accounts;
18 changes: 18 additions & 0 deletions packages/example-react-app/src/components/ProviderButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useContext } from 'react';
import type { EIP6963ProviderDetail } from 'web3';

import type { IWeb3Context } from '../web3/Web3Context';
import { Web3Context } from '../web3/Web3Context';

import './ProviderButton.css';

export function ProviderButton({ provider }: { provider: EIP6963ProviderDetail }) {
const web3Context: IWeb3Context = useContext(Web3Context);

return (
<button type="button" onClick={() => web3Context.setCurrentProvider(provider)}>
<img src={provider.info.icon} alt={provider.info.name} width="35" />
<span> {provider.info.name}</span>
</button>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useContext, useState } from 'react';
import { AddEthereumChainRequest } from 'web3-plugin-wallet-rpc';
import { Web3Context } from '../web3/Web3Context';

const chains: Record<string, AddEthereumChainRequest> = {
mantle: {
chainId: 5000,
blockExplorerUrls: ['https://mantlescan.xyz'],
chainName: 'Mantle',
iconUrls: ['https://icons.llamao.fi/icons/chains/rsz_mantle.jpg'],
nativeCurrency: {
name: 'Mantle',
symbol: 'MNT',
decimals: 18,
},
rpcUrls: ['https://rpc.mantle.xyz'],
},
scroll: {
chainId: 534352,
blockExplorerUrls: ['https://scrollscan.com'],
chainName: 'Scroll',
iconUrls: ['https://icons.llamao.fi/icons/chains/rsz_scroll.jpg'],
nativeCurrency: {
name: 'ETH',
symbol: 'ETH',
decimals: 18,
},
rpcUrls: ['https://rpc.scroll.io'],
},
};

function AddChainButton({ chainDetails }: { chainDetails: AddEthereumChainRequest }) {
const { web3 } = useContext(Web3Context);
const [error, setError] = useState<Error | undefined>(undefined);

const handleClick = () => {
web3.walletRpc
.addEthereumChain(chainDetails)
.then((response) => {
// eslint-disable-next-line no-console
console.log(
`Successfully added chain ${chainDetails.chainId} with response`,
response,
);
})
.catch((e) => {
// eslint-disable-next-line no-console
console.error(e);

if (e instanceof Error) {
setError(e);
}
});
};

return (
<>
<button type="button" onClick={handleClick}>
{`Add new chain: ${chainDetails.chainName} (${chainDetails.chainId})`}
</button>
{error && <div>{error.message}</div>}
</>
);
}

export function AddEthereumChain() {
return (
<div>
<h4>Add EVM Chain</h4>
<AddChainButton chainDetails={chains.mantle} />
<AddChainButton chainDetails={chains.scroll} />
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { useContext, useState } from 'react';
import { Permission } from 'web3-plugin-wallet-rpc';
import { Web3Context } from '../web3/Web3Context';

export function GetPermissions() {
const { web3 } = useContext(Web3Context);
const [error, setError] = useState<Error | undefined>(undefined);
const [permissions, setPermissions] = useState<Permission[] | undefined>(undefined);

const handleClick = () => {
web3.walletRpc
.getPermissions()
.then((response) => {
// eslint-disable-next-line no-console
console.log(`Successfully got permissions with response`, response);

setPermissions(response);
})
.catch((e) => {
// eslint-disable-next-line no-console
console.error(e);

if (e instanceof Error) {
setError(e);
}
});
};

return (
<>
<button type="button" onClick={handleClick}>
Get permissions
</button>
{permissions && <pre>{JSON.stringify(permissions, null, 2)}</pre>}
{error && <div>{error.message}</div>}
</>
);
}
14 changes: 14 additions & 0 deletions packages/example-react-app/src/wallet-components/Permissions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { GetPermissions } from './GetPermissions';
import { RequestPermissions } from './RequestPermissions';
import { RevokePermissions } from './RevokePermissions';

export function Permissions() {
return (
<div>
<h4>Request, get and revoke permissions</h4>
<RequestPermissions />
<GetPermissions />
<RevokePermissions />
</div>
);
}
Loading

0 comments on commit d4b9b00

Please sign in to comment.