Implement eth_sendTransaction
This commit is contained in:
parent
914f91967a
commit
c3daa5b2a9
@ -25,7 +25,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@walletconnect/types": "2.0.0-beta.22",
|
||||
"@types/node": "17.0.17",
|
||||
"@types/node": "17.0.18",
|
||||
"@types/react": "17.0.39",
|
||||
"eslint": "8.9.0",
|
||||
"eslint-config-next": "12.0.10",
|
||||
|
@ -1,5 +1,6 @@
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import SessionProposalModal from '@/views/SessionProposalModal'
|
||||
import SessionSendTransactionModal from '@/views/SessionSendTransactionModal'
|
||||
import SessionRequestModal from '@/views/SessionSignModal'
|
||||
import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal'
|
||||
import { Modal as NextModal } from '@nextui-org/react'
|
||||
@ -13,6 +14,7 @@ export default function Modal() {
|
||||
{view === 'SessionProposalModal' && <SessionProposalModal />}
|
||||
{view === 'SessionSignModal' && <SessionRequestModal />}
|
||||
{view === 'SessionSignTypedDataModal' && <SessionSignTypedDataModal />}
|
||||
{view === 'SessionSendTransactionModal' && <SessionSendTransactionModal />}
|
||||
</NextModal>
|
||||
)
|
||||
}
|
||||
|
@ -21,52 +21,32 @@ export const EIP155_MAINNET_CHAINS = {
|
||||
chainId: 1,
|
||||
name: 'Ethereum',
|
||||
logo: LOGO_BASE_URL + 'eip155:1.png',
|
||||
rgb: '99, 125, 234'
|
||||
},
|
||||
'eip155:10': {
|
||||
chainId: 10,
|
||||
name: 'Optimism',
|
||||
logo: LOGO_BASE_URL + 'eip155:10.png',
|
||||
rgb: '233, 1, 1'
|
||||
rgb: '99, 125, 234',
|
||||
rpc: 'https://cloudflare-eth.com/'
|
||||
},
|
||||
'eip155:137': {
|
||||
chainId: 137,
|
||||
name: 'Polygon',
|
||||
logo: LOGO_BASE_URL + 'eip155:137.png',
|
||||
rgb: '130, 71, 229'
|
||||
rgb: '130, 71, 229',
|
||||
rpc: 'https://polygon-rpc.com/'
|
||||
},
|
||||
'eip155:42161': {
|
||||
chainId: 42161,
|
||||
name: 'Arbitrum',
|
||||
logo: LOGO_BASE_URL + 'eip155:42161.png',
|
||||
rgb: '44, 55, 75'
|
||||
rgb: '44, 55, 75',
|
||||
rpc: 'https://arb1.arbitrum.io/rpc/'
|
||||
}
|
||||
}
|
||||
|
||||
export const EIP155_TEST_CHAINS = {
|
||||
'eip155:4': {
|
||||
chainId: 4,
|
||||
name: 'Ethereum Rinkeby',
|
||||
logo: LOGO_BASE_URL + 'eip155:1.png',
|
||||
rgb: '99, 125, 234'
|
||||
},
|
||||
'eip155:69': {
|
||||
chainId: 69,
|
||||
name: 'Optimism Kovan',
|
||||
logo: LOGO_BASE_URL + 'eip155:10.png',
|
||||
rgb: '233, 1, 1'
|
||||
},
|
||||
'eip155:80001': {
|
||||
chainId: 80001,
|
||||
name: 'Polygon Mumbai',
|
||||
logo: LOGO_BASE_URL + 'eip155:137.png',
|
||||
rgb: '130, 71, 229'
|
||||
},
|
||||
'eip155:421611': {
|
||||
chainId: 421611,
|
||||
name: 'Arbitrum Rinkeby',
|
||||
logo: LOGO_BASE_URL + 'eip155:42161.png',
|
||||
rgb: '44, 55, 75'
|
||||
rgb: '130, 71, 229',
|
||||
rpc: 'https://rpc-mumbai.maticvigil.com/'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,26 +6,30 @@ import { SessionTypes } from '@walletconnect/types'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
|
||||
export default function useWalletConnectEventsManager(initialized: boolean) {
|
||||
// 1. Open session proposal modal for confirmation / rejection
|
||||
/******************************************************************************
|
||||
* 1. Open session proposal modal for confirmation / rejection
|
||||
*****************************************************************************/
|
||||
const onSessionProposal = useCallback((proposal: SessionTypes.Proposal) => {
|
||||
ModalStore.open('SessionProposalModal', { proposal })
|
||||
}, [])
|
||||
|
||||
// 2. Open session created modal to show success feedback
|
||||
/******************************************************************************
|
||||
* 2. Open session created modal to show success feedback
|
||||
*****************************************************************************/
|
||||
const onSessionCreated = useCallback((created: SessionTypes.Created) => {}, [])
|
||||
|
||||
// 3. Open request handling modal based on method that was used
|
||||
/******************************************************************************
|
||||
* 3. Open request handling modal based on method that was used
|
||||
*****************************************************************************/
|
||||
const onSessionRequest = useCallback(async (requestEvent: SessionTypes.RequestEvent) => {
|
||||
const { topic, request } = requestEvent
|
||||
const { method } = request
|
||||
const requestSession = await walletConnectClient.session.get(topic)
|
||||
|
||||
// Hanle message signing requests of various formats
|
||||
if ([EIP155_SIGNING_METHODS.ETH_SIGN, EIP155_SIGNING_METHODS.PERSONAL_SIGN].includes(method)) {
|
||||
ModalStore.open('SessionSignModal', { requestEvent, requestSession })
|
||||
}
|
||||
|
||||
// Hanle data signing requests of various formats
|
||||
if (
|
||||
[
|
||||
EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA,
|
||||
@ -35,8 +39,15 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
|
||||
) {
|
||||
ModalStore.open('SessionSignTypedDataModal', { requestEvent, requestSession })
|
||||
}
|
||||
|
||||
if (EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION) {
|
||||
ModalStore.open('SessionSendTransactionModal', { requestEvent, requestSession })
|
||||
}
|
||||
}, [])
|
||||
|
||||
/******************************************************************************
|
||||
* Set up WalletConnect event listeners
|
||||
*****************************************************************************/
|
||||
useEffect(() => {
|
||||
if (initialized) {
|
||||
walletConnectClient.on(CLIENT_EVENTS.session.proposal, onSessionProposal)
|
||||
|
@ -13,7 +13,11 @@ interface ModalData {
|
||||
|
||||
interface State {
|
||||
open: boolean
|
||||
view?: 'SessionProposalModal' | 'SessionSignModal' | 'SessionSignTypedDataModal'
|
||||
view?:
|
||||
| 'SessionProposalModal'
|
||||
| 'SessionSignModal'
|
||||
| 'SessionSignTypedDataModal'
|
||||
| 'SessionSendTransactionModal'
|
||||
data?: ModalData
|
||||
}
|
||||
|
||||
|
@ -9,32 +9,26 @@ export async function approveEIP155Request(request: RequestEvent['request'], wal
|
||||
const { method, params, id } = request
|
||||
|
||||
switch (method) {
|
||||
/**
|
||||
* Handle message signing requests
|
||||
*/
|
||||
case EIP155_SIGNING_METHODS.PERSONAL_SIGN:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN:
|
||||
const message = getSignParamsMessage(params)
|
||||
const signedMessage = await wallet.signMessage(message)
|
||||
return formatJsonRpcResult(id, signedMessage)
|
||||
|
||||
/**
|
||||
* Handle data signing requests
|
||||
*/
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V3:
|
||||
case EIP155_SIGNING_METHODS.ETH_SIGN_TYPED_DATA_V4:
|
||||
const { domain, types, message: data } = getSignTypedDataParamsData(params)
|
||||
|
||||
// https://github.com/ethers-io/ethers.js/issues/687#issuecomment-714069471
|
||||
delete types.EIP712Domain
|
||||
|
||||
const signedData = await wallet._signTypedData(domain, types, data)
|
||||
return formatJsonRpcResult(id, signedData)
|
||||
|
||||
/**
|
||||
* Handle unsuported methods
|
||||
*/
|
||||
case EIP155_SIGNING_METHODS.ETH_SEND_TRANSACTION:
|
||||
const transaction = params[0]
|
||||
const { hash } = await wallet.sendTransaction(transaction)
|
||||
return formatJsonRpcError(id, hash)
|
||||
|
||||
default:
|
||||
throw new Error(ERROR.UNKNOWN_JSONRPC_METHOD.format().message)
|
||||
}
|
||||
|
@ -0,0 +1,182 @@
|
||||
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
|
||||
import ModalStore from '@/store/ModalStore'
|
||||
import { truncate } from '@/utils/HelperUtil'
|
||||
import { approveEIP155Request, rejectEIP155Request } from '@/utils/RequestHandlerUtil'
|
||||
import { walletConnectClient } from '@/utils/WalletConnectUtil'
|
||||
import { wallet } from '@/utils/WalletUtil'
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Col,
|
||||
Container,
|
||||
Divider,
|
||||
Link,
|
||||
Loading,
|
||||
Modal,
|
||||
Row,
|
||||
Text
|
||||
} from '@nextui-org/react'
|
||||
import { providers } from 'ethers'
|
||||
import { Fragment, useState } from 'react'
|
||||
|
||||
export default function SessionSendTransactionModal() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
// Get request and wallet data from store
|
||||
const requestEvent = ModalStore.state.data?.requestEvent
|
||||
const requestSession = ModalStore.state.data?.requestSession
|
||||
|
||||
// Ensure request and wallet are defined
|
||||
if (!requestEvent || !requestSession) {
|
||||
return <Text>Missing request data</Text>
|
||||
}
|
||||
|
||||
// Get required proposal data
|
||||
const { chainId } = requestEvent
|
||||
const { method, params } = requestEvent.request
|
||||
const { protocol } = requestSession.relay
|
||||
const { name, icons, url } = requestSession.peer.metadata
|
||||
const transaction = params[0]
|
||||
|
||||
console.log(transaction)
|
||||
|
||||
// Handle approve action
|
||||
async function onApprove() {
|
||||
if (requestEvent) {
|
||||
setLoading(true)
|
||||
const provider = new providers.JsonRpcProvider(EIP155_CHAINS[chainId as TEIP155Chain].rpc)
|
||||
const connectedWallet = wallet.connect(provider)
|
||||
const response = await approveEIP155Request(requestEvent.request, connectedWallet)
|
||||
await walletConnectClient.respond({
|
||||
topic: requestEvent.topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle reject action
|
||||
async function onReject() {
|
||||
if (requestEvent) {
|
||||
const response = rejectEIP155Request(requestEvent.request)
|
||||
await walletConnectClient.respond({
|
||||
topic: requestEvent.topic,
|
||||
response
|
||||
})
|
||||
ModalStore.close()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Modal.Header>
|
||||
<Text h3>Send Transaction</Text>
|
||||
</Modal.Header>
|
||||
|
||||
<Modal.Body>
|
||||
<Container css={{ padding: 0 }}>
|
||||
<Row align="center">
|
||||
<Col span={3}>
|
||||
<Avatar src={icons[0]} />
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<Text h5>{name}</Text>
|
||||
<Link href={url}>{url}</Link>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>From</Text>
|
||||
<Text color="$gray400">{truncate(transaction.from, 30)}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>To</Text>
|
||||
<Text color="$gray400">{truncate(transaction.to, 30)}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Value</Text>
|
||||
<Text color="$gray400">{transaction.value}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Gas Price</Text>
|
||||
<Text color="$gray400">{transaction.gasPrice}</Text>
|
||||
</Col>
|
||||
<Col>
|
||||
<Text h5>Gas Limit</Text>
|
||||
<Text color="$gray400">{transaction.gasLimit}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Nonce</Text>
|
||||
<Text color="$gray400">{transaction.nonce}</Text>
|
||||
</Col>
|
||||
<Col>
|
||||
<Text h5>Data</Text>
|
||||
<Text color="$gray400">{transaction.data}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Blockchain</Text>
|
||||
<Text color="$gray400">
|
||||
{EIP155_CHAINS[chainId as TEIP155Chain]?.name ?? chainId}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Method</Text>
|
||||
<Text color="$gray400">{method}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Divider y={2} />
|
||||
|
||||
<Row>
|
||||
<Col>
|
||||
<Text h5>Relay Protocol</Text>
|
||||
<Text color="$gray400">{protocol}</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<Button auto flat color="error" onClick={onReject} disabled={loading}>
|
||||
Reject
|
||||
</Button>
|
||||
<Button auto flat color="success" onClick={onApprove} disabled={loading}>
|
||||
{loading ? <Loading size="sm" color="white" /> : 'Approve'}
|
||||
</Button>
|
||||
</Modal.Footer>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
@ -794,10 +794,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
|
||||
|
||||
"@types/node@17.0.17":
|
||||
version "17.0.17"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.17.tgz#a8ddf6e0c2341718d74ee3dc413a13a042c45a0c"
|
||||
integrity sha512-e8PUNQy1HgJGV3iU/Bp2+D/DXh3PYeyli8LgIwsQcs1Ar1LoaWHSIT6Rw+H2rNJmiq6SNWiDytfx8+gYj7wDHw==
|
||||
"@types/node@17.0.18":
|
||||
version "17.0.18"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074"
|
||||
integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA==
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.4"
|
||||
|
Loading…
Reference in New Issue
Block a user