Added Near Protocol to examples (#59)

Co-authored-by: Ben Kremer <contact@bkrem.dev>
This commit is contained in:
amirsaran3 2022-10-18 12:31:08 +02:00 committed by GitHub
parent 270a6204ae
commit fcec9e477a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 1197 additions and 9 deletions

View File

@ -4,6 +4,7 @@ import * as eip155 from "./eip155";
import * as cosmos from "./cosmos";
import * as polkadot from "./polkadot";
import * as solana from "./solana";
import * as near from "./near";
import { ChainMetadata, ChainRequestRender } from "../helpers";
@ -18,6 +19,8 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return polkadot.getChainMetadata(chainId);
case "solana":
return solana.getChainMetadata(chainId);
case "near":
return near.getChainMetadata(chainId);
default:
throw new Error(`No metadata handler for namespace ${namespace}`);
}
@ -35,6 +38,8 @@ export function getChainRequestRender(
return cosmos.getChainRequestRender(request);
case "polkadot":
return polkadot.getChainRequestRender(request);
case "near":
return near.getChainRequestRender(request);
default:
throw new Error(`No render handler for namespace ${namespace}`);
}

View File

@ -0,0 +1,50 @@
import { JsonRpcRequest } from "@walletconnect/jsonrpc-utils";
import { ChainsMap } from "caip-api";
import { NamespaceMetadata, ChainMetadata, ChainRequestRender } from "../helpers";
export const NearMetadata: NamespaceMetadata = {
"testnet": {
logo: "https://avatars.githubusercontent.com/u/7613128?s=200&v=4",
rgb: "27, 31, 53",
}
};
// TODO: add `near` namespace to `caip-api` package to avoid manual specification here.
export const NearChainData: ChainsMap = {
"testnet": {
"name": "NEAR Testnet",
"id": "near:testnet",
"rpc": [
"https://rpc.testnet.near.org"
],
"slip44": 397,
"testnet": true
},
};
export function getChainMetadata(chainId: string): ChainMetadata {
const reference = chainId.split(":")[1];
const metadata = NearMetadata[reference];
if (typeof metadata === "undefined") {
throw new Error(`No chain metadata found for chainId: ${chainId}`);
}
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;
}

View File

@ -20,6 +20,7 @@ export const DEFAULT_TEST_CHAINS = [
"eip155:44787",
"solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
"polkadot:e143f23803ac50e8f6f8e62695d1ce9e",
"near:testnet"
];
export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS];
@ -82,6 +83,19 @@ export enum DEFAULT_POLKADOT_METHODS {
export enum DEFAULT_POLKADOT_EVENTS {}
/**
* NEAR
*/
export enum DEFAULT_NEAR_METHODS {
NEAR_SIGN_IN = 'near_signIn',
NEAR_SIGN_OUT = 'near_signOut',
NEAR_GET_ACCOUNTS = 'near_getAccounts',
NEAR_SIGN_AND_SEND_TRANSACTION = 'near_signAndSendTransaction',
NEAR_SIGN_AND_SEND_TRANSACTIONS = 'near_signAndSendTransactions',
}
export enum DEFAULT_NEAR_EVENTS {}
export const DEFAULT_GITHUB_REPO_URL =
"https://github.com/WalletConnect/web-examples/tree/main/dapps/react-dapp-v2";

View File

@ -10,6 +10,7 @@ import { SolanaChainData } from "../chains/solana";
import { PolkadotChainData } from "../chains/polkadot";
import { ChainNamespaces, getAllChainNamespaces } from "../helpers";
import { NearChainData } from "../chains/near";
/**
* Types
@ -44,6 +45,8 @@ export function ChainDataContextProvider({
chains = SolanaChainData;
} else if (namespace === "polkadot") {
chains = PolkadotChainData;
} else if (namespace === "near") {
chains = NearChainData;
} else {
chains = await apiGetChainNamespace(namespace);
}

View File

@ -30,6 +30,7 @@ import {
DEFAULT_EIP155_METHODS,
DEFAULT_SOLANA_METHODS,
DEFAULT_POLKADOT_METHODS,
DEFAULT_NEAR_METHODS,
} from "../constants";
import { useChainData } from "./ChainDataContext";
import { signatureVerify, cryptoWaitReady } from "@polkadot/util-crypto";
@ -67,6 +68,10 @@ interface IContext {
testSignMessage: TRpcRequestCallback;
testSignTransaction: TRpcRequestCallback;
};
nearRpc: {
testSignAndSendTransaction: TRpcRequestCallback;
testSignAndSendTransactions: TRpcRequestCallback;
};
rpcResult?: IFormattedRpcResponse | null;
isRpcRequestPending: boolean;
isTestnet: boolean;
@ -690,6 +695,95 @@ export function JsonRpcContextProvider({
},
),
};
// -------- NEAR RPC METHODS --------
const nearRpc = {
testSignAndSendTransaction: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION
const result = await client!.request({
topic: session!.topic,
chainId,
request: {
method,
params: {
transaction: {
signerId: address,
receiverId: "guest-book.testnet",
actions: [{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect!" },
gas: "30000000000000",
deposit: "0",
}
}]
}
},
},
});
return {
method,
address,
valid: true,
result: JSON.stringify((result as any).transaction),
};
}
),
testSignAndSendTransactions: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS
const result = await client!.request({
topic: session!.topic,
chainId,
request: {
method,
params: {
transactions: [
{
signerId: address,
receiverId: "guest-book.testnet",
actions: [{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect! (1/2)" },
gas: "30000000000000",
deposit: "0",
}
}]
},
{
signerId: address,
receiverId: "guest-book.testnet",
actions: [{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect! (2/2)" },
gas: "30000000000000",
deposit: "0",
}
}]
}
],
}
},
});
return {
method,
address,
valid: true,
result: JSON.stringify((result as any).map((r: any) => r.transaction)),
};
}
),
};
return (
<JsonRpcContext.Provider
value={{
@ -698,6 +792,7 @@ export function JsonRpcContextProvider({
cosmosRpc,
solanaRpc,
polkadotRpc,
nearRpc,
rpcResult: result,
isRpcRequestPending: pending,
isTestnet,

View File

@ -8,6 +8,8 @@ import {
DEFAULT_SOLANA_METHODS,
DEFAULT_POLKADOT_EVENTS,
DEFAULT_POLKADOT_METHODS,
DEFAULT_NEAR_METHODS,
DEFAULT_NEAR_EVENTS,
} from "../constants";
export const getNamespacesFromChains = (chains: string[]) => {
@ -32,6 +34,8 @@ export const getSupportedMethodsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_SOLANA_METHODS);
case "polkadot":
return Object.values(DEFAULT_POLKADOT_METHODS);
case "near":
return Object.values(DEFAULT_NEAR_METHODS);
default:
throw new Error(`No default methods for namespace: ${namespace}`);
}
@ -47,6 +51,8 @@ export const getSupportedEventsByNamespace = (namespace: string) => {
return Object.values(DEFAULT_SOLANA_EVENTS);
case "polkadot":
return Object.values(DEFAULT_POLKADOT_EVENTS);
case "near":
return Object.values(DEFAULT_NEAR_EVENTS);
default:
throw new Error(`No default events for namespace: ${namespace}`);
}

View File

@ -14,6 +14,7 @@ import {
DEFAULT_SOLANA_METHODS,
DEFAULT_POLKADOT_METHODS,
DEFAULT_TEST_CHAINS,
DEFAULT_NEAR_METHODS,
} from "../constants";
import { AccountAction, setLocaleStorageTestnetFlag } from "../helpers";
import Toggle from "../components/Toggle";
@ -69,6 +70,7 @@ const Home: NextPage = () => {
cosmosRpc,
solanaRpc,
polkadotRpc,
nearRpc,
isRpcRequestPending,
rpcResult,
isTestnet,
@ -210,6 +212,22 @@ const Home: NextPage = () => {
},
];
};
const getNearActions = (): AccountAction[] => {
const onSignAndSendTransaction = async (chainId: string, address: string) => {
openRequestModal();
await nearRpc.testSignAndSendTransaction(chainId, address);
};
const onSignAndSendTransactions = async (chainId: string, address: string) => {
openRequestModal();
await nearRpc.testSignAndSendTransactions(chainId, address);
};
return [
{ method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION, callback: onSignAndSendTransaction },
{ method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS, callback: onSignAndSendTransactions },
];
};
const getBlockchainActions = (chainId: string) => {
const [namespace] = chainId.split(":");
switch (namespace) {
@ -221,6 +239,8 @@ const Home: NextPage = () => {
return getSolanaActions();
case "polkadot":
return getPolkadotActions();
case "near":
return getNearActions();
default:
break;
}

View File

@ -12,6 +12,7 @@
"@cosmjs/encoding": "0.28.4",
"@cosmjs/proto-signing": "0.28.4",
"@json-rpc-tools/utils": "1.7.6",
"@near-wallet-selector/wallet-utils": "^7.0.2",
"@nextui-org/react": "1.0.8-beta.5",
"@polkadot/keyring": "^10.1.2",
"@solana/web3.js": "1.43.0",
@ -22,6 +23,7 @@
"ethers": "5.6.6",
"framer-motion": "6.3.3",
"mnemonic-keyring": "1.4.0",
"near-api-js": "^0.44.2",
"next": "12.1.5",
"react": "17.0.2",
"react-code-blocks": "0.0.9-0",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1,6 +1,7 @@
import SettingsStore from '@/store/SettingsStore'
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
import { nearAddresses } from '@/utils/NearWalletUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { useSnapshot } from 'valtio'
@ -13,6 +14,7 @@ export default function AccountPicker() {
SettingsStore.setEIP155Address(eip155Addresses[account])
SettingsStore.setCosmosAddress(cosmosAddresses[account])
SettingsStore.setSolanaAddress(solanaAddresses[account])
SettingsStore.setNearAddress(nearAddresses[account])
}
return (

View File

@ -3,6 +3,7 @@ import SessionProposalModal from '@/views/SessionProposalModal'
import SessionSendTransactionModal from '@/views/SessionSendTransactionModal'
import SessionSignCosmosModal from '@/views/SessionSignCosmosModal'
import SessionRequestModal from '@/views/SessionSignModal'
import SessionSignNearModal from '@/views/SessionSignNearModal'
import SessionSignPolkadotModal from '@/views/SessionSignPolkadotModal'
import SessionSignSolanaModal from '@/views/SessionSignSolanaModal'
import SessionSignTypedDataModal from '@/views/SessionSignTypedDataModal'
@ -23,6 +24,7 @@ export default function Modal() {
{view === 'SessionSignCosmosModal' && <SessionSignCosmosModal />}
{view === 'SessionSignSolanaModal' && <SessionSignSolanaModal />}
{view === 'SessionSignPolkadotModal' && <SessionSignPolkadotModal />}
{view === 'SessionSignNearModal' && <SessionSignNearModal />}
</NextModal>
)
}

View File

@ -1,5 +1,6 @@
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { Col, Divider, Row, Text } from '@nextui-org/react'
import { Fragment } from 'react'
@ -28,6 +29,7 @@ export default function RequesDetailsCard({ chains, protocol }: IProps) {
EIP155_CHAINS[chain as TEIP155Chain]?.name ??
COSMOS_MAINNET_CHAINS[chain as TCosmosChain]?.name ??
SOLANA_CHAINS[chain as TSolanaChain]?.name ??
NEAR_TEST_CHAINS[chain as TNearChain]?.name ??
chain
)
.join(', ')}

View File

@ -1,6 +1,7 @@
import ChainCard from '@/components/ChainCard'
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
import { NEAR_TEST_CHAINS } from '@/data/NEARData'
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
import { formatChainName } from '@/utils/HelperUtil'
import { Col, Row, Text } from '@nextui-org/react'
@ -15,7 +16,8 @@ const CHAIN_METADATA = {
...SOLANA_MAINNET_CHAINS,
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS
...SOLANA_TEST_CHAINS,
...NEAR_TEST_CHAINS,
}
/**

View File

@ -1,6 +1,7 @@
import ChainCard from '@/components/ChainCard'
import { COSMOS_MAINNET_CHAINS } from '@/data/COSMOSData'
import { EIP155_MAINNET_CHAINS, EIP155_TEST_CHAINS } from '@/data/EIP155Data'
import { NEAR_TEST_CHAINS } from '@/data/NEARData'
import { SOLANA_MAINNET_CHAINS, SOLANA_TEST_CHAINS } from '@/data/SolanaData'
import { formatChainName } from '@/utils/HelperUtil'
import { Col, Row, Text } from '@nextui-org/react'
@ -15,7 +16,8 @@ const CHAIN_METADATA = {
...SOLANA_MAINNET_CHAINS,
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS
...SOLANA_TEST_CHAINS,
...NEAR_TEST_CHAINS,
}
/**

View File

@ -0,0 +1,55 @@
/**
* @desc Reference list of NEAR chains
* @url https://chainlist.org
*/
/**
* Types
*/
export type TNearChain = keyof typeof NEAR_TEST_CHAINS
/**
* Chains
*/
export const NEAR_MAINNET_CHAINS = {
// TODO: Dev account creation isn't supported on NEAR Mainnet.
}
interface NearTestChains {
[key: string]: ChainMetadata;
}
type ChainMetadata = {
chainId: string;
name: string;
logo: string;
rgb: string;
rpc: string;
}
export const NEAR_TEST_CHAINS: NearTestChains = {
'near:testnet': {
chainId: 'testnet',
name: 'NEAR Testnet',
logo: '/chain-logos/near.png',
rgb: '99, 125, 234',
rpc: 'https://rpc.testnet.near.org'
},
}
export const NEAR_CHAINS = { ...NEAR_MAINNET_CHAINS, ...NEAR_TEST_CHAINS }
/**
* Methods
*/
export const NEAR_SIGNING_METHODS = {
NEAR_SIGN_IN: 'near_signIn',
NEAR_SIGN_OUT: 'near_signOut',
NEAR_GET_ACCOUNTS: 'near_getAccounts',
NEAR_SIGN_TRANSACTION: 'near_signTransaction',
NEAR_SIGN_AND_SEND_TRANSACTION: 'near_signAndSendTransaction',
NEAR_SIGN_TRANSACTIONS: 'near_signTransactions',
NEAR_SIGN_AND_SEND_TRANSACTIONS: 'near_signAndSendTransactions',
NEAR_VERIFY_OWNER: 'near_verifyOwner',
}

View File

@ -6,6 +6,7 @@ import { createOrRestorePolkadotWallet } from '@/utils/PolkadotWalletUtil'
import { createSignClient } from '@/utils/WalletConnectUtil'
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)
@ -19,12 +20,14 @@ export default function useInitialization() {
const { cosmosAddresses } = await createOrRestoreCosmosWallet()
const { solanaAddresses } = await createOrRestoreSolanaWallet()
const { polkadotAddresses } = await createOrRestorePolkadotWallet()
const { nearAddresses } = await createOrRestoreNearWallet()
SettingsStore.setEIP155Address(eip155Addresses[0])
SettingsStore.setCosmosAddress(cosmosAddresses[0])
SettingsStore.setSolanaAddress(solanaAddresses[0])
SettingsStore.setPolkadotAddress(polkadotAddresses[0])
SettingsStore.setNearAddress(nearAddresses[0])
await createSignClient(relayerRegionURL)
prevRelayerURLValue.current = relayerRegionURL

View File

@ -6,6 +6,8 @@ import ModalStore from '@/store/ModalStore'
import { signClient } from '@/utils/WalletConnectUtil'
import { SignClientTypes } from '@walletconnect/types'
import { useCallback, useEffect } from 'react'
import { NEAR_SIGNING_METHODS } from '@/data/NEARData'
import { approveNearRequest } from '@/utils/NearRequestHandlerUtil'
export default function useWalletConnectEventsManager(initialized: boolean) {
/******************************************************************************
@ -52,6 +54,20 @@ export default function useWalletConnectEventsManager(initialized: boolean) {
case POLKADOT_SIGNING_METHODS.POLKADOT_SIGN_MESSAGE:
case POLKADOT_SIGNING_METHODS.POLKADOT_SIGN_TRANSACTION:
return ModalStore.open('SessionSignPolkadotModal', { requestEvent, requestSession })
case NEAR_SIGNING_METHODS.NEAR_SIGN_IN:
case NEAR_SIGNING_METHODS.NEAR_SIGN_OUT:
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTION:
case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION:
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTIONS:
case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS:
case NEAR_SIGNING_METHODS.NEAR_VERIFY_OWNER:
return ModalStore.open('SessionSignNearModal', { requestEvent, requestSession })
case NEAR_SIGNING_METHODS.NEAR_GET_ACCOUNTS:
return signClient.respond({
topic,
response: await approveNearRequest(requestEvent)
})
default:
return ModalStore.open('SessionUnsuportedMethodModal', { requestEvent, requestSession })
}

View File

@ -0,0 +1,346 @@
import {
InMemorySigner,
providers,
keyStores as nearKeyStores,
transactions as nearTransactions,
utils,
} from "near-api-js";
import { AccessKeyView } from "near-api-js/lib/providers/provider";
import { signClient } from "@/utils/WalletConnectUtil";
import { NEAR_TEST_CHAINS, TNearChain } from "@/data/NEARData";
const MAX_ACCOUNTS = 2;
interface Account {
accountId: string;
publicKey: string;
}
interface Transaction {
signerId: string;
receiverId: string;
actions: Array<nearTransactions.Action>;
}
interface CreateTransactionsParams {
chainId: string;
transactions: Array<Transaction>;
}
interface GetAccountsParams {
topic: string;
}
interface SignInParams {
chainId: string;
topic: string;
permission: nearTransactions.FunctionCallPermission;
accounts: Array<Account>;
}
interface SignOutParams {
chainId: string;
topic: string;
accounts: Array<Account>;
}
interface SignTransactionsParams {
chainId: string;
topic: string;
transactions: Array<nearTransactions.Transaction>;
}
interface SignAndSendTransactionParams {
chainId: string;
topic: string;
transaction: nearTransactions.Transaction;
}
interface SignAndSendTransactionsParams {
chainId: string;
topic: string;
transactions: Array<nearTransactions.Transaction>;
}
export class NearWallet {
private networkId: string;
private keyStore: nearKeyStores.KeyStore;
static async init(networkId: string) {
const keyStore = new nearKeyStores.BrowserLocalStorageKeyStore();
const accounts = await keyStore.getAccounts(networkId);
for (let i = 0; i < Math.max(MAX_ACCOUNTS - accounts.length, 0); i += 1) {
const { accountId, keyPair } = await NearWallet.createDevAccount();
await keyStore.setKey(networkId, accountId, keyPair);
}
return new NearWallet(networkId, keyStore);
}
static async createDevAccount() {
const keyPair = utils.KeyPair.fromRandom("ed25519");
const randomNumber = Math.floor(Math.random() * (99999999999999 - 10000000000000) + 10000000000000);
const accountId = `dev-${Date.now()}-${randomNumber}`;
const publicKey = keyPair.getPublicKey().toString();
return fetch(`https://helper.testnet.near.org/account`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
newAccountId: accountId,
newAccountPublicKey: publicKey,
}),
})
.then((res) => {
if (res.ok) {
return {
accountId,
keyPair
};
}
throw new Error("Failed to create NEAR dev account");
});
}
private constructor(networkId: string, keyStore: nearKeyStores.KeyStore) {
this.networkId = networkId;
this.keyStore = keyStore;
}
getKeyStore() {
return this.keyStore;
}
// Retrieve all imported accounts from wallet.
async getAllAccounts(): Promise<Array<Account>> {
const accountIds = await this.keyStore.getAccounts(this.networkId);
return Promise.all(
accountIds.map(async (accountId) => {
const keyPair = await this.keyStore.getKey(this.networkId, accountId);
return {
accountId,
publicKey: keyPair.getPublicKey().toString(),
};
})
);
}
private isAccountsValid(topic: string, accounts: Array<{ accountId: string; }>) {
const session = signClient.session.get(topic);
const validAccountIds = session.namespaces.near.accounts.map((accountId) => {
return accountId.split(":")[2];
})
return accounts.every(({ accountId }) => {
return validAccountIds.includes(accountId);
});
}
private isTransactionsValid(topic: string, transactions: Array<nearTransactions.Transaction>) {
const accounts = transactions.map(({ signerId }) => ({ accountId: signerId }));
return this.isAccountsValid(topic, accounts);
}
async createTransactions({ chainId, transactions }: CreateTransactionsParams): Promise<Array<nearTransactions.Transaction>> {
const provider = new providers.JsonRpcProvider(NEAR_TEST_CHAINS[chainId as TNearChain].rpc);
const txs: Array<nearTransactions.Transaction> = [];
const [block, accounts] = await Promise.all([
provider.block({ finality: "final" }),
this.getAllAccounts(),
]);
for (let i = 0; i < transactions.length; i += 1) {
const transaction = transactions[i];
const account = accounts.find(
(x) => x.accountId === transaction.signerId
);
if (!account) {
throw new Error("Invalid signer id");
}
const accessKey = await provider.query<AccessKeyView>({
request_type: "view_access_key",
finality: "final",
account_id: transaction.signerId,
public_key: account.publicKey,
});
txs.push(
nearTransactions.createTransaction(
transaction.signerId,
utils.PublicKey.from(account.publicKey),
transaction.receiverId,
accessKey.nonce + i + 1,
transaction.actions,
utils.serialize.base_decode(block.header.hash)
)
);
}
return txs;
}
async getAccounts({ topic }: GetAccountsParams): Promise<Array<Account>> {
const session = signClient.session.get(topic);
return Promise.all(
session.namespaces.near.accounts.map(async (account) => {
const accountId = account.split(":")[2];
const keyPair = await this.keyStore.getKey(this.networkId, accountId);
return {
accountId,
publicKey: keyPair.getPublicKey().toString()
};
})
);
}
async signIn({ chainId, topic, permission, accounts }: SignInParams): Promise<Array<Account>> {
if (!this.isAccountsValid(topic, accounts)) {
throw new Error("Invalid accounts");
}
const result: Array<Account> = [];
for (let i = 0; i < accounts.length; i += 1) {
const account = accounts[i];
try {
const [transaction] = await this.createTransactions({
chainId,
transactions: [{
signerId: account.accountId,
receiverId: account.accountId,
actions: [
nearTransactions.addKey(
utils.PublicKey.from(account.publicKey),
nearTransactions.functionCallAccessKey(
permission.receiverId,
permission.methodNames,
permission.allowance
)
)
]
}]
});
await this.signAndSendTransaction({ chainId, topic, transaction });
result.push(account);
} catch (err) {
console.log(`Failed to create FunctionCall access key for ${account.accountId}`);
console.error(err);
}
}
return result;
}
async signOut({ chainId, topic, accounts }: SignOutParams): Promise<Array<Account>> {
if (!this.isAccountsValid(topic, accounts)) {
throw new Error("Invalid accounts");
}
const result: Array<Account> = [];
for (let i = 0; i < accounts.length; i += 1) {
const account = accounts[i];
try {
const [transaction] = await this.createTransactions({
chainId,
transactions: [{
signerId: account.accountId,
receiverId: account.accountId,
actions: [
nearTransactions.deleteKey(
utils.PublicKey.from(account.publicKey)
)
]
}]
});
await this.signAndSendTransaction({ chainId, topic, transaction });
} catch (err) {
console.log(`Failed to remove FunctionCall access key for ${account.accountId}`);
console.error(err);
result.push(account);
}
}
return result;
}
async signTransactions({
chainId,
topic,
transactions
}: SignTransactionsParams): Promise<Array<nearTransactions.SignedTransaction>> {
const networkId = chainId.split(":")[1];
const signer = new InMemorySigner(this.keyStore);
const signedTxs: Array<nearTransactions.SignedTransaction> = [];
if (!this.isTransactionsValid(topic, transactions)) {
throw new Error("Invalid transactions");
}
for (let i = 0; i < transactions.length; i += 1) {
const transaction = transactions[i];
const [, signedTx] = await nearTransactions.signTransaction(
transaction,
signer,
transaction.signerId,
networkId
);
signedTxs.push(signedTx);
}
return signedTxs;
}
async signAndSendTransaction({
chainId,
topic,
transaction
}: SignAndSendTransactionParams): Promise<providers.FinalExecutionOutcome> {
const provider = new providers.JsonRpcProvider(NEAR_TEST_CHAINS[chainId as TNearChain].rpc);
const [signedTx] = await this.signTransactions({
chainId,
topic,
transactions: [transaction]
});
return provider.sendTransaction(signedTx);
}
async signAndSendTransactions({
chainId,
topic,
transactions
}: SignAndSendTransactionsParams): Promise<Array<providers.FinalExecutionOutcome>> {
const provider = new providers.JsonRpcProvider(NEAR_TEST_CHAINS[chainId as TNearChain].rpc);
const signedTxs = await this.signTransactions({ chainId, topic, transactions });
const results: Array<providers.FinalExecutionOutcome> = [];
for (let i = 0; i < signedTxs.length; i += 1) {
const signedTx = signedTxs[i];
results.push(await provider.sendTransaction(signedTx));
}
return results;
}
}

View File

@ -9,9 +9,10 @@ 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'
export default function HomePage() {
const { testNets, eip155Address, cosmosAddress, solanaAddress, polkadotAddress } = useSnapshot(
const { testNets, eip155Address, cosmosAddress, solanaAddress, polkadotAddress, nearAddress } = useSnapshot(
SettingsStore.state
)
@ -50,6 +51,9 @@ export default function HomePage() {
{Object.values(POLKADOT_TEST_CHAINS).map(({ name, logo, rgb }) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={polkadotAddress} />
))}
{Object.values(NEAR_TEST_CHAINS).map(({ name, logo, rgb }) => (
<AccountCard key={name} name={name} logo={logo} rgb={rgb} address={nearAddress} />
))}
</Fragment>
) : null}
</Fragment>

View File

@ -21,6 +21,7 @@ interface State {
| 'SessionSignCosmosModal'
| 'SessionSignSolanaModal'
| 'SessionSignPolkadotModal'
| 'SessionSignNearModal'
data?: ModalData
}

View File

@ -10,6 +10,7 @@ interface State {
cosmosAddress: string
solanaAddress: string
polkadotAddress: string
nearAddress: string
relayerRegionURL: string
}
@ -23,6 +24,7 @@ const state = proxy<State>({
cosmosAddress: '',
solanaAddress: '',
polkadotAddress: '',
nearAddress: '',
relayerRegionURL: ''
})
@ -51,7 +53,9 @@ const SettingsStore = {
setPolkadotAddress(polkadotAddress: string) {
state.polkadotAddress = polkadotAddress
},
setNearAddress(nearAddress: string) {
state.nearAddress = nearAddress
},
setRelayerRegionURL(relayerRegionURL: string) {
state.relayerRegionURL = relayerRegionURL
},

View File

@ -1,5 +1,6 @@
import { COSMOS_MAINNET_CHAINS, TCosmosChain } from '@/data/COSMOSData'
import { EIP155_CHAINS, TEIP155Chain } from '@/data/EIP155Data'
import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData'
import { SOLANA_CHAINS, TSolanaChain } from '@/data/SolanaData'
import { utils } from 'ethers'
@ -101,6 +102,13 @@ export function isPolkadotChain(chain: string) {
return chain.includes('polkadot')
}
/**
* Check if chain is part of NEAR standard
*/
export function isNearChain(chain: string) {
return chain.includes('near')
}
/**
* Formats chainId to its name
*/
@ -109,6 +117,7 @@ export function formatChainName(chainId: string) {
EIP155_CHAINS[chainId as TEIP155Chain]?.name ??
COSMOS_MAINNET_CHAINS[chainId as TCosmosChain]?.name ??
SOLANA_CHAINS[chainId as TSolanaChain]?.name ??
NEAR_TEST_CHAINS[chainId as TNearChain]?.name ??
chainId
)
}

View File

@ -0,0 +1,194 @@
import { NEAR_SIGNING_METHODS, NEAR_TEST_CHAINS } from '@/data/NEARData'
import { formatJsonRpcError, formatJsonRpcResult } from '@json-rpc-tools/utils'
import { SignClientTypes } from '@walletconnect/types'
import { getSdkError } from '@walletconnect/utils'
import { nearWallet } from '@/utils/NearWalletUtil'
import { InMemorySigner, transactions, utils, Connection } from "near-api-js";
import { Transaction } from "@near-wallet-selector/core";
import { createAction } from "@near-wallet-selector/wallet-utils";
export async function approveNearRequest(
requestEvent: SignClientTypes.EventArguments['session_request']
) {
const { params, id, topic } = requestEvent
const { chainId, request } = params
switch (request.method) {
case NEAR_SIGNING_METHODS.NEAR_SIGN_IN: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const accounts = await nearWallet.signIn({
chainId,
topic,
permission: request.params.permission,
accounts: request.params.accounts,
});
return formatJsonRpcResult(id, accounts);
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_OUT: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const accounts = await nearWallet.signOut({
chainId,
topic,
accounts: request.params.accounts
});
return formatJsonRpcResult(id, accounts);
}
case NEAR_SIGNING_METHODS.NEAR_GET_ACCOUNTS: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const accounts = await nearWallet.getAccounts({ topic });
return formatJsonRpcResult(id, accounts);
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTION: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const [signedTx] = await nearWallet.signTransactions({
chainId,
topic,
transactions: [transactions.Transaction.decode(
Buffer.from(request.params.transaction),
)]
});
return formatJsonRpcResult(id, signedTx.encode());
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const [transaction] = await nearWallet.createTransactions({
chainId,
transactions: [{
...params.request.params.transaction,
actions: params.request.params.transaction.actions.map(createAction),
}]
});
const result = await nearWallet.signAndSendTransaction({
chainId,
topic,
transaction,
});
return formatJsonRpcResult(id, result);
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTIONS: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const signedTxs = await nearWallet.signTransactions({
chainId,
topic,
transactions: params.request.params.transactions.map((tx: Uint8Array) => {
return transactions.Transaction.decode(Buffer.from(tx));
}),
});
return formatJsonRpcResult(id, signedTxs.map((x) => x.encode()));
}
case NEAR_SIGNING_METHODS.NEAR_VERIFY_OWNER: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const accounts = await nearWallet.getAllAccounts();
const account = accounts.find(acc => acc.accountId === params.request.params.accountId);
if (!account) {
throw new Error(`Did not find account with id: ${params.request.params.accountId}`);
}
if (!NEAR_TEST_CHAINS[chainId]) {
throw new Error("Invalid chain id");
}
const signer = new InMemorySigner(nearWallet.getKeyStore());
const networkId = chainId.split(':')[1];
const connection = Connection.fromConfig({
networkId,
provider: { type: 'JsonRpcProvider', args: { url: NEAR_TEST_CHAINS[chainId].rpc } },
signer
});
const blockInfo = await connection.provider.block({ finality: 'final' });
const publicKey = utils.PublicKey.from(account.publicKey);
const data = {
accountId: account.accountId,
message: params.request.params.message,
blockId: blockInfo.header.hash,
publicKey: Buffer.from(publicKey.data).toString('base64'),
keyType: publicKey.keyType
};
const encoded = new Uint8Array(Buffer.from(JSON.stringify(data)));
const signed = await signer.signMessage(encoded, account.accountId, networkId);
return formatJsonRpcResult(id, {
...data,
signature: Buffer.from(signed.signature).toString('base64'),
keyType: signed.publicKey.keyType
});
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS: {
console.log("approve", { id, params });
if (!chainId) {
throw new Error("Invalid chain id");
}
const transactions = await nearWallet.createTransactions({
chainId,
transactions: params.request.params.transactions.map((transaction: Transaction) => ({
...transaction,
actions: transaction.actions.map(createAction),
}))
});
const result = await nearWallet.signAndSendTransactions({
chainId,
topic,
transactions,
});
return formatJsonRpcResult(id, result);
}
default:
throw new Error(getSdkError("INVALID_METHOD").message)
}
}
export function rejectNearRequest(request: SignClientTypes.EventArguments['session_request']) {
const { id } = request
return formatJsonRpcError(id, getSdkError('USER_REJECTED_METHODS').message)
}

View File

@ -0,0 +1,21 @@
import { NearWallet } from "@/lib/NearLib";
export let nearAddresses: string[];
export let nearWallet: NearWallet;
/**
* Utilities
*/
export async function createOrRestoreNearWallet() {
// NEAR only supports dev accounts in testnet.
const wallet = await NearWallet.init("testnet");
const accounts = await wallet.getAllAccounts();
nearAddresses = accounts.map((x) => x.accountId);
nearWallet = wallet;
return {
nearWallet,
nearAddresses
}
}

View File

@ -6,13 +6,14 @@ import ModalStore from '@/store/ModalStore'
import { cosmosAddresses } from '@/utils/CosmosWalletUtil'
import { eip155Addresses } from '@/utils/EIP155WalletUtil'
import { polkadotAddresses } from '@/utils/PolkadotWalletUtil'
import { isCosmosChain, isEIP155Chain, isSolanaChain, isPolkadotChain } from '@/utils/HelperUtil'
import { isCosmosChain, isEIP155Chain, isSolanaChain, isPolkadotChain, isNearChain } from '@/utils/HelperUtil'
import { solanaAddresses } from '@/utils/SolanaWalletUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { SessionTypes } from '@walletconnect/types'
import { getSdkError } from '@walletconnect/utils'
import { Fragment, useState } from 'react'
import { nearAddresses } from '@/utils/NearWalletUtil'
export default function SessionProposalModal() {
const [selectedAccounts, setSelectedAccounts] = useState<Record<string, string[]>>({})
@ -122,6 +123,15 @@ export default function SessionProposalModal() {
chain={chain}
/>
)
} else if (isNearChain(chain)) {
return (
<ProposalSelectSection
addresses={nearAddresses}
selectedAddresses={selectedAccounts[chain]}
onSelect={onSelectAccount}
chain={chain}
/>
)
}
}

View File

@ -0,0 +1,195 @@
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 { approveNearRequest, rejectNearRequest } from '@/utils/NearRequestHandlerUtil'
import { signClient } from '@/utils/WalletConnectUtil'
import { NEAR_SIGNING_METHODS } from "@/data/NEARData";
import { transactions } from "near-api-js";
import { Button, Divider, Modal, Text } from '@nextui-org/react'
import { Fragment } from 'react'
export default function SessionSignNearModal() {
// 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
const formatTransaction = (transaction: Uint8Array) => {
const tx = transactions.Transaction.decode(Buffer.from(transaction));
return {
signerId: tx.signerId,
receiverId: tx.receiverId,
publicKey: tx.publicKey.toString(),
actions: tx.actions.map((action) => {
switch (action.enum) {
case "createAccount": {
return {
type: "CreateAccount",
params: action.createAccount
};
}
case "deployContract": {
return {
type: "DeployContract",
params: {
...action.deployContract,
args: Buffer.from(action.deployContract.code).toString(),
}
};
}
case "functionCall": {
return {
type: "FunctionCall",
params: {
...action.functionCall,
args: JSON.parse(Buffer.from(action.functionCall.args).toString()),
}
};
}
case "transfer": {
return {
type: "Transfer",
params: action.transfer
};
}
case "stake": {
return {
type: "Stake",
params: {
...action.stake,
publicKey: action.stake.publicKey.toString()
}
};
}
case "addKey": {
return {
type: "AddKey",
params: {
...action.addKey,
publicKey: action.addKey.publicKey.toString()
}
};
}
case "deleteKey": {
return {
type: "DeleteKey",
params: {
...action.deleteKey,
publicKey: action.deleteKey.publicKey.toString()
}
};
}
case "deleteAccount": {
return {
type: "DeleteAccount",
params: action.deleteAccount
};
}
default:
return {
type: action.enum,
params: {}
}
}
})
}
}
const formatParams = () => {
switch (params.request.method) {
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTION:
return {
...params,
request: {
...params.request,
params: {
...params.request.params,
transaction: formatTransaction(params.request.params.transaction),
}
}
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTIONS:
return {
...params,
request: {
...params.request,
params: {
...params.request.params,
transactions: params.request.params.transactions.map(formatTransaction),
}
}
}
default:
return params;
}
}
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
const response = await approveNearRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
}
}
// Handle reject action
async function onReject() {
if (requestEvent) {
const response = rejectNearRequest(requestEvent)
await signClient.respond({
topic,
response
})
ModalStore.close()
}
}
return (
<Fragment>
<RequestModalContainer title="NEAR">
<ProjectInfoCard metadata={requestSession.peer.metadata} />
<Divider y={2} />
<RequestDetailsCard
chains={[chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<Divider y={2} />
<RequestDataCard data={formatParams()} />
<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>
)
}

View File

@ -1015,6 +1015,21 @@
"@json-rpc-tools/types" "^1.7.6"
"@pedrouid/environment" "^1.0.1"
"@near-wallet-selector/core@7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@near-wallet-selector/core/-/core-7.0.2.tgz#0646e73628a5b4625c97a776090ac9f15aca547b"
integrity sha512-JaHYjc6YOf2OPq5I13Yps4dLcXL8g8C0q3gIyWTaT5hc7WDQEOxCL1laxFSkSGwz6b1+jpQ1jak/bo6zU3a6Qw==
dependencies:
rxjs "^7.5.5"
"@near-wallet-selector/wallet-utils@^7.0.2":
version "7.0.2"
resolved "https://registry.yarnpkg.com/@near-wallet-selector/wallet-utils/-/wallet-utils-7.0.2.tgz#6208a0c97408bdb90152626db47cd64a8cb39d14"
integrity sha512-9QjMNZRTt2HIdSmsMu/34t/MmnAjh9WE0HldITOTUTT1f7FXhtnmxj0jjFvNhkk1midh2IRHrboSRrZIWXPOsQ==
dependencies:
"@near-wallet-selector/core" "7.0.2"
bn.js "^5.2.0"
"@next/env@12.1.5":
version "12.1.5"
resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.5.tgz#a21ba6708022d630402ca2b340316e69a0296dfc"
@ -2587,6 +2602,11 @@ bl@^4.0.3:
inherits "^2.0.4"
readable-stream "^3.4.0"
bn.js@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002"
integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==
bn.js@^4.11.8, bn.js@^4.11.9:
version "4.12.0"
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
@ -2597,6 +2617,15 @@ bn.js@^5.0.0, bn.js@^5.2.0, bn.js@^5.2.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70"
integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==
borsh@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.6.0.tgz#a7c9eeca6a31ca9e0607cb49f329cb659eb791e1"
integrity sha512-sl5k89ViqsThXQpYa9XDtz1sBl3l1lI313cFUY1HKr+wvMILnb+58xpkqTNrYbelh99dY7K8usxoCusQmqix9Q==
dependencies:
bn.js "^5.2.0"
bs58 "^4.0.0"
text-encoding-utf-8 "^1.0.2"
borsh@^0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a"
@ -2713,6 +2742,11 @@ caniuse-lite@^1.0.30001283:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001343.tgz#8e1107e30d9a4d2f63782b48ae0a3ce34e2f9c2a"
integrity sha512-8KeCrAtPMabo/XW14B+R9sZYoClx1n0b+WYgwDKZPtWR3TcdvWzdSy7mPyFEmR5WU1St9v1PW6sdO5dkFOEzfA==
capability@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/capability/-/capability-0.2.5.tgz#51ad87353f1936ffd77f2f21c74633a4dea88801"
integrity sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==
chalk@2.4.2, chalk@^2.0.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@ -2981,6 +3015,16 @@ delegates@^1.0.0:
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
depd@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
detect-browser@5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca"
@ -3057,6 +3101,15 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1:
dependencies:
once "^1.4.0"
error-polyfill@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/error-polyfill/-/error-polyfill-0.1.3.tgz#df848b61ad8834f7a5db69a70b9913df86721d15"
integrity sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==
dependencies:
capability "^0.2.5"
o3 "^1.0.3"
u3 "^0.1.1"
es-abstract@^1.19.0, es-abstract@^1.19.1, es-abstract@^1.19.2, es-abstract@^1.19.5:
version "1.20.1"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.20.1.tgz#027292cd6ef44bd12b1913b828116f54787d1814"
@ -3756,6 +3809,17 @@ hoist-non-react-statics@^3.0.0:
dependencies:
react-is "^16.7.0"
http-errors@^1.7.2:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.1"
ieee754@^1.1.13, ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
@ -3787,7 +3851,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -4001,6 +4065,11 @@ joycon@^2.2.5:
resolved "https://registry.yarnpkg.com/joycon/-/joycon-2.2.5.tgz#8d4cf4cbb2544d7b7583c216fcdfec19f6be1615"
integrity sha512-YqvUxoOcVPnCp0VU1/56f+iKSdvIRJYPznH22BdXV3xMk75SFXhWeJkZ8C9XxUWt1b5x2X1SxuFygW1U0FmkEQ==
js-sha256@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==
js-sha3@0.8.0, js-sha3@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
@ -4265,6 +4334,11 @@ multiformats@^9.4.2:
resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-9.6.5.tgz#f2d894a26664b454a90abf5a8911b7e39195db80"
integrity sha512-vMwf/FUO+qAPvl3vlSZEgEVFY/AxeZq5yg761ScF3CZsXgmTi/HGkicUiNN0CI4PW8FiY2P0OLklOcmQjdQJhw==
mustache@^4.0.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64"
integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
nan@^2.13.2:
version "2.16.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.16.0.tgz#664f43e45460fb98faf00edca0bb0d7b8dce7916"
@ -4285,6 +4359,23 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
near-api-js@^0.44.2:
version "0.44.2"
resolved "https://registry.yarnpkg.com/near-api-js/-/near-api-js-0.44.2.tgz#e451f68f2c56bd885c7b918db5818a3e6e9423d0"
integrity sha512-eMnc4V+geggapEUa3nU2p8HSHn/njtloI4P2mceHQWO8vDE1NGpnAw8FuTBrLmXSgIv9m6oocgFc9t3VNf5zwg==
dependencies:
bn.js "5.2.0"
borsh "^0.6.0"
bs58 "^4.0.0"
depd "^2.0.0"
error-polyfill "^0.1.3"
http-errors "^1.7.2"
js-sha256 "^0.9.0"
mustache "^4.0.0"
node-fetch "^2.6.1"
text-encoding-utf-8 "^1.0.2"
tweetnacl "^1.0.1"
next@12.1.5:
version "12.1.5"
resolved "https://registry.yarnpkg.com/next/-/next-12.1.5.tgz#7a07687579ddce61ee519493e1c178d83abac063"
@ -4320,7 +4411,7 @@ 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.7, node-fetch@^2.6.1:
version "2.6.7"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad"
integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==
@ -4347,6 +4438,13 @@ number-is-nan@^1.0.0:
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
o3@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/o3/-/o3-1.0.3.tgz#192ce877a882dfa6751f0412a865fafb2da1dac0"
integrity sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==
dependencies:
capability "^0.2.5"
object-assign@^4.1.0, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -4914,6 +5012,13 @@ run-parallel@^1.1.9:
dependencies:
queue-microtask "^1.2.2"
rxjs@^7.5.5:
version "7.5.6"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc"
integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw==
dependencies:
tslib "^2.1.0"
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
@ -4973,6 +5078,11 @@ set-blocking@~2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8:
version "2.4.11"
resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
@ -5070,6 +5180,11 @@ split2@^3.1.1:
dependencies:
readable-stream "^3.0.0"
"statuses@>= 1.5.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
@ -5285,6 +5400,11 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
toidentifier@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
@ -5324,7 +5444,7 @@ tunnel-agent@^0.6.0:
dependencies:
safe-buffer "^5.0.1"
tweetnacl@1.x.x, tweetnacl@^1.0.0, tweetnacl@^1.0.3:
tweetnacl@1.x.x, tweetnacl@^1.0.0, tweetnacl@^1.0.1, tweetnacl@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
@ -5358,6 +5478,11 @@ typescript@4.6.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9"
integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==
u3@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/u3/-/u3-0.1.1.tgz#5f52044f42ee76cd8de33148829e14528494b73b"
integrity sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==
uint8arrays@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-3.1.0.tgz#8186b8eafce68f28bd29bd29d683a311778901e2"