🗂
[Astar]コントラクト備忘録48(Polkadot.jsを使って、接続したウォレットからトランザクションを起こしてみよう!)
今回は、「Polkadot.js」を用いて、接続されたウォレットからトランザクションを行ってみましょう。
ポイントはsignerに「injector.signer」を指定しているところです。
https://polkadot.js.org/docs/extension/cookbook
簡単に見てみましょう。
下のように、shibuyaのノードから「provider」を作り、そこから「api」を作成しています。
そして、そのapiを使い、「api.tx.balances.transfer」を作成しています。
ここではまだ署名されていません。
それを元にして、signAndSendを行っています。
ここでポイントなのは「account」から取得した「injector」を用いて、「signer」に「injector.signer」を指定していることです。
では、実際にやってみましょう。
ウォレットを接続した後に、「transfer」を押します。
すると、「talisman」のウォレットを接続していた場合には、このようにポップアップが起動し、送付することができます。
今回は以上です。
import Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import styles from '@/styles/Home.module.css'
import React, { useState } from 'react';
import { stringToHex } from "@polkadot/util";
import { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";
import { ApiPromise, WsProvider } from '@polkadot/api';
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const [address, setAddress] = useState('');
const [source, setSource] = useState('');
const [account, setAccount] = useState<InjectedAccountWithMeta | null>(null);;
const [signature, setSignature] = useState('');
async function connectWallet () {
const { web3Accounts, web3Enable} = await import(
"@polkadot/extension-dapp"
);
const allInjected = await web3Enable('my dapp');
if (allInjected.length === 0) {
return;
}
const accounts = await web3Accounts();
console.log("accounts",accounts)
const account = accounts[0];
setAccount(account);
console.log("account",account)
const address = account?.address
const source = account?.meta?.source
console.log("address",address)
console.log("source",source)
setAddress(address);
setSource(source);
}
async function signMessage () {
const { web3FromSource} = await import(
"@polkadot/extension-dapp"
);
if (account) {
const injector = await web3FromSource(account.meta.source);
console.log("injector",injector)
const signRaw = injector?.signer?.signRaw;
console.log("signRaw",signRaw)
if (!!signRaw) {
// after making sure that signRaw is defined
// we can use it to sign our message
const { signature } = await signRaw({
address: account.address,
data: stringToHex('message to sign'),
type: 'bytes'
});
console.log("signature",signature)
setSignature(signature);
}
}
}
async function transfer () {
const { web3FromSource} = await import(
"@polkadot/extension-dapp"
);
const provider = new WsProvider('wss://rpc.shibuya.astar.network');
// Create the API and wait until ready
const api = await ApiPromise.create({ provider });
const transferExtrinsic = api.tx.balances.transfer('5CfmGa2TsXxP7vuyTYzp22XvtfcaS2MeydXmP4B9yMzUyxkk', 1)
if (account) {
const injector = await web3FromSource(account.meta.source);
transferExtrinsic.signAndSend(account.address, { signer: injector.signer }, ({ status }) => {
if (status.isInBlock) {
console.log(`Completed at block hash #${status.asInBlock.toString()}`);
} else {
console.log(`Current status: ${status.type}`);
console.log(`Current status: ${status.hash.toString()}`);
}
}).catch((error: any) => {
console.log(':( transaction failed', error);
});
}
}
<div>
<button onClick={connectWallet}>Connect Wallet</button>
{address && <p>Address: {address}</p>}
{source && <p>Source: {source}</p>}
<button onClick={signMessage} style={{marginTop: "20px"}}>sign a message</button>
{signature && <p>Signature: {signature}</p>}
<button onClick={transfer} style={{marginTop: "20px"}}>transfer</button>
</div>
↓色々と機能を加えたものです。
port Head from 'next/head'
import Image from 'next/image'
import { Inter } from 'next/font/google'
import styles from '@/styles/Home.module.css'
import React, { useState } from 'react';
import { stringToHex } from "@polkadot/util";
import { InjectedAccountWithMeta } from "@polkadot/extension-inject/types";
import { ApiPromise, WsProvider } from '@polkadot/api';
const inter = Inter({ subsets: ['latin'] })
export default function Home() {
const [address, setAddress] = useState('');
const [source, setSource] = useState('');
const [account, setAccount] = useState<InjectedAccountWithMeta | null>(null);;
const [signature, setSignature] = useState('');
const [amount, setAmount] = useState(1);
const [error, setError] = useState('');
const [toError, setToError] = useState('');
const [destination, setDestination] = useState('');
const handleAmountChange = (event:any) => {
const value = Number(event.target.value);
if (value <= 0) {
setError('Amount must be greater than 0');
} else {
setError('');
setAmount(value);
}
}
const handleDestinationChange = (event:any) => {
setDestination(event.target.value);
};
async function connectWallet () {
const { web3Accounts, web3Enable} = await import(
"@polkadot/extension-dapp"
);
const allInjected = await web3Enable('my dapp');
if (allInjected.length === 0) {
return;
}
const accounts = await web3Accounts();
console.log("accounts",accounts)
const account = accounts[0];
setAccount(account);
console.log("account",account)
const address = account?.address
const source = account?.meta?.source
console.log("address",address)
console.log("source",source)
setAddress(address);
setSource(source);
}
async function signMessage () {
const { web3FromSource} = await import(
"@polkadot/extension-dapp"
);
if (account) {
const injector = await web3FromSource(account.meta.source);
console.log("injector",injector)
const signRaw = injector?.signer?.signRaw;
console.log("signRaw",signRaw)
if (!!signRaw) {
// after making sure that signRaw is defined
// we can use it to sign our message
const { signature } = await signRaw({
address: account.address,
data: stringToHex('message to sign'),
type: 'bytes'
});
console.log("signature",signature)
setSignature(signature);
}
}
}
async function transfer () {
if (destination.trim() === '') {
setToError('to is required');
return;
}
const { web3FromSource} = await import(
"@polkadot/extension-dapp"
);
const provider = new WsProvider('wss://rpc.shibuya.astar.network');
// Create the API and wait until ready
const api = await ApiPromise.create({ provider });
const transferExtrinsic = api.tx.balances.transfer(destination, amount)
if (account) {
const injector = await web3FromSource(account.meta.source);
transferExtrinsic.signAndSend(account.address, { signer: injector.signer }, ({ status }) => {
if (status.isInBlock) {
console.log(`Completed at block hash #${status.asInBlock.toString()}`);
} else {
console.log(`Current status: ${status.type}`);
console.log(`Current status: ${status.hash.toString()}`);
}
}).catch((error: any) => {
console.log(':( transaction failed', error);
});
}
}
<div>
<button className={styles.rotatebutton} onClick={connectWallet}>Connect Wallet</button>
{address && <p>Address: {address}</p>}
{source && <p>Source: {source}</p>}
<button className={styles.rotatebutton} onClick={signMessage} style={{marginTop: "20px"}}>sign a message</button>
{signature && <p>Signature: {signature}</p>}
<button className={styles.rotatebutton} onClick={transfer} style={{marginTop: "20px"}}>transfer</button>
<div>
<p>amount:<input type="number" value={amount} onChange={handleAmountChange} style={{ width: '60px' }}/>
{error && <p style={{ color: 'red' }}>{error}</p>}</p>
<p>to:<input type="text" value={destination} onChange={handleDestinationChange} style={{ width: '400px' }}/>
{toError && <p style={{ color: 'red' }}>{toError}</p>}</p>
</div>
</div>
Discussion