UNPKG

stellar-plus

Version:

beta version of stellar-plus, an all-in-one sdk for the Stellar blockchain

136 lines (135 loc) 7.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SorobanAuthPipeline = void 0; const tslib_1 = require("tslib"); const stellar_sdk_1 = require("@stellar/stellar-sdk"); const conveyor_belt_1 = require("../../../../stellar-plus/error/helpers/conveyor-belt"); const conveyor_belts_1 = require("../../../../stellar-plus/utils/pipeline/conveyor-belts"); const errors_1 = require("./errors"); const types_1 = require("./types"); const simulate_transaction_1 = require("../simulate-transaction"); class SorobanAuthPipeline extends conveyor_belts_1.ConveyorBelt { constructor(plugins) { super({ type: types_1.SorobanAuthPipelineType.id, plugins: plugins || [], }); } process(item, itemId) { return tslib_1.__awaiter(this, void 0, void 0, function* () { var _a, _b; const { transaction, simulation, signers, rpcHandler, additionalSorobanAuthToSign, additionalSignedSorobanAuth, } = item; const authEntriesToSign = [ ...this.removeSourceCredentialAuth((_a = simulation.result) === null || _a === void 0 ? void 0 : _a.auth), // Source credentials are handled in the classic signing pipeline ...(additionalSorobanAuthToSign || []), // Additional auth entries to sign can come from other simulations and more complex authorization use cases ]; if (authEntriesToSign.length === 0 && (!additionalSignedSorobanAuth || additionalSignedSorobanAuth.length < 1)) return transaction; if (signers.length === 0) throw errors_1.PSAError.noSignersProvided((0, conveyor_belt_1.extractConveyorBeltErrorMeta)(item, this.getMeta(itemId))); const authEntries = additionalSignedSorobanAuth ? [...additionalSignedSorobanAuth] : []; for (const authEntry of authEntriesToSign) { const requiredSigner = this.getRequiredSigner(authEntry, item, itemId); const signer = signers.find((s) => s.getPublicKey() === requiredSigner); if (!signer) throw errors_1.PSAError.signerNotFound((0, conveyor_belt_1.extractConveyorBeltErrorMeta)(item, this.getMeta(itemId)), transaction, signers.map((s) => s.getPublicKey()), requiredSigner, authEntry); const signedEntry = yield signer.signSorobanAuthEntry(authEntry, yield this.calculateExpirationLedgerFromTimeout(rpcHandler, transaction), transaction.networkPassphrase); authEntries.push(signedEntry); } let updatedTransaction; try { updatedTransaction = this.updateTransaction(transaction, [ ...this.getSourceCredentialAuth((_b = simulation.result) === null || _b === void 0 ? void 0 : _b.auth), // Reinject unsigned source credentials. These are signed in the classic signing pipeline ...authEntries, ], simulation.transactionData); } catch (error) { throw errors_1.PSAError.couldntUpdateTransaction(error, (0, conveyor_belt_1.extractConveyorBeltErrorMeta)(item, this.getMeta(itemId)), transaction, authEntries); } let simulatedTransaction; try { simulatedTransaction = yield this.simulate(updatedTransaction, rpcHandler); } catch (error) { throw errors_1.PSAError.couldntSimulateAuthorizedTransaction(error, (0, conveyor_belt_1.extractConveyorBeltErrorMeta)(item, this.getMeta(itemId)), updatedTransaction, authEntries); } return simulatedTransaction; }); } updateTransaction(transaction, authEntries, sorobanData) { const op = transaction.toEnvelope().v1().tx().operations()[0]; const authorizedOperation = stellar_sdk_1.Operation.invokeHostFunction({ func: op.body().invokeHostFunctionOp().hostFunction(), auth: authEntries, }); const sourceAccount = new stellar_sdk_1.Account(transaction.source, (Number(transaction.sequence) - 1).toString()); const updatedTransaction = new stellar_sdk_1.TransactionBuilder(sourceAccount, { fee: transaction.fee, memo: transaction.memo, networkPassphrase: transaction.networkPassphrase, timebounds: transaction.timeBounds, ledgerbounds: transaction.ledgerBounds, minAccountSequence: transaction.minAccountSequence, minAccountSequenceAge: transaction.minAccountSequenceAge, minAccountSequenceLedgerGap: transaction.minAccountSequenceLedgerGap, extraSigners: transaction.extraSigners, sorobanData: sorobanData === null || sorobanData === void 0 ? void 0 : sorobanData.build(), }); updatedTransaction.addOperation(authorizedOperation); return updatedTransaction.build(); } simulate(transaction, rpcHandler) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const simulateTransactionPipeline = new simulate_transaction_1.SimulateTransactionPipeline(); const simulateOutput = yield simulateTransactionPipeline.execute({ transaction: transaction, rpcHandler, }); return simulateOutput.assembledTransaction; }); } calculateExpirationLedgerFromTimeout(rpcHandler, transaction) { return tslib_1.__awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d; // The signatures will be valid up to the same ledger as the transaction if ((_a = transaction.ledgerBounds) === null || _a === void 0 ? void 0 : _a.maxLedger) { return transaction.ledgerBounds.maxLedger; } const timeout = ((_b = transaction.timeBounds) === null || _b === void 0 ? void 0 : _b.maxTime) && Number((_c = transaction.timeBounds) === null || _c === void 0 ? void 0 : _c.maxTime) > 0 ? Number((_d = transaction.timeBounds) === null || _d === void 0 ? void 0 : _d.maxTime) - Date.now() / 1000 : 600; // Arbitrary 10 min default const ledger = yield rpcHandler.getLatestLedger(); const expirationLedger = (ledger.sequence + timeout / 5 + 1).toFixed(0); return Number(expirationLedger); }); } // // Source credentials are handled in the classic signing pipeline. // This method removes them from the auth entries to be signed. // removeSourceCredentialAuth(authEntries) { return authEntries ? authEntries.filter((entry) => { const credentials = entry.credentials(); return credentials.switch() !== stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount(); }) : []; } getSourceCredentialAuth(authEntries) { return authEntries ? authEntries.filter((entry) => { const credentials = entry.credentials(); return credentials.switch() === stellar_sdk_1.xdr.SorobanCredentialsType.sorobanCredentialsSourceAccount(); }) : []; } getRequiredSigner(authEntry, item, itemId) { if (authEntry.credentials().address().address().switch().name === 'scAddressTypeContract') { throw errors_1.PSAError.contractAuthNotSupported(stellar_sdk_1.Address.contract(authEntry.credentials().address().address().contractId()).toString(), (0, conveyor_belt_1.extractConveyorBeltErrorMeta)(item, this.getMeta(itemId))); } return stellar_sdk_1.Address.account(authEntry.credentials().address().address().accountId().ed25519()).toString(); } } exports.SorobanAuthPipeline = SorobanAuthPipeline;