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; return metadata;
} }
export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRender[] { export function getChainRequestRender(
let params = [{ label: "Method", value: request.method }]; request: JsonRpcRequest
): ChainRequestRender[] {
switch (request.method) { return [
default: { label: "Method", value: request.method },
params = [
...params,
{ {
label: "params", label: "params",
value: JSON.stringify(request.params, null, "\t"), value: JSON.stringify(request.params, null, "\t"),
}, },
]; ];
break;
}
return params;
} }

View File

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

View File

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

View File

@ -12,6 +12,9 @@
"dependencies": { "dependencies": {
"@celo/wallet-base": "^3.0.1", "@celo/wallet-base": "^3.0.1",
"@ethereumjs/tx": "^3.5.0", "@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-core": "11.6.0",
"@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet": "4.2.0",
"@polkadot/util-crypto": "^10.1.2", "@polkadot/util-crypto": "^10.1.2",
@ -20,7 +23,7 @@
"@walletconnect/sign-client": "2.9.0", "@walletconnect/sign-client": "2.9.0",
"@walletconnect/types": "2.9.0", "@walletconnect/types": "2.9.0",
"@walletconnect/utils": "2.9.0", "@walletconnect/utils": "2.9.0",
"@web3modal/standalone": "2.2.0", "@web3modal/standalone": "2.4.3",
"axios": "^0.21.1", "axios": "^0.21.1",
"blockies-ts": "^1.0.0", "blockies-ts": "^1.0.0",
"bs58": "^5.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( export function getChainRequestRender(
request: JsonRpcRequest request: JsonRpcRequest
): ChainRequestRender[] { ): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }]; return [
{ label: "Method", value: request.method },
switch (request.method) {
default:
params = [
...params,
{ {
label: "params", label: "params",
value: JSON.stringify(request.params, null, "\t"), value: JSON.stringify(request.params, null, "\t"),
}, },
]; ];
break;
}
return params;
} }

View File

@ -8,6 +8,7 @@ import * as near from "./near";
import * as multiversx from "./multiversx"; import * as multiversx from "./multiversx";
import * as tron from "./tron"; import * as tron from "./tron";
import * as tezos from "./tezos"; import * as tezos from "./tezos";
import * as kadena from "./kadena";
import { ChainMetadata, ChainRequestRender } from "../helpers"; import { ChainMetadata, ChainRequestRender } from "../helpers";
@ -24,6 +25,8 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return solana.getChainMetadata(chainId); return solana.getChainMetadata(chainId);
case "near": case "near":
return near.getChainMetadata(chainId); return near.getChainMetadata(chainId);
case "kadena":
return kadena.getChainMetadata(chainId);
case "mvx": case "mvx":
return multiversx.getChainMetadata(chainId); return multiversx.getChainMetadata(chainId);
case "tron": case "tron":
@ -51,6 +54,8 @@ export function getChainRequestRender(
return near.getChainRequestRender(request); return near.getChainRequestRender(request);
case "tezos": case "tezos":
return tezos.getChainRequestRender(request); return tezos.getChainRequestRender(request);
case "kadena":
return kadena.getChainRequestRender(request);
default: default:
throw new Error(`No render handler for namespace ${namespace}`); 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( export function getChainRequestRender(
request: JsonRpcRequest request: JsonRpcRequest
): ChainRequestRender[] { ): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }]; return [
{ label: "Method", value: request.method },
switch (request.method) {
default:
params = [
...params,
{ {
label: "params", label: "params",
value: JSON.stringify(request.params, null, "\t"), value: JSON.stringify(request.params, null, "\t"),
}, },
]; ];
break;
}
return params;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@ export const DEFAULT_MAIN_CHAINS = [
"mvx:1", "mvx:1",
"tron:0x2b6653dc", "tron:0x2b6653dc",
"tezos:mainnet", "tezos:mainnet",
"kadena:mainnet01",
]; ];
export const DEFAULT_TEST_CHAINS = [ export const DEFAULT_TEST_CHAINS = [
@ -32,6 +33,7 @@ export const DEFAULT_TEST_CHAINS = [
"mvx:D", "mvx:D",
"tron:0xcd8690dc", "tron:0xcd8690dc",
"tezos:testnet", "tezos:testnet",
"kadena:testnet04",
]; ];
export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS]; export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS];
@ -153,6 +155,17 @@ type RelayerType = {
label: string; 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[] = [ export const REGIONALIZED_RELAYER_ENDPOINTS: RelayerType[] = [
{ {
value: DEFAULT_RELAY_URL, value: DEFAULT_RELAY_URL,

View File

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

View File

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

View File

@ -21,6 +21,14 @@ import {
// @ts-expect-error // @ts-expect-error
import TronWeb from "tronweb"; import TronWeb from "tronweb";
import { import {
IPactCommand,
PactCommand,
createWalletConnectQuicksign,
createWalletConnectSign,
} from "@kadena/client";
import { PactNumber } from "@kadena/pactjs";
import {
KadenaAccount,
eip712, eip712,
formatTestTransaction, formatTestTransaction,
getLocalStorageTestnetFlag, getLocalStorageTestnetFlag,
@ -39,6 +47,7 @@ import {
DEFAULT_MULTIVERSX_METHODS, DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TRON_METHODS, DEFAULT_TRON_METHODS,
DEFAULT_TEZOS_METHODS, DEFAULT_TEZOS_METHODS,
DEFAULT_KADENA_METHODS,
DEFAULT_EIP155_OPTIONAL_METHODS, DEFAULT_EIP155_OPTIONAL_METHODS,
} from "../constants"; } from "../constants";
import { useChainData } from "./ChainDataContext"; import { useChainData } from "./ChainDataContext";
@ -52,6 +61,7 @@ import {
SignableMessage, SignableMessage,
} from "@multiversx/sdk-core"; } from "@multiversx/sdk-core";
import { UserVerifier } from "@multiversx/sdk-wallet/out/userVerifier"; import { UserVerifier } from "@multiversx/sdk-wallet/out/userVerifier";
import { SignClient } from "@walletconnect/sign-client/dist/types/client";
/** /**
* Types * Types
@ -63,7 +73,11 @@ interface IFormattedRpcResponse {
result: string; result: string;
} }
type TRpcRequestCallback = (chainId: string, address: string) => Promise<void>; type TRpcRequestCallback = (
chainId: string,
address: string,
message?: string
) => Promise<void>;
interface IContext { interface IContext {
ping: () => Promise<void>; ping: () => Promise<void>;
@ -105,6 +119,11 @@ interface IContext {
testSignMessage: TRpcRequestCallback; testSignMessage: TRpcRequestCallback;
testSignTransaction: TRpcRequestCallback; testSignTransaction: TRpcRequestCallback;
}; };
kadenaRpc: {
testGetAccounts: TRpcRequestCallback;
testSign: TRpcRequestCallback;
testQuicksign: TRpcRequestCallback;
};
rpcResult?: IFormattedRpcResponse | null; rpcResult?: IFormattedRpcResponse | null;
isRpcRequestPending: boolean; isRpcRequestPending: boolean;
isTestnet: boolean; isTestnet: boolean;
@ -128,6 +147,10 @@ export function JsonRpcContextProvider({
const [result, setResult] = useState<IFormattedRpcResponse | null>(); const [result, setResult] = useState<IFormattedRpcResponse | null>();
const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag()); const [isTestnet, setIsTestnet] = useState(getLocalStorageTestnetFlag());
const [kadenaAccount, setKadenaAccount] = useState<KadenaAccount | null>(
null
);
const { client, session, accounts, balances, solanaPublicKeys } = const { client, session, accounts, balances, solanaPublicKeys } =
useWalletConnectClient(); 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 ( return (
<JsonRpcContext.Provider <JsonRpcContext.Provider
value={{ value={{
@ -1321,6 +1496,7 @@ export function JsonRpcContextProvider({
multiversxRpc, multiversxRpc,
tronRpc, tronRpc,
tezosRpc, tezosRpc,
kadenaRpc,
rpcResult: result, rpcResult: result,
isRpcRequestPending: pending, isRpcRequestPending: pending,
isTestnet, isTestnet,

View File

@ -1,5 +1,8 @@
import axios, { AxiosInstance } from "axios"; import axios, { AxiosInstance } from "axios";
import { apiGetKadenaAccountBalance } from "./kadena";
import { AssetData } from "./types"; import { AssetData } from "./types";
import { PactCommand } from "@kadena/client";
export const rpcProvidersByChainId: Record<number, any> = { export const rpcProvidersByChainId: Record<number, any> = {
1: { 1: {
@ -121,10 +124,19 @@ export async function apiGetAccountBalance(
address: string, address: string,
chainId: string chainId: string
): Promise<AssetData> { ): 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") { if (namespace !== "eip155") {
return { balance: "", symbol: "", name: "" }; return { balance: "", symbol: "", name: "" };
} }
const ethChainId = chainId.split(":")[1]; const ethChainId = chainId.split(":")[1];
const rpc = rpcProvidersByChainId[Number(ethChainId)]; const rpc = rpcProvidersByChainId[Number(ethChainId)];
if (!rpc) { 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_POLKADOT_METHODS,
DEFAULT_NEAR_METHODS, DEFAULT_NEAR_METHODS,
DEFAULT_NEAR_EVENTS, DEFAULT_NEAR_EVENTS,
DEFAULT_KADENA_METHODS,
DEFAULT_KADENA_EVENTS,
DEFAULT_MULTIVERSX_EVENTS, DEFAULT_MULTIVERSX_EVENTS,
DEFAULT_MULTIVERSX_METHODS, DEFAULT_MULTIVERSX_METHODS,
DEFAULT_TRON_METHODS, DEFAULT_TRON_METHODS,
@ -49,6 +51,8 @@ export const getSupportedRequiredMethodsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_TRON_METHODS); return Object.values(DEFAULT_TRON_METHODS);
case "tezos": case "tezos":
return Object.values(DEFAULT_TEZOS_METHODS); return Object.values(DEFAULT_TEZOS_METHODS);
case "kadena":
return Object.values(DEFAULT_KADENA_METHODS);
default: default:
throw new Error( throw new Error(
`No default required methods for namespace: ${namespace}` `No default required methods for namespace: ${namespace}`
@ -67,6 +71,7 @@ export const getSupportedOptionalMethodsByNamespace = (namespace: string) => {
case "mvx": case "mvx":
case "tron": case "tron":
case "tezos": case "tezos":
case "kadena":
return []; return [];
default: default:
throw new Error( throw new Error(
@ -93,6 +98,8 @@ export const getSupportedEventsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_TRON_EVENTS); return Object.values(DEFAULT_TRON_EVENTS);
case "tezos": case "tezos":
return Object.values(DEFAULT_TEZOS_EVENTS); return Object.values(DEFAULT_TEZOS_EVENTS);
case "kadena":
return Object.values(DEFAULT_KADENA_EVENTS);
default: default:
throw new Error(`No default events for namespace: ${namespace}`); 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 { export interface AssetData {
symbol: string; symbol: string;
name: string; name: string;
@ -154,3 +157,9 @@ export interface AccountAction {
export interface AccountBalances { export interface AccountBalances {
[account: string]: AssetData[]; [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_MULTIVERSX_METHODS,
DEFAULT_TEST_CHAINS, DEFAULT_TEST_CHAINS,
DEFAULT_NEAR_METHODS, DEFAULT_NEAR_METHODS,
DEFAULT_KADENA_METHODS,
DEFAULT_TRON_METHODS, DEFAULT_TRON_METHODS,
DEFAULT_TEZOS_METHODS, DEFAULT_TEZOS_METHODS,
DEFAULT_EIP155_OPTIONAL_METHODS, DEFAULT_EIP155_OPTIONAL_METHODS,
@ -78,6 +79,7 @@ const Home: NextPage = () => {
multiversxRpc, multiversxRpc,
tronRpc, tronRpc,
tezosRpc, tezosRpc,
kadenaRpc,
isRpcRequestPending, isRpcRequestPending,
rpcResult, rpcResult,
isTestnet, 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 getBlockchainActions = (chainId: string) => {
const [namespace] = chainId.split(":"); const [namespace] = chainId.split(":");
switch (namespace) { switch (namespace) {
@ -370,6 +403,8 @@ const Home: NextPage = () => {
return getTronActions(); return getTronActions();
case "tezos": case "tezos":
return getTezosActions(); return getTezosActions();
case "kadena":
return getKadenaActions();
default: default:
break; break;
} }
@ -411,6 +446,7 @@ const Home: NextPage = () => {
const renderContent = () => { const renderContent = () => {
const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS; const chainOptions = isTestnet ? DEFAULT_TEST_CHAINS : DEFAULT_MAIN_CHAINS;
return !accounts.length && !Object.keys(balances).length ? ( return !accounts.length && !Object.keys(balances).length ? (
<SLanding center> <SLanding center>
<Banner /> <Banner />
@ -431,7 +467,7 @@ const Home: NextPage = () => {
/> />
))} ))}
<SConnectButton left onClick={onConnect} disabled={!chains.length}> <SConnectButton left onClick={onConnect} disabled={!chains.length}>
{"Connect"} Connect
</SConnectButton> </SConnectButton>
<Dropdown <Dropdown
relayerRegion={relayerRegion} relayerRegion={relayerRegion}
@ -449,7 +485,7 @@ const Home: NextPage = () => {
return ( return (
<Blockchain <Blockchain
key={account} key={account}
active={true} active
chainData={chainData} chainData={chainData}
fetching={isFetchingBalances} fetching={isFetchingBalances}
address={address} address={address}

View File

@ -2023,6 +2023,57 @@
"@jridgewell/resolve-uri" "3.1.0" "@jridgewell/resolve-uri" "3.1.0"
"@jridgewell/sourcemap-codec" "1.4.14" "@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": "@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz#64df34e2f12e68e78ac57e571d25ec07fa460ca9" 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" "@motionone/utils" "^10.15.1"
tslib "^2.3.1" tslib "^2.3.1"
"@motionone/dom@^10.15.5", "@motionone/dom@^10.16.2": "@motionone/dom@^10.16.2":
version "10.16.2" version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.16.2.tgz#0c44df8ee3d1cfc50ee11d27050b27824355a61a" resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.16.2.tgz#0c44df8ee3d1cfc50ee11d27050b27824355a61a"
integrity sha512-bnuHdNbge1FutZXv+k7xub9oPWcF0hsu8y1HTH/qg6av58YI0VufZ3ngfC7p2xhMJMnoh0LXFma2EGTgPeCkeg== integrity sha512-bnuHdNbge1FutZXv+k7xub9oPWcF0hsu8y1HTH/qg6av58YI0VufZ3ngfC7p2xhMJMnoh0LXFma2EGTgPeCkeg==
@ -2074,7 +2125,7 @@
"@motionone/utils" "^10.15.1" "@motionone/utils" "^10.15.1"
tslib "^2.3.1" tslib "^2.3.1"
"@motionone/svelte@^10.15.5": "@motionone/svelte@^10.16.2":
version "10.16.2" version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/svelte/-/svelte-10.16.2.tgz#0b37c3b12927814d31d24941d1ca0ff49981b444" resolved "https://registry.yarnpkg.com/@motionone/svelte/-/svelte-10.16.2.tgz#0b37c3b12927814d31d24941d1ca0ff49981b444"
integrity sha512-38xsroKrfK+aHYhuQlE6eFcGy0EwrB43Q7RGjF73j/kRUTcLNu/LAaKiLLsN5lyqVzCgTBVt4TMT/ShWbTbc5Q== integrity sha512-38xsroKrfK+aHYhuQlE6eFcGy0EwrB43Q7RGjF73j/kRUTcLNu/LAaKiLLsN5lyqVzCgTBVt4TMT/ShWbTbc5Q==
@ -2096,7 +2147,7 @@
hey-listen "^1.0.8" hey-listen "^1.0.8"
tslib "^2.3.1" tslib "^2.3.1"
"@motionone/vue@^10.15.5": "@motionone/vue@^10.16.2":
version "10.16.2" version "10.16.2"
resolved "https://registry.yarnpkg.com/@motionone/vue/-/vue-10.16.2.tgz#faf13afc27620a2df870c71c58a04ee8de8dea65" resolved "https://registry.yarnpkg.com/@motionone/vue/-/vue-10.16.2.tgz#faf13afc27620a2df870c71c58a04ee8de8dea65"
integrity sha512-7/dEK/nWQXOkJ70bqb2KyNfSWbNvWqKKq1C8juj+0Mg/AorgD8O5wE3naddK0G+aXuNMqRuc4jlsYHHWHtIzVw== 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" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz#693b316ad323ea97eed6b38ed1a3cc02b1672b57"
integrity sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w== 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": "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" 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" "@walletconnect/utils" "2.9.0"
events "^3.3.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": "@walletconnect/time@^1.0.2":
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523" resolved "https://registry.yarnpkg.com/@walletconnect/time/-/time-1.0.2.tgz#6c5888b835750ecb4299d28eecc5e72c6d336523"
@ -3527,6 +3598,18 @@
"@walletconnect/logger" "^2.0.1" "@walletconnect/logger" "^2.0.1"
events "^3.3.0" 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": "@walletconnect/utils@2.9.0":
version "2.9.0" version "2.9.0"
resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.0.tgz#c73925edb9fefe79021bcf028e957028f986b728" resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.9.0.tgz#c73925edb9fefe79021bcf028e957028f986b728"
@ -3562,31 +3645,31 @@
"@walletconnect/window-getters" "^1.0.1" "@walletconnect/window-getters" "^1.0.1"
tslib "1.14.1" tslib "1.14.1"
"@web3modal/core@2.2.0": "@web3modal/core@2.4.3":
version "2.2.0" version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/core/-/core-2.2.0.tgz#847459e1ab1766f312c39715270a7ca0fe831666" resolved "https://registry.yarnpkg.com/@web3modal/core/-/core-2.4.3.tgz#ea6d3911e52a132c70defb7584f869d09a8af974"
integrity sha512-Kafg/KtK6S9x0Ofcaq9hj7dRK5/541nM+LnayPmHxx4fSrDgcM9YYhL12fI4BG1xGOJwkeZjgFOtS0qf123Cjw== integrity sha512-7Z/sDe9RIYQ2k9ITcxgEa/u7FvlI76vcVVZn9UY4ISivefqrH4JAS3GX4JmVNUUlovwuiZdyqBv4llAQOMK6Rg==
dependencies: dependencies:
buffer "6.0.3" buffer "6.0.3"
valtio "1.9.0" valtio "1.10.5"
"@web3modal/standalone@2.2.0": "@web3modal/standalone@2.4.3":
version "2.2.0" version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/standalone/-/standalone-2.2.0.tgz#9f81ed976dd16bd795f902503065f75c9160eab3" resolved "https://registry.yarnpkg.com/@web3modal/standalone/-/standalone-2.4.3.tgz#98aaa65eba725c34d5be9078ef04b4e9b769d0f3"
integrity sha512-cLFW4VamSJ7L4sM5OGmr1SHK3FgyLUMEaacvHsCA3XSvUF0LxbMC+N4uBsONrW4c0JyIjTdeii1GqG4B3jwn7Q== integrity sha512-5ATXBoa4GGm+TIUSsKWsfWCJunv1XevOizpgTFhqyeGgRDmWhqsz9UIPzH/1mk+g0iJ/xqMKs5F6v9D2QeKxag==
dependencies: dependencies:
"@web3modal/core" "2.2.0" "@web3modal/core" "2.4.3"
"@web3modal/ui" "2.2.0" "@web3modal/ui" "2.4.3"
"@web3modal/ui@2.2.0": "@web3modal/ui@2.4.3":
version "2.2.0" version "2.4.3"
resolved "https://registry.yarnpkg.com/@web3modal/ui/-/ui-2.2.0.tgz#2837da46706f1a3fcdf2f2c22e7ed029e235a3ab" resolved "https://registry.yarnpkg.com/@web3modal/ui/-/ui-2.4.3.tgz#986c6bed528dccab679c734ff531e42f6605c5b2"
integrity sha512-jcV5C9AuMdsFdf6Ljsr0v2lInu8FJJyXcZPaMHkgYNIczzgMEpDE+UOA7hLnyCTUxM9R0AgRcgfTyMWb9H8Ssw== integrity sha512-J989p8CdtEhI9gZHf/rZ/WFqYlrAHWw9GmAhFoiNODwjAp0BoG/uoaPiijJMchXdngihZOjLGCQwDXU16DHiKg==
dependencies: dependencies:
"@web3modal/core" "2.2.0" "@web3modal/core" "2.4.3"
lit "2.6.1" lit "2.7.5"
motion "10.15.5" motion "10.16.2"
qrcode "1.5.1" qrcode "1.5.3"
"@webassemblyjs/ast@1.9.0": "@webassemblyjs/ast@1.9.0":
version "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" resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6"
integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== 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: binary-extensions@^1.0.0:
version "1.13.1" version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" 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" blake2b-wasm "^1.1.0"
nanoassert "^1.0.0" nanoassert "^1.0.0"
blakejs@^1.1.0: blakejs@^1.1.0, blakejs@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814"
integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== 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" safe-buffer "^5.0.1"
sha.js "^2.4.8" 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: cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2:
version "7.0.3" version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 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: dependencies:
ms "2.0.0" 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" version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== 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" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== 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: end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4" version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 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: dependencies:
safer-buffer ">= 2.1.2 < 3" 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: icss-utils@^4.0.0, icss-utils@^4.1.1:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" 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" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
lit-element@^3.2.0: lit-element@^3.3.0:
version "3.3.2" version "3.3.2"
resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.2.tgz#9913bf220b85065f0e5f1bb8878cc44f36b50cfa" resolved "https://registry.yarnpkg.com/lit-element/-/lit-element-3.3.2.tgz#9913bf220b85065f0e5f1bb8878cc44f36b50cfa"
integrity sha512-xXAeVWKGr4/njq0rGC9dethMnYCq5hpKYrgQZYTzawt9YQhMiXfD+T1RgrdY3NamOxwq2aXlb0vOI6e29CKgVQ== integrity sha512-xXAeVWKGr4/njq0rGC9dethMnYCq5hpKYrgQZYTzawt9YQhMiXfD+T1RgrdY3NamOxwq2aXlb0vOI6e29CKgVQ==
@ -9404,21 +9513,21 @@ lit-element@^3.2.0:
"@lit/reactive-element" "^1.3.0" "@lit/reactive-element" "^1.3.0"
lit-html "^2.7.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" version "2.7.4"
resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.7.4.tgz#6d75001977c206683685b9d76594a516afda2954" resolved "https://registry.yarnpkg.com/lit-html/-/lit-html-2.7.4.tgz#6d75001977c206683685b9d76594a516afda2954"
integrity sha512-/Jw+FBpeEN+z8X6PJva5n7+0MzCVAH2yypN99qHYYkq8bI+j7I39GH+68Z/MZD6rGKDK9RpzBw7CocfmHfq6+g== integrity sha512-/Jw+FBpeEN+z8X6PJva5n7+0MzCVAH2yypN99qHYYkq8bI+j7I39GH+68Z/MZD6rGKDK9RpzBw7CocfmHfq6+g==
dependencies: dependencies:
"@types/trusted-types" "^2.0.2" "@types/trusted-types" "^2.0.2"
lit@2.6.1: lit@2.7.5:
version "2.6.1" version "2.7.5"
resolved "https://registry.yarnpkg.com/lit/-/lit-2.6.1.tgz#5951a2098b9bde5b328c73b55c15fdc0eefd96d7" resolved "https://registry.yarnpkg.com/lit/-/lit-2.7.5.tgz#60bc82990cfad169d42cd786999356dcf79b035f"
integrity sha512-DT87LD64f8acR7uVp7kZfhLRrHkfC/N4BVzAtnw9Yg8087mbBJ//qedwdwX0kzDbxgPccWRW6mFwGbRQIxy0pw== integrity sha512-i/cH7Ye6nBDUASMnfwcictBnsTN91+aBjXoTHF2xARghXScKxpD4F4WYI+VLXg9lqbMinDfvoI7VnZXjyHgdfQ==
dependencies: dependencies:
"@lit/reactive-element" "^1.6.0" "@lit/reactive-element" "^1.6.0"
lit-element "^3.2.0" lit-element "^3.3.0"
lit-html "^2.6.0" lit-html "^2.7.0"
loader-runner@^2.4.0: loader-runner@^2.4.0:
version "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" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
motion@10.15.5: motion@10.16.2:
version "10.15.5" version "10.16.2"
resolved "https://registry.yarnpkg.com/motion/-/motion-10.15.5.tgz#d336ddbdd37bc28bb99fbb243fe309df6c685ad6" resolved "https://registry.yarnpkg.com/motion/-/motion-10.16.2.tgz#7dc173c6ad62210a7e9916caeeaf22c51e598d21"
integrity sha512-ejP6KioN4pigTGxL93APzOnvtLklParL59UQB2T3HWXQBxFcIp5/7YXFmkgiA6pNKKzjvnLhnonRBN5iSFMnNw== integrity sha512-p+PurYqfUdcJZvtnmAqu5fJgV2kR0uLFQuBKtLeFVTrYEVllI99tiOTSefVNYuip9ELTEkepIIDftNdze76NAQ==
dependencies: dependencies:
"@motionone/animation" "^10.15.1" "@motionone/animation" "^10.15.1"
"@motionone/dom" "^10.15.5" "@motionone/dom" "^10.16.2"
"@motionone/svelte" "^10.15.5" "@motionone/svelte" "^10.16.2"
"@motionone/types" "^10.15.1" "@motionone/types" "^10.15.1"
"@motionone/utils" "^10.15.1" "@motionone/utils" "^10.15.1"
"@motionone/vue" "^10.15.5" "@motionone/vue" "^10.16.2"
move-concurrently@^1.0.1: move-concurrently@^1.0.1:
version "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" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== 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: node-fetch@^2.6.7:
version "2.6.11" version "2.6.11"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" 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" forwarded "0.2.0"
ipaddr.js "1.9.1" ipaddr.js "1.9.1"
proxy-compare@2.4.0: proxy-compare@2.5.1:
version "2.4.0" version "2.5.1"
resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.4.0.tgz#90f6abffe734ef86d8e37428c5026268606a9c1b" resolved "https://registry.yarnpkg.com/proxy-compare/-/proxy-compare-2.5.1.tgz#17818e33d1653fbac8c2ec31406bce8a2966f600"
integrity sha512-FD8KmQUQD6Mfpd0hywCOzcon/dbkFP8XBd9F1ycbKtvVsfv6TsFUKJ2eC0Iz2y+KzlkdT1Z8SY6ZSgm07zOyqg== integrity sha512-oyfc0Tx87Cpwva5ZXezSp5V9vht1c7dZBhvuV/y3ctkgMVUmiAGDVeeB0dKhGSyT0v1ZTEQYpe/RXlBVBNuCLA==
prr@~1.0.1: prr@~1.0.1:
version "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" resolved "https://registry.yarnpkg.com/qr-image/-/qr-image-3.2.0.tgz#9fa8295beae50c4a149cf9f909a1db464a8672e8"
integrity sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw== integrity sha512-rXKDS5Sx3YipVsqmlMJsJsk6jXylEpiHRC2+nJy66fxA5ExYyGa4PqwteW69SaVmAb2OQ18HbYriT7cGQMbduw==
qrcode@1.5.1: qrcode@1.5.3:
version "1.5.1" version "1.5.3"
resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.1.tgz#0103f97317409f7bc91772ef30793a54cd59f0cb" resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.3.tgz#03afa80912c0dccf12bc93f615a535aad1066170"
integrity sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg== integrity sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==
dependencies: dependencies:
dijkstrajs "^1.0.1" dijkstrajs "^1.0.1"
encode-utf8 "^1.0.3" 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" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== 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" version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
@ -13977,12 +14093,12 @@ validator@^13.7.0:
resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855"
integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==
valtio@1.9.0: valtio@1.10.5:
version "1.9.0" version "1.10.5"
resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.9.0.tgz#d5d9f664319eaf18dd98f758d50495eca28eb0b8" resolved "https://registry.yarnpkg.com/valtio/-/valtio-1.10.5.tgz#7852125e3b774b522827d96bd9c76d285c518678"
integrity sha512-mQLFsAlKbYascZygFQh6lXuDjU5WHLoeZ8He4HqMnWfasM96V6rDbeFkw1XeG54xycmDonr/Jb4xgviHtuySrA== integrity sha512-jTp0k63VXf4r5hPoaC6a6LCG4POkVSh629WLi1+d5PlajLsbynTMd7qAgEiOSPxzoX5iNvbN7iZ/k/g29wrNiQ==
dependencies: dependencies:
proxy-compare "2.4.0" proxy-compare "2.5.1"
use-sync-external-store "1.2.0" use-sync-external-store "1.2.0"
vary@~1.1.2: vary@~1.1.2:
@ -14586,6 +14702,11 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== 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: yargs-parser@^13.1.2:
version "13.1.2" version "13.1.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 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 NEXT_PUBLIC_RELAY_URL=wss://relay.walletconnect.com

View File

@ -13,6 +13,8 @@
"@cosmjs/encoding": "0.31.0", "@cosmjs/encoding": "0.31.0",
"@cosmjs/proto-signing": "0.31.0", "@cosmjs/proto-signing": "0.31.0",
"@json-rpc-tools/utils": "1.7.6", "@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-core": "11.6.0",
"@multiversx/sdk-wallet": "4.2.0", "@multiversx/sdk-wallet": "4.2.0",
"@near-wallet-selector/wallet-utils": "^7.0.2", "@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) { export default function AccountCard({ name, logo, rgb, address, chainId }: Props) {
const [copied, setCopied] = useState(false) const [copied, setCopied] = useState(false)
const { activeChainId, account } = useSnapshot( const { activeChainId, account } = useSnapshot(SettingsStore.state)
SettingsStore.state,
);
function onCopy() { function onCopy() {
navigator?.clipboard?.writeText(address) navigator?.clipboard?.writeText(address)
setCopied(true) setCopied(true)
@ -28,8 +26,8 @@ export default function AccountCard({ name, logo, rgb, address, chainId }: Props
} }
async function onChainChanged(chainId: string, address: string) { async function onChainChanged(chainId: string, address: string) {
SettingsStore.setActiveChainId(chainId); SettingsStore.setActiveChainId(chainId)
await updateSignClientChainId(chainId.toString(), address); await updateSignClientChainId(chainId.toString(), address)
} }
return ( return (
@ -62,13 +60,13 @@ export default function AccountCard({ name, logo, rgb, address, chainId }: Props
<Button <Button
size="sm" size="sm"
css={{ css={{
minWidth: "auto", minWidth: 'auto',
backgroundColor: "rgba(255, 255, 255, 0.15)", backgroundColor: 'rgba(255, 255, 255, 0.15)',
marginLeft: "$5", marginLeft: '$5'
}} }}
data-testid={'chain-switch-button' + chainId} data-testid={'chain-switch-button' + chainId}
onPress={() => { onPress={() => {
onChainChanged(chainId, address); onChainChanged(chainId, address)
}} }}
> >
{activeChainId === chainId ? `` : `🔄`} {activeChainId === chainId ? `` : `🔄`}

View File

@ -6,6 +6,7 @@ import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { multiversxAddresses } from '@/utils/MultiversxWalletUtil' import { multiversxAddresses } from '@/utils/MultiversxWalletUtil'
import { tronAddresses } from '@/utils/TronWalletUtil' import { tronAddresses } from '@/utils/TronWalletUtil'
import { tezosAddresses } from '@/utils/TezosWalletUtil' import { tezosAddresses } from '@/utils/TezosWalletUtil'
import { kadenaAddresses } from '@/utils/KadenaWalletUtil'
import { useSnapshot } from 'valtio' import { useSnapshot } from 'valtio'
export default function AccountPicker() { export default function AccountPicker() {
@ -21,6 +22,7 @@ export default function AccountPicker() {
SettingsStore.setMultiversxAddress(multiversxAddresses[account]) SettingsStore.setMultiversxAddress(multiversxAddresses[account])
SettingsStore.setTronAddress(tronAddresses[account]) SettingsStore.setTronAddress(tronAddresses[account])
SettingsStore.setTezosAddress(tezosAddresses[account]) SettingsStore.setTezosAddress(tezosAddresses[account])
SettingsStore.setKadenaAddress(kadenaAddresses[account])
} }
return ( return (

View File

@ -9,6 +9,7 @@ import SessionSignSolanaModal from '@/views/SessionSignSolanaModal'
import SessionSignMultiversxModal from '@/views/SessionSignMultiversxModal' import SessionSignMultiversxModal from '@/views/SessionSignMultiversxModal'
import SessionSignTronModal from '@/views/SessionSignTronModal' import SessionSignTronModal from '@/views/SessionSignTronModal'
import SessionSignTezosModal from '@/views/SessionSignTezosModal' import SessionSignTezosModal from '@/views/SessionSignTezosModal'
import SessionSignKadenaModal from '@/views/SessionSignKadenaModal'
import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal' import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal'
import SessionUnsuportedMethodModal from '@/views/SessionUnsuportedMethodModal' import SessionUnsuportedMethodModal from '@/views/SessionUnsuportedMethodModal'
import { Modal as NextModal } from '@nextui-org/react' import { Modal as NextModal } from '@nextui-org/react'
@ -31,6 +32,7 @@ export default function Modal() {
{view === 'SessionSignMultiversxModal' && <SessionSignMultiversxModal />} {view === 'SessionSignMultiversxModal' && <SessionSignMultiversxModal />}
{view === 'SessionSignTronModal' && <SessionSignTronModal />} {view === 'SessionSignTronModal' && <SessionSignTronModal />}
{view === 'SessionSignTezosModal' && <SessionSignTezosModal />} {view === 'SessionSignTezosModal' && <SessionSignTezosModal />}
{view === 'SessionSignKadenaModal' && <SessionSignKadenaModal />}
</NextModal> </NextModal>
) )
} }

View File

@ -1,5 +1,6 @@
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData' import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data' import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { KADENA_CHAINS, TKadenaChain } from '@/data/KadenaData'
import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData' import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData' import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { MULTIVERSX_CHAINS, TMultiversxChain } from '@/data/MultiversxData' import { MULTIVERSX_CHAINS, TMultiversxChain } from '@/data/MultiversxData'
@ -18,7 +19,7 @@ interface IProps {
/** /**
* Component * Component
*/ */
export default function RequesDetailsCard({ chains, protocol }: IProps) { export default function RequestDetailsCard({ chains, protocol }: IProps) {
return ( return (
<Fragment> <Fragment>
<Row> <Row>
@ -34,6 +35,7 @@ export default function RequesDetailsCard({ chains, protocol }: IProps) {
NEAR_TEST_CHAINS[chain as TNearChain]?.name ?? NEAR_TEST_CHAINS[chain as TNearChain]?.name ??
MULTIVERSX_CHAINS[chain as TMultiversxChain]?.name ?? MULTIVERSX_CHAINS[chain as TMultiversxChain]?.name ??
TRON_CHAINS[chain as TTronChain]?.name ?? TRON_CHAINS[chain as TTronChain]?.name ??
KADENA_CHAINS[chain as TKadenaChain]?.name ??
chain chain
) )
.join(', ')} .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 { createOrRestoreEIP155Wallet } from '@/utils/EIP155WalletUtil'
import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil' import { createOrRestoreSolanaWallet } from '@/utils/SolanaWalletUtil'
import { createOrRestorePolkadotWallet } from '@/utils/PolkadotWalletUtil' import { createOrRestorePolkadotWallet } from '@/utils/PolkadotWalletUtil'
import { createOrRestoreNearWallet } from '@/utils/NearWalletUtil'
import { createOrRestoreMultiversxWallet } from '@/utils/MultiversxWalletUtil' import { createOrRestoreMultiversxWallet } from '@/utils/MultiversxWalletUtil'
import { createOrRestoreTronWallet } from '@/utils/TronWalletUtil' import { createOrRestoreTronWallet } from '@/utils/TronWalletUtil'
import { createOrRestoreTezosWallet } from '@/utils/TezosWalletUtil' import { createOrRestoreTezosWallet } from '@/utils/TezosWalletUtil'
import { createSignClient, signClient } from '@/utils/WalletConnectUtil' import { createSignClient, signClient } from '@/utils/WalletConnectUtil'
import { createOrRestoreKadenaWallet } from '@/utils/KadenaWalletUtil'
import { useCallback, useEffect, useRef, useState } from 'react' import { useCallback, useEffect, useRef, useState } from 'react'
import { useSnapshot } from 'valtio' import { useSnapshot } from 'valtio'
import { createOrRestoreNearWallet } from '@/utils/NearWalletUtil'
export default function useInitialization() { export default function useInitialization() {
const [initialized, setInitialized] = useState(false) const [initialized, setInitialized] = useState(false)
@ -27,6 +28,7 @@ export default function useInitialization() {
const { multiversxAddresses } = await createOrRestoreMultiversxWallet() const { multiversxAddresses } = await createOrRestoreMultiversxWallet()
const { tronAddresses } = await createOrRestoreTronWallet() const { tronAddresses } = await createOrRestoreTronWallet()
const { tezosAddresses } = await createOrRestoreTezosWallet() const { tezosAddresses } = await createOrRestoreTezosWallet()
const { kadenaAddresses } = await createOrRestoreKadenaWallet()
SettingsStore.setEIP155Address(eip155Addresses[0]) SettingsStore.setEIP155Address(eip155Addresses[0])
SettingsStore.setCosmosAddress(cosmosAddresses[0]) SettingsStore.setCosmosAddress(cosmosAddresses[0])
@ -36,6 +38,7 @@ export default function useInitialization() {
SettingsStore.setMultiversxAddress(multiversxAddresses[0]) SettingsStore.setMultiversxAddress(multiversxAddresses[0])
SettingsStore.setTronAddress(tronAddresses[0]) SettingsStore.setTronAddress(tronAddresses[0])
SettingsStore.setTezosAddress(tezosAddresses[0]) SettingsStore.setTezosAddress(tezosAddresses[0])
SettingsStore.setKadenaAddress(kadenaAddresses[0])
await createSignClient(relayerRegionURL) await createSignClient(relayerRegionURL)
setInitialized(true) setInitialized(true)
} catch (err: unknown) { } catch (err: unknown) {

View File

@ -11,6 +11,7 @@ import { useCallback, useEffect } from 'react'
import { NEAR_SIGNING_METHODS } from '@/data/NEARData' import { NEAR_SIGNING_METHODS } from '@/data/NEARData'
import { approveNearRequest } from '@/utils/NearRequestHandlerUtil' import { approveNearRequest } from '@/utils/NearRequestHandlerUtil'
import { TEZOS_SIGNING_METHODS } from '@/data/TezosData' import { TEZOS_SIGNING_METHODS } from '@/data/TezosData'
import { KADENA_SIGNING_METHODS } from '@/data/KadenaData'
export default function useWalletConnectEventsManager(initialized: boolean) { export default function useWalletConnectEventsManager(initialized: boolean) {
/****************************************************************************** /******************************************************************************
@ -80,6 +81,7 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
topic, topic,
response: await approveNearRequest(requestEvent) response: await approveNearRequest(requestEvent)
}) })
case TRON_SIGNING_METHODS.TRON_SIGN_MESSAGE: case TRON_SIGNING_METHODS.TRON_SIGN_MESSAGE:
case TRON_SIGNING_METHODS.TRON_SIGN_TRANSACTION: case TRON_SIGNING_METHODS.TRON_SIGN_TRANSACTION:
return ModalStore.open('SessionSignTronModal', { requestEvent, requestSession }) 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_SEND:
case TEZOS_SIGNING_METHODS.TEZOS_SIGN: case TEZOS_SIGNING_METHODS.TEZOS_SIGN:
return ModalStore.open('SessionSignTezosModal', { requestEvent, requestSession }) 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: default:
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession }) 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 { POLKADOT_MAINNET_CHAINS, POLKADOT_TEST_CHAINS } from '@/data/PolkadotData'
import { MULTIVERSX_MAINNET_CHAINS, MULTIVERSX_TEST_CHAINS } from '@/data/MultiversxData' import { MULTIVERSX_MAINNET_CHAINS, MULTIVERSX_TEST_CHAINS } from '@/data/MultiversxData'
import { TRON_MAINNET_CHAINS, TRON_TEST_CHAINS } from '@/data/TronData' 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 SettingsStore from '@/store/SettingsStore'
import { Text } from '@nextui-org/react' import { Text } from '@nextui-org/react'
import { Fragment } from 'react' import { Fragment } from 'react'
import { useSnapshot } from 'valtio' 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() { export default function HomePage() {
const { const {
@ -24,37 +25,105 @@ export default function HomePage() {
nearAddress, nearAddress,
multiversxAddress, multiversxAddress,
tronAddress, tronAddress,
tezosAddress tezosAddress,
kadenaAddress
} = useSnapshot(SettingsStore.state) } = useSnapshot(SettingsStore.state)
return ( return (
<Fragment> <Fragment>
<PageHeader title="Accounts"> <PageHeader title="Accounts">
<AccountPicker data-testid='account-picker' /> <AccountPicker data-testid="account-picker" />
</PageHeader> </PageHeader>
<Text h4 css={{ marginBottom: '$5' }}> <Text h4 css={{ marginBottom: '$5' }}>
Mainnets Mainnets
</Text> </Text>
{Object.entries(EIP155_MAINNET_CHAINS).map(([caip10, { name, logo, rgb }]) => ( {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()} /> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 ? ( {testNets ? (
@ -63,25 +132,92 @@ export default function HomePage() {
Testnets Testnets
</Text> </Text>
{Object.entries(EIP155_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => ( {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()}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <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 }]) => ( {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}/> <AccountCard
key={name}
name={name}
logo={logo}
rgb={rgb}
address={multiversxAddress}
chainId={caip10}
data-testid={'chain-card-' + caip10.toString()}
/>
))} ))}
{Object.entries(TRON_TEST_CHAINS).map(([caip10, { name, logo, rgb }]) => ( {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}/> <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 }]) => ( {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}/> <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> </Fragment>
) : null} ) : null}

View File

@ -6,6 +6,7 @@ import { eip155Wallets } from '@/utils/EIP155WalletUtil'
import { solanaWallets } from '@/utils/SolanaWalletUtil' import { solanaWallets } from '@/utils/SolanaWalletUtil'
import { multiversxWallets } from '@/utils/MultiversxWalletUtil' import { multiversxWallets } from '@/utils/MultiversxWalletUtil'
import { tronWallets } from '@/utils/TronWalletUtil' import { tronWallets } from '@/utils/TronWalletUtil'
import { kadenaWallets } from '@/utils/KadenaWalletUtil'
import { Card, Divider, Row, Switch, Text } from '@nextui-org/react' import { Card, Divider, Row, Switch, Text } from '@nextui-org/react'
import { Fragment } from 'react' import { Fragment } from 'react'
import { useSnapshot } from 'valtio' import { useSnapshot } from 'valtio'
@ -20,7 +21,8 @@ export default function SettingsPage() {
solanaAddress, solanaAddress,
multiversxAddress, multiversxAddress,
tronAddress, tronAddress,
tezosAddress tezosAddress,
kadenaAddress
} = useSnapshot(SettingsStore.state) } = useSnapshot(SettingsStore.state)
return ( return (
@ -94,7 +96,9 @@ export default function SettingsPage() {
MultiversX Mnemonic MultiversX Mnemonic
</Text> </Text>
<Card bordered borderWeight="light" css={{ minHeight: '215px', wordWrap: 'break-word' }}> <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> </Card>
<Text h4 css={{ marginTop: '$10', marginBottom: '$5' }}> <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' }}> <Card bordered borderWeight="light" css={{ minHeight: '100px', wordWrap: 'break-word' }}>
<Text css={{ fontFamily: '$mono' }}>{tezosWallets[tezosAddress].getMnemonic()}</Text> <Text css={{ fontFamily: '$mono' }}>{tezosWallets[tezosAddress].getMnemonic()}</Text>
</Card> </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> </Fragment>
) )
} }

View File

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

View File

@ -14,6 +14,7 @@ interface State {
multiversxAddress: string multiversxAddress: string
tronAddress: string tronAddress: string
tezosAddress: string tezosAddress: string
kadenaAddress: string
relayerRegionURL: string relayerRegionURL: string
activeChainId: string activeChainId: string
} }
@ -33,6 +34,7 @@ const state = proxy<State>({
multiversxAddress: '', multiversxAddress: '',
tronAddress: '', tronAddress: '',
tezosAddress: '', tezosAddress: '',
kadenaAddress: '',
relayerRegionURL: '' relayerRegionURL: ''
}) })
@ -64,6 +66,9 @@ const SettingsStore = {
setNearAddress(nearAddress: string) { setNearAddress(nearAddress: string) {
state.nearAddress = nearAddress state.nearAddress = nearAddress
}, },
setKadenaAddress(kadenaAddress: string) {
state.kadenaAddress = kadenaAddress
},
setRelayerRegionURL(relayerRegionURL: string) { setRelayerRegionURL(relayerRegionURL: string) {
state.relayerRegionURL = relayerRegionURL state.relayerRegionURL = relayerRegionURL
}, },

View File

@ -6,6 +6,7 @@ import { POLKADOT_CHAINS, TPolkadotChain } from '@/data/PolkadotData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData' import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { TEZOS_CHAINS, TTezosChain } from '@/data/TezosData' import { TEZOS_CHAINS, TTezosChain } from '@/data/TezosData'
import { TRON_CHAINS, TTronChain } from '@/data/TronData' import { TRON_CHAINS, TTronChain } from '@/data/TronData'
import { KADENA_CHAINS, TKadenaChain } from '@/data/KadenaData'
import { utils } from 'ethers' import { utils } from 'ethers'
@ -114,6 +115,13 @@ export function isNearChain(chain: string) {
return chain.includes('near') 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 * Check if chain is part of MULTIVERSX standard
*/ */
@ -146,8 +154,9 @@ export function formatChainName(chainId: string) {
NEAR_TEST_CHAINS[chainId as TNearChain]?.name ?? NEAR_TEST_CHAINS[chainId as TNearChain]?.name ??
POLKADOT_CHAINS[chainId as TPolkadotChain]?.name ?? POLKADOT_CHAINS[chainId as TPolkadotChain]?.name ??
SOLANA_CHAINS[chainId as TSolanaChain]?.name ?? SOLANA_CHAINS[chainId as TSolanaChain]?.name ??
TEZOS_CHAINS[chainId as TTezosChain]?.name ??
TRON_CHAINS[chainId as TTronChain]?.name ?? TRON_CHAINS[chainId as TTronChain]?.name ??
TEZOS_CHAINS[chainId as TTezosChain]?.name ??
KADENA_CHAINS[chainId as TKadenaChain]?.name ??
chainId 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, isNearChain,
isMultiversxChain, isMultiversxChain,
isTronChain, isTronChain,
isTezosChain isTezosChain,
isKadenaChain
} from '@/utils/HelperUtil' } from '@/utils/HelperUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil' import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { signClient } from '@/utils/WalletConnectUtil' import { signClient } from '@/utils/WalletConnectUtil'
@ -26,6 +27,7 @@ import { SessionTypes } from '@walletconnect/types'
import { getSdkError, mergeArrays } from '@walletconnect/utils' import { getSdkError, mergeArrays } from '@walletconnect/utils'
import { Fragment, useEffect, useState } from 'react' import { Fragment, useEffect, useState } from 'react'
import { nearAddresses } from '@/utils/NearWalletUtil' import { nearAddresses } from '@/utils/NearWalletUtil'
import { kadenaAddresses } from '@/utils/KadenaWalletUtil'
export default function SessionProposalModal() { export default function SessionProposalModal() {
const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({}) const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({})
@ -201,6 +203,15 @@ export default function SessionProposalModal() {
chain={chain} 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