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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 1524 additions and 545 deletions

View File

@ -20,19 +20,14 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return metadata;
}
export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -20,19 +20,14 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return metadata;
}
export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -1,5 +1,4 @@
import { JsonRpcRequest } from "@walletconnect/jsonrpc-utils";
import { BLOCKCHAIN_LOGO_BASE_URL } from "../constants";
import { NamespaceMetadata, ChainMetadata, ChainRequestRender } from "../helpers";
@ -20,19 +19,14 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return metadata;
}
export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -12,6 +12,9 @@
"dependencies": {
"@celo/wallet-base": "^3.0.1",
"@ethereumjs/tx": "^3.5.0",
"@kadena/client": "^0.5.0",
"@kadena/cryptography-utils": "^0.3.3",
"@kadena/types": "^0.3.3",
"@multiversx/sdk-core": "11.6.0",
"@multiversx/sdk-wallet": "4.2.0",
"@polkadot/util-crypto": "^10.1.2",
@ -20,7 +23,7 @@
"@walletconnect/sign-client": "2.9.0",
"@walletconnect/types": "2.9.0",
"@walletconnect/utils": "2.9.0",
"@web3modal/standalone": "2.2.0",
"@web3modal/standalone": "2.4.3",
"axios": "^0.21.1",
"blockies-ts": "^1.0.0",
"bs58": "^5.0.0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View File

@ -59,18 +59,11 @@ export function getChainMetadata(chainId: string): ChainMetadata {
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -8,6 +8,7 @@ import * as near from "./near";
import * as multiversx from "./multiversx";
import * as tron from "./tron";
import * as tezos from "./tezos";
import * as kadena from "./kadena";
import { ChainMetadata, ChainRequestRender } from "../helpers";
@ -24,6 +25,8 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return solana.getChainMetadata(chainId);
case "near":
return near.getChainMetadata(chainId);
case "kadena":
return kadena.getChainMetadata(chainId);
case "mvx":
return multiversx.getChainMetadata(chainId);
case "tron":
@ -51,6 +54,8 @@ export function getChainRequestRender(
return near.getChainRequestRender(request);
case "tezos":
return tezos.getChainRequestRender(request);
case "kadena":
return kadena.getChainRequestRender(request);
default:
throw new Error(`No render handler for namespace ${namespace}`);
}

View File

@ -0,0 +1,58 @@
import { JsonRpcRequest } from "@walletconnect/jsonrpc-utils";
import {
NamespaceMetadata,
ChainMetadata,
ChainRequestRender,
ChainsMap,
} from "../helpers";
export const KadenaMetadata: NamespaceMetadata = {
mainnet01: {
logo: "/assets/kadena.png",
rgb: "237, 9, 143",
},
testnet04: {
logo: "/assets/kadena.png",
rgb: "237, 9, 143",
},
};
// TODO: add `kadena` namespace to `caip-api` package to avoid manual specification here.
export const KadenaChainData: ChainsMap = {
mainnet01: {
name: "Kadena",
id: "kadena:mainnet01",
rpc: ["https://api.chainweb.com"],
slip44: 626,
testnet: false,
},
testnet04: {
name: "Kadena Testnet",
id: "kadena:testnet04",
rpc: ["https://api.chainweb.com"],
slip44: 626,
testnet: true,
},
};
export function getChainMetadata(chainId: string): ChainMetadata {
const reference = chainId.split(":")[1];
const metadata = KadenaMetadata[reference];
if (typeof metadata === "undefined") {
throw new Error(`No chain metadata found for chainId: ${chainId}`);
}
return metadata;
}
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -36,18 +36,11 @@ export function getChainMetadata(chainId: string): ChainMetadata {
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -48,18 +48,11 @@ export function getChainMetadata(chainId: string): ChainMetadata {
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -47,18 +47,11 @@ export function getChainMetadata(chainId: string): ChainMetadata {
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
default:
params = [
...params,
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
break;
}
return params;
return [
{ label: "Method", value: request.method },
{
label: "params",
value: JSON.stringify(request.params, null, "\t"),
},
];
}

View File

@ -7,8 +7,9 @@ import { AssetData, fromWad } from "../helpers";
import { getChainMetadata } from "../chains";
const xdai = getChainMetadata("eip155:100").logo;
const matic = getChainMetadata("eip155:137").logo;
const xdaiLogo = getChainMetadata("eip155:100").logo;
const maticLogo = getChainMetadata("eip155:137").logo;
const kadenaLogo = getChainMetadata("kadena:testnet04").logo;
const SAsset = styled.div`
width: 100%;
@ -42,9 +43,11 @@ function getAssetIcon(asset: AssetData): JSX.Element {
case "eth":
return <Icon src={"/assets/eth.svg"} />;
case "xdai":
return <Icon src={xdai} />;
return <Icon src={xdaiLogo} />;
case "matic":
return <Icon src={matic} />;
return <Icon src={maticLogo} />;
case "kda":
return <Icon src={kadenaLogo} />;
default:
return <Icon src={"/assets/eth20.svg"} />;
}
@ -63,9 +66,9 @@ const Asset = (props: AssetProps) => {
<SAssetName>{asset.name}</SAssetName>
</SAssetLeft>
<SAssetRight>
<SAssetBalance>{`${fromWad(asset.balance || "0")} ${
asset.symbol
}`}</SAssetBalance>
<SAssetBalance>
{fromWad(asset.balance || "0")} {asset.symbol}
</SAssetBalance>
</SAssetRight>
</SAsset>
);

View File

@ -65,6 +65,7 @@ const SCloseButton = styled.div<CloseButtonStyleProps>`
top: ${({ size }) => `${size / 1.6667}px`};
opacity: 0.5;
cursor: pointer;
&:hover {
opacity: 1;
}
@ -130,9 +131,8 @@ export default function Modal({ children, show, opacity, closeModal }: IProps) {
<SLightbox show={show} offset={offset} opacity={opacity} ref={lightboxRef}>
<SModalContainer>
<SHitbox onClick={closeModal} />
<SCard>
<SCloseButton size={25} color={"dark"} onClick={closeModal} />
<SCloseButton size={25} color="dark" onClick={closeModal} />
<SModalContent>{children}</SModalContent>
</SCard>
</SModalContainer>

View File

@ -10,7 +10,7 @@ export const SContainer = styled.div`
word-break: break-word;
`;
export const STable = styled(SContainer as any)`
export const STable = styled(SContainer)`
flex-direction: column;
text-align: left;
`;

View File

@ -16,6 +16,7 @@ export const DEFAULT_MAIN_CHAINS = [
"mvx:1",
"tron:0x2b6653dc",
"tezos:mainnet",
"kadena:mainnet01",
];
export const DEFAULT_TEST_CHAINS = [
@ -32,6 +33,7 @@ export const DEFAULT_TEST_CHAINS = [
"mvx:D",
"tron:0xcd8690dc",
"tezos:testnet",
"kadena:testnet04",
];
export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS];
@ -153,6 +155,17 @@ type RelayerType = {
label: string;
};
/**
* KADENA
*/
export enum DEFAULT_KADENA_METHODS {
KADENA_GET_ACCOUNTS = "kadena_getAccounts_v1",
KADENA_SIGN = "kadena_sign_v1",
KADENA_QUICKSIGN = "kadena_quicksign_v1",
}
export enum DEFAULT_KADENA_EVENTS {}
export const REGIONALIZED_RELAYER_ENDPOINTS: RelayerType[] = [
{
value: DEFAULT_RELAY_URL,

View File

@ -15,6 +15,7 @@ import { NearChainData } from "../chains/near";
import { CosmosChainData } from "../chains/cosmos";
import { EIP155ChainData } from "../chains/eip155";
import { TezosChainData } from "../chains/tezos";
import { KadenaChainData } from "../chains/kadena";
/**
* Types
@ -69,6 +70,9 @@ export function ChainDataContextProvider({
case "tezos":
chains = TezosChainData;
break;
case "kadena":
chains = KadenaChainData;
break;
default:
console.error("Unknown chain namespace: ", namespace);
}

View File

@ -103,6 +103,7 @@ export function ClientContextProvider({
const [namespace, reference, address] = account.split(":");
const chainId = `${namespace}:${reference}`;
const assets = await apiGetAccountBalance(address, chainId);
return { account, assets: [assets] };
})
);
@ -130,6 +131,7 @@ export function ClientContextProvider({
setChains(allNamespaceChains);
setAccounts(allNamespaceAccounts);
setSolanaPublicKeys(getPublicKeysFromAccounts(allNamespaceAccounts));
await getAccountBalances(allNamespaceAccounts);
},
[]

View File

@ -21,6 +21,14 @@ import {
// @ts-expect-error
import TronWeb from "tronweb";
import {
IPactCommand,
PactCommand,
createWalletConnectQuicksign,
createWalletConnectSign,
} from "@kadena/client";
import { PactNumber } from "@kadena/pactjs";
import {
KadenaAccount,
eip712,
formatTestTransaction,
getLocalStorageTestnetFlag,
@ -39,6 +47,7 @@ import {
DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TRON_METHODS,
DEFAULT_TEZOS_METHODS,
DEFAULT_KADENA_METHODS,
DEFAULT_EIP155_OPTIONAL_METHODS,
} from "../constants";
import { useChainData } from "./ChainDataContext";
@ -52,6 +61,7 @@ import {
SignableMessage,
} from "@multiversx/sdk-core";
import { UserVerifier } from "@multiversx/sdk-wallet/out/userVerifier";
import { SignClient } from "@walletconnect/sign-client/dist/types/client";
/**
* Types
@ -63,7 +73,11 @@ interface IFormattedRpcResponse {
result: string;
}
type TRpcRequestCallback = (chainId: string, address: string) => Promise<void>;
type TRpcRequestCallback = (
chainId: string,
address: string,
message?: string
) => Promise<void>;
interface IContext {
ping: () => Promise<void>;
@ -105,6 +119,11 @@ interface IContext {
testSignMessage: TRpcRequestCallback;
testSignTransaction: TRpcRequestCallback;
};
kadenaRpc: {
testGetAccounts: TRpcRequestCallback;
testSign: TRpcRequestCallback;
testQuicksign: TRpcRequestCallback;
};
rpcResult?: IFormattedRpcResponse | null;
isRpcRequestPending: boolean;
isTestnet: boolean;
@ -128,6 +147,10 @@ export function JsonRpcContextProvider({
const [result, setResult] = useState<IFormattedRpcResponse | null>();
const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag());
const [kadenaAccount, setKadenaAccount] = useState<KadenaAccount | null>(
null
);
const { client, session, accounts, balances, solanaPublicKeys } =
useWalletConnectClient();
@ -1309,6 +1332,158 @@ export function JsonRpcContextProvider({
),
};
// -------- KADENA RPC METHODS --------
const kadenaRpc = {
testGetAccounts: _createJsonRpcRequestHandler(
async (
WCNetworkId: string,
publicKey: string
): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_KADENA_METHODS.KADENA_GET_ACCOUNTS;
const result = await client!.request<any>({
topic: session!.topic,
chainId: WCNetworkId,
request: {
method,
params: {
account: `${WCNetworkId}:${publicKey}`,
contracts: ["coin"],
},
},
});
// In a real app you would let the user pick which account they want to use. For this example we'll just set it to the first one.
const [firstAccount] = result.accounts;
// The information below will later be used to create a transaction
setKadenaAccount({
publicKey: firstAccount.publicKey, // Kadena public key
account: firstAccount.kadenaAccounts[0].name, // Kadena account
chainId: firstAccount.kadenaAccounts[0].chains[0], // Kadena ChainId
});
return {
method,
address: publicKey,
valid: true,
result: JSON.stringify(result, null, 2),
};
}
),
testSign: _createJsonRpcRequestHandler(
async (
WCNetworkId: string,
publicKey: string
): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_KADENA_METHODS.KADENA_SIGN;
const [_, networkId] = WCNetworkId.split(":");
if (!kadenaAccount) {
throw new Error("No Kadena account selected. Call getAccounts first");
}
if (!client) {
throw new Error("No client found");
}
const pactCommand = new PactCommand();
pactCommand.code = `(coin.transfer "${
kadenaAccount.account
}" "k:abcabcabcabc" ${new PactNumber(1).toDecimal()})`;
pactCommand
.setMeta(
{
chainId: kadenaAccount.chainId,
gasLimit: 1000,
gasPrice: 1.0e-6,
ttl: 10 * 60,
sender: kadenaAccount.account,
},
networkId as IPactCommand["networkId"]
)
.addCap("coin.GAS", kadenaAccount.publicKey)
.addCap(
"coin.TRANSFER",
kadenaAccount.publicKey, // public key of sender
kadenaAccount.account, // account of sender
"k:abcabcabcabc", // account of receiver
{ decimal: `1` } // amount
);
const signWithWalletConnect = createWalletConnectSign(
client as any,
session as any,
WCNetworkId as any
);
const result = await signWithWalletConnect(pactCommand);
return {
method,
address: kadenaAccount.publicKey,
valid: true,
result: JSON.stringify(result, null, 2),
};
}
),
testQuicksign: _createJsonRpcRequestHandler(
async (
WCNetworkId: string,
publicKey: string
): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_KADENA_METHODS.KADENA_QUICKSIGN;
const [_, networkId] = WCNetworkId.split(":");
if (!kadenaAccount) {
throw new Error("No Kadena account selected. Call getAccounts first");
}
const pactCommand = new PactCommand();
pactCommand.code = `(coin.transfer "${
kadenaAccount.account
}" "k:abcabcabcabc" ${new PactNumber(1).toDecimal()})`;
pactCommand
.setMeta(
{
chainId: kadenaAccount.chainId,
gasLimit: 1000,
gasPrice: 1.0e-6,
ttl: 10 * 60,
sender: kadenaAccount.account,
},
networkId as IPactCommand["networkId"]
)
.addCap("coin.GAS", publicKey)
.addCap(
"coin.TRANSFER",
publicKey, // pubKey of sender
kadenaAccount.account, // account of sender
"k:abcabcabcabc", // account of receiver
{ decimal: `1` } // amount
);
const quicksignWithWalletConnect = createWalletConnectQuicksign(
client as any,
session as any,
WCNetworkId as any
);
const result = await quicksignWithWalletConnect(pactCommand);
return {
method,
address: publicKey,
valid: true,
result: JSON.stringify(result, null, 2),
};
}
),
};
return (
<JsonRpcContext.Provider
value={{
@ -1321,6 +1496,7 @@ export function JsonRpcContextProvider({
multiversxRpc,
tronRpc,
tezosRpc,
kadenaRpc,
rpcResult: result,
isRpcRequestPending: pending,
isTestnet,

View File

@ -1,5 +1,8 @@
import axios, { AxiosInstance } from "axios";
import { apiGetKadenaAccountBalance } from "./kadena";
import { AssetData } from "./types";
import { PactCommand } from "@kadena/client";
export const rpcProvidersByChainId: Record<number, any> = {
1: {
@ -121,10 +124,19 @@ export async function apiGetAccountBalance(
address: string,
chainId: string
): Promise<AssetData> {
const namespace = chainId.split(":")[0];
const [namespace, networkId] = chainId.split(":");
if (namespace === "kadena") {
return apiGetKadenaAccountBalance(
address,
networkId as PactCommand["networkId"]
);
}
if (namespace !== "eip155") {
return { balance: "", symbol: "", name: "" };
}
const ethChainId = chainId.split(":")[1];
const rpc = rpcProvidersByChainId[Number(ethChainId)];
if (!rpc) {

View File

@ -0,0 +1,81 @@
import { IPactCommand, PactCommand } from "@kadena/client";
export async function getKadenaChainAmount(
WCNetworkId: string
): Promise<number> {
const ENDPOINT = WCNetworkId === "testnet04" ? "testnet." : "";
try {
const response = await fetch(`https://api.${ENDPOINT}chainweb.com/info`, {
mode: "cors",
});
const json = await response.json();
return json.nodeNumberOfChains;
} catch (e) {
console.error("Error fetching Kadena chain info", e);
return 0;
}
}
async function getKadenaBalanceForChain(
publicKey: string,
WCNetworkId: IPactCommand["networkId"],
kadenaChainID: IPactCommand["publicMeta"]["chainId"]
): Promise<number> {
const ENDPOINT = WCNetworkId === "testnet04" ? "testnet." : "";
const API_HOST = `https://api.${ENDPOINT}chainweb.com/chainweb/0.0/${WCNetworkId}/chain/${kadenaChainID}/pact`;
// This request will fail if there is no on-chain activity for the given account yet
try {
const command = new PactCommand();
command.code = `(coin.get-balance "k:${publicKey}")`;
command.setMeta(
{ sender: `k:${publicKey}`, chainId: kadenaChainID },
WCNetworkId
);
const { result } = await command.local(API_HOST, {
preflight: false,
signatureVerification: false,
});
if (result.status !== "success") return 0;
return result.data * 10e17;
} catch (e) {
return 0;
}
}
const kadenaNumberOfChains: Record<string, number> = {
mainnet01: 0,
testnet04: 0,
};
export async function apiGetKadenaAccountBalance(
publicKey: string,
WCNetworkId: IPactCommand["networkId"]
) {
if (!kadenaNumberOfChains[WCNetworkId]) {
kadenaNumberOfChains[WCNetworkId] = await getKadenaChainAmount(WCNetworkId);
}
const chainBalances = await Promise.all(
Array.from(Array(kadenaNumberOfChains[WCNetworkId])).map(
async (_val, chainNumber) =>
getKadenaBalanceForChain(
publicKey,
WCNetworkId,
chainNumber.toString() as IPactCommand["publicMeta"]["chainId"]
)
)
);
const totalBalance = chainBalances.reduce((acc, item) => acc + item, 0);
return {
balance: totalBalance.toString(),
symbol: "KDA",
name: "KDA",
};
}

View File

@ -10,6 +10,8 @@ import {
DEFAULT_POLKADOT_METHODS,
DEFAULT_NEAR_METHODS,
DEFAULT_NEAR_EVENTS,
DEFAULT_KADENA_METHODS,
DEFAULT_KADENA_EVENTS,
DEFAULT_MULTIVERSX_EVENTS,
DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TRON_METHODS,
@ -49,6 +51,8 @@ export const getSupportedRequiredMethodsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_TRON_METHODS);
case "tezos":
return Object.values(DEFAULT_TEZOS_METHODS);
case "kadena":
return Object.values(DEFAULT_KADENA_METHODS);
default:
throw new Error(
`No default required methods for namespace: ${namespace}`
@ -67,6 +71,7 @@ export const getSupportedOptionalMethodsByNamespace = (namespace: string) => {
case "mvx":
case "tron":
case "tezos":
case "kadena":
return [];
default:
throw new Error(
@ -93,6 +98,8 @@ export const getSupportedEventsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_TRON_EVENTS);
case "tezos":
return Object.values(DEFAULT_TEZOS_EVENTS);
case "kadena":
return Object.values(DEFAULT_KADENA_EVENTS);
default:
throw new Error(`No default events for namespace: ${namespace}`);
}

View File

@ -1,3 +1,6 @@
import { IPactCommand } from "@kadena/client";
import { ChainId } from "@kadena/types";
export interface AssetData {
symbol: string;
name: string;
@ -154,3 +157,9 @@ export interface AccountAction {
export interface AccountBalances {
[account: string]: AssetData[];
}
export interface KadenaAccount {
publicKey: string; // Kadena public key
account: string; // Kadena account
chainId: ChainId; // Kadena ChainId
}

View File

@ -16,6 +16,7 @@ import {
DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TEST_CHAINS,
DEFAULT_NEAR_METHODS,
DEFAULT_KADENA_METHODS,
DEFAULT_TRON_METHODS,
DEFAULT_TEZOS_METHODS,
DEFAULT_EIP155_OPTIONAL_METHODS,
@ -78,6 +79,7 @@ const Home: NextPage = () => {
multiversxRpc,
tronRpc,
tezosRpc,
kadenaRpc,
isRpcRequestPending,
rpcResult,
isTestnet,
@ -351,6 +353,37 @@ const Home: NextPage = () => {
];
};
const getKadenaActions = (): AccountAction[] => {
const testGetAccounts = async (chainId: string, address: string) => {
openRequestModal();
await kadenaRpc.testGetAccounts(chainId, address);
};
const testSign = async (chainId: string, address: string) => {
openRequestModal();
await kadenaRpc.testSign(chainId, address);
};
const testSignMessage = async (chainId: string, address: string) => {
openRequestModal();
await kadenaRpc.testQuicksign(chainId, address);
};
return [
{
method: DEFAULT_KADENA_METHODS.KADENA_GET_ACCOUNTS,
callback: testGetAccounts,
},
{
method: DEFAULT_KADENA_METHODS.KADENA_SIGN,
callback: testSign,
},
{
method: DEFAULT_KADENA_METHODS.KADENA_QUICKSIGN,
callback: testSignMessage,
},
];
};
const getBlockchainActions = (chainId: string) => {
const [namespace] = chainId.split(":");
switch (namespace) {
@ -370,6 +403,8 @@ const Home: NextPage = () => {
return getTronActions();
case "tezos":
return getTezosActions();
case "kadena":
return getKadenaActions();
default:
break;
}
@ -411,6 +446,7 @@ const Home: NextPage = () => {
const renderContent = () => {
const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS;
return !accounts.length && !Object.keys(balances).length ? (
<SLanding center>
<Banner />
@ -431,7 +467,7 @@ const Home: NextPage = () => {
/>
))}
<SConnectButton left onClick={onConnect} disabled={!chains.length}>
{"Connect"}
Connect
</SConnectButton>
<Dropdown
relayerRegion={relayerRegion}
@ -449,7 +485,7 @@ const Home: NextPage = () => {
return (
<Blockchain
key={account}
active={true}
active
chainData={chainData}
fetching={isFetchingBalances}
address={address}

View File

@ -2023,6 +2023,57 @@
"@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14"
"@kadena/chainweb-node-client@0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@kadena/chainweb-node-client/-/chainweb-node-client-0.3.3.tgz#46e97caeff081804667fe398f993f08c8a2a978e"
integrity sha512-QmJYfRPMWJaMJEPD4Cai+9t1rA4ljACQo8XDr6dZ6WQnOItV968rLIDr43KG3p7FsyrJW2G6W97GqQUXcqVdDQ==
dependencies:
"@kadena/cryptography-utils" "0.3.3"
"@kadena/pactjs" "0.2.9"
"@kadena/types" "0.3.3"
"@types/isomorphic-fetch" "~0.0.36"
cross-fetch "~3.1.5"
node-fetch "~2.6.2"
"@kadena/client@^0.5.0":
version "0.5.0"
resolved "https://registry.yarnpkg.com/@kadena/client/-/client-0.5.0.tgz#99d5eeea867b19e13df477e2c6a63b3e4fbd1874"
integrity sha512-F3GPdfKBfmto7BGoDd2+gXAZe7IhSIAI1l3VgPUpZgqAz5jiSQp7CNR94nc5YsyZZE05cYsEOsk64odihDQqZQ==
dependencies:
"@kadena/chainweb-node-client" "0.3.3"
"@kadena/cryptography-utils" "0.3.3"
"@kadena/pactjs" "0.2.9"
"@kadena/types" "0.3.3"
"@walletconnect/sign-client" "~2.8.1"
"@walletconnect/types" "~2.8.1"
cross-fetch "~3.1.5"
debug "~4.3.4"
encoding "~0.1.13"
yaml "~2.1.1"
"@kadena/cryptography-utils@0.3.3", "@kadena/cryptography-utils@^0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@kadena/cryptography-utils/-/cryptography-utils-0.3.3.tgz#fea284b28a413a998fd5600698000aedbe0d97ba"
integrity sha512-6GYpjXKbMEeVR9TwIPnE2gv1yjIlIxnlMTH6R0fqlgg8AMkk5WwJ1DpKlahEh2ii2shoZISfmlKLa24U8Fkd/g==
dependencies:
"@kadena/types" "0.3.3"
blakejs "^1.2.1"
buffer "^6.0.3"
tweetnacl "^1.0.3"
"@kadena/pactjs@0.2.9":
version "0.2.9"
resolved "https://registry.yarnpkg.com/@kadena/pactjs/-/pactjs-0.2.9.tgz#c636ea14ab146150ee8c9c869ca664eaf2836a18"
integrity sha512-Y4c9QmcKCHFWOSqAQhQLVN/neFLsNhQRMHNmUvRjnY4BypTX+8PVKVTRWk6y92C709Smkdyh8uzmE6aRfkMHtQ==
dependencies:
"@kadena/types" "0.3.3"
bignumber.js "^9.0.2"
"@kadena/types@0.3.3", "@kadena/types@^0.3.3":
version "0.3.3"
resolved "https://registry.yarnpkg.com/@kadena/types/-/types-0.3.3.tgz#e1b1a65a3a0ebde53cd81ecbc77f5926a24022da"
integrity sha512-61ltE1vx81r/OSrrHaEte1m2QixsCVLBT8koBmWu7wmITGltjEzjkIJNNUs/A0d4aZzlUVOa+6tnRq22clQu3w==
"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9"
@ -2045,7 +2096,7 @@
"@motionone/utils" "^10.15.1"
tslib "^2.3.1"
"@motionone/dom@^10.15.5", "@motionone/dom@^10.16.2":
"@motionone/dom@^10.16.2":
version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.16.2.tgz#0c44df8ee3d1cfc50ee11d27050b27824355a61a"
integrity sha512-bnuHdNbge1FutZXv+k7xub9oPWcF0hsu8y1HTH/qg6av58YI0VufZ3ngfC7p2xhMJMnoh0LXFma2EGTgPeCkeg==
@ -2074,7 +2125,7 @@
"@motionone/utils" "^10.15.1"
tslib "^2.3.1"
"@motionone/svelte@^10.15.5":
"@motionone/svelte@^10.16.2":
version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/svelte/-/svelte-10.16.2.tgz#0b37c3b12927814d31d24941d1ca0ff49981b444"
integrity sha512-38xsroKrfK+aHYhuQlE6eFcGy0EwrB43Q7RGjF73j/kRUTcLNu/LAaKiLLsN5lyqVzCgTBVt4TMT/ShWbTbc5Q==
@ -2096,7 +2147,7 @@
hey-listen "^1.0.8"
tslib "^2.3.1"
"@motionone/vue@^10.15.5":
"@motionone/vue@^10.16.2":
version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/vue/-/vue-10.16.2.tgz#faf13afc27620a2df870c71c58a04ee8de8dea65"
integrity sha512-7/dEK/nWQXOkJ70bqb2KyNfSWbNvWqKKq1C8juj+0Mg/AorgD8O5wE3naddK0G+aXuNMqRuc4jlsYHHWHtIzVw==
@ -2954,6 +3005,11 @@
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57"
integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==
"@types/isomorphic-fetch@~0.0.36":
version "0.0.36"
resolved "https://registry.yarnpkg.com/@types/isomorphic-fetch/-/isomorphic-fetch-0.0.36.tgz#3a6d8f63974baf26b10fd1314db910633108a769"
integrity sha512-ulw4d+vW1HKn4oErSmNN2HYEcHGq0N1C5exlrMM0CRqX1UUpFhGb5lwiom5j9KN3LBJJDLRmYIZz1ghm7FIzZw==
"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44"
@ -3508,6 +3564,21 @@
"@walletconnect/utils" "2.9.0"
events "^3.3.0"
"@walletconnect/sign-client@~2.8.1":
version "2.8.6"
resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.8.6.tgz#7c83fa769d0403efd05172c72bd6b5f678e67a69"
integrity sha512-rOFTKTHP7oJfXgYHX7+SdB8VbcsEE3ZFG/bMdmZboWaBim1mrY3vUyDdKrNr0VgI3AwBiEQezQDfKxBX0pMSQQ==
dependencies:
"@walletconnect/core" "2.8.6"
"@walletconnect/events" "^1.0.1"
"@walletconnect/heartbeat" "1.2.1"
"@walletconnect/jsonrpc-utils" "1.0.8"
"@walletconnect/logger" "^2.0.1"
"@walletconnect/time" "^1.0.2"
"@walletconnect/types" "2.8.6"
"@walletconnect/utils" "2.8.6"
events "^3.3.0"
"@walletconnect/time@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523"
@ -3527,6 +3598,18 @@
"@walletconnect/logger" "^2.0.1"
events "^3.3.0"
"@walletconnect/types@~2.8.1":
version "2.8.6"
resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.8.6.tgz#71426144db3fa693170a95f89f5d6e594ab2d901"
integrity sha512-Z/PFa3W1XdxeTcCtdR6lUsFgZfU/69wWJBPyclPwn7cu1+eriuCr6XZXQpJjib3flU+HnwHiXeUuqZaheehPxw==
dependencies:
"@walletconnect/events" "^1.0.1"
"@walletconnect/heartbeat" "1.2.1"
"@walletconnect/jsonrpc-types" "1.0.3"
"@walletconnect/keyvaluestorage" "^1.0.2"
"@walletconnect/logger" "^2.0.1"
events "^3.3.0"
"@walletconnect/utils@2.9.0":
version "2.9.0"
resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.0.tgz#c73925edb9fefe79021bcf028e957028f986b728"
@ -3562,31 +3645,31 @@
"@walletconnect/window-getters" "^1.0.1"
tslib "1.14.1"
"@web3modal/core@2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@web3modal/core/-/core-2.2.0.tgz#847459e1ab1766f312c39715270a7ca0fe831666"
integrity sha512-Kafg/KtK6S9x0Ofcaq9hj7dRK5/541nM+LnayPmHxx4fSrDgcM9YYhL12fI4BG1xGOJwkeZjgFOtS0qf123Cjw==
"@web3modal/core@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/core/-/core-2.4.3.tgz#ea6d3911e52a132c70defb7584f869d09a8af974"
integrity sha512-7Z/sDe9RIYQ2k9ITcxgEa/u7FvlI76vcVVZn9UY4ISivefqrH4JAS3GX4JmVNUUlovwuiZdyqBv4llAQOMK6Rg==
dependencies:
buffer "6.0.3"
valtio "1.9.0"
valtio "1.10.5"
"@web3modal/standalone@2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@web3modal/standalone/-/standalone-2.2.0.tgz#9f81ed976dd16bd795f902503065f75c9160eab3"
integrity sha512-cLFW4VamSJ7L4sM5OGmr1SHK3FgyLUMEaacvHsCA3XSvUF0LxbMC+N4uBsONrW4c0JyIjTdeii1GqG4B3jwn7Q==
"@web3modal/standalone@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/standalone/-/standalone-2.4.3.tgz#98aaa65eba725c34d5be9078ef04b4e9b769d0f3"
integrity sha512-5ATXBoa4GGm+TIUSsKWsfWCJunv1XevOizpgTFhqyeGgRDmWhqsz9UIPzH/1mk+g0iJ/xqMKs5F6v9D2QeKxag==
dependencies:
"@web3modal/core" "2.2.0"
"@web3modal/ui" "2.2.0"
"@web3modal/core" "2.4.3"
"@web3modal/ui" "2.4.3"
"@web3modal/ui@2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@web3modal/ui/-/ui-2.2.0.tgz#2837da46706f1a3fcdf2f2c22e7ed029e235a3ab"
integrity sha512-jcV5C9AuMdsFdf6Ljsr0v2lInu8FJJyXcZPaMHkgYNIczzgMEpDE+UOA7hLnyCTUxM9R0AgRcgfTyMWb9H8Ssw==
"@web3modal/ui@2.4.3":
version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/ui/-/ui-2.4.3.tgz#986c6bed528dccab679c734ff531e42f6605c5b2"
integrity sha512-J989p8CdtEhI9gZHf/rZ/WFqYlrAHWw9GmAhFoiNODwjAp0BoG/uoaPiijJMchXdngihZOjLGCQwDXU16DHiKg==
dependencies:
"@web3modal/core" "2.2.0"
lit "2.6.1"
motion "10.15.5"
qrcode "1.5.1"
"@web3modal/core" "2.4.3"
lit "2.7.5"
motion "10.16.2"
qrcode "1.5.3"
"@webassemblyjs/ast@1.9.0":
version "1.9.0"
@ -4504,6 +4587,11 @@ bignumber.js@^9.0.0, bignumber.js@^9.0.1:
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6"
integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==
bignumber.js@^9.0.2:
version "9.1.0"
resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.0.tgz"
integrity sha512-4LwHK4nfDOraBCtst+wOWIHbu1vhvAPJK8g8nROd4iuc3PSEjWif/qwbkh8jwCJz6yDBvtU4KPynETgrfh7y3A==
binary-extensions@^1.0.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
@ -4553,7 +4641,7 @@ blake2b@2.1.3:
blake2b-wasm "^1.1.0"
nanoassert "^1.0.0"
blakejs@^1.1.0:
blakejs@^1.1.0, blakejs@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814"
integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==
@ -5423,6 +5511,13 @@ create-hmac@1.1.7, create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
cross-fetch@~3.1.5:
version "3.1.5"
resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz"
integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==
dependencies:
node-fetch "2.6.7"
cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@ -5740,7 +5835,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
@ -6203,6 +6298,13 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
encoding@~0.1.13:
version "0.1.13"
resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
dependencies:
iconv-lite "^0.6.2"
end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@ -7961,6 +8063,13 @@ iconv-lite@0.4.24:
dependencies:
safer-buffer ">= 2.1.2 < 3"
iconv-lite@^0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
icss-utils@^4.0.0, icss-utils@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
@ -9395,7 +9504,7 @@ lines-and-columns@^1.1.6:
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lit-element@^3.2.0:
lit-element@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.2.tgz#9913bf220b85065f0e5f1bb8878cc44f36b50cfa"
integrity sha512-xXAeVWKGr4/njq0rGC9dethMnYCq5hpKYrgQZYTzawt9YQhMiXfD+T1RgrdY3NamOxwq2aXlb0vOI6e29CKgVQ==
@ -9404,21 +9513,21 @@ lit-element@^3.2.0:
"@lit/reactive-element" "^1.3.0"
lit-html "^2.7.0"
lit-html@^2.6.0, lit-html@^2.7.0:
lit-html@^2.7.0:
version "2.7.4"
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.7.4.tgz#6d75001977c206683685b9d76594a516afda2954"
integrity sha512-/Jw+FBpeEN+z8X6PJva5n7+0MzCVAH2yypN99qHYYkq8bI+j7I39GH+68Z/MZD6rGKDK9RpzBw7CocfmHfq6+g==
dependencies:
"@types/trusted-types" "^2.0.2"
lit@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/lit/-/lit-2.6.1.tgz#5951a2098b9bde5b328c73b55c15fdc0eefd96d7"
integrity sha512-DT87LD64f8acR7uVp7kZfhLRrHkfC/N4BVzAtnw9Yg8087mbBJ//qedwdwX0kzDbxgPccWRW6mFwGbRQIxy0pw==
lit@2.7.5:
version "2.7.5"
resolved "https://registry.yarnpkg.com/lit/-/lit-2.7.5.tgz#60bc82990cfad169d42cd786999356dcf79b035f"
integrity sha512-i/cH7Ye6nBDUASMnfwcictBnsTN91+aBjXoTHF2xARghXScKxpD4F4WYI+VLXg9lqbMinDfvoI7VnZXjyHgdfQ==
dependencies:
"@lit/reactive-element" "^1.6.0"
lit-element "^3.2.0"
lit-html "^2.6.0"
lit-element "^3.3.0"
lit-html "^2.7.0"
loader-runner@^2.4.0:
version "2.4.0"
@ -9863,17 +9972,17 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
motion@10.15.5:
version "10.15.5"
resolved "https://registry.yarnpkg.com/motion/-/motion-10.15.5.tgz#d336ddbdd37bc28bb99fbb243fe309df6c685ad6"
integrity sha512-ejP6KioN4pigTGxL93APzOnvtLklParL59UQB2T3HWXQBxFcIp5/7YXFmkgiA6pNKKzjvnLhnonRBN5iSFMnNw==
motion@10.16.2:
version "10.16.2"
resolved "https://registry.yarnpkg.com/motion/-/motion-10.16.2.tgz#7dc173c6ad62210a7e9916caeeaf22c51e598d21"
integrity sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==
dependencies:
"@motionone/animation" "^10.15.1"
"@motionone/dom" "^10.15.5"
"@motionone/svelte" "^10.15.5"
"@motionone/dom" "^10.16.2"
"@motionone/svelte" "^10.16.2"
"@motionone/types" "^10.15.1"
"@motionone/utils" "^10.15.1"
"@motionone/vue" "^10.15.5"
"@motionone/vue" "^10.16.2"
move-concurrently@^1.0.1:
version "1.0.1"
@ -10023,6 +10132,13 @@ node-addon-api@^2.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
node-fetch@2.6.7, node-fetch@~2.6.2:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
dependencies:
whatwg-url "^5.0.0"
node-fetch@^2.6.7:
version "2.6.11"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25"
@ -11589,10 +11705,10 @@ proxy-addr@~2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
proxy-compare@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.4.0.tgz#90f6abffe734ef86d8e37428c5026268606a9c1b"
integrity sha512-FD8KmQUQD6Mfpd0hywCOzcon/dbkFP8XBd9F1ycbKtvVsfv6TsFUKJ2eC0Iz2y+KzlkdT1Z8SY6ZSgm07zOyqg==
proxy-compare@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.5.1.tgz#17818e33d1653fbac8c2ec31406bce8a2966f600"
integrity sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==
prr@~1.0.1:
version "1.0.1"
@ -11666,10 +11782,10 @@ qr-image@^3.2.0:
resolved "https://registry.yarnpkg.com/qr-image/-/qr-image-3.2.0.tgz#9fa8295beae50c4a149cf9f909a1db464a8672e8"
integrity sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw==
qrcode@1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb"
integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==
qrcode@1.5.3:
version "1.5.3"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170"
integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==
dependencies:
dijkstrajs "^1.0.1"
encode-utf8 "^1.0.3"
@ -12393,7 +12509,7 @@ safe-stable-stringify@^2.1.0, safe-stable-stringify@^2.3.1:
resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@ -13977,12 +14093,12 @@ validator@^13.7.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
valtio@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.9.0.tgz#d5d9f664319eaf18dd98f758d50495eca28eb0b8"
integrity sha512-mQLFsAlKbYascZygFQh6lXuDjU5WHLoeZ8He4HqMnWfasM96V6rDbeFkw1XeG54xycmDonr/Jb4xgviHtuySrA==
valtio@1.10.5:
version "1.10.5"
resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.10.5.tgz#7852125e3b774b522827d96bd9c76d285c518678"
integrity sha512-jTp0k63VXf4r5hPoaC6a6LCG4POkVSh629WLi1+d5PlajLsbynTMd7qAgEiOSPxzoX5iNvbN7iZ/k/g29wrNiQ==
dependencies:
proxy-compare "2.4.0"
proxy-compare "2.5.1"
use-sync-external-store "1.2.0"
vary@~1.1.2:
@ -14586,6 +14702,11 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@~2.1.1:
version "2.1.3"
resolved "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz"
integrity sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==
yargs-parser@^13.1.2:
version "13.1.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38"

View File

@ -1,2 +1,2 @@
NEXT_PUBLIC_PROJECT_ID=...
NEXT_PUBLIC_PROJECT_ID=
NEXT_PUBLIC_RELAY_URL=wss://relay.walletconnect.com

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

View File

@ -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 ? `` : `🔄`}

View File

@ -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 (

View File

@ -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>
)
}

View File

@ -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(', ')}

View File

@ -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'
}

View File

@ -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) {

View File

@ -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 })
}

View File

@ -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 }] }
}
]
}
}
}

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}

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>
)
}

View File

@ -25,6 +25,7 @@ interface State {
| 'SessionSignMultiversxModal'
| 'SessionSignTronModal'
| 'SessionSignTezosModal'
| 'SessionSignKadenaModal'
data?: ModalData
}

View File

@ -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
},

View File

@ -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
)
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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}
/>
)
}
}

View File

@ -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