style: run prettier on all files

This commit is contained in:
Ben Kremer 2022-10-18 12:37:52 +02:00
parent fcec9e477a
commit b31232f2f6
21 changed files with 429 additions and 369 deletions

View File

@ -2,7 +2,7 @@
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
distDir: 'build'
distDir: "build",
};
module.exports = nextConfig;

View File

@ -1,25 +1,27 @@
import { JsonRpcRequest } from "@walletconnect/jsonrpc-utils";
import { ChainsMap } from "caip-api";
import { NamespaceMetadata, ChainMetadata, ChainRequestRender } from "../helpers";
import {
NamespaceMetadata,
ChainMetadata,
ChainRequestRender,
} from "../helpers";
export const NearMetadata: NamespaceMetadata = {
"testnet": {
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
testnet: {
name: "NEAR Testnet",
id: "near:testnet",
rpc: ["https://rpc.testnet.near.org"],
slip44: 397,
testnet: true,
},
};
@ -32,7 +34,9 @@ export function getChainMetadata(chainId: string): ChainMetadata {
return metadata;
}
export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRender[] {
export function getChainRequestRender(
request: JsonRpcRequest
): ChainRequestRender[] {
let params = [{ label: "Method", value: request.method }];
switch (request.method) {
@ -47,4 +51,4 @@ export function getChainRequestRender(request: JsonRpcRequest): ChainRequestRend
break;
}
return params;
}
}

View File

@ -20,7 +20,7 @@ const SelectContainer = styled.select`
position: absolute;
bottom: 40px;
left: 50px;
direction: ltr;
direction: ltr;
unicode-bidi: embed;
`;
@ -30,24 +30,34 @@ const SelectOption = styled.option`
const Dropdown = (props: DropdownProps) => {
const { relayerRegion, setRelayerRegion } = props;
const [openSelect, setOpenSelect] = useState(false)
const selectRef = React.createRef()
const [openSelect, setOpenSelect] = useState(false);
const selectRef = React.createRef();
const openDropdown = () => {
setOpenSelect(!openSelect)
}
setOpenSelect(!openSelect);
};
return (
<div style={{paddingTop: 72, width: 250, display: "flex", justifyContent: "center", alignItems: "flex-end"}}>
<button onClick={openDropdown} style={{background: "transparent"}}>
<Icon size={30} src={"/assets/settings.svg"} />
<div
style={{
paddingTop: 72,
width: 250,
display: "flex",
justifyContent: "center",
alignItems: "flex-end",
}}
>
<button onClick={openDropdown} style={{ background: "transparent" }}>
<Icon size={30} src={"/assets/settings.svg"} />
</button>
{openSelect && (
{openSelect && (
<SelectContainer
value={relayerRegion}
onChange={(e) => setRelayerRegion?.(e?.target?.value)}
>
<option selected disabled>Relayer Region:</option>
<option selected disabled>
Relayer Region:
</option>
{REGIONALIZED_RELAYER_ENDPOINTS.map((e, i) => {
return (
<SelectOption key={i} value={e.value}>
@ -55,8 +65,8 @@ const Dropdown = (props: DropdownProps) => {
</SelectOption>
);
})}
</SelectContainer>)}
</SelectContainer>
)}
</div>
);
};

View File

@ -20,7 +20,7 @@ export const DEFAULT_TEST_CHAINS = [
"eip155:44787",
"solana:8E9rvCKLFQia2Y35HXjjpWzj8weVo44K",
"polkadot:e143f23803ac50e8f6f8e62695d1ce9e",
"near:testnet"
"near:testnet",
];
export const DEFAULT_CHAINS = [...DEFAULT_MAIN_CHAINS, ...DEFAULT_TEST_CHAINS];
@ -86,12 +86,12 @@ 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_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 {}

View File

@ -238,7 +238,7 @@ export function ClientContextProvider({
const createClient = useCallback(async () => {
try {
setIsInitializing(true);
const _client = await Client.init({
logger: DEFAULT_LOGGER,
relayUrl: relayerRegion,

View File

@ -628,13 +628,19 @@ export function JsonRpcContextProvider({
const polkadotRpc = {
testSignTransaction: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
async (
chainId: string,
address: string
): Promise<IFormattedRpcResponse> => {
// Below example is a scale encoded payload for system.remark("this is a test wallet-connect remark") transaction.
// decode url: https://polkadot.js.org/apps/?rpc=wss%3A%2F%2Frpc.polkadot.io#/extrinsics/decode/0x00019074686973206973206120746573742077616c6c65742d636f6e6e6563742072656d61726b
const transactionPayload =
"0x00019074686973206973206120746573742077616c6c65742d636f6e6e6563742072656d61726b05010000222400000d00000091b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3dc1f37ce7899cf20f63f5ea343f33e9e7b229c7e245049c2a7afc236861fc8b4";
try {
const result = await client!.request<{ payload: string; signature: string }>({
const result = await client!.request<{
payload: string;
signature: string;
}>({
chainId,
topic: session!.topic,
request: {
@ -645,11 +651,15 @@ export function JsonRpcContextProvider({
},
},
});
// sr25519 signatures need to wait for WASM to load
await cryptoWaitReady();
const { isValid: valid } = signatureVerify(transactionPayload, result.signature, address);
const { isValid: valid } = signatureVerify(
transactionPayload,
result.signature,
address
);
return {
method: DEFAULT_POLKADOT_METHODS.POLKADOT_SIGN_TRANSACTION,
address,
@ -659,11 +669,13 @@ export function JsonRpcContextProvider({
} catch (error: any) {
throw new Error(error);
}
},
}
),
testSignMessage: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
async (
chainId: string,
address: string
): Promise<IFormattedRpcResponse> => {
const message = `This is an example message to be signed - ${Date.now()}`;
try {
@ -681,7 +693,11 @@ export function JsonRpcContextProvider({
// sr25519 signatures need to wait for WASM to load
await cryptoWaitReady();
const { isValid: valid } = signatureVerify(message, result.signature, address);
const { isValid: valid } = signatureVerify(
message,
result.signature,
address
);
return {
method: DEFAULT_POLKADOT_METHODS.POLKADOT_SIGN_MESSAGE,
@ -692,7 +708,7 @@ export function JsonRpcContextProvider({
} catch (error: any) {
throw new Error(error);
}
},
}
),
};
@ -700,8 +716,11 @@ export function JsonRpcContextProvider({
const nearRpc = {
testSignAndSendTransaction: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION
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,
@ -711,16 +730,18 @@ export function JsonRpcContextProvider({
transaction: {
signerId: address,
receiverId: "guest-book.testnet",
actions: [{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect!" },
gas: "30000000000000",
deposit: "0",
}
}]
}
actions: [
{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect!" },
gas: "30000000000000",
deposit: "0",
},
},
],
},
},
},
});
@ -734,8 +755,11 @@ export function JsonRpcContextProvider({
}
),
testSignAndSendTransactions: _createJsonRpcRequestHandler(
async (chainId: string, address: string): Promise<IFormattedRpcResponse> => {
const method = DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS
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,
@ -746,31 +770,35 @@ export function JsonRpcContextProvider({
{
signerId: address,
receiverId: "guest-book.testnet",
actions: [{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect! (1/2)" },
gas: "30000000000000",
deposit: "0",
}
}]
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",
}
}]
}
actions: [
{
type: "FunctionCall",
params: {
methodName: "addMessage",
args: { text: "Hello from Wallet Connect! (2/2)" },
gas: "30000000000000",
deposit: "0",
},
},
],
},
],
}
},
},
});
@ -778,7 +806,9 @@ export function JsonRpcContextProvider({
method,
address,
valid: true,
result: JSON.stringify((result as any).map((r: any) => r.transaction)),
result: JSON.stringify(
(result as any).map((r: any) => r.transaction)
),
};
}
),

View File

@ -214,17 +214,29 @@ const Home: NextPage = () => {
};
const getNearActions = (): AccountAction[] => {
const onSignAndSendTransaction = async (chainId: string, address: string) => {
const onSignAndSendTransaction = async (
chainId: string,
address: string
) => {
openRequestModal();
await nearRpc.testSignAndSendTransaction(chainId, address);
};
const onSignAndSendTransactions = async (chainId: string, address: string) => {
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 },
{
method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION,
callback: onSignAndSendTransaction,
},
{
method: DEFAULT_NEAR_METHODS.NEAR_SIGN_AND_SEND_TRANSACTIONS,
callback: onSignAndSendTransactions,
},
];
};
@ -305,9 +317,9 @@ const Home: NextPage = () => {
{"Connect"}
</SConnectButton>
<Dropdown
relayerRegion={relayerRegion}
setRelayerRegion={setRelayerRegion}
/>
relayerRegion={relayerRegion}
setRelayerRegion={setRelayerRegion}
/>
</SButtonContainer>
</SLanding>
) : (

View File

@ -5,7 +5,8 @@
"dev": "next dev -p 3001",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"prettier:write": "prettier --write '**/*.{js,ts,jsx,tsx}'"
},
"dependencies": {
"@cosmjs/amino": "0.28.4",

View File

@ -25,4 +25,3 @@ export default function AccountPicker() {
</select>
)
}

View File

@ -17,7 +17,7 @@ const CHAIN_METADATA = {
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS,
...NEAR_TEST_CHAINS,
...NEAR_TEST_CHAINS
}
/**

View File

@ -17,7 +17,7 @@ const CHAIN_METADATA = {
...EIP155_MAINNET_CHAINS,
...EIP155_TEST_CHAINS,
...SOLANA_TEST_CHAINS,
...NEAR_TEST_CHAINS,
...NEAR_TEST_CHAINS
}
/**

View File

@ -16,18 +16,17 @@ export const NEAR_MAINNET_CHAINS = {
}
interface NearTestChains {
[key: string]: ChainMetadata;
[key: string]: ChainMetadata
}
type ChainMetadata = {
chainId: string;
name: string;
logo: string;
rgb: string;
rpc: string;
chainId: string
name: string
logo: string
rgb: string
rpc: string
}
export const NEAR_TEST_CHAINS: NearTestChains = {
'near:testnet': {
chainId: 'testnet',
@ -35,7 +34,7 @@ export const NEAR_TEST_CHAINS: NearTestChains = {
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 }
@ -51,5 +50,5 @@ export const NEAR_SIGNING_METHODS = {
NEAR_SIGN_AND_SEND_TRANSACTION: 'near_signAndSendTransaction',
NEAR_SIGN_TRANSACTIONS: 'near_signTransactions',
NEAR_SIGN_AND_SEND_TRANSACTIONS: 'near_signAndSendTransactions',
NEAR_VERIFY_OWNER: 'near_verifyOwner',
}
NEAR_VERIFY_OWNER: 'near_verifyOwner'
}

View File

@ -28,4 +28,4 @@ export const REGIONALIZED_RELAYER_ENDPOINTS: RelayerType[] = [
value: 'wss://ap-southeast-1.relay.walletconnect.com/',
label: 'Asia Pacific'
}
]
]

View File

@ -3,176 +3,178 @@ import {
providers,
keyStores as nearKeyStores,
transactions as nearTransactions,
utils,
} from "near-api-js";
import { AccessKeyView } from "near-api-js/lib/providers/provider";
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";
import { signClient } from '@/utils/WalletConnectUtil'
import { NEAR_TEST_CHAINS, TNearChain } from '@/data/NEARData'
const MAX_ACCOUNTS = 2;
const MAX_ACCOUNTS = 2
interface Account {
accountId: string;
publicKey: string;
accountId: string
publicKey: string
}
interface Transaction {
signerId: string;
receiverId: string;
actions: Array<nearTransactions.Action>;
signerId: string
receiverId: string
actions: Array<nearTransactions.Action>
}
interface CreateTransactionsParams {
chainId: string;
transactions: Array<Transaction>;
chainId: string
transactions: Array<Transaction>
}
interface GetAccountsParams {
topic: string;
topic: string
}
interface SignInParams {
chainId: string;
topic: string;
permission: nearTransactions.FunctionCallPermission;
accounts: Array<Account>;
chainId: string
topic: string
permission: nearTransactions.FunctionCallPermission
accounts: Array<Account>
}
interface SignOutParams {
chainId: string;
topic: string;
accounts: Array<Account>;
chainId: string
topic: string
accounts: Array<Account>
}
interface SignTransactionsParams {
chainId: string;
topic: string;
transactions: Array<nearTransactions.Transaction>;
chainId: string
topic: string
transactions: Array<nearTransactions.Transaction>
}
interface SignAndSendTransactionParams {
chainId: string;
topic: string;
transaction: nearTransactions.Transaction;
chainId: string
topic: string
transaction: nearTransactions.Transaction
}
interface SignAndSendTransactionsParams {
chainId: string;
topic: string;
transactions: Array<nearTransactions.Transaction>;
chainId: string
topic: string
transactions: Array<nearTransactions.Transaction>
}
export class NearWallet {
private networkId: string;
private keyStore: nearKeyStores.KeyStore;
private networkId: string
private keyStore: nearKeyStores.KeyStore
static async init(networkId: string) {
const keyStore = new nearKeyStores.BrowserLocalStorageKeyStore();
const accounts = await keyStore.getAccounts(networkId);
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();
const { accountId, keyPair } = await NearWallet.createDevAccount()
await keyStore.setKey(networkId, accountId, keyPair);
await keyStore.setKey(networkId, accountId, keyPair)
}
return new NearWallet(networkId, keyStore);
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();
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" },
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
newAccountId: accountId,
newAccountPublicKey: publicKey,
}),
})
.then((res) => {
if (res.ok) {
return {
accountId,
keyPair
};
newAccountPublicKey: publicKey
})
}).then(res => {
if (res.ok) {
return {
accountId,
keyPair
}
}
throw new Error("Failed to create NEAR dev account");
});
throw new Error('Failed to create NEAR dev account')
})
}
private constructor(networkId: string, keyStore: nearKeyStores.KeyStore) {
this.networkId = networkId;
this.keyStore = keyStore;
this.networkId = networkId
this.keyStore = keyStore
}
getKeyStore() {
return this.keyStore;
return this.keyStore
}
// Retrieve all imported accounts from wallet.
async getAllAccounts(): Promise<Array<Account>> {
const accountIds = await this.keyStore.getAccounts(this.networkId);
const accountIds = await this.keyStore.getAccounts(this.networkId)
return Promise.all(
accountIds.map(async (accountId) => {
const keyPair = await this.keyStore.getKey(this.networkId, accountId);
accountIds.map(async accountId => {
const keyPair = await this.keyStore.getKey(this.networkId, accountId)
return {
accountId,
publicKey: keyPair.getPublicKey().toString(),
};
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];
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);
});
return validAccountIds.includes(accountId)
})
}
private isTransactionsValid(topic: string, transactions: Array<nearTransactions.Transaction>) {
const accounts = transactions.map(({ signerId }) => ({ accountId: signerId }));
const accounts = transactions.map(({ signerId }) => ({ accountId: signerId }))
return this.isAccountsValid(topic, accounts);
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> = [];
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(),
]);
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
);
const transaction = transactions[i]
const account = accounts.find(x => x.accountId === transaction.signerId)
if (!account) {
throw new Error("Invalid signer id");
throw new Error('Invalid signer id')
}
const accessKey = await provider.query<AccessKeyView>({
request_type: "view_access_key",
finality: "final",
request_type: 'view_access_key',
finality: 'final',
account_id: transaction.signerId,
public_key: account.publicKey,
});
public_key: account.publicKey
})
txs.push(
nearTransactions.createTransaction(
@ -183,103 +185,103 @@ export class NearWallet {
transaction.actions,
utils.serialize.base_decode(block.header.hash)
)
);
)
}
return txs;
return txs
}
async getAccounts({ topic }: GetAccountsParams): Promise<Array<Account>> {
const session = signClient.session.get(topic);
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);
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");
throw new Error('Invalid accounts')
}
const result: Array<Account> = [];
const result: Array<Account> = []
for (let i = 0; i < accounts.length; i += 1) {
const account = accounts[i];
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
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 });
await this.signAndSendTransaction({ chainId, topic, transaction })
result.push(account);
result.push(account)
} catch (err) {
console.log(`Failed to create FunctionCall access key for ${account.accountId}`);
console.error(err);
console.log(`Failed to create FunctionCall access key for ${account.accountId}`)
console.error(err)
}
}
return result;
return result
}
async signOut({ chainId, topic, accounts }: SignOutParams): Promise<Array<Account>> {
if (!this.isAccountsValid(topic, accounts)) {
throw new Error("Invalid accounts");
throw new Error('Invalid accounts')
}
const result: Array<Account> = [];
const result: Array<Account> = []
for (let i = 0; i < accounts.length; i += 1) {
const account = accounts[i];
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)
)
]
}]
});
transactions: [
{
signerId: account.accountId,
receiverId: account.accountId,
actions: [nearTransactions.deleteKey(utils.PublicKey.from(account.publicKey))]
}
]
})
await this.signAndSendTransaction({ chainId, topic, transaction });
await this.signAndSendTransaction({ chainId, topic, transaction })
} catch (err) {
console.log(`Failed to remove FunctionCall access key for ${account.accountId}`);
console.error(err);
console.log(`Failed to remove FunctionCall access key for ${account.accountId}`)
console.error(err)
result.push(account);
result.push(account)
}
}
return result;
return result
}
async signTransactions({
@ -287,28 +289,28 @@ export class NearWallet {
topic,
transactions
}: SignTransactionsParams): Promise<Array<nearTransactions.SignedTransaction>> {
const networkId = chainId.split(":")[1];
const signer = new InMemorySigner(this.keyStore);
const signedTxs: 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");
throw new Error('Invalid transactions')
}
for (let i = 0; i < transactions.length; i += 1) {
const transaction = transactions[i];
const transaction = transactions[i]
const [, signedTx] = await nearTransactions.signTransaction(
transaction,
signer,
transaction.signerId,
networkId
);
)
signedTxs.push(signedTx);
signedTxs.push(signedTx)
}
return signedTxs;
return signedTxs
}
async signAndSendTransaction({
@ -316,14 +318,14 @@ export class NearWallet {
topic,
transaction
}: SignAndSendTransactionParams): Promise<providers.FinalExecutionOutcome> {
const provider = new providers.JsonRpcProvider(NEAR_TEST_CHAINS[chainId as TNearChain].rpc);
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);
return provider.sendTransaction(signedTx)
}
async signAndSendTransactions({
@ -331,16 +333,16 @@ export class NearWallet {
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> = [];
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];
const signedTx = signedTxs[i]
results.push(await provider.sendTransaction(signedTx));
results.push(await provider.sendTransaction(signedTx))
}
return results;
return results
}
}
}

View File

@ -12,9 +12,8 @@ import { useSnapshot } from 'valtio'
import { NEAR_TEST_CHAINS } from '@/data/NEARData'
export default function HomePage() {
const { testNets, eip155Address, cosmosAddress, solanaAddress, polkadotAddress, nearAddress } = useSnapshot(
SettingsStore.state
)
const { testNets, eip155Address, cosmosAddress, solanaAddress, polkadotAddress, nearAddress } =
useSnapshot(SettingsStore.state)
return (
<Fragment>

View File

@ -44,12 +44,11 @@ export default function SettingsPage() {
<Divider y={2} />
<Row justify="space-between" align="center">
<Text h4 css={{ marginBottom: '$5' }}>
Relayer Region
</Text>
<RelayRegionPicker/>
</Text>
<RelayRegionPicker />
</Row>
<Divider y={2} />

View File

@ -105,7 +105,7 @@ export function isPolkadotChain(chain: string) {
/**
* Check if chain is part of NEAR standard
*/
export function isNearChain(chain: string) {
export function isNearChain(chain: string) {
return chain.includes('near')
}

View File

@ -3,9 +3,9 @@ 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";
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']
@ -15,132 +15,135 @@ export async function approveNearRequest(
switch (request.method) {
case NEAR_SIGNING_METHODS.NEAR_SIGN_IN: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const accounts = await nearWallet.signIn({
chainId,
topic,
permission: request.params.permission,
accounts: request.params.accounts,
});
accounts: request.params.accounts
})
return formatJsonRpcResult(id, accounts);
return formatJsonRpcResult(id, accounts)
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_OUT: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const accounts = await nearWallet.signOut({
chainId,
topic,
accounts: request.params.accounts
});
})
return formatJsonRpcResult(id, accounts);
return formatJsonRpcResult(id, accounts)
}
case NEAR_SIGNING_METHODS.NEAR_GET_ACCOUNTS: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const accounts = await nearWallet.getAccounts({ topic });
const accounts = await nearWallet.getAccounts({ topic })
return formatJsonRpcResult(id, accounts);
return formatJsonRpcResult(id, accounts)
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTION: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const [signedTx] = await nearWallet.signTransactions({
chainId,
topic,
transactions: [transactions.Transaction.decode(
Buffer.from(request.params.transaction),
)]
});
transactions: [transactions.Transaction.decode(Buffer.from(request.params.transaction))]
})
return formatJsonRpcResult(id, signedTx.encode());
return formatJsonRpcResult(id, signedTx.encode())
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_AND_SEND_TRANSACTION: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
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),
}]
});
transactions: [
{
...params.request.params.transaction,
actions: params.request.params.transaction.actions.map(createAction)
}
]
})
const result = await nearWallet.signAndSendTransaction({
chainId,
topic,
transaction,
});
transaction
})
return formatJsonRpcResult(id, result);
return formatJsonRpcResult(id, result)
}
case NEAR_SIGNING_METHODS.NEAR_SIGN_TRANSACTIONS: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
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 transactions.Transaction.decode(Buffer.from(tx))
})
})
return formatJsonRpcResult(id, signedTxs.map((x) => x.encode()));
return formatJsonRpcResult(
id,
signedTxs.map(x => x.encode())
)
}
case NEAR_SIGNING_METHODS.NEAR_VERIFY_OWNER: {
console.log("approve", { id, params });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const accounts = await nearWallet.getAllAccounts();
const account = accounts.find(acc => acc.accountId === params.request.params.accountId);
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}`);
throw new Error(`Did not find account with id: ${params.request.params.accountId}`)
}
if (!NEAR_TEST_CHAINS[chainId]) {
throw new Error("Invalid chain id");
throw new Error('Invalid chain id')
}
const signer = new InMemorySigner(nearWallet.getKeyStore());
const networkId = chainId.split(':')[1];
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 blockInfo = await connection.provider.block({ finality: 'final' })
const publicKey = utils.PublicKey.from(account.publicKey)
const data = {
accountId: account.accountId,
@ -148,42 +151,42 @@ export async function approveNearRequest(
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);
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 });
console.log('approve', { id, params })
if (!chainId) {
throw new Error("Invalid chain id");
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),
actions: transaction.actions.map(createAction)
}))
});
})
const result = await nearWallet.signAndSendTransactions({
chainId,
topic,
transactions,
});
transactions
})
return formatJsonRpcResult(id, result);
return formatJsonRpcResult(id, result)
}
default:
throw new Error(getSdkError("INVALID_METHOD").message)
throw new Error(getSdkError('INVALID_METHOD').message)
}
}

View File

@ -1,21 +1,21 @@
import { NearWallet } from "@/lib/NearLib";
import { NearWallet } from '@/lib/NearLib'
export let nearAddresses: string[];
export let nearWallet: NearWallet;
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();
const wallet = await NearWallet.init('testnet')
const accounts = await wallet.getAllAccounts()
nearAddresses = accounts.map((x) => x.accountId);
nearWallet = wallet;
nearAddresses = accounts.map(x => x.accountId)
nearWallet = wallet
return {
nearWallet,
nearAddresses
}
}
}

View File

@ -6,7 +6,13 @@ 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, isNearChain } 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'

View File

@ -6,8 +6,8 @@ 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 { 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'
@ -26,76 +26,76 @@ export default function SessionSignNearModal() {
const { request, chainId } = params
const formatTransaction = (transaction: Uint8Array) => {
const tx = transactions.Transaction.decode(Buffer.from(transaction));
const tx = transactions.Transaction.decode(Buffer.from(transaction))
return {
signerId: tx.signerId,
receiverId: tx.receiverId,
publicKey: tx.publicKey.toString(),
actions: tx.actions.map((action) => {
actions: tx.actions.map(action => {
switch (action.enum) {
case "createAccount": {
case 'createAccount': {
return {
type: "CreateAccount",
type: 'CreateAccount',
params: action.createAccount
};
}
}
case "deployContract": {
case 'deployContract': {
return {
type: "DeployContract",
type: 'DeployContract',
params: {
...action.deployContract,
args: Buffer.from(action.deployContract.code).toString(),
args: Buffer.from(action.deployContract.code).toString()
}
};
}
}
case "functionCall": {
case 'functionCall': {
return {
type: "FunctionCall",
type: 'FunctionCall',
params: {
...action.functionCall,
args: JSON.parse(Buffer.from(action.functionCall.args).toString()),
args: JSON.parse(Buffer.from(action.functionCall.args).toString())
}
};
}
}
case "transfer": {
case 'transfer': {
return {
type: "Transfer",
type: 'Transfer',
params: action.transfer
};
}
}
case "stake": {
case 'stake': {
return {
type: "Stake",
type: 'Stake',
params: {
...action.stake,
publicKey: action.stake.publicKey.toString()
}
};
}
}
case "addKey": {
case 'addKey': {
return {
type: "AddKey",
type: 'AddKey',
params: {
...action.addKey,
publicKey: action.addKey.publicKey.toString()
}
};
}
}
case "deleteKey": {
case 'deleteKey': {
return {
type: "DeleteKey",
type: 'DeleteKey',
params: {
...action.deleteKey,
publicKey: action.deleteKey.publicKey.toString()
}
};
}
}
case "deleteAccount": {
case 'deleteAccount': {
return {
type: "DeleteAccount",
type: 'DeleteAccount',
params: action.deleteAccount
};
}
}
default:
return {
@ -116,7 +116,7 @@ export default function SessionSignNearModal() {
...params.request,
params: {
...params.request.params,
transaction: formatTransaction(params.request.params.transaction),
transaction: formatTransaction(params.request.params.transaction)
}
}
}
@ -127,16 +127,15 @@ export default function SessionSignNearModal() {
...params.request,
params: {
...params.request.params,
transactions: params.request.params.transactions.map(formatTransaction),
transactions: params.request.params.transactions.map(formatTransaction)
}
}
}
default:
return params;
return params
}
}
// Handle approve action (logic varies based on request method)
async function onApprove() {
if (requestEvent) {
@ -168,10 +167,7 @@ export default function SessionSignNearModal() {
<Divider y={2} />
<RequestDetailsCard
chains={[chainId ?? '']}
protocol={requestSession.relay.protocol}
/>
<RequestDetailsCard chains={[chainId ?? '']} protocol={requestSession.relay.protocol} />
<Divider y={2} />