@next-wallet/provider v0.0.9-alpha.0
流程
iframe

需要解决的问题:
- 业务系统与 iframe-web 打通授权,现存市场上的钱包 "auth 内嵌钱包",业务系统集成 auth,业务系统使用 auth 的 jwt
- iframe 约束消息范围(注:现存浏览器插件钱包如:metamask 等,全 origin 广播,任何页面都可以收到消息)
新增设备

创建嵌入钱包

生成私钥

签名交易

发交易

其他 api 同 viem

example

Embedded Wallet Provider
This package provides an EmbeddedWalletProvider class to manage blockchain interactions through an embedded wallet within an iframe. It supports general transactions, blob transactions, message signing, and chain management.
Table of Contents
Installation
To use this package, you'll need to install the required dependencies:
npm install viem @next-wallet/providerUsage
To use the EmbeddedWalletProvider, you need to import it and initialize it with the required parameters.
import { defineChain, http } from 'viem';
import { sepolia } from 'viem/chains';
import { EmbeddedWalletProvider } from '@next-wallet/provider';
const defaultChain = defineChain({
id: 1,
name: 'Ethereum Mainnet',
rpcUrls: ['https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'],
});
const params: EmbeddedWalletProviderParams = {
defaultChain: sepolia,
supportedChains: [sepolia],
address: '0xYourWalletAddress', // @next-wallet/provider 创建的钱包地址
iframeSrc: 'https://your-iframe-source.com', // your iframe
onReady: (res) => {
console.log('Iframe is ready', res);
},
};
const walletProvider = new EmbeddedWalletProvider(params);API
Constructor
EmbeddedWalletProvider(parameters: EmbeddedWalletProviderParams)
parameters: An object containing the following properties:defaultChain: The default blockchain chain.supportedChains: An array of supported blockchain chains.address: The address of the embedded wallet.iframeSrc: The source URL of the embedded wallet iframe.transport: (Optional) The transport method for blockchain communication.onReady: A callback function that is called when the iframe is ready.
Methods
createWallet(): Promise<ResponsePayload>
Creates a new wallet.
exportDeviceShare(address: Hex): Promise<ResponsePayload>
Exports the device share for the given address.
exportPrivateKey(address: Hex): Promise<ResponsePayload>
Exports the private key for the given address.
switchAddress(address: Hex): void
Switches the current address to the provided address.
getAllAddress(): Promise<ResponsePayload>
Gets all addresses associated with the wallet.
generateClient(): Promise<void>
Generates a public and wallet client.
signTransaction(transaction: GeneralTransaction | BlobTransaction): Promise<Hex>
Signs a transaction.
sendTransaction(transaction: GeneralTransaction | BlobTransaction): Promise<Hex>
Sends a signed transaction.
sendRawTransaction(args: SendRawTransactionParameters): Promise<Hex>
Sends a raw transaction.
waitForTransactionReceipt(args: WaitForTransactionReceiptParameters): Promise<TransactionReceipt>
Waits for the transaction receipt of the given transaction hash.
signMessage(message: string): Promise<Hex>
Signs a message.
signTypedData(typedData: TypedDataParameter): Promise<Hex>
Signs typed data (EIP-712).
sendBlobDataTransaction(): Promise<void>
(Not implemented) Sends a blob data transaction.
addChain(chain: Chain): Promise<void>
Adds a new chain to the supported chains.
switchChain(id: Chain['id']): Promise<void>
Switches to the chain with the given ID.
getChains(): Promise<Chain[]>
Gets all supported chains.
Example
Here is an example of how to use the EmbeddedWalletProvider to sign and send a transaction:
import { defineChain, http } from 'viem';
import { EmbeddedWalletProvider, EmbeddedWalletProviderParams } from './path-to-your-provider-file';
const defaultChain = defineChain({
id: 1,
name: 'Ethereum Mainnet',
rpcUrls: ['https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID'],
});
const params: EmbeddedWalletProviderParams = {
defaultChain,
supportedChains: [defaultChain],
address: '0xYourWalletAddress',
iframeSrc: 'https://your-iframe-source.com',
onReady: (res) => {
console.log('Iframe is ready', res);
},
};
const walletProvider = new EmbeddedWalletProvider(params);
async function sendTransaction() {
const transaction = {
maxFeePerGas: BigInt(20000000000),
maxPriorityFeePerGas: BigInt(2000000000),
gas: 21000,
to: '0xRecipientAddress',
value: BigInt(1000000000000000000), // 1 ETH
};
try {
const signedTransaction = await walletProvider.signTransaction(transaction);
const txHash = await walletProvider.sendTransaction(signedTransaction);
console.log('Transaction sent with hash:', txHash);
} catch (error) {
console.error('Error sending transaction:', error);
}
}
sendTransaction();This example demonstrates how to initialize the EmbeddedWalletProvider, sign a transaction, and send it to the blockchain.
React Example
import { useCallback, useEffect, useRef, useState } from 'react';
// import { sepolia } from 'viem/chains';
import { EmbeddedWalletProvider } from '@next-wallet/provider';
import { Hex, TransactionReceipt, defineChain, parseEther, parseGwei } from 'viem';
interface Receipt extends Omit<TransactionReceipt, 'gasUsed' | 'blockNumber' | 'cumulativeGasUsed' | 'effectiveGasPrice'> {
gasUsed: string;
blockNumber: string;
cumulativeGasUsed: string;
effectiveGasPrice: string;
}
export const sepolia = defineChain({
id: 11_155_111,
name: 'Sepolia',
nativeCurrency: { name: 'Sepolia Ether', symbol: 'ETH', decimals: 18 },
rpcUrls: {
default: {
http: ['https://ethereum-sepolia-rpc.publicnode.com'],
},
},
blockExplorers: {
default: {
name: 'Etherscan',
url: 'https://sepolia.etherscan.io',
apiUrl: 'https://api-sepolia.etherscan.io/api',
},
},
contracts: {
multicall3: {
address: '0xca11bde05977b3631167028862be2a173976ca11',
blockCreated: 751532,
},
ensRegistry: { address: '0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e' },
ensUniversalResolver: {
address: '0xc8Af999e38273D658BE1b921b88A9Ddf005769cC',
blockCreated: 5_317_080,
},
},
testnet: true,
});
function App() {
const walletProviderInstance = useRef<EmbeddedWalletProvider>();
const [address, setAddress] = useState<Hex>();
const [addressList, setAddressList] = useState<Hex[]>([]);
const [embeededWalletIsReady, setEmbeededWalletIsReady] = useState(false);
const [txReceipt, setTxReceipt] = useState<Receipt>();
const [loading, setLoading] = useState(false);
const [deviceShare, setDeviceShare] = useState<Hex>();
const [privateKey, setPrivateKey] = useState('');
useEffect(() => {
handelMountIframe();
}, []);
const handelSendTransaction = useCallback(async () => {
try {
setLoading(true);
const txhash = await walletProviderInstance.current?.sendTransaction({
maxFeePerGas: parseGwei('20'),
maxPriorityFeePerGas: parseGwei('3'),
gas: 21000,
to: '0x88E4CaB47eDfE9BaB5dB525c0F3598Cad73436CD',
value: parseEther('0.00001'),
});
const receipt = await walletProviderInstance.current?.waitForTransactionReceipt({
hash: txhash!,
});
if (receipt) {
console.log('receipt', receipt);
setTxReceipt({
...receipt,
blockNumber: receipt.blockNumber.toString(),
cumulativeGasUsed: receipt.cumulativeGasUsed.toString(),
gasUsed: receipt.gasUsed.toString(),
effectiveGasPrice: receipt.effectiveGasPrice.toString(),
} as Receipt);
setLoading(false);
}
} catch (error) {
console.error('error', error);
}
}, []);
const handelMountIframe = useCallback(() => {
walletProviderInstance.current = new EmbeddedWalletProvider({
iframeSrc: 'http://localhost:3000/apps/293c01a03c7e78b9fcf70627562b1a1d0864bfb3',
defaultChain: sepolia,
supportedChains: [sepolia],
address: '0xFaA1311Dab753F720afCbdF37082E110Dc66846c',
onReady: (res) => {
console.log('res->handelMountIframe', res);
setEmbeededWalletIsReady(true);
getAllAddress();
},
});
}, []);
const getAllAddress = useCallback(() => {
walletProviderInstance.current?.getAllAddress().then((res) => {
console.log('res', res);
if (res.success) {
setAddressList(res.data);
}
});
}, []);
const handleSwitchAccount = useCallback((address: Hex) => {
walletProviderInstance.current?.switchAddress(address);
setAddress(address);
}, []);
const createWallet = useCallback(async () => {
const address = await walletProviderInstance.current?.createWallet();
console.log('createWallet->address', address);
getAllAddress();
}, [getAllAddress]);
const exportDeviceShare = useCallback(async () => {
const res = await walletProviderInstance.current?.exportDeviceShare(address!);
console.log('res->exportDeviceShare', res);
if (res?.success) {
setDeviceShare(res.data);
}
}, [address]);
const exportPrivateKey = useCallback(async () => {
const res = await walletProviderInstance.current?.exportPrivateKey(address!);
console.log('res->exportDeviceShare', res);
if (res?.success) {
setPrivateKey(res.data);
}
}, [address]);
return (
<div>
<button onClick={handelMountIframe}>step1: handelMountIframe</button>
<br />
<button disabled={!embeededWalletIsReady} onClick={getAllAddress}>
step2: getAllAddress
</button>
{addressList.map((item) => (
<p key={item} onClick={() => handleSwitchAccount(item)} style={{ color: item === address ? '#4980ff' : '' }}>
{item}
</p>
))}
<br />
<button disabled={!embeededWalletIsReady} onClick={createWallet}>
创建一个嵌入钱包
</button>
<h3>step3: 选中第一个地址 account: {address}</h3>
<button disabled={!embeededWalletIsReady || !address} onClick={handelSendTransaction}>
step3: 选中第一个地址,发送交易
</button>
<pre>{loading ? '交易确认中...' : JSON.stringify(txReceipt, null, 4)}</pre>
<hr />
<button disabled={!embeededWalletIsReady || !address} onClick={exportDeviceShare}>
选中第一个地址,导出deviceShare
</button>
<p>deviceShare:{deviceShare}</p>
<button disabled={!embeededWalletIsReady || !address} onClick={exportPrivateKey}>
选中第一个地址,导出priviteKey
</button>
<p>privateKey:{privateKey}</p>
</div>
);
}
export default App;1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago