feat: adds Kadena support (#70)

This commit is contained in:
Ashwin
2023-07-14 12:29:17 +02:00
committed by GitHub
parent a48d4b6aa9
commit 8f612a0d73
45 changed files with 1524 additions and 545 deletions
+1 -1
View File
@@ -1,2 +1,2 @@
NEXT_PUBLIC_PROJECT_ID=...
NEXT_PUBLIC_PROJECT_ID=
NEXT_PUBLIC_RELAY_URL=wss://relay.walletconnect.com
+2
View File
@@ -13,6 +13,8 @@
"@cosmjs/encoding": "0.31.0",
"@cosmjs/proto-signing": "0.31.0",
"@json-rpc-tools/utils": "1.7.6",
"@kadena/cryptography-utils": "^0.3.2",
"@kadena/types": "^0.3.2",
"@multiversx/sdk-core": "11.6.0",
"@multiversx/sdk-wallet": "4.2.0",
"@near-wallet-selector/wallet-utils": "^7.0.2",
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

@@ -18,9 +18,7 @@ interface Props {
export default function AccountCard({ name, logo, rgb, address, chainId }: Props) {
const [copied, setCopied] = useState(false)
const { activeChainId, account } = useSnapshot(
SettingsStore.state,
);
const { activeChainId, account } = useSnapshot(SettingsStore.state)
function onCopy() {
navigator?.clipboard?.writeText(address)
setCopied(true)
@@ -28,8 +26,8 @@ export default function AccountCard({ name, logo, rgb, address, chainId }: Props
}
async function onChainChanged(chainId: string, address: string) {
SettingsStore.setActiveChainId(chainId);
await updateSignClientChainId(chainId.toString(), address);
SettingsStore.setActiveChainId(chainId)
await updateSignClientChainId(chainId.toString(), address)
}
return (
@@ -59,16 +57,16 @@ export default function AccountCard({ name, logo, rgb, address, chainId }: Props
/>
</Button>
</Tooltip>
<Button
<Button
size="sm"
css={{
minWidth: "auto",
backgroundColor: "rgba(255, 255, 255, 0.15)",
marginLeft: "$5",
minWidth: 'auto',
backgroundColor: 'rgba(255, 255, 255, 0.15)',
marginLeft: '$5'
}}
data-testid={'chain-switch-button' + chainId}
onPress={() => {
onChainChanged(chainId, address);
onChainChanged(chainId, address)
}}
>
{activeChainId === chainId ? `` : `🔄`}
@@ -6,6 +6,7 @@ import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { multiversxAddresses } from '@/utils/MultiversxWalletUtil'
import { tronAddresses } from '@/utils/TronWalletUtil'
import { tezosAddresses } from '@/utils/TezosWalletUtil'
import { kadenaAddresses } from '@/utils/KadenaWalletUtil'
import { useSnapshot } from 'valtio'
export default function AccountPicker() {
@@ -21,6 +22,7 @@ export default function AccountPicker() {
SettingsStore.setMultiversxAddress(multiversxAddresses[account])
SettingsStore.setTronAddress(tronAddresses[account])
SettingsStore.setTezosAddress(tezosAddresses[account])
SettingsStore.setKadenaAddress(kadenaAddresses[account])
}
return (
@@ -9,6 +9,7 @@ import SessionSignSolanaModal from '@/views/SessionSignSolanaModal'
import SessionSignMultiversxModal from '@/views/SessionSignMultiversxModal'
import SessionSignTronModal from '@/views/SessionSignTronModal'
import SessionSignTezosModal from '@/views/SessionSignTezosModal'
import SessionSignKadenaModal from '@/views/SessionSignKadenaModal'
import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal'
import SessionUnsuportedMethodModal from '@/views/SessionUnsuportedMethodModal'
import { Modal as NextModal } from '@nextui-org/react'
@@ -31,6 +32,7 @@ export default function Modal() {
{view === 'SessionSignMultiversxModal' && <SessionSignMultiversxModal />}
{view === 'SessionSignTronModal' && <SessionSignTronModal />}
{view === 'SessionSignTezosModal' && <SessionSignTezosModal />}
{view === 'SessionSignKadenaModal' && <SessionSignKadenaModal />}
</NextModal>
)
}
@@ -1,5 +1,6 @@
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { KADENA_CHAINS, TKadenaChain } from '@/data/KadenaData'
import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { MULTIVERSX_CHAINS, TMultiversxChain } from '@/data/MultiversxData'
@@ -18,7 +19,7 @@ interface IProps {
/**
* Component
*/
export default function RequesDetailsCard({ chains, protocol }: IProps) {
export default function RequestDetailsCard({ chains, protocol }: IProps) {
return (
<Fragment>
<Row>
@@ -34,6 +35,7 @@ export default function RequesDetailsCard({ chains, protocol }: IProps) {
NEAR_TEST_CHAINS[chain as TNearChain]?.name ??
MULTIVERSX_CHAINS[chain as TMultiversxChain]?.name ??
TRON_CHAINS[chain as TTronChain]?.name ??
KADENA_CHAINS[chain as TKadenaChain]?.name ??
chain
)
.join(', ')}
@@ -0,0 +1,36 @@
/**
* Types
*/
export type TKadenaChain = keyof typeof KADENA_MAINNET_CHAINS
/**
* Chains
*/
export const KADENA_MAINNET_CHAINS = {
'kadena:mainnet01': {
chainId: 'mainnet01',
name: 'Kadena',
logo: '/chain-logos/kadena.png',
rgb: '237, 9, 143'
}
}
export const KADENA_TEST_CHAINS = {
'kadena:testnet04': {
chainId: 'testnet04',
name: 'Kadena Testnet',
logo: '/chain-logos/kadena.png',
rgb: '237, 9, 143'
}
}
export const KADENA_CHAINS = { ...KADENA_MAINNET_CHAINS, ...KADENA_TEST_CHAINS }
/**
* Methods
*/
export const KADENA_SIGNING_METHODS = {
KADENA_GET_ACCOUNTS: 'kadena_getAccounts_v1',
KADENA_SIGN: 'kadena_sign_v1',
KADENA_QUICKSIGN: 'kadena_quicksign_v1'
}
@@ -3,13 +3,14 @@ import { createOrRestoreCosmosWallet } from '@/utils/CosmosWalletUtil'
import { createOrRestoreEIP155Wallet } from '@/utils/EIP155WalletUtil'
import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil'
import { createOrRestorePolkadotWallet } from '@/utils/PolkadotWalletUtil'
import { createOrRestoreNearWallet } from '@/utils/NearWalletUtil'
import { createOrRestoreMultiversxWallet } from '@/utils/MultiversxWalletUtil'
import { createOrRestoreTronWallet } from '@/utils/TronWalletUtil'
import { createOrRestoreTezosWallet } from '@/utils/TezosWalletUtil'
import { createSignClient, signClient } from '@/utils/WalletConnectUtil'
import { createOrRestoreKadenaWallet } from '@/utils/KadenaWalletUtil'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useSnapshot } from 'valtio'
import { createOrRestoreNearWallet } from '@/utils/NearWalletUtil'
export default function useInitialization() {
const [initialized, setInitialized] = useState(false)
@@ -27,6 +28,7 @@ export default function useInitialization() {
const { multiversxAddresses } = await createOrRestoreMultiversxWallet()
const { tronAddresses } = await createOrRestoreTronWallet()
const { tezosAddresses } = await createOrRestoreTezosWallet()
const { kadenaAddresses } = await createOrRestoreKadenaWallet()
SettingsStore.setEIP155Address(eip155Addresses[0])
SettingsStore.setCosmosAddress(cosmosAddresses[0])
@@ -36,6 +38,7 @@ export default function useInitialization() {
SettingsStore.setMultiversxAddress(multiversxAddresses[0])
SettingsStore.setTronAddress(tronAddresses[0])
SettingsStore.setTezosAddress(tezosAddresses[0])
SettingsStore.setKadenaAddress(kadenaAddresses[0])
await createSignClient(relayerRegionURL)
setInitialized(true)
} catch (err: unknown) {
@@ -11,6 +11,7 @@ import { useCallback, useEffect } from 'react'
import { NEAR_SIGNING_METHODS } from '@/data/NEARData'
import { approveNearRequest } from '@/utils/NearRequestHandlerUtil'
import { TEZOS_SIGNING_METHODS } from '@/data/TezosData'
import { KADENA_SIGNING_METHODS } from '@/data/KadenaData'
export default function useWalletConnectEventsManager(initialized: boolean) {
/******************************************************************************
@@ -80,6 +81,7 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
topic,
response: await approveNearRequest(requestEvent)
})
case TRON_SIGNING_METHODS.TRON_SIGN_MESSAGE:
case TRON_SIGNING_METHODS.TRON_SIGN_TRANSACTION:
return ModalStore.open('SessionSignTronModal', { requestEvent, requestSession })
@@ -87,6 +89,10 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
case TEZOS_SIGNING_METHODS.TEZOS_SEND:
case TEZOS_SIGNING_METHODS.TEZOS_SIGN:
return ModalStore.open('SessionSignTezosModal', { requestEvent, requestSession })
case KADENA_SIGNING_METHODS.KADENA_GET_ACCOUNTS:
case KADENA_SIGNING_METHODS.KADENA_SIGN:
case KADENA_SIGNING_METHODS.KADENA_QUICKSIGN:
return ModalStore.open('SessionSignKadenaModal', { requestEvent, requestSession })
default:
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession })
}
@@ -0,0 +1,48 @@
import { restoreKeyPairFromSecretKey, genKeyPair, sign } from '@kadena/cryptography-utils'
import { IKeyPair } from '@kadena/types'
interface IInitArguments {
secretKey?: string
}
export default class KadenaLib {
keyPair: IKeyPair
constructor(keyPair: IKeyPair) {
this.keyPair = keyPair
}
static init({ secretKey }: IInitArguments) {
const keyPair = secretKey ? restoreKeyPairFromSecretKey(secretKey) : genKeyPair()
return new KadenaLib(keyPair)
}
public getAddress() {
return this.keyPair.publicKey
}
public getSecretKey() {
return this.keyPair.secretKey!
}
public signRequest(transaction: string) {
const signResponse = sign(transaction.toString(), this.keyPair)
return { body: { cmd: transaction, sigs: [signResponse.sig] } }
}
public quicksignRequest(transactions: any) {
const transaction = transactions.commandSigDatas[0].cmd
const signResponse = sign(transaction.toString(), this.keyPair)
return {
responses: [
{
outcome: { result: 'success', hash: signResponse.hash },
commandSigData: { sigs: [{ sig: signResponse.sig, pubKey: this.keyPair.publicKey }] }
}
]
}
}
}
+169 -33
View File
@@ -7,12 +7,13 @@ import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
import { POLKADOT_MAINNET_CHAINS, POLKADOT_TEST_CHAINS } from '@/data/PolkadotData'
import { MULTIVERSX_MAINNET_CHAINS, MULTIVERSX_TEST_CHAINS } from '@/data/MultiversxData'
import { TRON_MAINNET_CHAINS, TRON_TEST_CHAINS } from '@/data/TronData'
import { NEAR_TEST_CHAINS } from '@/data/NEARData'
import { TEZOS_MAINNET_CHAINS, TEZOS_TEST_CHAINS } from '@/data/TezosData'
import { KADENA_MAINNET_CHAINS, KADENA_TEST_CHAINS } from '@/data/KadenaData'
import SettingsStore from '@/store/SettingsStore'
import { Text } from '@nextui-org/react'
import { Fragment } from 'react'
import { useSnapshot } from 'valtio'
import { NEAR_TEST_CHAINS } from '@/data/NEARData'
import { TEZOS_MAINNET_CHAINS, TEZOS_TEST_CHAINS } from '@/data/TezosData'
export default function HomePage() {
const {
@@ -24,37 +25,105 @@ export default function HomePage() {
nearAddress,
multiversxAddress,
tronAddress,
tezosAddress
tezosAddress,
kadenaAddress
} = useSnapshot(SettingsStore.state)
return (
<Fragment>
<PageHeader title="Accounts">
<AccountPicker data-testid='account-picker' />
<AccountPicker data-testid="account-picker" />
</PageHeader>
<Text h4 css={{ marginBottom: '$5' }}>
Mainnets
</Text>
{Object.entries(EIP155_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={eip155Address} chainId={caip10.toString()} data-testid={'chain-card-' + caip10.toString()} />
{Object.entries(EIP155_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={eip155Address}
chainId={caip10.toString()}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(COSMOS_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={cosmosAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(COSMOS_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={cosmosAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(SOLANA_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={solanaAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(SOLANA_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={solanaAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(POLKADOT_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={polkadotAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(POLKADOT_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={polkadotAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(MULTIVERSX_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={multiversxAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(MULTIVERSX_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={multiversxAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(TRON_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={tronAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(TRON_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={tronAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(TEZOS_MAINNET_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={tezosAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(TEZOS_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={tezosAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(KADENA_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={kadenaAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{testNets ? (
@@ -62,26 +131,93 @@ export default function HomePage() {
<Text h4 css={{ marginBottom: '$5' }}>
Testnets
</Text>
{Object.entries(EIP155_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={eip155Address} chainId={caip10.toString()} data-testid={'chain-card-' + caip10.toString()}/>
{Object.entries(EIP155_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={eip155Address}
chainId={caip10.toString()}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(SOLANA_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={solanaAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(SOLANA_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={solanaAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(POLKADOT_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={polkadotAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(POLKADOT_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={polkadotAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(NEAR_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={nearAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(NEAR_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={nearAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(MULTIVERSX_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={multiversxAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
))}
{Object.entries(TRON_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={tronAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(MULTIVERSX_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={multiversxAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(TEZOS_TEST_CHAINS).map(([caip10, {name, logo, rgb}]) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={tezosAddress} chainId={caip10} data-testid={'chain-card-' + caip10}/>
{Object.entries(TRON_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={tronAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(TEZOS_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={tezosAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
{Object.entries(KADENA_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => (
<AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={kadenaAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))}
</Fragment>
) : null}
+15 -2
View File
@@ -6,6 +6,7 @@ import { eip155Wallets } from '@/utils/EIP155WalletUtil'
import { solanaWallets } from '@/utils/SolanaWalletUtil'
import { multiversxWallets } from '@/utils/MultiversxWalletUtil'
import { tronWallets } from '@/utils/TronWalletUtil'
import { kadenaWallets } from '@/utils/KadenaWalletUtil'
import { Card, Divider, Row, Switch, Text } from '@nextui-org/react'
import { Fragment } from 'react'
import { useSnapshot } from 'valtio'
@@ -20,7 +21,8 @@ export default function SettingsPage() {
solanaAddress,
multiversxAddress,
tronAddress,
tezosAddress
tezosAddress,
kadenaAddress
} = useSnapshot(SettingsStore.state)
return (
@@ -94,7 +96,9 @@ export default function SettingsPage() {
MultiversX Mnemonic
</Text>
<Card bordered borderWeight="light" css={{ minHeight: '215px', wordWrap: 'break-word' }}>
<Text css={{ fontFamily: '$mono' }}>{multiversxWallets[multiversxAddress].getMnemonic()}</Text>
<Text css={{ fontFamily: '$mono' }}>
{multiversxWallets[multiversxAddress].getMnemonic()}
</Text>
</Card>
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}>
@@ -110,6 +114,15 @@ export default function SettingsPage() {
<Card bordered borderWeight="light" css={{ minHeight: '100px', wordWrap: 'break-word' }}>
<Text css={{ fontFamily: '$mono' }}>{tezosWallets[tezosAddress].getMnemonic()}</Text>
</Card>
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}>
Kadena Secret Key
</Text>
<Card bordered borderWeight="light" css={{ wordWrap: 'break-word' }}>
<Text css={{ fontFamily: '$mono' }}>{kadenaWallets[kadenaAddress].getSecretKey()}</Text>
</Card>
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}></Text>
</Fragment>
)
}
@@ -25,6 +25,7 @@ interface State {
| 'SessionSignMultiversxModal'
| 'SessionSignTronModal'
| 'SessionSignTezosModal'
| 'SessionSignKadenaModal'
data?: ModalData
}
@@ -14,6 +14,7 @@ interface State {
multiversxAddress: string
tronAddress: string
tezosAddress: string
kadenaAddress: string
relayerRegionURL: string
activeChainId: string
}
@@ -33,6 +34,7 @@ const state = proxy<State>({
multiversxAddress: '',
tronAddress: '',
tezosAddress: '',
kadenaAddress: '',
relayerRegionURL: ''
})
@@ -64,6 +66,9 @@ const SettingsStore = {
setNearAddress(nearAddress: string) {
state.nearAddress = nearAddress
},
setKadenaAddress(kadenaAddress: string) {
state.kadenaAddress = kadenaAddress
},
setRelayerRegionURL(relayerRegionURL: string) {
state.relayerRegionURL = relayerRegionURL
},
@@ -6,6 +6,7 @@ import { POLKADOT_CHAINS, TPolkadotChain } from '@/data/PolkadotData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { TEZOS_CHAINS, TTezosChain } from '@/data/TezosData'
import { TRON_CHAINS, TTronChain } from '@/data/TronData'
import { KADENA_CHAINS, TKadenaChain } from '@/data/KadenaData'
import { utils } from 'ethers'
@@ -114,6 +115,13 @@ export function isNearChain(chain: string) {
return chain.includes('near')
}
/**
* Check if chain is part of KADENA standard
*/
export function isKadenaChain(chain: string) {
return chain.includes('kadena')
}
/**
* Check if chain is part of MULTIVERSX standard
*/
@@ -146,8 +154,9 @@ export function formatChainName(chainId: string) {
NEAR_TEST_CHAINS[chainId as TNearChain]?.name ??
POLKADOT_CHAINS[chainId as TPolkadotChain]?.name ??
SOLANA_CHAINS[chainId as TSolanaChain]?.name ??
TEZOS_CHAINS[chainId as TTezosChain]?.name ??
TRON_CHAINS[chainId as TTronChain]?.name ??
TEZOS_CHAINS[chainId as TTezosChain]?.name ??
KADENA_CHAINS[chainId as TKadenaChain]?.name ??
chainId
)
}
@@ -0,0 +1,58 @@
import { KADENA_SIGNING_METHODS } from '@/data/KadenaData'
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
import { SignClientTypes } from '@walletconnect/types'
import { getSdkError } from '@walletconnect/utils'
import { getWalletAddressFromParams } from './HelperUtil'
import { kadenaAddresses, kadenaWallets } from './KadenaWalletUtil'
export async function approveKadenaRequest(
requestEvent: SignClientTypes.EventArguments['session_request']
) {
const { params, id } = requestEvent
const { request } = params
const account = getWalletAddressFromParams(kadenaAddresses, params)
const wallet = kadenaWallets[account]
switch (request.method) {
case KADENA_SIGNING_METHODS.KADENA_GET_ACCOUNTS:
const mockAccount = `k:${account}`
return formatJsonRpcResult(id, {
accounts: [
{
account: mockAccount,
publicKey: account,
kadenaAccounts: [
{
name: mockAccount,
contract: 'coin',
chains: ['2', '4', '7', '18']
},
{
name: 'w:abcdabcdabcdabcd',
contract: 'coin',
chains: ['8', '17']
}
]
}
]
})
case KADENA_SIGNING_METHODS.KADENA_SIGN:
const signedRequest = wallet.signRequest(request.params)
return formatJsonRpcResult(id, signedRequest)
case KADENA_SIGNING_METHODS.KADENA_QUICKSIGN:
const signedMessage = wallet.quicksignRequest(request.params)
return formatJsonRpcResult(id, signedMessage)
default:
throw new Error(getSdkError('UNSUPPORTED_METHODS').message)
}
}
export function rejectKadenaRequest(request: SignClientTypes.EventArguments['session_request']) {
const { id } = request
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message)
}
@@ -0,0 +1,35 @@
import KadenaLib from '@/lib/KadenaLib'
export let wallet: KadenaLib
export let kadenaWallets: Record<string, KadenaLib>
export let kadenaAddresses: string[]
/**
* Utilities
*/
export async function createOrRestoreKadenaWallet() {
const secretKey = localStorage.getItem('KADENA_SECRET_KEY')
if (secretKey) {
wallet = KadenaLib.init({ secretKey })
} else {
wallet = KadenaLib.init({})
}
if (wallet.getSecretKey()) {
localStorage.setItem('KADENA_SECRET_KEY', wallet.getSecretKey())
}
const address = wallet.getAddress()
kadenaAddresses = [address]
kadenaWallets = {
[address]: wallet
}
return {
kadenaWallets,
kadenaAddresses
}
}
@@ -17,7 +17,8 @@ import {
isNearChain,
isMultiversxChain,
isTronChain,
isTezosChain
isTezosChain,
isKadenaChain
} from '@/utils/HelperUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { signClient } from '@/utils/WalletConnectUtil'
@@ -26,6 +27,7 @@ import { SessionTypes } from '@walletconnect/types'
import { getSdkError, mergeArrays } from '@walletconnect/utils'
import { Fragment, useEffect, useState } from 'react'
import { nearAddresses } from '@/utils/NearWalletUtil'
import { kadenaAddresses } from '@/utils/KadenaWalletUtil'
export default function SessionProposalModal() {
const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({})
@@ -201,6 +203,15 @@ export default function SessionProposalModal() {
chain={chain}
/>
)
} else if (isKadenaChain(chain)) {
return (
<ProposalSelectSection
addresses={kadenaAddresses}
selectedAddresses={selectedAccounts[chain]}
onSelect={onSelectAccount}
chain={chain}
/>
)
}
}
@@ -0,0 +1,95 @@
import ProjectInfoCard from '@/components/ProjectInfoCard'
import RequestDataCard from '@/components/RequestDataCard'
import RequestDetailsCard from '@/components/RequestDetalilsCard'
import RequestMethodCard from '@/components/RequestMethodCard'
import RequestModalContainer from '@/components/RequestModalContainer'
import ModalStore from '@/store/ModalStore'
import { convertHexToUtf8, getSignParamsMessage } from '@/utils/HelperUtil'
import { approveKadenaRequest, rejectKadenaRequest } from '@/utils/KadenaRequestHandlerUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Col, Divider, Modal, Row, Text } from '@nextui-org/react'
import { Fragment } from 'react'
export default function SessionSignKadenaModal() {
// 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 request data
const { topic, params } = requestEvent
const { request, chainId } = params
// Get message, convert it to UTF8 string if it is valid hex
const message = convertHexToUtf8(request.params.message)
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveKadenaRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
}
}
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectKadenaRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
}
}
return (
<Fragment>
<RequestModalContainer title="Sign Message">
<ProjectInfoCard metadata={requestSession.peer.metadata} />
<Divider y={2} />
<RequestDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />
{message && (
<>
<Row>
<Col>
<Text h5>Message</Text>
<Text color="$gray400">{message}</Text>
</Col>
</Row>
<Divider y={2} />
</>
)}
<RequestDataCard data={params} />
<Divider y={2} />
<RequestMethodCard methods={[request.method]} />
</RequestModalContainer>
<Modal.Footer>
<Button auto flat color="error" onClick={onReject}>
Reject
</Button>
<Button auto flat color="success" onClick={onApprove}>
Approve
</Button>
</Modal.Footer>
</Fragment>
)
}
File diff suppressed because it is too large Load Diff