PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/near-api-js/lib
Просмотр файла: wallet-account.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectedWalletAccount = exports.WalletAccount = exports.WalletConnection = void 0;
/**
* The classes in this module are used in conjunction with the {@link BrowserLocalStorageKeyStore}. This module exposes two classes:
* * {@link WalletConnection} which redirects users to {@link https://docs.near.org/docs/tools/near-wallet | NEAR Wallet} for key management.
* * {@link ConnectedWalletAccount} is an {@link Account} implementation that uses {@link WalletConnection} to get keys
*
* @module walletAccount
*/
const depd_1 = __importDefault(require("depd"));
const account_1 = require("./account");
const transaction_1 = require("./transaction");
const utils_1 = require("./utils");
const borsh_1 = require("borsh");
const borsh_2 = require("borsh");
const LOGIN_WALLET_URL_SUFFIX = '/login/';
const MULTISIG_HAS_METHOD = 'add_request_and_confirm';
const LOCAL_STORAGE_KEY_SUFFIX = '_wallet_auth_key';
const PENDING_ACCESS_KEY_PREFIX = 'pending_key'; // browser storage key for a pending access key (i.e. key has been generated but we are not sure it was added yet)
/**
* This class is used in conjunction with the {@link BrowserLocalStorageKeyStore}.
* It redirects users to {@link https://docs.near.org/docs/tools/near-wallet | NEAR Wallet} for key management.
*
* @example {@link https://docs.near.org/docs/develop/front-end/naj-quick-reference#wallet}
* @example
* ```js
* // create new WalletConnection instance
* const wallet = new WalletConnection(near, 'my-app');
*
* // If not signed in redirect to the NEAR wallet to sign in
* // keys will be stored in the BrowserLocalStorageKeyStore
* if(!wallet.isSingnedIn()) return wallet.requestSignIn()
* ```
*/
class WalletConnection {
constructor(near, appKeyPrefix) {
this._near = near;
const authDataKey = appKeyPrefix + LOCAL_STORAGE_KEY_SUFFIX;
const authData = JSON.parse(window.localStorage.getItem(authDataKey));
this._networkId = near.config.networkId;
this._walletBaseUrl = near.config.walletUrl;
appKeyPrefix = appKeyPrefix || near.config.contractName || 'default';
this._keyStore = near.connection.signer.keyStore;
this._authData = authData || { allKeys: [] };
this._authDataKey = authDataKey;
if (!this.isSignedIn()) {
this._completeSignInWithAccessKey();
}
}
/**
* Returns true, if this WalletAccount is authorized with the wallet.
* @example
* ```js
* const wallet = new WalletConnection(near, 'my-app');
* wallet.isSignedIn();
* ```
*/
isSignedIn() {
return !!this._authData.accountId;
}
/**
* Returns authorized Account ID.
* @example
* ```js
* const wallet = new WalletConnection(near, 'my-app');
* wallet.getAccountId();
* ```
*/
getAccountId() {
return this._authData.accountId || '';
}
/**
* Redirects current page to the wallet authentication page.
* @param options An optional options object
* @param options.contractId The NEAR account where the contract is deployed
* @param options.successUrl URL to redirect upon success. Default: current url
* @param options.failureUrl URL to redirect upon failure. Default: current url
*
* @example
* ```js
* const wallet = new WalletConnection(near, 'my-app');
* // redirects to the NEAR Wallet
* wallet.requestSignIn({ contractId: 'account-with-deploy-contract.near' });
* ```
*/
async requestSignIn(contractIdOrOptions = {}, title, successUrl, failureUrl) {
let options;
if (typeof contractIdOrOptions === 'string') {
const deprecate = depd_1.default('requestSignIn(contractId, title)');
deprecate('`title` ignored; use `requestSignIn({ contractId, methodNames, successUrl, failureUrl })` instead');
options = { contractId: contractIdOrOptions, successUrl, failureUrl };
}
else {
options = contractIdOrOptions;
}
const currentUrl = new URL(window.location.href);
const newUrl = new URL(this._walletBaseUrl + LOGIN_WALLET_URL_SUFFIX);
newUrl.searchParams.set('success_url', options.successUrl || currentUrl.href);
newUrl.searchParams.set('failure_url', options.failureUrl || currentUrl.href);
if (options.contractId) {
/* Throws exception if contract account does not exist */
const contractAccount = await this._near.account(options.contractId);
await contractAccount.state();
newUrl.searchParams.set('contract_id', options.contractId);
const accessKey = utils_1.KeyPair.fromRandom('ed25519');
newUrl.searchParams.set('public_key', accessKey.getPublicKey().toString());
await this._keyStore.setKey(this._networkId, PENDING_ACCESS_KEY_PREFIX + accessKey.getPublicKey(), accessKey);
}
if (options.methodNames) {
options.methodNames.forEach(methodName => {
newUrl.searchParams.append('methodNames', methodName);
});
}
window.location.assign(newUrl.toString());
}
async requestSignTransactions(...args) {
if (Array.isArray(args[0])) {
const deprecate = depd_1.default('WalletConnection.requestSignTransactions(transactions, callbackUrl, meta)');
deprecate('use `WalletConnection.requestSignTransactions(RequestSignTransactionsOptions)` instead');
return this._requestSignTransactions({
transactions: args[0],
callbackUrl: args[1],
meta: args[2]
});
}
return this._requestSignTransactions(args[0]);
}
async _requestSignTransactions({ transactions, meta, callbackUrl }) {
const currentUrl = new URL(window.location.href);
const newUrl = new URL('sign', this._walletBaseUrl);
newUrl.searchParams.set('transactions', transactions
.map(transaction => borsh_2.serialize(transaction_1.SCHEMA, transaction))
.map(serialized => Buffer.from(serialized).toString('base64'))
.join(','));
newUrl.searchParams.set('callbackUrl', callbackUrl || currentUrl.href);
if (meta)
newUrl.searchParams.set('meta', meta);
window.location.assign(newUrl.toString());
}
/**
* @hidden
* Complete sign in for a given account id and public key. To be invoked by the app when getting a callback from the wallet.
*/
async _completeSignInWithAccessKey() {
const currentUrl = new URL(window.location.href);
const publicKey = currentUrl.searchParams.get('public_key') || '';
const allKeys = (currentUrl.searchParams.get('all_keys') || '').split(',');
const accountId = currentUrl.searchParams.get('account_id') || '';
// TODO: Handle errors during login
if (accountId) {
this._authData = {
accountId,
allKeys
};
window.localStorage.setItem(this._authDataKey, JSON.stringify(this._authData));
if (publicKey) {
await this._moveKeyFromTempToPermanent(accountId, publicKey);
}
}
currentUrl.searchParams.delete('public_key');
currentUrl.searchParams.delete('all_keys');
currentUrl.searchParams.delete('account_id');
currentUrl.searchParams.delete('meta');
currentUrl.searchParams.delete('transactionHashes');
window.history.replaceState({}, document.title, currentUrl.toString());
}
/**
* @hidden
* @param accountId The NEAR account owning the given public key
* @param publicKey The public key being set to the key store
*/
async _moveKeyFromTempToPermanent(accountId, publicKey) {
const keyPair = await this._keyStore.getKey(this._networkId, PENDING_ACCESS_KEY_PREFIX + publicKey);
await this._keyStore.setKey(this._networkId, accountId, keyPair);
await this._keyStore.removeKey(this._networkId, PENDING_ACCESS_KEY_PREFIX + publicKey);
}
/**
* Sign out from the current account
* @example
* walletAccount.signOut();
*/
signOut() {
this._authData = {};
window.localStorage.removeItem(this._authDataKey);
}
/**
* Returns the current connected wallet account
*/
account() {
if (!this._connectedAccount) {
this._connectedAccount = new ConnectedWalletAccount(this, this._near.connection, this._authData.accountId);
}
return this._connectedAccount;
}
}
exports.WalletConnection = WalletConnection;
exports.WalletAccount = WalletConnection;
/**
* {@link Account} implementation which redirects to wallet using {@link WalletConnection} when no local key is available.
*/
class ConnectedWalletAccount extends account_1.Account {
constructor(walletConnection, connection, accountId) {
super(connection, accountId);
this.walletConnection = walletConnection;
}
// Overriding Account methods
/**
* Sign a transaction by redirecting to the NEAR Wallet
* @see {@link WalletConnection.requestSignTransactions}
*/
signAndSendTransaction(...args) {
if (typeof args[0] === 'string') {
return this._signAndSendTransaction({ receiverId: args[0], actions: args[1] });
}
return this._signAndSendTransaction(args[0]);
}
async _signAndSendTransaction({ receiverId, actions, walletMeta, walletCallbackUrl = window.location.href }) {
const localKey = await this.connection.signer.getPublicKey(this.accountId, this.connection.networkId);
let accessKey = await this.accessKeyForTransaction(receiverId, actions, localKey);
if (!accessKey) {
throw new Error(`Cannot find matching key for transaction sent to ${receiverId}`);
}
if (localKey && localKey.toString() === accessKey.public_key) {
try {
return await super.signAndSendTransaction({ receiverId, actions });
}
catch (e) {
if (e.type === 'NotEnoughAllowance') {
accessKey = await this.accessKeyForTransaction(receiverId, actions);
}
else {
throw e;
}
}
}
const block = await this.connection.provider.block({ finality: 'final' });
const blockHash = borsh_1.baseDecode(block.header.hash);
const publicKey = utils_1.PublicKey.from(accessKey.public_key);
// TODO: Cache & listen for nonce updates for given access key
const nonce = accessKey.access_key.nonce + 1;
const transaction = transaction_1.createTransaction(this.accountId, publicKey, receiverId, nonce, actions, blockHash);
await this.walletConnection.requestSignTransactions({
transactions: [transaction],
meta: walletMeta,
callbackUrl: walletCallbackUrl
});
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('Failed to redirect to sign transaction'));
}, 1000);
});
// TODO: Aggregate multiple transaction request with "debounce".
// TODO: Introduce TrasactionQueue which also can be used to watch for status?
}
/**
* Check if given access key allows the function call or method attempted in transaction
* @param accessKey Array of {access_key: AccessKey, public_key: PublicKey} items
* @param receiverId The NEAR account attempting to have access
* @param actions The action(s) needed to be checked for access
*/
async accessKeyMatchesTransaction(accessKey, receiverId, actions) {
const { access_key: { permission } } = accessKey;
if (permission === 'FullAccess') {
return true;
}
if (permission.FunctionCall) {
const { receiver_id: allowedReceiverId, method_names: allowedMethods } = permission.FunctionCall;
/********************************
Accept multisig access keys and let wallets attempt to signAndSendTransaction
If an access key has itself as receiverId and method permission add_request_and_confirm, then it is being used in a wallet with multisig contract: https://github.com/near/core-contracts/blob/671c05f09abecabe7a7e58efe942550a35fc3292/multisig/src/lib.rs#L149-L153
********************************/
if (allowedReceiverId === this.accountId && allowedMethods.includes(MULTISIG_HAS_METHOD)) {
return true;
}
if (allowedReceiverId === receiverId) {
if (actions.length !== 1) {
return false;
}
const [{ functionCall }] = actions;
return functionCall &&
(!functionCall.deposit || functionCall.deposit.toString() === '0') && // TODO: Should support charging amount smaller than allowance?
(allowedMethods.length === 0 || allowedMethods.includes(functionCall.methodName));
// TODO: Handle cases when allowance doesn't have enough to pay for gas
}
}
// TODO: Support other permissions than FunctionCall
return false;
}
/**
* Helper function returning the access key (if it exists) to the receiver that grants the designated permission
* @param receiverId The NEAR account seeking the access key for a transaction
* @param actions The action(s) sought to gain access to
* @param localKey A local public key provided to check for access
* @returns Promise<any>
*/
async accessKeyForTransaction(receiverId, actions, localKey) {
const accessKeys = await this.getAccessKeys();
if (localKey) {
const accessKey = accessKeys.find(key => key.public_key.toString() === localKey.toString());
if (accessKey && await this.accessKeyMatchesTransaction(accessKey, receiverId, actions)) {
return accessKey;
}
}
const walletKeys = this.walletConnection._authData.allKeys;
for (const accessKey of accessKeys) {
if (walletKeys.indexOf(accessKey.public_key) !== -1 && await this.accessKeyMatchesTransaction(accessKey, receiverId, actions)) {
return accessKey;
}
}
return null;
}
}
exports.ConnectedWalletAccount = ConnectedWalletAccount;
Выполнить команду
Для локальной разработки. Не используйте в интернете!