UNPKG

@velas/account-agent

Version:

sdk

844 lines (713 loc) 39.2 kB
import bs58 from 'bs58'; import AccountConstructor from '../helper/account'; import assert from '../helper/assert'; import ErrorHendler from '../helper/error'; import ScopesConstructor from '../helper/scopes'; import { SolidInstruction, SignerType } from '../helper/instructions' const errorHendler = new ErrorHendler('Client'); /** * Creates a new API Client to blockchain * @constructor * @param {Object} options */ function Client(options, keyStorage) { this.keyStorage = keyStorage; this.connection = new options.client_provider.Connection(options.client_host, 'singleGossip'); this.broadcast = options.broadcastTransactionHendler; this.web3 = options.client_provider; this.account_contract = options.client_account_contract; this.transactions_sponsor_pub_key = options.transactions_sponsor_pub_key; this.sc = new ScopesConstructor({ account_contract: options.client_account_contract }); this.accountDataConstructor = new AccountConstructor({ connection: this.connection, account_contract: options.client_account_contract, PublicKey: this.web3.PublicKey, }); }; Client.prototype.signAndBroadcastWithKey = async function({ account, op_key, message, csrf_token, host, }) { assert.check(account, { type: 'string', message: 'account option is required' }); assert.check(op_key, { type: 'string', message: 'op_key option is required' }); assert.check(message, { type: 'object', message: 'message option is required' }); assert.check(csrf_token, { type: 'string', message: 'csrf_token option is required' }); assert.check(host, { type: 'string', message: 'host option is required' }); const transaction = this.web3.Transaction.populate(this.web3.Message.from(message), []); const signature = await this.keyStorage.signWithKey(op_key, message); const signatures = [[op_key, bs58.encode(signature)]]; const { error, transactions_signatures } = await this.broadcast(host, { transactions: [{ account, message: bs58.encode(transaction.serializeMessage()), signatures, }], csrf_token }); if (error) throw new Error(error); return transactions_signatures[0]; }; Client.prototype.signAndSendWithKey = async function({ account, op_key, message, }) { assert.check(account, { type: 'string', message: 'account option is required' }); assert.check(op_key, { type: 'string', message: 'op_key option is required' }); assert.check(message, { type: 'object', message: 'message option is required' }); const transaction = this.web3.Transaction.populate(this.web3.Message.from(message), []); const signature = await this.keyStorage.signWithKey(op_key, message); transaction.feePayer = new this.web3.PublicKey(op_key); transaction.addSignature(new this.web3.PublicKey(op_key), signature); if (!transaction.verifySignatures()) throw new Error(`Signature verification failed! Signer must be only one and it must be current session key: ${op_key}.`); return await this.web3.sendAndConfirmRawTransaction( this.connection, transaction.serialize(), { commitment: 'single', skipPreflight: true, }, ); }; Client.prototype.findAccountAddressWithPublicKey = async function(publicKey, return_base58 = true) { const ownerPublicKey = typeof publicKey === 'string' ? new this.web3.PublicKey(publicKey) : publicKey; const vaccount = await this.web3.PublicKey.findProgramAddress( [ ownerPublicKey.toBuffer().slice(0, 32), Buffer.from("vaccount"), ], new this.web3.PublicKey(this.account_contract), ); if (return_base58) return vaccount[0].toBase58(); return vaccount[0]; }; Client.prototype.getAccountPrograms = function(accountData) { return this.accountDataConstructor.getAccountPrograms(accountData); }; Client.prototype.getAccountData = function(base58PublicKey) { const vaccountPublicKey = new this.web3.PublicKey(base58PublicKey); return this.accountDataConstructor.getAccountData(vaccountPublicKey); }; Client.prototype.getClientData = async function(client_id) { try { if (!client_id) return undefined; const publickKey = new this.web3.PublicKey(client_id); const account = await this.connection.getParsedAccountInfo(publickKey); if (!account.value || account.value.data.program !== 'velas-relying-party') return undefined; return { client_name: account.value.data.parsed.related_program_data.name, client_uri: account.value.data.parsed.related_program_data.domain_name, redirect_uris: account.value.data.parsed.related_program_data.redirect_uri } } catch (_) { return undefined; }; }; Client.prototype.getBalance = function(base58PublicKey) { const publickKey = new this.web3.PublicKey(base58PublicKey); return this.connection.getBalance(publickKey); }; Client.prototype.transactionStatus = function(signature) { return this.connection.getSignatureStatus(signature); }; Client.prototype.sendMessage = async function({ transaction_name, params, transactions_sponsor_api_host, csrf_token, cb, }) { try { assert.check(params, { type: 'object', message: 'params option is required' }); assert.check(transactions_sponsor_api_host, { type: 'string', message: 'transactions_sponsor_api_host option is required' }); assert.check(csrf_token, { type: 'string', message: 'csrf_token option is required' }); assert.check(transaction_name, { type: 'string', message: 'transaction_name option is required' }); assert.check(cb, { type: 'function', message: 'cb option is required' }); if (![ 'proxy', 'transfer', 'initializeTransaction', 'addOwnerTransaction', 'replaceOwnerTransaction', 'addOperationalAddressTransaction', 'removeOperationalAddressTransaction', 'extendOperationalScopesTransaction', ].includes(transaction_name)) throw new Error(`unsupported transaction_name param`); var expression = /^(http:\/\/|https:\/\/)+(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-:]*[A-Za-z0-9])$/; var regex = new RegExp(expression); if (!transactions_sponsor_api_host.match(regex)) throw new Error('wrong host address for transactions_sponsor_api_host param'); } catch(e) { return cb({ error: 'send_message_invalid_params', description: e.message || e, description: `SendMessage error: ${e.message || e}`, }); }; let message_data, transaction_id; try { message_data = await this[transaction_name](params); } catch(e) { return cb({ error: 'send_message_generation_data_error', description: `Preparing a transaction error: ${e.message || e}`, }); }; try { const { error, transactions_signatures } = await this.broadcast(transactions_sponsor_api_host, { ...message_data, csrf_token }); if (error) { return cb({ error: 'send_message_transaction_failed', description: `Broadcast transaction error: ${error}`, }); }; if (!transactions_signatures) throw new Error('no transaction transactions_signatures from broadcast host'); transaction_id = transactions_signatures.pop(); } catch(e) { return cb({ error: 'send_message_broadcast_host_error', description: `Broadcast host error: ${e.message || e}`, }); }; let i = 17; await ( async () => { while (i > 0) { try { const status = await this.transactionStatus(transaction_id); if (status && status.value && status.value.confirmationStatus === 'finalized') { return cb(null, { transaction_id, account: message_data.account, }); }; i--; if (status && status.value && status.value.err) { throw new Error( `Transaction failed: ${status.value.err}. ${transaction_id}`); }; if (i === 0) throw new Error(`Transaction wasn't completed within this time. ${transaction_id}`); } catch(e) { return cb({ error: 'send_message_invalid_transaction_status', description: `Transaction status error: ${e.message || e}. ${transaction_id}`, }); }; await new Promise(resolve => setTimeout(resolve, 2000)); }; })(); }; Client.prototype.proxy = function(params) { return params; }; Client.prototype.transactionParamsValidator = async function(params = {}, { required }) { for (const req of required) { if (!params[req]) errorHendler.error(`${req} option is required`, null); }; delete params.vaccount; if (params.account) { try { params.vaccount = typeof params.account === 'string' ? new this.web3.PublicKey(bs58.decode(params.account)) : params.account; if (!params.vaccount instanceof this.web3.PublicKey) throw new Error('account should be an instance of PublicKey'); params.accountData = await this.accountDataConstructor.getAccountData(params.vaccount); delete params.account; } catch (error) { errorHendler.error(`incorrect param: account`, error); }; }; // SECRET -> secretOwnerOrOperationalToSignTx -> ownerOrOperationalToSignTx if (params.secretOwnerOrOperationalToSignTx) { try { params.secretOwnerOrOperationalToSignTx = typeof params.secretOwnerOrOperationalToSignTx === 'string' ? bs58.decode(params.secretOwnerOrOperationalToSignTx) : params.secretOwnerOrOperationalToSignTx; params.ownerOrOperationalToSignTx = { account: new this.web3.Account(params.secretOwnerOrOperationalToSignTx) }; params.ownerOrOperationalToSignTx.pubkey = params.ownerOrOperationalToSignTx.account.publicKey; delete params.secretOwnerOrOperationalToSignTx; } catch (error) { errorHendler.error(`incorrect param: secretOwnerOrOperationalToSignTx`, error); }; if (!params.vaccount) errorHendler.error(`vaccount not found to process secretOwnerOrOperationalToSignTx`); if (!params.accountData || !params.accountData.owner_keys) errorHendler.error(`accountData not found to process secretOwnerOrOperationalToSignTx`); const base58PublicKey = params.ownerOrOperationalToSignTx.account.publicKey.toBase58(); const isOperationalKey = params.accountData.operational_keys[base58PublicKey]; const isOwnerKey = params.accountData.owner_keys.includes(base58PublicKey); if (!isOperationalKey && !isOwnerKey) errorHendler.error(`incorrect param: secretOwnerOrOperationalToSignTx. ${base58PublicKey} not found.`); params.ownerOrOperationalToSignTx.type = isOperationalKey ? 'operational' : 'owner'; params.ownerOrOperationalToSignTx.operationalIndex = isOperationalKey ? isOperationalKey.index : null; params.ownerOrOperationalToSignTx.signerType = isOwnerKey ? SignerType.owner() : SignerType.operational(isOperationalKey.index); }; if (params.secretOperationalOrOwner) { // TO DO: refactring (rename secretOperationalOrOwner) try { params.secretOperationalOrOwner = typeof params.secretOperationalOrOwner === 'string' ? bs58.decode(params.secretOperationalOrOwner) : params.secretOperationalOrOwner; params.ownerOrOprationalAccount = new this.web3.Account(params.secretOperationalOrOwner); params.ownerOrOprationalPubKey = params.ownerOrOprationalAccount.publicKey delete params.secretOperationalOrOwner; } catch (error) { errorHendler.error(`incorrect param: secret`, error); }; }; // PUBKEY publicKeyOperationalToRemove -> operationalToRemove if (params.publicKeyOperationalToRemove) { try { params.operationalToRemove = { pubkey: typeof params.publicKeyOperationalToRemove === 'string' ? new this.web3.PublicKey(bs58.decode(params.publicKeyOperationalToRemove)) : params.publicKeyOperationalToRemove, }; delete params.publicKeyOperationalToRemove; } catch (error) { errorHendler.error(`incorrect param: publicKeyOperationalToRemove`, error); }; if (!params.vaccount) errorHendler.error(`incorrect param: publicKeyOperationalToRemove (vaccount not found)`); if (!params.accountData) errorHendler.error(`account ${params.vaccount.toBase58()} not found`); const base58PublicKey = params.operationalToRemove.pubkey.toBase58(); const isOperationalKey = params.accountData.operational_keys[base58PublicKey]; const isOwnerKey = params.accountData.owner_keys.includes(base58PublicKey); if (!isOperationalKey && !isOwnerKey) errorHendler.error(`incorrect param: publicKeyOperationalToRemove (vaccount does't have key: ${base58PublicKey})`); params.operationalToRemove.operationalIndex = isOperationalKey ? isOperationalKey.index : null params.operationalToRemove.signerType = isOwnerKey ? SignerType.owner() : SignerType.operational(isOperationalKey.index); }; // PUBKEY ownerOrOprationalPubKey -> ownerOrOprational if (params.ownerOrOprationalPubKey) { try { params.ownerOrOprational = { pubkey: typeof params.ownerOrOprationalPubKey === 'string' ? new this.web3.PublicKey(bs58.decode(params.ownerOrOprationalPubKey)) : params.ownerOrOprationalPubKey, }; delete params.ownerOrOprationalPubKey; } catch (error) { errorHendler.error(`incorrect param: ownerOrOprationalPubKey`, error); }; if (!params.vaccount) errorHendler.error(`incorrect param: ownerOrOprationalPubKey (vaccount not found)`); if (!params.accountData) errorHendler.error(`account ${params.vaccount.toBase58()} not found`); const key = params.ownerOrOprational.pubkey.toBase58(); const isOperationalKey = params.accountData.operational_keys[key]; const isOwnerKey = params.accountData.owner_keys.includes(key); if (!isOperationalKey && !isOwnerKey) errorHendler.error(`incorrect param: ownerOrOprationalPubKey (vaccount does't have key: ${key})`); params.ownerOrOprational.operationalIndex = isOperationalKey ? isOperationalKey.index : null params.ownerOrOprational.signerType = isOwnerKey ? SignerType.owner() : SignerType.operational(isOperationalKey.index); }; // ====== if (params.secret) { // TO DO: refactring (rename secret) try { params.secret = typeof params.secret === 'string' ? bs58.decode(params.secret) : params.secret; params.owner = new this.web3.Account(params.secret); delete params.secret; } catch (error) { errorHendler.error(`incorrect param: secret`, error); }; if (!params.vaccount){ if (!params.account) { params.vaccount = await this.findAccountAddressWithPublicKey(params.owner.publicKey, false); } else { try { params.vaccount = new this.web3.PublicKey(params.account); } catch (error) { errorHendler.error(`incorrect param: secret`, error); }; }; } }; if (params.secret_new) { // TO DO: refactring (rename secret_new) try { params.secret_new = typeof params.secret_new === 'string' ? bs58.decode(params.secret_new) : params.secret_new; params.owner_new = new this.web3.Account(params.secret_new); delete params.secret_new; } catch (error) { errorHendler.error(`incorrect param: secret`, error); }; }; if (params.op_key) { // TO DO: refactring (rename op_key) try { params.op_key = typeof params.op_key === 'string' ? bs58.decode(params.op_key) : params.op_key; params.operationalPublicKey = new this.web3.PublicKey(params.op_key); delete params.op_key; } catch (error) { errorHendler.error(`incorrect param: op_key`, error); }; }; if (params.transactions_sponsor_pub_key) { try { params.transactions_sponsor_pub_key = typeof params.transactions_sponsor_pub_key === 'string' ? bs58.decode(params.transactions_sponsor_pub_key) : params.transactions_sponsor_pub_key; params.payerPublicKey = new this.web3.PublicKey(params.transactions_sponsor_pub_key); delete params.transactions_sponsor_pub_key; } catch (error) { errorHendler.error(`incorrect param: transactions_sponsor_pub_key`, error); }; } else { params.payerPublicKey = new this.web3.PublicKey(this.transactions_sponsor_pub_key || this.sc.SYSTEM_PROGRAM_ADDRESS); }; if (params.agent_type) { // TO DO: refactring (rename agent_type) if (typeof params.agent_type !== 'string') errorHendler.error(`incorrect param: agent_type`, null); params.agentType = params.agent_type; delete params.agent_type; } else { params.agentType = 'Incognito'; }; if (params.fromAccountPubKey) { // TO DO: refactoring (remove params.vaccount) try { params.vaccount = typeof params.fromAccountPubKey === 'string' ? new this.web3.PublicKey(bs58.decode(params.fromAccountPubKey)) : params.fromAccountPubKey; if (!params.vaccount instanceof this.web3.PublicKey) errorHendler.error(`incorrect param: fromAccountPubKey`, 'not instance of PublicKey'); delete params.fromAccountPubKey; } catch (error) { errorHendler.error(`incorrect param: fromAccountPubKey`, error); }; }; if (params.toPubKey) { try { params.toPubKey = typeof params.toPubKey === 'string' ? new this.web3.PublicKey(bs58.decode(params.toPubKey)) : params.toPubKey; } catch (error) { errorHendler.error(`incorrect param: toPubKey`, error); }; }; // TO DO: scopes validation; // TO DO: lamports validation; return params; }; Client.prototype.prepareTransaction = async function({ feePayer, vaccount, instructions, owSigner, opSigner, }) { const { blockhash: recentBlockhash } = await this.connection.getRecentBlockhash(); const transaction = new this.web3.Transaction({ recentBlockhash, feePayer }).add(...instructions); if (owSigner.length) transaction.sign(...owSigner); const ow_signatures = []; for(const ow of owSigner) { const owPubKey = ow.publicKey.toBase58(); for(const item of transaction.signatures) { const signPubKey = item.publicKey.toBase58(); if ((owPubKey === signPubKey) && item.signature) { console.log("prepareTransaction: found owner signature for - ", owPubKey, bs58.encode(item.signature)) ow_signatures.push([signPubKey, bs58.encode(item.signature)]) } }; }; const signatures = [...ow_signatures]; if (opSigner) { const op_signature = await this.keyStorage.signWithKey(opSigner.toBase58(), transaction.serializeMessage()); signatures.push([opSigner.toBase58(), bs58.encode(op_signature)]); }; return { account: vaccount.toBase58(), message: bs58.encode(transaction.serializeMessage()), signatures, }; }; Client.prototype.initializeTransaction = async function(params) { const { owner, operationalPublicKey, payerPublicKey, vaccount, agentType, scopes, } = await this.transactionParamsValidator(params, { required: ['secret', 'op_key'] }); const accountData = await this.accountDataConstructor.getAccountData(vaccount, true); console.log("accountDat1a", accountData); if (!accountData.ephimeric) throw new Error('Account ' + vaccount.toBase58() + ' already exists for specified key'); const addOperationalData = await this.accountDataConstructor.addOperationalData(accountData, { pubkey: operationalPublicKey, agentType: agentType, scopes: scopes, }); const transfer = this.web3.SystemProgram.transfer({ fromPubkey: payerPublicKey, toPubkey: vaccount, lamports: addOperationalData.storage.rent }); const init = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: owner.publicKey, isSigner: true, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, ], data: accountData.instruction.initializeEncoded, }); let addPrograms = []; for (const programObject of addOperationalData.storage.whitelistPrograms) { addPrograms.push(new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: programObject.pubkey, isSigner: false, isWritable: false }, { pubkey: programObject.current, isSigner: false, isWritable: true }, { pubkey: programObject.next, isSigner: false, isWritable: true }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: owner.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.addProgramEncoded, })) }; const addOperationalAddressInstruction = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.tokens_next, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.programs_next, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_next, isSigner: false, isWritable: true }, { pubkey: operationalPublicKey, isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: owner.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.addOperationalEncoded, }); return { transactions: [await this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [transfer, init, ...addPrograms, addOperationalAddressInstruction], owSigner: [owner], //opSigner: operationalPublicKey, })] }; }; Client.prototype.addOperationalAddressTransaction = async function(params) { const { operationalPublicKey, payerPublicKey, vaccount, agentType, scopes, ownerOrOprational, ownerOrOprationalAccount, } = await this.transactionParamsValidator(params, { required: ['secretOperationalOrOwner', 'op_key', 'account' ] }); const accountData = await this.accountDataConstructor.getAccountData(vaccount); if (!accountData) throw new Error("Specified account not found"); // if (!accountData.owner_keys.includes(owner.publicKey.toBase58()) && !accountData.operational_keys[owner.publicKey.toBase58()]) throw new Error("You dont have rights to specified account"); // TODO: write new validation; const addOperationalData = await this.accountDataConstructor.addOperationalData(accountData, { pubkey: operationalPublicKey, agentType: agentType, scopes: scopes, }, ownerOrOprational); let instructions = []; if (addOperationalData.storage.rent > 0) { instructions.push(this.web3.SystemProgram.transfer({ fromPubkey: payerPublicKey, toPubkey: vaccount, lamports: addOperationalData.storage.rent })); }; for (const programObject of addOperationalData.storage.whitelistPrograms) { instructions.push(new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: programObject.pubkey, isSigner: false, isWritable: false }, { pubkey: programObject.current, isSigner: false, isWritable: true }, { pubkey: programObject.next, isSigner: false, isWritable: true }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOprationalAccount.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.addProgramEncoded, })) }; const addOperationalAddressInstruction = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.tokens_next, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.programs_next, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_next, isSigner: false, isWritable: true }, { pubkey: operationalPublicKey, isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOprationalAccount.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.addOperationalEncoded, }); return { transactions: [await this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [...instructions, addOperationalAddressInstruction], owSigner: [ownerOrOprationalAccount], // opSigner: operationalPublicKey, })] }; }; Client.prototype.transfer = async function(params) { const { vaccount, toPubKey, lamports, ownerOrOprational, accountData, } = await this.transactionParamsValidator(params, { required: [ 'fromAccountPubKey', 'toPubKey', 'lamports', 'ownerOrOprationalPubKey' ]}); const transfer = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: toPubKey, isSigner: false, isWritable: true }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOprational.pubkey, isSigner: true, isWritable: false }, ], data: SolidInstruction.transfer({ amount: lamports, signerType: ownerOrOprational.signerType }).encode(), }); return new this.web3.Transaction().add(transfer); }; Client.prototype.replaceOwnerTransaction = async function(params) { const { owner, owner_new, payerPublicKey, vaccount, } = await this.transactionParamsValidator(params, { required: ['secret', 'secret_new', 'account'] }); const accountData = await this.accountDataConstructor.getAccountData(vaccount); if (!accountData) throw new Error("Specified account not found"); if (!accountData.owner_keys.includes(owner.publicKey.toBase58())) throw new Error("You dont have rights to specified account"); const replaceOwnerInstruction = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: owner.publicKey, isSigner: false, isWritable: false }, { pubkey: owner_new.publicKey, isSigner: true, isWritable: false }, { pubkey: owner.publicKey, isSigner: true, isWritable: false }, ], data: accountData.instruction.replaceOwnerEncoded, }); return this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [replaceOwnerInstruction], owSigner: [owner, owner_new], }); }; Client.prototype.removeOperationalAddressTransaction = async function(params) { const { payerPublicKey, vaccount, ownerOrOperationalToSignTx, operationalToRemove, accountData, } = await this.transactionParamsValidator(params, { required: ['account', 'secretOwnerOrOperationalToSignTx', 'publicKeyOperationalToRemove'] }); if (!accountData) throw new Error("Specified account not found"); const removeOperationalData = await this.accountDataConstructor.removeOperationalData(accountData, operationalToRemove.pubkey); let removePrograms = []; for (const permissionToRemoveIndex of removeOperationalData.storage.programPermissionsToRemove) { removePrograms.push(new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: removeOperationalData.storage.programs_current, isSigner: false, isWritable: true }, { pubkey: ownerOrOperationalToSignTx.pubkey, isSigner: true, isWritable: false }, // !!! ], data: SolidInstruction.removeProgramPermission({ operational2RemoveIndex: operationalToRemove.operationalIndex, signerType: ownerOrOperationalToSignTx.signerType, program2RemoveIndex: permissionToRemoveIndex, }).encode(), })); }; const removeOperationalAddressInstruction = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_next, isSigner: false, isWritable: true }, { pubkey: operationalToRemove.pubkey, isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOperationalToSignTx.pubkey, isSigner: true, isWritable: false }, // !!! ], data: SolidInstruction.removeOperational({ operational2RemoveIndex: operationalToRemove.operationalIndex, signerType: ownerOrOperationalToSignTx.signerType, }).encode(), }); const owSigner = ownerOrOperationalToSignTx.type === 'owner' ? [ownerOrOperationalToSignTx.account] : []; const opSigner = ownerOrOperationalToSignTx.type === 'owner' ? null : ownerOrOperationalToSignTx.pubkey; const transactions = await Promise.all(removePrograms.map(async (instruction) => { return await this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [instruction], owSigner, opSigner, }) })); const removeTransaction = await this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [removeOperationalAddressInstruction], owSigner, opSigner, }) transactions.push(removeTransaction); return { transactions }; }; Client.prototype.extendOperationalScopesTransaction = async function(params) { const { operationalPublicKey, payerPublicKey, vaccount, ownerOrOprational, agentType, scopes, ownerOrOprationalAccount, } = await this.transactionParamsValidator(params, { required: ['secretOperationalOrOwner', 'account', 'op_key', 'scopes'] }); const accountData = await this.accountDataConstructor.getAccountData(vaccount); if (!accountData) throw new Error("Specified account not found"); const addOperationalData = await this.accountDataConstructor.addOperationalData(accountData, { pubkey: operationalPublicKey, agentType: agentType, scopes: scopes, extend: true }, ownerOrOprational); let instructions = []; for (const programObject of addOperationalData.storage.whitelistPrograms) { instructions.push(new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: programObject.pubkey, isSigner: false, isWritable: false }, { pubkey: programObject.current, isSigner: false, isWritable: true }, { pubkey: programObject.next, isSigner: false, isWritable: true }, { pubkey: new this.web3.PublicKey(this.sc.SYSVAR_RENT_ADDRESS), isSigner: false, isWritable: false }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOprationalAccount.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.addProgramEncoded, })) }; const extendOperationalScopesInstruction = new this.web3.TransactionInstruction({ programId: new this.web3.PublicKey(this.account_contract), keys: [ { pubkey: vaccount, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.tokens_current, isSigner: false, isWritable: true }, { pubkey: addOperationalData.storage.programs_next, isSigner: false, isWritable: true }, { pubkey: accountData.storage.storage_current, isSigner: false, isWritable: true }, { pubkey: new this.web3.PublicKey(this.sc.SYSTEM_PROGRAM_ADDRESS), isSigner: false, isWritable: false }, { pubkey: ownerOrOprationalAccount.publicKey, isSigner: true, isWritable: false }, ], data: addOperationalData.storage.extendOperationalScopesEncoded, }); return this.prepareTransaction({ feePayer: payerPublicKey, vaccount: vaccount, instructions: [...instructions, extendOperationalScopesInstruction], owSigner: [ownerOrOprationalAccount], }); }; export default Client;