Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update docs #1274

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions packages/accounts/src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,14 @@ export class Account {
}

/**
* Sign a transaction to preform a list of actions and broadcast it using the RPC API.
* Sign a transaction to perform a list of actions and broadcast it using the RPC API.
* @see {@link "@near-js/providers".json-rpc-provider.JsonRpcProvider | JsonRpcProvider }
*
* @param options The options for signing and sending the transaction.
* @param options.receiverId The NEAR account ID of the transaction receiver.
* @param options.actions The list of actions to be performed in the transaction.
* @param options.returnError Whether to return an error if the transaction fails.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction.
*/
async signAndSendTransaction({ receiverId, actions, returnError }: SignAndSendTransactionOptions): Promise<FinalExecutionOutcome> {
let txHash, signedTx;
Expand Down Expand Up @@ -382,9 +388,19 @@ export class Account {
return Buffer.concat([Buffer.from(contractId), Buffer.from([0]), Buffer.from(method), Buffer.from([0]), Buffer.from(args)]);
}

/**
* Execute function call
* @returns {Promise<FinalExecutionOutcome>}
/**
* Execute a function call.
* @param options The options for the function call.
* @param options.contractId The NEAR account ID of the smart contract.
* @param options.methodName The name of the method to be called on the smart contract.
* @param options.args The arguments to be passed to the method.
* @param options.gas The maximum amount of gas to be used for the function call.
* @param options.attachedDeposit The amount of NEAR tokens to be attached to the function call.
* @param options.walletMeta Metadata for wallet integration.
* @param options.walletCallbackUrl The callback URL for wallet integration.
* @param options.stringify A function to convert input arguments into bytes array
* @param options.jsContract Whether the contract is from JS SDK, automatically encodes args from JS SDK to binary.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the function call.
*/
async functionCall({ contractId, methodName, args = {}, gas = DEFAULT_FUNCTION_CALL_GAS, attachedDeposit, walletMeta, walletCallbackUrl, stringify, jsContract }: ChangeFunctionCallOptions): Promise<FinalExecutionOutcome> {
this.validateArgs(args);
Expand Down
60 changes: 59 additions & 1 deletion packages/accounts/src/account_2fa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ export class Account2FA extends AccountMultisig {
/**
* Sign a transaction to preform a list of actions and broadcast it using the RPC API.
* @see {@link "@near-js/providers".json-rpc-provider.JsonRpcProvider.sendTransaction | JsonRpcProvider.sendTransaction}
*
* @param options Options for the transaction.
* @param options.receiverId The NEAR account ID of the transaction receiver.
* @param options.actions The list of actions to be included in the transaction.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction.
*/
async signAndSendTransaction({ receiverId, actions }: SignAndSendTransactionOptions): Promise<FinalExecutionOutcome> {
await super.signAndSendTransaction({ receiverId, actions });
Expand All @@ -62,6 +67,11 @@ export class Account2FA extends AccountMultisig {

// default helpers for CH deployments of multisig

/**
* Deploy a multisig contract with 2FA and handle the deployment process.
* @param contractBytes - The bytecode of the multisig contract.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the deployment.
*/
async deployMultisig(contractBytes: Uint8Array) {
const { accountId } = this;

Expand Down Expand Up @@ -100,6 +110,13 @@ export class Account2FA extends AccountMultisig {
}
}

/**
* Disable 2FA with the option to clean up contract state.
* @param options Options for disabling 2FA.
* @param options.contractBytes The bytecode of the contract to deploy.
* @param options.cleanupContractBytes The bytecode of the cleanup contract (optional).
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the operation.
*/
async disableWithFAK({ contractBytes, cleanupContractBytes }: { contractBytes: Uint8Array; cleanupContractBytes?: Uint8Array }) {
let cleanupActions = [];
if(cleanupContractBytes) {
Expand All @@ -123,6 +140,11 @@ export class Account2FA extends AccountMultisig {
return this.signAndSendTransactionWithAccount(this.accountId, actions);
}

/**
* Retrieves cleanup actions for disabling 2FA.
* @param cleanupContractBytes - The bytecode of the cleanup contract.
* @returns {Promise<Action[]>} - A promise that resolves to an array of cleanup actions.
*/
async get2faDisableCleanupActions(cleanupContractBytes: Uint8Array) {
const currentAccountState: { key: Buffer; value: Buffer }[] = await this.viewState('').catch(error => {
const cause = error.cause && error.cause.name;
Expand All @@ -141,6 +163,10 @@ export class Account2FA extends AccountMultisig {
] : [];
}

/**
* Retrieves key conversion actions for disabling 2FA.
* @returns {Promise<Action[]>} - A promise that resolves to an array of key conversion actions.
*/
async get2faDisableKeyConversionActions() {
const { accountId } = this;
const accessKeys = await this.getAccessKeys();
Expand All @@ -163,7 +189,8 @@ export class Account2FA extends AccountMultisig {
/**
* This method converts LAKs back to FAKs, clears state and deploys an 'empty' contract (contractBytes param)
* @param [contractBytes]{@link https://github.com/near/near-wallet/blob/master/packages/frontend/src/wasm/main.wasm?raw=true}
* @param [cleanupContractBytes]{@link https://github.com/near/core-contracts/blob/master/state-cleanup/res/state_cleanup.wasm?raw=true}
* @param [cleanupContractBytes]{@link https://github.com/near/core-contracts/blob/master/state-manipulation/res/state_cleanup.wasm?raw=true}
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the operation.
*/
async disable(contractBytes: Uint8Array, cleanupContractBytes: Uint8Array) {
const { stateStatus } = await this.checkMultisigCodeAndStateStatus();
Expand Down Expand Up @@ -193,6 +220,10 @@ export class Account2FA extends AccountMultisig {
});
}

/**
* Default implementation for sending the 2FA code.
* @returns {Promise<string>} - A promise that resolves to the request ID.
*/
async sendCodeDefault() {
const { accountId } = this;
const { requestId } = this.getRequest();
Expand All @@ -209,6 +240,10 @@ export class Account2FA extends AccountMultisig {
throw new Error('There is no getCode callback provided. Please provide your own in AccountMultisig constructor options. It has a parameter method where method.kind is "email" or "phone".');
}

/**
* Prompts the user to enter and verify the 2FA code.
* @returns {Promise<any>} - A promise that resolves to the verification result.
*/
async promptAndVerify() {
const method = await this.get2faMethod();
const securityCode = await this.getCode(method);
Expand All @@ -227,6 +262,11 @@ export class Account2FA extends AccountMultisig {
}
}

/**
* Verify the 2FA code using the default method.
* @param securityCode - The security code to verify.
* @returns {Promise<any>} A promise that resolves to the verification result.
*/
async verifyCodeDefault(securityCode: string) {
const { accountId } = this;
const request = this.getRequest();
Expand All @@ -241,6 +281,10 @@ export class Account2FA extends AccountMultisig {
});
}

/**
* Retrieves recovery methods for the account.
* @returns {Promise<{ accountId: string, data: any }>} - A promise that resolves to recovery methods data.
*/
async getRecoveryMethods() {
const { accountId } = this;
return {
Expand All @@ -249,6 +293,10 @@ export class Account2FA extends AccountMultisig {
};
}

/**
* Gets the 2FA method (kind and detail).
* @returns {Promise<{ kind: string, detail: string } | null>} - A promise that resolves to the 2FA method.
vikinatora marked this conversation as resolved.
Show resolved Hide resolved
*/
async get2faMethod() {
let { data } = await this.getRecoveryMethods();
if (data && data.length) {
Expand All @@ -259,6 +307,10 @@ export class Account2FA extends AccountMultisig {
return { kind, detail };
}

/**
* Generates a signature for the current block number.
vikinatora marked this conversation as resolved.
Show resolved Hide resolved
* @returns {Promise<{ blockNumber: string, blockNumberSignature: string }>} - A promise that resolves to the signature information.
*/
async signatureFor() {
const { accountId } = this;
const block = await this.connection.provider.block({ finality: 'final' });
Expand All @@ -268,6 +320,12 @@ export class Account2FA extends AccountMultisig {
return { blockNumber, blockNumberSignature };
}

/**
* Sends a signed JSON request to a specified path.
* @param path - The path for the request.
* @param body - The request body.
* @returns {Promise<any>} - A promise that resolves to the response from the helper.
*/
async postSignedJson(path, body) {
return await fetchJson(this.helperUrl + path, JSON.stringify({
...body,
Expand Down
38 changes: 37 additions & 1 deletion packages/accounts/src/account_multisig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,37 @@ export class AccountMultisig extends Account {
public storage: any;
public onAddRequestResult: (any) => any;

/**
* Constructs an instance of the `AccountMultisig` class.
* @param connection The NEAR connection object.
* @param accountId The NEAR account ID.
* @param options Additional options for the multisig account.
* @param options.storage Storage to store data related to multisig operations.
* @param options.onAddRequestResult Callback function to handle the result of adding a request.
*/
constructor(connection: Connection, accountId: string, options: any) {
super(connection, accountId);
this.storage = options.storage;
this.onAddRequestResult = options.onAddRequestResult;
}

/**
* Sign and send a transaction with the multisig account as the sender.
* @param receiverId - The NEAR account ID of the transaction receiver.
* @param actions - The list of actions to be included in the transaction.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction.
*/
async signAndSendTransactionWithAccount(receiverId: string, actions: Action[]): Promise<FinalExecutionOutcome> {
return super.signAndSendTransaction({ receiverId, actions });
}

/**
* Sign and send a multisig transaction to add a request and confirm it.
* @param options Options for the multisig transaction.
* @param options.receiverId The NEAR account ID of the transaction receiver.
* @param options.actions The list of actions to be included in the transaction.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction.
*/
async signAndSendTransaction({ receiverId, actions }: SignAndSendTransactionOptions): Promise<FinalExecutionOutcome> {
const { accountId } = this;

Expand Down Expand Up @@ -91,10 +112,12 @@ export class AccountMultisig extends Account {
return result;
}

/*
/**
* This method submits a canary transaction that is expected to always fail in order to determine whether the contract currently has valid multisig state
* and whether it is initialized. The canary transaction attempts to delete a request at index u32_max and will go through if a request exists at that index.
* a u32_max + 1 and -1 value cannot be used for the canary due to expected u32 error thrown before deserialization attempt.
* @param contractBytes The bytecode of the multisig contract.
* @returns {Promise<{ codeStatus: MultisigCodeStatus; stateStatus: MultisigStateStatus }>} A promise that resolves to the status of the code and state.
*/
async checkMultisigCodeAndStateStatus(contractBytes?: Uint8Array): Promise<{ codeStatus: MultisigCodeStatus; stateStatus: MultisigStateStatus }> {
const u32_max = 4_294_967_295;
Expand Down Expand Up @@ -128,20 +151,33 @@ export class AccountMultisig extends Account {
}
}

/**
* Delete a multisig request by its ID.
* @param request_id The ID of the multisig request to be deleted.
* @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the deletion.
*/
deleteRequest(request_id) {
return super.signAndSendTransaction({
receiverId: this.accountId,
actions: [functionCall('delete_request', { request_id }, MULTISIG_GAS, MULTISIG_DEPOSIT)]
});
}

/**
* Delete all multisig requests associated with the account.
* @returns {Promise<void>} A promise that resolves when all requests are deleted.
*/
async deleteAllRequests() {
const request_ids = await this.getRequestIds();
if(request_ids.length) {
await Promise.all(request_ids.map((id) => this.deleteRequest(id)));
}
}

/**
* Delete unconfirmed multisig requests associated with the account.
* @returns {Promise<void>} A promise that resolves when unconfirmed requests are deleted.
*/
async deleteUnconfirmedRequests () {
// TODO: Delete in batch, don't delete unexpired
// TODO: Delete in batch, don't delete unexpired (can reduce gas usage dramatically)
Expand Down
9 changes: 9 additions & 0 deletions packages/accounts/src/local-view-execution/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ export class LocalViewExecution {
return fetched;
}

/**
* Calls a view function on a contract, fetching the contract code and state if needed.
* @param options Options for calling the view function.
* @param options.contractId The contract account ID.
* @param options.methodName The name of the view function to call.
* @param options.args The arguments to pass to the view function.
* @param options.blockQuery The block query options.
* @returns {Promise<any>} - A promise that resolves to the result of the view function.
*/
public async viewFunction({ contractId, methodName, args = {}, blockQuery = { finality: 'optimistic' }, ...ignored }: ViewFunctionCallOptions) {
const methodArgs = JSON.stringify(args);

Expand Down
4 changes: 2 additions & 2 deletions packages/biometric-ed25519/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ export const getKeys = async (username: string): Promise<[KeyPair, KeyPair]> =>
Buffer.from(new Uint8Array(base64.toArrayBuffer(getAssertionResponse.response.clientDataJSON, true)))
);
const clientDataJSONHash = await clientDataSha256.digest();
const AuthenticatiorDataJSONHash = Buffer.from(new Uint8Array(base64.toArrayBuffer(getAssertionResponse.response.authenticatorData, true)));
const authenticatorAndClientDataJSONHash = Buffer.concat([AuthenticatiorDataJSONHash, clientDataJSONHash]);
const AuthenticatorDataJSONHash = Buffer.from(new Uint8Array(base64.toArrayBuffer(getAssertionResponse.response.authenticatorData, true)));
vikinatora marked this conversation as resolved.
Show resolved Hide resolved
const authenticatorAndClientDataJSONHash = Buffer.concat([AuthenticatorDataJSONHash, clientDataJSONHash]);

const correctPKs = await recoverPublicKey(rAndS.children[0].value, rAndS.children[1].value, authenticatorAndClientDataJSONHash, 0);

Expand Down
5 changes: 5 additions & 0 deletions packages/crypto/src/key_pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export abstract class KeyPair extends KeyPairBase {
}
}

/**
* Creates a key pair from an encoded key string.
* @param encodedKey The encoded key string.
* @returns {KeyPair} The key pair created from the encoded key string.
*/
static fromString(encodedKey: string): KeyPair {
const parts = encodedKey.split(':');
if (parts.length === 1) {
Expand Down
21 changes: 20 additions & 1 deletion packages/crypto/src/key_pair_ed25519.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class KeyPairEd25519 extends KeyPairBase {
/**
* Construct an instance of key pair given a secret key.
* It's generally assumed that these are encoded in base58.
* @param {string} extendedSecretKey
* @param extendedSecretKey
*/
constructor(extendedSecretKey: string) {
super();
Expand Down Expand Up @@ -47,19 +47,38 @@ export class KeyPairEd25519 extends KeyPairBase {
return new KeyPairEd25519(baseEncode(extendedSecretKey));
}

/**
* Signs a message using the key pair's secret key.
* @param message The message to be signed.
* @returns {Signature} The signature object containing the signature and the public key.
*/
sign(message: Uint8Array): Signature {
const signature = ed25519.sign(message, baseDecode(this.secretKey));
return { signature, publicKey: this.publicKey };
}

/**
* Verifies the signature of a message using the key pair's public key.
* @param message The message to be verified.
* @param signature The signature to be verified.
* @returns {boolean} `true` if the signature is valid, otherwise `false`.
*/
verify(message: Uint8Array, signature: Uint8Array): boolean {
return this.publicKey.verify(message, signature);
}

/**
* Returns a string representation of the key pair in the format 'ed25519:[extendedSecretKey]'.
* @returns {string} The string representation of the key pair.
*/
toString(): string {
return `ed25519:${this.extendedSecretKey}`;
}

/**
* Retrieves the public key associated with the key pair.
* @returns {PublicKey} The public key.
*/
getPublicKey(): PublicKey {
return this.publicKey;
}
Expand Down
Loading
Loading