@algorandfoundation/algokit-utils 10.0.0-alpha.43 → 10.0.0-alpha.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app-deployer.mjs CHANGED
@@ -73,9 +73,9 @@ var AppDeployer = class {
73
73
  data: metadata,
74
74
  format: "j"
75
75
  });
76
- if (existingDeployments && existingDeployments.creator.toString() !== createParams.sender.toString()) throw new Error(`Received invalid existingDeployments value for creator ${existingDeployments.creator} when attempting to deploy for creator ${createParams.sender}`);
76
+ if (existingDeployments && existingDeployments.creator.toString() !== createParams.sender.toString()) throw new Error(`Received invalid existingDeployments value for creator ${existingDeployments.creator} when attempting to deploy for creator ${getAddress(createParams.sender)}`);
77
77
  if (!existingDeployments && !this._indexer) throw new Error(`Didn't receive an indexer client when this AppManager was created, but also didn't receive an existingDeployments cache - one of them must be provided`);
78
- Config.getLogger(sendParams?.suppressLog).info(`Idempotently deploying app "${metadata.name}" from creator ${createParams.sender} using ${createParams.approvalProgram.length} bytes of ${typeof createParams.approvalProgram === "string" ? "teal code" : "AVM bytecode"} and ${createParams.clearStateProgram.length} bytes of ${typeof createParams.approvalProgram === "string" ? "teal code" : "AVM bytecode"}`);
78
+ Config.getLogger(sendParams?.suppressLog).info(`Idempotently deploying app "${metadata.name}" from creator ${getAddress(createParams.sender)} using ${createParams.approvalProgram.length} bytes of ${typeof createParams.approvalProgram === "string" ? "teal code" : "AVM bytecode"} and ${createParams.clearStateProgram.length} bytes of ${typeof createParams.approvalProgram === "string" ? "teal code" : "AVM bytecode"}`);
79
79
  const compiledApproval = typeof createParams.approvalProgram === "string" ? await this._appManager.compileTealTemplate(createParams.approvalProgram, deployTimeParams, metadata) : void 0;
80
80
  const approvalProgram = compiledApproval ? compiledApproval.compiledBase64ToBytes : createParams.approvalProgram;
81
81
  const compiledClear = typeof createParams.clearStateProgram === "string" ? await this._appManager.compileTealTemplate(createParams.clearStateProgram, deployTimeParams) : void 0;
@@ -111,7 +111,7 @@ var AppDeployer = class {
111
111
  };
112
112
  };
113
113
  const updateApp = async (existingApp) => {
114
- Config.getLogger(sendParams?.suppressLog).info(`Updating existing ${metadata.name} app for ${createParams.sender} to version ${metadata.version}.`);
114
+ Config.getLogger(sendParams?.suppressLog).info(`Updating existing ${metadata.name} app for ${getAddress(createParams.sender)} to version ${metadata.version}.`);
115
115
  const result = await ("method" in updateParams ? this._transactionSender.appUpdateMethodCall({
116
116
  appId: existingApp.appId,
117
117
  approvalProgram,
@@ -144,8 +144,8 @@ var AppDeployer = class {
144
144
  };
145
145
  };
146
146
  const replaceApp = async (existingApp) => {
147
- Config.getLogger(sendParams?.suppressLog).info(`Deploying a new ${metadata.name} app for ${createParams.sender}; deploying app with version ${metadata.version}.`);
148
- Config.getLogger(sendParams?.suppressLog).warn(`Deleting existing ${metadata.name} app with id ${existingApp.appId} from ${deleteParams.sender} account.`);
147
+ Config.getLogger(sendParams?.suppressLog).info(`Deploying a new ${metadata.name} app for ${getAddress(createParams.sender)}; deploying app with version ${metadata.version}.`);
148
+ Config.getLogger(sendParams?.suppressLog).warn(`Deleting existing ${metadata.name} app with id ${existingApp.appId} from ${getAddress(deleteParams.sender)} account.`);
149
149
  const composer = this._transactionSender.newGroup();
150
150
  if ("method" in createParams) composer.addAppCreateMethodCall({
151
151
  ...createParams,
@@ -170,7 +170,7 @@ var AppDeployer = class {
170
170
  const confirmation = result.confirmations.at(createIndex - 1);
171
171
  const transaction = result.transactions.at(createIndex - 1);
172
172
  const deleteTransaction = result.transactions.at(-1);
173
- Config.getLogger(sendParams?.suppressLog).warn(`Sent transactions ${transaction.txId()} to create app with id ${confirmation.appId} and ${deleteTransaction.txId()} to delete app with id ${existingApp.appId} from ${createParams.sender} account.`);
173
+ Config.getLogger(sendParams?.suppressLog).warn(`Sent transactions ${transaction.txId()} to create app with id ${confirmation.appId} and ${deleteTransaction.txId()} to delete app with id ${existingApp.appId} from ${getAddress(createParams.sender)} account.`);
174
174
  const appMetadata = {
175
175
  appId: confirmation.appId,
176
176
  appAddress: getApplicationAddress(confirmation.appId),
@@ -199,10 +199,10 @@ var AppDeployer = class {
199
199
  };
200
200
  const existingApp = (existingDeployments ?? await this.getCreatorAppsByName(createParams.sender, ignoreCache)).apps[metadata.name];
201
201
  if (!existingApp || existingApp.deleted) {
202
- Config.getLogger(sendParams?.suppressLog).info(`App ${metadata.name} not found in apps created by ${createParams.sender}; deploying app with version ${metadata.version}.`);
202
+ Config.getLogger(sendParams?.suppressLog).info(`App ${metadata.name} not found in apps created by ${getAddress(createParams.sender)}; deploying app with version ${metadata.version}.`);
203
203
  return await createApp();
204
204
  }
205
- Config.getLogger(sendParams?.suppressLog).info(`Existing app ${metadata.name} found by creator ${createParams.sender}, with app id ${existingApp.appId} and version ${existingApp.version}.`);
205
+ Config.getLogger(sendParams?.suppressLog).info(`Existing app ${metadata.name} found by creator ${getAddress(createParams.sender)}, with app id ${existingApp.appId} and version ${existingApp.version}.`);
206
206
  const existingAppRecord = await this._appManager.getById(existingApp.appId);
207
207
  const existingApproval = Buffer.from(existingAppRecord.approvalProgram).toString("base64");
208
208
  const existingClear = Buffer.from(existingAppRecord.clearStateProgram).toString("base64");
@@ -237,7 +237,7 @@ var AppDeployer = class {
237
237
  return await replaceApp(existingApp);
238
238
  }
239
239
  if (isUpdate) {
240
- Config.getLogger(sendParams?.suppressLog).info(`Detected a TEAL update in app ${existingApp.appId} for creator ${createParams.sender}`);
240
+ Config.getLogger(sendParams?.suppressLog).info(`Detected a TEAL update in app ${existingApp.appId} for creator ${getAddress(createParams.sender)}`);
241
241
  if (onUpdate === void 0 || onUpdate === "fail" || onUpdate === OnUpdate.Fail) throw new Error("Update detected and onUpdate=Fail, stopping deployment. Try a different onUpdate value to not fail.");
242
242
  if (onUpdate === "append" || onUpdate === OnUpdate.AppendApp) {
243
243
  Config.getLogger(sendParams?.suppressLog).info("onUpdate=AppendApp, will attempt to create a new app");
@@ -1 +1 @@
1
- {"version":3,"file":"app-deployer.mjs","names":[],"sources":["../src/app-deployer.ts"],"sourcesContent":["import { ABIReturn } from '@algorandfoundation/algokit-abi'\nimport { Address, Expand, getAddress, getApplicationAddress, ReadableAddress } from '@algorandfoundation/algokit-common'\nimport { IndexerClient } from '@algorandfoundation/algokit-indexer-client'\nimport { TransactionType } from '@algorandfoundation/algokit-transact'\nimport { AlgorandClientTransactionSender } from './algorand-client-transaction-sender'\nimport {\n APP_DEPLOY_NOTE_DAPP,\n OnSchemaBreak,\n OnUpdate,\n type AppDeployMetadata,\n type SendAppCreateTransactionResult,\n type SendAppUpdateTransactionResult,\n type TealTemplateParams,\n} from './app'\nimport { AppManager } from './app-manager'\nimport {\n AppCreateMethodCall,\n AppCreateParams,\n AppDeleteMethodCall,\n AppDeleteParams,\n AppUpdateMethodCall,\n AppUpdateParams,\n TransactionComposer,\n} from './composer'\nimport { Config } from './config'\nimport { lookupAccountCreatedApplicationByAddress, searchTransactions } from './indexer-client'\nimport { ConfirmedTransactionResult, SendParams } from './transaction/types'\nimport { calculateExtraProgramPages } from './util'\n\n/** Params to specify an update transaction for an app deployment */\nexport type DeployAppUpdateParams = Expand<Omit<AppUpdateParams, 'appId' | 'approvalProgram' | 'clearStateProgram'>>\n/** Params to specify an update method call for an app deployment */\nexport type DeployAppUpdateMethodCall = Expand<Omit<AppUpdateMethodCall, 'appId' | 'approvalProgram' | 'clearStateProgram'>>\n/** Params to specify a transaction for an app deployment */\nexport type DeployAppDeleteParams = Expand<Omit<AppDeleteParams, 'appId'>>\n/** Params to specify a delete method call for an app deployment */\nexport type DeployAppDeleteMethodCall = Expand<Omit<AppDeleteMethodCall, 'appId'>>\n\n/** The parameters to idempotently deploy an app */\nexport type AppDeployParams = Expand<\n SendParams & {\n /** The deployment metadata */\n metadata: AppDeployMetadata\n /** Any deploy-time parameters to replace in the TEAL code before compiling it (used if teal code is passed in as a string) */\n deployTimeParams?: TealTemplateParams\n /** What action to perform if a schema break (storage schema or extra pages change) is detected:\n *\n * * `fail` - Fail the deployment (throw an error, **default**)\n * * `replace` - Delete the old app and create a new one\n * * `append` - Deploy a new app and leave the old one as is\n */\n onSchemaBreak?: 'replace' | 'fail' | 'append' | OnSchemaBreak\n /** What action to perform if a TEAL code update is detected:\n *\n * * `fail` - Fail the deployment (throw an error, **default**)\n * * `update` - Update the app with the new TEAL code\n * * `replace` - Delete the old app and create a new one\n * * `append` - Deploy a new app and leave the old one as is\n */\n onUpdate?: 'update' | 'replace' | 'fail' | 'append' | OnUpdate\n /** Create transaction parameters to use if a create needs to be issued as part of deployment */\n createParams: AppCreateParams | AppCreateMethodCall\n /** Update transaction parameters to use if an update needs to be issued as part of deployment */\n updateParams: DeployAppUpdateParams | DeployAppUpdateMethodCall\n /** Delete transaction parameters to use if a delete needs to be issued as part of deployment */\n deleteParams: DeployAppDeleteParams | DeployAppDeleteMethodCall\n /** Optional cached value of the existing apps for the given creator; use this to avoid an indexer lookup */\n existingDeployments?: AppLookup\n /** Whether or not to ignore the app metadata cache and force a lookup, default: use the cache **/\n ignoreCache?: boolean\n }\n>\n\n/** The metadata that can be collected about a deployed app */\nexport interface AppMetadata extends AppDeployMetadata {\n /** The id of the app */\n appId: bigint\n /** The Algorand address of the account associated with the app */\n appAddress: Address\n /** The round the app was created */\n createdRound: bigint\n /** The last round that the app was updated */\n updatedRound: bigint\n /** The metadata when the app was created */\n createdMetadata: AppDeployMetadata\n /** Whether or not the app is deleted */\n deleted: boolean\n}\n\n/** A lookup of name -> Algorand app for a creator */\nexport interface AppLookup {\n /** The address of the creator associated with this lookup */\n creator: Readonly<Address>\n /** A hash map of app name to app metadata */\n apps: {\n [name: string]: AppMetadata\n }\n}\n\nexport type AppDeployResult =\n | Expand<{ operationPerformed: 'create' } & Omit<AppMetadata, 'appId' | 'appAddress'> & SendAppCreateTransactionResult>\n | Expand<{ operationPerformed: 'update' } & AppMetadata & SendAppUpdateTransactionResult>\n | Expand<\n { operationPerformed: 'replace' } & Omit<AppMetadata, 'appId' | 'appAddress'> &\n SendAppCreateTransactionResult & {\n deleteReturn?: ABIReturn\n deleteResult: ConfirmedTransactionResult\n }\n >\n | Expand<{ operationPerformed: 'nothing' } & AppMetadata>\n\n/** Allows management of deployment and deployment metadata of applications. */\nexport class AppDeployer {\n private _appManager: AppManager\n private _transactionSender: AlgorandClientTransactionSender\n private _indexer?: IndexerClient\n private _appLookups = new Map<string, AppLookup>()\n\n /**\n * Creates an `AppManager`\n * @param appManager An `AppManager` instance\n * @param transactionSender An `AlgorandClientTransactionSender` instance\n * @param indexer An optional indexer instance; supply if you want to indexer to look up app metadata\n * @example\n * ```ts\n * const deployer = new AppDeployer(appManager, transactionSender, indexer)\n * ```\n */\n constructor(appManager: AppManager, transactionSender: AlgorandClientTransactionSender, indexer?: IndexerClient) {\n this._appManager = appManager\n this._transactionSender = transactionSender\n this._indexer = indexer\n }\n\n /**\n * Idempotently deploy (create if not exists, update if changed) an app against the given name for the given creator account, including deploy-time TEAL template placeholder substitutions (if specified).\n *\n * To understand the architecture decisions behind this functionality please see https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md\n *\n * **Note:** When using the return from this function be sure to check `operationPerformed` to get access to various return properties like `transaction`, `confirmation` and `deleteResult`.\n *\n * **Note:** if there is a breaking state schema change to an existing app (and `onSchemaBreak` is set to `'replace'`) the existing app will be deleted and re-created.\n *\n * **Note:** if there is an update (different TEAL code) to an existing app (and `onUpdate` is set to `'replace'`) the existing app will be deleted and re-created.\n * @param deployment The arguments to control the app deployment\n * @returns The result of the deployment\n * @example\n * ```ts\n * const deployResult = await deployer.deploy({\n * createParams: {\n * sender: 'SENDER_ADDRESS',\n * approvalProgram: 'APPROVAL PROGRAM',\n * clearStateProgram: 'CLEAR PROGRAM',\n * schema: {\n * globalByteSlices: 0,\n * globalInts: 0,\n * localByteSlices: 0,\n * localInts: 0\n * }\n * },\n * updateParams: {\n * sender: 'SENDER_ADDRESS'\n * },\n * deleteParams: {\n * sender: 'SENDER_ADDRESS'\n * },\n * metadata: { name: 'my_app', version: '2.0', updatable: false, deletable: false },\n * onSchemaBreak: 'append',\n * onUpdate: 'append'\n * })\n * ```\n */\n async deploy(deployment: AppDeployParams): Promise<AppDeployResult> {\n const {\n metadata,\n deployTimeParams,\n onSchemaBreak,\n onUpdate,\n createParams,\n updateParams,\n deleteParams,\n existingDeployments,\n ignoreCache,\n ...sendParams\n } = deployment\n\n // Set creation note\n\n createParams.note = updateParams.note = TransactionComposer.arc2Note({\n dAppName: APP_DEPLOY_NOTE_DAPP,\n data: metadata,\n format: 'j',\n })\n\n // Check for required fields\n\n if (existingDeployments && existingDeployments.creator.toString() !== createParams.sender.toString()) {\n throw new Error(\n `Received invalid existingDeployments value for creator ${existingDeployments.creator} when attempting to deploy for creator ${createParams.sender}`,\n )\n }\n if (!existingDeployments && !this._indexer) {\n throw new Error(\n `Didn't receive an indexer client when this AppManager was created, but also didn't receive an existingDeployments cache - one of them must be provided`,\n )\n }\n\n Config.getLogger(sendParams?.suppressLog).info(\n `Idempotently deploying app \"${metadata.name}\" from creator ${createParams.sender} using ${createParams.approvalProgram.length} bytes of ${typeof createParams.approvalProgram === 'string' ? 'teal code' : 'AVM bytecode'} and ${createParams.clearStateProgram.length} bytes of ${typeof createParams.approvalProgram === 'string' ? 'teal code' : 'AVM bytecode'}`,\n )\n\n // Compile code if required\n\n const compiledApproval =\n typeof createParams.approvalProgram === 'string'\n ? await this._appManager.compileTealTemplate(createParams.approvalProgram, deployTimeParams, metadata)\n : undefined\n const approvalProgram = compiledApproval ? compiledApproval.compiledBase64ToBytes : createParams.approvalProgram\n\n const compiledClear =\n typeof createParams.clearStateProgram === 'string'\n ? await this._appManager.compileTealTemplate(createParams.clearStateProgram, deployTimeParams)\n : undefined\n const clearStateProgram = compiledClear ? compiledClear.compiledBase64ToBytes : createParams.clearStateProgram\n\n // Define routines for create, update, and replace\n\n const createApp = async () => {\n const result = await ('method' in createParams\n ? this._transactionSender.appCreateMethodCall({ ...createParams, approvalProgram, clearStateProgram, ...sendParams })\n : this._transactionSender.appCreate({ ...createParams, approvalProgram, clearStateProgram, ...sendParams }))\n const appMetadata: AppMetadata = {\n appId: result.appId,\n appAddress: result.appAddress,\n ...metadata,\n createdMetadata: metadata,\n createdRound: BigInt(result.confirmation.confirmedRound!),\n updatedRound: BigInt(result.confirmation.confirmedRound!),\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n return {\n operationPerformed: 'create',\n compiledApproval,\n compiledClear,\n ...result,\n ...appMetadata,\n } satisfies SendAppCreateTransactionResult & AppMetadata & { operationPerformed: 'create' }\n }\n const updateApp = async (existingApp: AppMetadata) => {\n Config.getLogger(sendParams?.suppressLog).info(\n `Updating existing ${metadata.name} app for ${createParams.sender} to version ${metadata.version}.`,\n )\n const result = await ('method' in updateParams\n ? this._transactionSender.appUpdateMethodCall({\n appId: existingApp.appId,\n approvalProgram,\n clearStateProgram,\n ...updateParams,\n ...sendParams,\n })\n : this._transactionSender.appUpdate({\n appId: existingApp.appId,\n approvalProgram,\n clearStateProgram,\n ...updateParams,\n ...sendParams,\n }))\n const appMetadata: AppMetadata = {\n appId: existingApp.appId,\n appAddress: existingApp.appAddress,\n createdMetadata: existingApp.createdMetadata,\n createdRound: existingApp.createdRound,\n updatedRound: BigInt(result.confirmation.confirmedRound!),\n ...metadata,\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n return {\n operationPerformed: 'update',\n compiledApproval,\n compiledClear,\n ...result,\n ...appMetadata,\n } satisfies SendAppUpdateTransactionResult & AppMetadata & { operationPerformed: 'update' }\n }\n const replaceApp = async (existingApp: AppMetadata) => {\n Config.getLogger(sendParams?.suppressLog).info(\n `Deploying a new ${metadata.name} app for ${createParams.sender}; deploying app with version ${metadata.version}.`,\n )\n\n Config.getLogger(sendParams?.suppressLog).warn(\n `Deleting existing ${metadata.name} app with id ${existingApp.appId} from ${deleteParams.sender} account.`,\n )\n\n const composer = this._transactionSender.newGroup()\n if ('method' in createParams) {\n composer.addAppCreateMethodCall({ ...createParams, approvalProgram, clearStateProgram })\n } else {\n composer.addAppCreate({ ...createParams, approvalProgram, clearStateProgram })\n }\n const createIndex = await composer.count()\n if ('method' in deleteParams) {\n composer.addAppDeleteMethodCall({ appId: existingApp.appId, ...deleteParams })\n } else {\n composer.addAppDelete({ appId: existingApp.appId, ...deleteParams })\n }\n const result = await composer.send({ ...sendParams })\n const confirmation = result.confirmations.at(createIndex - 1)!\n const transaction = result.transactions.at(createIndex - 1)!\n const deleteTransaction = result.transactions.at(-1)!\n\n Config.getLogger(sendParams?.suppressLog).warn(\n `Sent transactions ${transaction.txId()} to create app with id ${confirmation.appId} and ${deleteTransaction.txId()} to delete app with id ${\n existingApp.appId\n } from ${createParams.sender} account.`,\n )\n\n const appMetadata: AppMetadata = {\n appId: confirmation.appId!,\n appAddress: getApplicationAddress(confirmation.appId!),\n ...metadata,\n createdMetadata: metadata,\n createdRound: BigInt(confirmation.confirmedRound!),\n updatedRound: BigInt(confirmation.confirmedRound!),\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n\n return {\n operationPerformed: 'replace',\n ...result,\n compiledApproval,\n compiledClear,\n transaction,\n confirmation,\n return: 'method' in createParams ? result.returns?.[0] : undefined,\n deleteReturn: 'method' in deleteParams ? result.returns?.at(-1) : undefined,\n ...appMetadata,\n deleteResult: { transaction: deleteTransaction, confirmation: result.confirmations.at(-1)! },\n } satisfies { operationPerformed: 'replace' } & AppMetadata &\n SendAppCreateTransactionResult & {\n deleteReturn?: ABIReturn\n deleteResult: ConfirmedTransactionResult\n }\n }\n\n // Lookup existing app metadata\n\n const apps = existingDeployments ?? (await this.getCreatorAppsByName(createParams.sender, ignoreCache))\n\n const existingApp = apps.apps[metadata.name]\n if (!existingApp || existingApp.deleted) {\n Config.getLogger(sendParams?.suppressLog).info(\n `App ${metadata.name} not found in apps created by ${createParams.sender}; deploying app with version ${metadata.version}.`,\n )\n\n return await createApp()\n }\n\n Config.getLogger(sendParams?.suppressLog).info(\n `Existing app ${metadata.name} found by creator ${createParams.sender}, with app id ${existingApp.appId} and version ${existingApp.version}.`,\n )\n\n const existingAppRecord = await this._appManager.getById(existingApp.appId)\n const existingApproval = Buffer.from(existingAppRecord.approvalProgram).toString('base64')\n const existingClear = Buffer.from(existingAppRecord.clearStateProgram).toString('base64')\n const extraPages = existingAppRecord.extraProgramPages ?? 0\n\n const newApprovalBytes = Buffer.from(approvalProgram)\n const newClearBytes = Buffer.from(clearStateProgram)\n const newApproval = newApprovalBytes.toString('base64')\n const newClear = newClearBytes.toString('base64')\n const newExtraPages = calculateExtraProgramPages(newApprovalBytes, newClearBytes)\n\n // Check for changes\n\n const isUpdate = newApproval !== existingApproval || newClear !== existingClear\n const isSchemaBreak =\n existingAppRecord.localInts < (createParams.schema?.localInts ?? 0) ||\n existingAppRecord.globalInts < (createParams.schema?.globalInts ?? 0) ||\n existingAppRecord.localByteSlices < (createParams.schema?.localByteSlices ?? 0) ||\n existingAppRecord.globalByteSlices < (createParams.schema?.globalByteSlices ?? 0) ||\n extraPages < newExtraPages\n\n if (isSchemaBreak) {\n Config.getLogger(sendParams?.suppressLog).warn(`Detected a breaking app schema change in app ${existingApp.appId}:`, {\n from: {\n globalInts: existingAppRecord.globalInts,\n globalByteSlices: existingAppRecord.globalByteSlices,\n localInts: existingAppRecord.localInts,\n localByteSlices: existingAppRecord.localByteSlices,\n extraProgramPages: extraPages,\n },\n to: { ...createParams.schema, extraProgramPages: newExtraPages },\n })\n\n if (onSchemaBreak === undefined || onSchemaBreak === 'fail' || onSchemaBreak === OnSchemaBreak.Fail) {\n throw new Error(\n 'Schema break detected and onSchemaBreak=OnSchemaBreak.Fail, stopping deployment. ' +\n 'If you want to try deleting and recreating the app then ' +\n 're-run with onSchemaBreak=OnSchemaBreak.ReplaceApp',\n )\n }\n\n if (onSchemaBreak === 'append' || onSchemaBreak === OnSchemaBreak.AppendApp) {\n Config.getLogger(sendParams?.suppressLog).info('onSchemaBreak=AppendApp, will attempt to create a new app')\n return await createApp()\n }\n\n if (existingApp.deletable) {\n Config.getLogger(sendParams?.suppressLog).info(\n 'App is deletable and onSchemaBreak=ReplaceApp, will attempt to create new app and delete old app',\n )\n } else {\n Config.getLogger(sendParams?.suppressLog).info(\n 'App is not deletable but onSchemaBreak=ReplaceApp, will attempt to delete app, delete will most likely fail',\n )\n }\n\n return await replaceApp(existingApp)\n }\n\n if (isUpdate) {\n Config.getLogger(sendParams?.suppressLog).info(\n `Detected a TEAL update in app ${existingApp.appId} for creator ${createParams.sender}`,\n )\n\n if (onUpdate === undefined || onUpdate === 'fail' || onUpdate === OnUpdate.Fail) {\n throw new Error('Update detected and onUpdate=Fail, stopping deployment. Try a different onUpdate value to not fail.')\n }\n\n if (onUpdate === 'append' || onUpdate === OnUpdate.AppendApp) {\n Config.getLogger(sendParams?.suppressLog).info('onUpdate=AppendApp, will attempt to create a new app')\n return await createApp()\n }\n\n if (onUpdate === 'update' || onUpdate === OnUpdate.UpdateApp) {\n if (existingApp.updatable) {\n Config.getLogger(sendParams?.suppressLog).info(`App is updatable and onUpdate=UpdateApp, updating app...`)\n } else {\n Config.getLogger(sendParams?.suppressLog).warn(\n `App is not updatable but onUpdate=UpdateApp, will attempt to update app, update will most likely fail`,\n )\n }\n\n return await updateApp(existingApp)\n }\n\n if (onUpdate === 'replace' || onUpdate === OnUpdate.ReplaceApp) {\n if (existingApp.deletable) {\n Config.getLogger(sendParams?.suppressLog).warn(\n 'App is deletable and onUpdate=ReplaceApp, creating new app and deleting old app...',\n )\n } else {\n Config.getLogger(sendParams?.suppressLog).warn(\n 'App is not deletable and onUpdate=ReplaceApp, will attempt to create new app and delete old app, delete will most likely fail',\n )\n }\n\n return await replaceApp(existingApp)\n }\n }\n\n Config.getLogger(sendParams?.suppressLog).debug('No detected changes in app, nothing to do.')\n\n return { ...existingApp, operationPerformed: 'nothing' }\n }\n\n private updateAppLookup(sender: ReadableAddress, appMetadata: AppMetadata) {\n const s = getAddress(sender).toString()\n const lookup = this._appLookups.get(s)\n if (!lookup) {\n this._appLookups.set(s, { creator: Address.fromString(s), apps: { [appMetadata.name]: appMetadata } })\n } else {\n lookup.apps[appMetadata.name] = appMetadata\n }\n }\n\n /**\n * Returns a lookup of name => app metadata (id, address, ...metadata) for all apps created by the given account that have\n * an [ARC-2](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0002.md) `AppDeployNote` as the transaction\n * note of the app creation transaction.\n *\n * This function caches the result for the given creator account so that subsequent calls will not require an indexer lookup.\n *\n * If the `AppManager` instance wasn't created with an indexer client, this function will throw an error.\n *\n * @param creator The address of the account that is the creator of the apps you want to search for\n * @param ignoreCache Whether or not to ignore the cache and force a lookup, default: use the cache\n * @returns A name-based lookup of the app metadata\n * @example\n * ```ts\n * const result = await deployer.getCreatorAppsByName(creator)\n */\n async getCreatorAppsByName(creator: ReadableAddress, ignoreCache?: boolean): Promise<AppLookup> {\n const appLookup: Record<string, AppMetadata> = {}\n\n const creatorAddress = getAddress(creator)\n const creatorString = creatorAddress.toString()\n if (!ignoreCache && this._appLookups.has(creatorString)) {\n return this._appLookups.get(creatorString)!\n }\n\n if (!this._indexer) {\n throw new Error(`Didn't receive an indexer client when this AppManager was created, but received a call to getCreatorApps`)\n }\n\n // Extract all apps that account created\n const createdApps = (await lookupAccountCreatedApplicationByAddress(this._indexer, creatorString))\n .map((a) => {\n return { id: a.id, createdAtRound: a.createdAtRound!, deleted: a.deleted }\n })\n .sort((a, b) => Number(a.createdAtRound - b.createdAtRound))\n\n // For each app that account created (in parallel)...\n const apps = await Promise.all(\n createdApps.map(async (createdApp) => {\n // Find any app transactions for that app in the round it was created (should always just be a single creation transaction)\n const appTransactions = await searchTransactions(this._indexer!, {\n minRound: createdApp.createdAtRound,\n txType: TransactionType.AppCall,\n applicationId: createdApp.id,\n address: creatorAddress,\n addressRole: 'sender',\n notePrefix: Buffer.from(APP_DEPLOY_NOTE_DAPP).toString('base64'),\n })\n\n // Triple check the transaction is intact by filtering for the one we want:\n // * application-id is 0 when the app is first created\n // * also verify the sender to prevent a potential security risk\n const appCreationTransaction = appTransactions.transactions.filter(\n (t) => t.applicationTransaction?.applicationId === 0n && t.sender.toString() === creatorAddress.toString(),\n )[0]\n\n const latestAppUpdateTransaction = appTransactions.transactions\n .filter((t) => t.sender.toString() === creatorAddress.toString())\n .sort((a, b) =>\n a.confirmedRound === b.confirmedRound\n ? (b.intraRoundOffset! - a.intraRoundOffset!) / 10\n : Number(b.confirmedRound! - a.confirmedRound!),\n )[0]\n\n if (!appCreationTransaction?.note)\n // No note; ignoring\n return null\n\n return { createdApp, appCreationTransaction, latestAppUpdateTransaction }\n }),\n )\n\n apps\n .filter((a) => a !== null)\n .forEach((a) => {\n const { createdApp, appCreationTransaction, latestAppUpdateTransaction } = a!\n\n const parseNote = (note?: string) => {\n if (!note) {\n // No note; ignoring...\n return\n }\n\n if (!note.startsWith(`${APP_DEPLOY_NOTE_DAPP}:j{`))\n // Clearly not APP_DEPLOY JSON; ignoring...\n return\n\n return JSON.parse(note.substring(APP_DEPLOY_NOTE_DAPP.length + 2)) as AppDeployMetadata\n }\n\n try {\n const creationNote = parseNote(\n appCreationTransaction.note ? Buffer.from(appCreationTransaction.note).toString('utf-8') : undefined,\n )\n const updateNote = parseNote(\n latestAppUpdateTransaction.note ? Buffer.from(latestAppUpdateTransaction.note).toString('utf-8') : undefined,\n )\n if (creationNote?.name) {\n appLookup[creationNote.name] = {\n appId: createdApp.id,\n appAddress: getApplicationAddress(createdApp.id),\n createdMetadata: creationNote,\n createdRound: appCreationTransaction.confirmedRound ?? 0n,\n ...(updateNote ?? creationNote),\n updatedRound: latestAppUpdateTransaction?.confirmedRound ?? 0n,\n deleted: createdApp.deleted ?? false,\n }\n }\n } catch (e) {\n Config.logger.warn(\n `Received error trying to retrieve app with ${createdApp.id} for creator ${creatorAddress}; failing silently`,\n e,\n )\n return\n }\n })\n\n const lookup = {\n creator: creatorAddress,\n apps: appLookup,\n }\n\n this._appLookups.set(creatorString, lookup)\n\n return lookup\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"app-deployer.mjs","names":[],"sources":["../src/app-deployer.ts"],"sourcesContent":["import { ABIReturn } from '@algorandfoundation/algokit-abi'\nimport { Address, Expand, getAddress, getApplicationAddress, ReadableAddress } from '@algorandfoundation/algokit-common'\nimport { IndexerClient } from '@algorandfoundation/algokit-indexer-client'\nimport { TransactionType } from '@algorandfoundation/algokit-transact'\nimport { AlgorandClientTransactionSender } from './algorand-client-transaction-sender'\nimport {\n APP_DEPLOY_NOTE_DAPP,\n OnSchemaBreak,\n OnUpdate,\n type AppDeployMetadata,\n type SendAppCreateTransactionResult,\n type SendAppUpdateTransactionResult,\n type TealTemplateParams,\n} from './app'\nimport { AppManager } from './app-manager'\nimport {\n AppCreateMethodCall,\n AppCreateParams,\n AppDeleteMethodCall,\n AppDeleteParams,\n AppUpdateMethodCall,\n AppUpdateParams,\n TransactionComposer,\n} from './composer'\nimport { Config } from './config'\nimport { lookupAccountCreatedApplicationByAddress, searchTransactions } from './indexer-client'\nimport { ConfirmedTransactionResult, SendParams } from './transaction/types'\nimport { calculateExtraProgramPages } from './util'\n\n/** Params to specify an update transaction for an app deployment */\nexport type DeployAppUpdateParams = Expand<Omit<AppUpdateParams, 'appId' | 'approvalProgram' | 'clearStateProgram'>>\n/** Params to specify an update method call for an app deployment */\nexport type DeployAppUpdateMethodCall = Expand<Omit<AppUpdateMethodCall, 'appId' | 'approvalProgram' | 'clearStateProgram'>>\n/** Params to specify a transaction for an app deployment */\nexport type DeployAppDeleteParams = Expand<Omit<AppDeleteParams, 'appId'>>\n/** Params to specify a delete method call for an app deployment */\nexport type DeployAppDeleteMethodCall = Expand<Omit<AppDeleteMethodCall, 'appId'>>\n\n/** The parameters to idempotently deploy an app */\nexport type AppDeployParams = Expand<\n SendParams & {\n /** The deployment metadata */\n metadata: AppDeployMetadata\n /** Any deploy-time parameters to replace in the TEAL code before compiling it (used if teal code is passed in as a string) */\n deployTimeParams?: TealTemplateParams\n /** What action to perform if a schema break (storage schema or extra pages change) is detected:\n *\n * * `fail` - Fail the deployment (throw an error, **default**)\n * * `replace` - Delete the old app and create a new one\n * * `append` - Deploy a new app and leave the old one as is\n */\n onSchemaBreak?: 'replace' | 'fail' | 'append' | OnSchemaBreak\n /** What action to perform if a TEAL code update is detected:\n *\n * * `fail` - Fail the deployment (throw an error, **default**)\n * * `update` - Update the app with the new TEAL code\n * * `replace` - Delete the old app and create a new one\n * * `append` - Deploy a new app and leave the old one as is\n */\n onUpdate?: 'update' | 'replace' | 'fail' | 'append' | OnUpdate\n /** Create transaction parameters to use if a create needs to be issued as part of deployment */\n createParams: AppCreateParams | AppCreateMethodCall\n /** Update transaction parameters to use if an update needs to be issued as part of deployment */\n updateParams: DeployAppUpdateParams | DeployAppUpdateMethodCall\n /** Delete transaction parameters to use if a delete needs to be issued as part of deployment */\n deleteParams: DeployAppDeleteParams | DeployAppDeleteMethodCall\n /** Optional cached value of the existing apps for the given creator; use this to avoid an indexer lookup */\n existingDeployments?: AppLookup\n /** Whether or not to ignore the app metadata cache and force a lookup, default: use the cache **/\n ignoreCache?: boolean\n }\n>\n\n/** The metadata that can be collected about a deployed app */\nexport interface AppMetadata extends AppDeployMetadata {\n /** The id of the app */\n appId: bigint\n /** The Algorand address of the account associated with the app */\n appAddress: Address\n /** The round the app was created */\n createdRound: bigint\n /** The last round that the app was updated */\n updatedRound: bigint\n /** The metadata when the app was created */\n createdMetadata: AppDeployMetadata\n /** Whether or not the app is deleted */\n deleted: boolean\n}\n\n/** A lookup of name -> Algorand app for a creator */\nexport interface AppLookup {\n /** The address of the creator associated with this lookup */\n creator: Readonly<Address>\n /** A hash map of app name to app metadata */\n apps: {\n [name: string]: AppMetadata\n }\n}\n\nexport type AppDeployResult =\n | Expand<{ operationPerformed: 'create' } & Omit<AppMetadata, 'appId' | 'appAddress'> & SendAppCreateTransactionResult>\n | Expand<{ operationPerformed: 'update' } & AppMetadata & SendAppUpdateTransactionResult>\n | Expand<\n { operationPerformed: 'replace' } & Omit<AppMetadata, 'appId' | 'appAddress'> &\n SendAppCreateTransactionResult & {\n deleteReturn?: ABIReturn\n deleteResult: ConfirmedTransactionResult\n }\n >\n | Expand<{ operationPerformed: 'nothing' } & AppMetadata>\n\n/** Allows management of deployment and deployment metadata of applications. */\nexport class AppDeployer {\n private _appManager: AppManager\n private _transactionSender: AlgorandClientTransactionSender\n private _indexer?: IndexerClient\n private _appLookups = new Map<string, AppLookup>()\n\n /**\n * Creates an `AppManager`\n * @param appManager An `AppManager` instance\n * @param transactionSender An `AlgorandClientTransactionSender` instance\n * @param indexer An optional indexer instance; supply if you want to indexer to look up app metadata\n * @example\n * ```ts\n * const deployer = new AppDeployer(appManager, transactionSender, indexer)\n * ```\n */\n constructor(appManager: AppManager, transactionSender: AlgorandClientTransactionSender, indexer?: IndexerClient) {\n this._appManager = appManager\n this._transactionSender = transactionSender\n this._indexer = indexer\n }\n\n /**\n * Idempotently deploy (create if not exists, update if changed) an app against the given name for the given creator account, including deploy-time TEAL template placeholder substitutions (if specified).\n *\n * To understand the architecture decisions behind this functionality please see https://github.com/algorandfoundation/algokit-cli/blob/main/docs/architecture-decisions/2023-01-12_smart-contract-deployment.md\n *\n * **Note:** When using the return from this function be sure to check `operationPerformed` to get access to various return properties like `transaction`, `confirmation` and `deleteResult`.\n *\n * **Note:** if there is a breaking state schema change to an existing app (and `onSchemaBreak` is set to `'replace'`) the existing app will be deleted and re-created.\n *\n * **Note:** if there is an update (different TEAL code) to an existing app (and `onUpdate` is set to `'replace'`) the existing app will be deleted and re-created.\n * @param deployment The arguments to control the app deployment\n * @returns The result of the deployment\n * @example\n * ```ts\n * const deployResult = await deployer.deploy({\n * createParams: {\n * sender: 'SENDER_ADDRESS',\n * approvalProgram: 'APPROVAL PROGRAM',\n * clearStateProgram: 'CLEAR PROGRAM',\n * schema: {\n * globalByteSlices: 0,\n * globalInts: 0,\n * localByteSlices: 0,\n * localInts: 0\n * }\n * },\n * updateParams: {\n * sender: 'SENDER_ADDRESS'\n * },\n * deleteParams: {\n * sender: 'SENDER_ADDRESS'\n * },\n * metadata: { name: 'my_app', version: '2.0', updatable: false, deletable: false },\n * onSchemaBreak: 'append',\n * onUpdate: 'append'\n * })\n * ```\n */\n async deploy(deployment: AppDeployParams): Promise<AppDeployResult> {\n const {\n metadata,\n deployTimeParams,\n onSchemaBreak,\n onUpdate,\n createParams,\n updateParams,\n deleteParams,\n existingDeployments,\n ignoreCache,\n ...sendParams\n } = deployment\n\n // Set creation note\n\n createParams.note = updateParams.note = TransactionComposer.arc2Note({\n dAppName: APP_DEPLOY_NOTE_DAPP,\n data: metadata,\n format: 'j',\n })\n\n // Check for required fields\n\n if (existingDeployments && existingDeployments.creator.toString() !== createParams.sender.toString()) {\n throw new Error(\n `Received invalid existingDeployments value for creator ${existingDeployments.creator} when attempting to deploy for creator ${getAddress(createParams.sender)}`,\n )\n }\n if (!existingDeployments && !this._indexer) {\n throw new Error(\n `Didn't receive an indexer client when this AppManager was created, but also didn't receive an existingDeployments cache - one of them must be provided`,\n )\n }\n\n Config.getLogger(sendParams?.suppressLog).info(\n `Idempotently deploying app \"${metadata.name}\" from creator ${getAddress(createParams.sender)} using ${createParams.approvalProgram.length} bytes of ${typeof createParams.approvalProgram === 'string' ? 'teal code' : 'AVM bytecode'} and ${createParams.clearStateProgram.length} bytes of ${typeof createParams.approvalProgram === 'string' ? 'teal code' : 'AVM bytecode'}`,\n )\n\n // Compile code if required\n\n const compiledApproval =\n typeof createParams.approvalProgram === 'string'\n ? await this._appManager.compileTealTemplate(createParams.approvalProgram, deployTimeParams, metadata)\n : undefined\n const approvalProgram = compiledApproval ? compiledApproval.compiledBase64ToBytes : createParams.approvalProgram\n\n const compiledClear =\n typeof createParams.clearStateProgram === 'string'\n ? await this._appManager.compileTealTemplate(createParams.clearStateProgram, deployTimeParams)\n : undefined\n const clearStateProgram = compiledClear ? compiledClear.compiledBase64ToBytes : createParams.clearStateProgram\n\n // Define routines for create, update, and replace\n\n const createApp = async () => {\n const result = await ('method' in createParams\n ? this._transactionSender.appCreateMethodCall({ ...createParams, approvalProgram, clearStateProgram, ...sendParams })\n : this._transactionSender.appCreate({ ...createParams, approvalProgram, clearStateProgram, ...sendParams }))\n const appMetadata: AppMetadata = {\n appId: result.appId,\n appAddress: result.appAddress,\n ...metadata,\n createdMetadata: metadata,\n createdRound: BigInt(result.confirmation.confirmedRound!),\n updatedRound: BigInt(result.confirmation.confirmedRound!),\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n return {\n operationPerformed: 'create',\n compiledApproval,\n compiledClear,\n ...result,\n ...appMetadata,\n } satisfies SendAppCreateTransactionResult & AppMetadata & { operationPerformed: 'create' }\n }\n const updateApp = async (existingApp: AppMetadata) => {\n Config.getLogger(sendParams?.suppressLog).info(\n `Updating existing ${metadata.name} app for ${getAddress(createParams.sender)} to version ${metadata.version}.`,\n )\n const result = await ('method' in updateParams\n ? this._transactionSender.appUpdateMethodCall({\n appId: existingApp.appId,\n approvalProgram,\n clearStateProgram,\n ...updateParams,\n ...sendParams,\n })\n : this._transactionSender.appUpdate({\n appId: existingApp.appId,\n approvalProgram,\n clearStateProgram,\n ...updateParams,\n ...sendParams,\n }))\n const appMetadata: AppMetadata = {\n appId: existingApp.appId,\n appAddress: existingApp.appAddress,\n createdMetadata: existingApp.createdMetadata,\n createdRound: existingApp.createdRound,\n updatedRound: BigInt(result.confirmation.confirmedRound!),\n ...metadata,\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n return {\n operationPerformed: 'update',\n compiledApproval,\n compiledClear,\n ...result,\n ...appMetadata,\n } satisfies SendAppUpdateTransactionResult & AppMetadata & { operationPerformed: 'update' }\n }\n const replaceApp = async (existingApp: AppMetadata) => {\n Config.getLogger(sendParams?.suppressLog).info(\n `Deploying a new ${metadata.name} app for ${getAddress(createParams.sender)}; deploying app with version ${metadata.version}.`,\n )\n\n Config.getLogger(sendParams?.suppressLog).warn(\n `Deleting existing ${metadata.name} app with id ${existingApp.appId} from ${getAddress(deleteParams.sender)} account.`,\n )\n\n const composer = this._transactionSender.newGroup()\n if ('method' in createParams) {\n composer.addAppCreateMethodCall({ ...createParams, approvalProgram, clearStateProgram })\n } else {\n composer.addAppCreate({ ...createParams, approvalProgram, clearStateProgram })\n }\n const createIndex = await composer.count()\n if ('method' in deleteParams) {\n composer.addAppDeleteMethodCall({ appId: existingApp.appId, ...deleteParams })\n } else {\n composer.addAppDelete({ appId: existingApp.appId, ...deleteParams })\n }\n const result = await composer.send({ ...sendParams })\n const confirmation = result.confirmations.at(createIndex - 1)!\n const transaction = result.transactions.at(createIndex - 1)!\n const deleteTransaction = result.transactions.at(-1)!\n\n Config.getLogger(sendParams?.suppressLog).warn(\n `Sent transactions ${transaction.txId()} to create app with id ${confirmation.appId} and ${deleteTransaction.txId()} to delete app with id ${\n existingApp.appId\n } from ${getAddress(createParams.sender)} account.`,\n )\n\n const appMetadata: AppMetadata = {\n appId: confirmation.appId!,\n appAddress: getApplicationAddress(confirmation.appId!),\n ...metadata,\n createdMetadata: metadata,\n createdRound: BigInt(confirmation.confirmedRound!),\n updatedRound: BigInt(confirmation.confirmedRound!),\n deleted: false,\n }\n this.updateAppLookup(createParams.sender, appMetadata)\n\n return {\n operationPerformed: 'replace',\n ...result,\n compiledApproval,\n compiledClear,\n transaction,\n confirmation,\n return: 'method' in createParams ? result.returns?.[0] : undefined,\n deleteReturn: 'method' in deleteParams ? result.returns?.at(-1) : undefined,\n ...appMetadata,\n deleteResult: { transaction: deleteTransaction, confirmation: result.confirmations.at(-1)! },\n } satisfies { operationPerformed: 'replace' } & AppMetadata &\n SendAppCreateTransactionResult & {\n deleteReturn?: ABIReturn\n deleteResult: ConfirmedTransactionResult\n }\n }\n\n // Lookup existing app metadata\n\n const apps = existingDeployments ?? (await this.getCreatorAppsByName(createParams.sender, ignoreCache))\n\n const existingApp = apps.apps[metadata.name]\n if (!existingApp || existingApp.deleted) {\n Config.getLogger(sendParams?.suppressLog).info(\n `App ${metadata.name} not found in apps created by ${getAddress(createParams.sender)}; deploying app with version ${metadata.version}.`,\n )\n\n return await createApp()\n }\n\n Config.getLogger(sendParams?.suppressLog).info(\n `Existing app ${metadata.name} found by creator ${getAddress(createParams.sender)}, with app id ${existingApp.appId} and version ${existingApp.version}.`,\n )\n\n const existingAppRecord = await this._appManager.getById(existingApp.appId)\n const existingApproval = Buffer.from(existingAppRecord.approvalProgram).toString('base64')\n const existingClear = Buffer.from(existingAppRecord.clearStateProgram).toString('base64')\n const extraPages = existingAppRecord.extraProgramPages ?? 0\n\n const newApprovalBytes = Buffer.from(approvalProgram)\n const newClearBytes = Buffer.from(clearStateProgram)\n const newApproval = newApprovalBytes.toString('base64')\n const newClear = newClearBytes.toString('base64')\n const newExtraPages = calculateExtraProgramPages(newApprovalBytes, newClearBytes)\n\n // Check for changes\n\n const isUpdate = newApproval !== existingApproval || newClear !== existingClear\n const isSchemaBreak =\n existingAppRecord.localInts < (createParams.schema?.localInts ?? 0) ||\n existingAppRecord.globalInts < (createParams.schema?.globalInts ?? 0) ||\n existingAppRecord.localByteSlices < (createParams.schema?.localByteSlices ?? 0) ||\n existingAppRecord.globalByteSlices < (createParams.schema?.globalByteSlices ?? 0) ||\n extraPages < newExtraPages\n\n if (isSchemaBreak) {\n Config.getLogger(sendParams?.suppressLog).warn(`Detected a breaking app schema change in app ${existingApp.appId}:`, {\n from: {\n globalInts: existingAppRecord.globalInts,\n globalByteSlices: existingAppRecord.globalByteSlices,\n localInts: existingAppRecord.localInts,\n localByteSlices: existingAppRecord.localByteSlices,\n extraProgramPages: extraPages,\n },\n to: { ...createParams.schema, extraProgramPages: newExtraPages },\n })\n\n if (onSchemaBreak === undefined || onSchemaBreak === 'fail' || onSchemaBreak === OnSchemaBreak.Fail) {\n throw new Error(\n 'Schema break detected and onSchemaBreak=OnSchemaBreak.Fail, stopping deployment. ' +\n 'If you want to try deleting and recreating the app then ' +\n 're-run with onSchemaBreak=OnSchemaBreak.ReplaceApp',\n )\n }\n\n if (onSchemaBreak === 'append' || onSchemaBreak === OnSchemaBreak.AppendApp) {\n Config.getLogger(sendParams?.suppressLog).info('onSchemaBreak=AppendApp, will attempt to create a new app')\n return await createApp()\n }\n\n if (existingApp.deletable) {\n Config.getLogger(sendParams?.suppressLog).info(\n 'App is deletable and onSchemaBreak=ReplaceApp, will attempt to create new app and delete old app',\n )\n } else {\n Config.getLogger(sendParams?.suppressLog).info(\n 'App is not deletable but onSchemaBreak=ReplaceApp, will attempt to delete app, delete will most likely fail',\n )\n }\n\n return await replaceApp(existingApp)\n }\n\n if (isUpdate) {\n Config.getLogger(sendParams?.suppressLog).info(\n `Detected a TEAL update in app ${existingApp.appId} for creator ${getAddress(createParams.sender)}`,\n )\n\n if (onUpdate === undefined || onUpdate === 'fail' || onUpdate === OnUpdate.Fail) {\n throw new Error('Update detected and onUpdate=Fail, stopping deployment. Try a different onUpdate value to not fail.')\n }\n\n if (onUpdate === 'append' || onUpdate === OnUpdate.AppendApp) {\n Config.getLogger(sendParams?.suppressLog).info('onUpdate=AppendApp, will attempt to create a new app')\n return await createApp()\n }\n\n if (onUpdate === 'update' || onUpdate === OnUpdate.UpdateApp) {\n if (existingApp.updatable) {\n Config.getLogger(sendParams?.suppressLog).info(`App is updatable and onUpdate=UpdateApp, updating app...`)\n } else {\n Config.getLogger(sendParams?.suppressLog).warn(\n `App is not updatable but onUpdate=UpdateApp, will attempt to update app, update will most likely fail`,\n )\n }\n\n return await updateApp(existingApp)\n }\n\n if (onUpdate === 'replace' || onUpdate === OnUpdate.ReplaceApp) {\n if (existingApp.deletable) {\n Config.getLogger(sendParams?.suppressLog).warn(\n 'App is deletable and onUpdate=ReplaceApp, creating new app and deleting old app...',\n )\n } else {\n Config.getLogger(sendParams?.suppressLog).warn(\n 'App is not deletable and onUpdate=ReplaceApp, will attempt to create new app and delete old app, delete will most likely fail',\n )\n }\n\n return await replaceApp(existingApp)\n }\n }\n\n Config.getLogger(sendParams?.suppressLog).debug('No detected changes in app, nothing to do.')\n\n return { ...existingApp, operationPerformed: 'nothing' }\n }\n\n private updateAppLookup(sender: ReadableAddress, appMetadata: AppMetadata) {\n const s = getAddress(sender).toString()\n const lookup = this._appLookups.get(s)\n if (!lookup) {\n this._appLookups.set(s, { creator: Address.fromString(s), apps: { [appMetadata.name]: appMetadata } })\n } else {\n lookup.apps[appMetadata.name] = appMetadata\n }\n }\n\n /**\n * Returns a lookup of name => app metadata (id, address, ...metadata) for all apps created by the given account that have\n * an [ARC-2](https://github.com/algorandfoundation/ARCs/blob/main/ARCs/arc-0002.md) `AppDeployNote` as the transaction\n * note of the app creation transaction.\n *\n * This function caches the result for the given creator account so that subsequent calls will not require an indexer lookup.\n *\n * If the `AppManager` instance wasn't created with an indexer client, this function will throw an error.\n *\n * @param creator The address of the account that is the creator of the apps you want to search for\n * @param ignoreCache Whether or not to ignore the cache and force a lookup, default: use the cache\n * @returns A name-based lookup of the app metadata\n * @example\n * ```ts\n * const result = await deployer.getCreatorAppsByName(creator)\n */\n async getCreatorAppsByName(creator: ReadableAddress, ignoreCache?: boolean): Promise<AppLookup> {\n const appLookup: Record<string, AppMetadata> = {}\n\n const creatorAddress = getAddress(creator)\n const creatorString = creatorAddress.toString()\n if (!ignoreCache && this._appLookups.has(creatorString)) {\n return this._appLookups.get(creatorString)!\n }\n\n if (!this._indexer) {\n throw new Error(`Didn't receive an indexer client when this AppManager was created, but received a call to getCreatorApps`)\n }\n\n // Extract all apps that account created\n const createdApps = (await lookupAccountCreatedApplicationByAddress(this._indexer, creatorString))\n .map((a) => {\n return { id: a.id, createdAtRound: a.createdAtRound!, deleted: a.deleted }\n })\n .sort((a, b) => Number(a.createdAtRound - b.createdAtRound))\n\n // For each app that account created (in parallel)...\n const apps = await Promise.all(\n createdApps.map(async (createdApp) => {\n // Find any app transactions for that app in the round it was created (should always just be a single creation transaction)\n const appTransactions = await searchTransactions(this._indexer!, {\n minRound: createdApp.createdAtRound,\n txType: TransactionType.AppCall,\n applicationId: createdApp.id,\n address: creatorAddress,\n addressRole: 'sender',\n notePrefix: Buffer.from(APP_DEPLOY_NOTE_DAPP).toString('base64'),\n })\n\n // Triple check the transaction is intact by filtering for the one we want:\n // * application-id is 0 when the app is first created\n // * also verify the sender to prevent a potential security risk\n const appCreationTransaction = appTransactions.transactions.filter(\n (t) => t.applicationTransaction?.applicationId === 0n && t.sender.toString() === creatorAddress.toString(),\n )[0]\n\n const latestAppUpdateTransaction = appTransactions.transactions\n .filter((t) => t.sender.toString() === creatorAddress.toString())\n .sort((a, b) =>\n a.confirmedRound === b.confirmedRound\n ? (b.intraRoundOffset! - a.intraRoundOffset!) / 10\n : Number(b.confirmedRound! - a.confirmedRound!),\n )[0]\n\n if (!appCreationTransaction?.note)\n // No note; ignoring\n return null\n\n return { createdApp, appCreationTransaction, latestAppUpdateTransaction }\n }),\n )\n\n apps\n .filter((a) => a !== null)\n .forEach((a) => {\n const { createdApp, appCreationTransaction, latestAppUpdateTransaction } = a!\n\n const parseNote = (note?: string) => {\n if (!note) {\n // No note; ignoring...\n return\n }\n\n if (!note.startsWith(`${APP_DEPLOY_NOTE_DAPP}:j{`))\n // Clearly not APP_DEPLOY JSON; ignoring...\n return\n\n return JSON.parse(note.substring(APP_DEPLOY_NOTE_DAPP.length + 2)) as AppDeployMetadata\n }\n\n try {\n const creationNote = parseNote(\n appCreationTransaction.note ? Buffer.from(appCreationTransaction.note).toString('utf-8') : undefined,\n )\n const updateNote = parseNote(\n latestAppUpdateTransaction.note ? Buffer.from(latestAppUpdateTransaction.note).toString('utf-8') : undefined,\n )\n if (creationNote?.name) {\n appLookup[creationNote.name] = {\n appId: createdApp.id,\n appAddress: getApplicationAddress(createdApp.id),\n createdMetadata: creationNote,\n createdRound: appCreationTransaction.confirmedRound ?? 0n,\n ...(updateNote ?? creationNote),\n updatedRound: latestAppUpdateTransaction?.confirmedRound ?? 0n,\n deleted: createdApp.deleted ?? false,\n }\n }\n } catch (e) {\n Config.logger.warn(\n `Received error trying to retrieve app with ${createdApp.id} for creator ${creatorAddress}; failing silently`,\n e,\n )\n return\n }\n })\n\n const lookup = {\n creator: creatorAddress,\n apps: appLookup,\n }\n\n this._appLookups.set(creatorString, lookup)\n\n return lookup\n }\n}\n"],"mappings":"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"}
package/app-factory.d.ts CHANGED
@@ -211,9 +211,9 @@ declare class AppFactory {
211
211
  sender: Address;
212
212
  signer: AddressWithTransactionSigner | TransactionSigner | undefined;
213
213
  method: ABIMethod;
214
- args: (Transaction | TransactionWithSigner | Promise<Transaction> | ABIValue | AppMethodCall<{
215
- sender: SendingAddress;
214
+ args: (Transaction | Promise<Transaction> | ABIValue | TransactionWithSigner | AppMethodCall<{
216
215
  signer?: (TransactionSigner | AddressWithTransactionSigner) | undefined;
216
+ sender: SendingAddress;
217
217
  rekeyTo?: ReadableAddress | undefined;
218
218
  note?: (Uint8Array | string) | undefined;
219
219
  lease?: (Uint8Array | string) | undefined;
@@ -293,9 +293,9 @@ declare class AppFactory {
293
293
  sender: Address;
294
294
  signer: AddressWithTransactionSigner | TransactionSigner | undefined;
295
295
  method: ABIMethod;
296
- args: (Transaction | TransactionWithSigner | Promise<Transaction> | ABIValue | AppMethodCall<{
297
- sender: SendingAddress;
296
+ args: (Transaction | Promise<Transaction> | ABIValue | TransactionWithSigner | AppMethodCall<{
298
297
  signer?: (TransactionSigner | AddressWithTransactionSigner) | undefined;
298
+ sender: SendingAddress;
299
299
  rekeyTo?: ReadableAddress | undefined;
300
300
  note?: (Uint8Array | string) | undefined;
301
301
  lease?: (Uint8Array | string) | undefined;
@@ -375,9 +375,9 @@ declare class AppFactory {
375
375
  sender: Address;
376
376
  signer: AddressWithTransactionSigner | TransactionSigner | undefined;
377
377
  method: ABIMethod;
378
- args: (Transaction | TransactionWithSigner | Promise<Transaction> | ABIValue | AppMethodCall<{
379
- sender: SendingAddress;
378
+ args: (Transaction | Promise<Transaction> | ABIValue | TransactionWithSigner | AppMethodCall<{
380
379
  signer?: (TransactionSigner | AddressWithTransactionSigner) | undefined;
380
+ sender: SendingAddress;
381
381
  rekeyTo?: ReadableAddress | undefined;
382
382
  note?: (Uint8Array | string) | undefined;
383
383
  lease?: (Uint8Array | string) | undefined;
@@ -653,7 +653,6 @@ declare class AppFactory {
653
653
  compiledApproval?: CompiledTeal | undefined;
654
654
  compiledClear?: CompiledTeal | undefined;
655
655
  operationPerformed: "create";
656
- version: string;
657
656
  updatable?: boolean | undefined;
658
657
  deletable?: boolean | undefined;
659
658
  createdRound: bigint;
@@ -661,6 +660,7 @@ declare class AppFactory {
661
660
  createdMetadata: AppDeployMetadata;
662
661
  deleted: boolean;
663
662
  name: string;
663
+ version: string;
664
664
  groupId: string | undefined;
665
665
  txIds: string[];
666
666
  returns?: ABIReturn[] | undefined;
@@ -699,7 +699,6 @@ declare class AppFactory {
699
699
  compiledApproval?: CompiledTeal | undefined;
700
700
  compiledClear?: CompiledTeal | undefined;
701
701
  operationPerformed: "replace";
702
- version: string;
703
702
  updatable?: boolean | undefined;
704
703
  deletable?: boolean | undefined;
705
704
  createdRound: bigint;
@@ -707,6 +706,7 @@ declare class AppFactory {
707
706
  createdMetadata: AppDeployMetadata;
708
707
  deleted: boolean;
709
708
  name: string;
709
+ version: string;
710
710
  groupId: string | undefined;
711
711
  txIds: string[];
712
712
  returns?: ABIReturn[] | undefined;
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "**"
7
7
  ],
8
8
  "name": "@algorandfoundation/algokit-utils",
9
- "version": "10.0.0-alpha.43",
9
+ "version": "10.0.0-alpha.45",
10
10
  "private": false,
11
11
  "description": "A set of core Algorand utilities written in TypeScript and released via npm that make it easier to build solutions on Algorand.",
12
12
  "author": "Algorand Foundation",
@@ -29,8 +29,8 @@ const throwWrapUnwrapErrors = (operationError, wrapError, operationName) => {
29
29
  throw new AggregateError([operationError, wrapError], `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`);
30
30
  };
31
31
  function rawSign(extendedSecretKey, data) {
32
- const scalar = (0, _noble_curves_utils_js.bytesToNumberLE)(extendedSecretKey.slice(0, 32));
33
- const kR = extendedSecretKey.slice(32, 64);
32
+ const scalar = (0, _noble_curves_utils_js.bytesToNumberLE)(extendedSecretKey.subarray(0, 32));
33
+ const kR = extendedSecretKey.subarray(32, 64);
34
34
  const publicKey = rawPubkey(extendedSecretKey);
35
35
  const r = (0, _noble_curves_abstract_modular_js.mod)((0, _noble_curves_utils_js.bytesToNumberLE)((0, _noble_hashes_sha2_js.sha512)(new Uint8Array([...kR, ...data]))), _noble_curves_ed25519_js.ed25519.Point.Fn.ORDER);
36
36
  const R = _noble_curves_ed25519_js.ed25519.Point.BASE.multiply(r);
@@ -42,7 +42,9 @@ function rawSign(extendedSecretKey, data) {
42
42
  return new Uint8Array([...R.toBytes(), ...(0, _noble_curves_utils_js.numberToBytesLE)(S, 32)]);
43
43
  }
44
44
  function rawPubkey(extendedSecretKey) {
45
- const reducedScalar = (0, _noble_curves_abstract_modular_js.mod)((0, _noble_curves_utils_js.bytesToNumberLE)(extendedSecretKey.slice(0, 32)) & (1n << 255n) - 1n, _noble_curves_ed25519_js.ed25519.Point.Fn.ORDER);
45
+ const scalar = (0, _noble_curves_utils_js.bytesToNumberLE)(extendedSecretKey.subarray(0, 32));
46
+ if ((scalar & 1n << 255n) !== 0n) throw new Error("Invalid HD-expanded Ed25519 secret scalar: most-significant bit (bit 255) of the 32-byte scalar must be 0 for rawSign/rawPubkey inputs.");
47
+ const reducedScalar = (0, _noble_curves_abstract_modular_js.mod)(scalar, _noble_curves_ed25519_js.ed25519.Point.Fn.ORDER);
46
48
  return _noble_curves_ed25519_js.ed25519.Point.BASE.multiply(reducedScalar).toBytes();
47
49
  }
48
50
  /**
@@ -71,7 +73,7 @@ const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap) => {
71
73
  } else if ("unwrapHdExtendedPrivateKey" in wrapUnwrap) {
72
74
  secret = await wrapUnwrap.unwrapHdExtendedPrivateKey();
73
75
  assertEd25519SecretLength(secret, "HD extended key");
74
- signature = rawSign(secret.slice(0, 64), bytesToSign);
76
+ signature = rawSign(secret.subarray(0, 64), bytesToSign);
75
77
  } else throw new Error("Invalid WrappedEd25519Secret: missing unwrap function");
76
78
  } catch (error) {
77
79
  signingError = error;
@@ -102,7 +104,7 @@ const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap) => {
102
104
  } else if ("unwrapHdExtendedPrivateKey" in wrapUnwrap) {
103
105
  secret = await wrapUnwrap.unwrapHdExtendedPrivateKey();
104
106
  assertEd25519SecretLength(secret, "HD extended key");
105
- pubkey = rawPubkey(secret.slice(0, 64));
107
+ pubkey = rawPubkey(secret.subarray(0, 64));
106
108
  } else throw new Error("Invalid WrappedEd25519Secret: missing unwrap function");
107
109
  } catch (error) {
108
110
  pubkeyError = error;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["ed25519","ed"],"sources":["../../../../packages/crypto/src/index.ts"],"sourcesContent":["import { Ed25519SigningKey, WrappedEd25519Seed } from './ed25519'\nimport * as ed from '@noble/ed25519'\nimport { WrappedHdExtendedPrivateKey } from './hd'\nimport { ed25519 } from '@noble/curves/ed25519.js'\nimport { sha512 } from '@noble/hashes/sha2.js'\nimport { bytesToNumberLE, numberToBytesLE } from '@noble/curves/utils.js'\nimport { mod } from '@noble/curves/abstract/modular.js'\n\nexport * from './ed25519'\nexport * from './hash'\nexport * from './hd'\n\nexport type WrappedEd25519Secret = WrappedEd25519Seed | WrappedHdExtendedPrivateKey\n\nconst ED25519_SEED_LENGTH = 32\nconst ED25519_EXTENDED_PRIVATE_KEY_LENGTH = 96\n\nconst assertEd25519SecretLength = (secret: Uint8Array, secretType: 'ed25519 seed' | 'HD extended key'): void => {\n let expectedLength: number\n switch (secretType) {\n case 'ed25519 seed':\n expectedLength = ED25519_SEED_LENGTH\n break\n case 'HD extended key':\n expectedLength = ED25519_EXTENDED_PRIVATE_KEY_LENGTH\n break\n default:\n throw new Error(`Unknown secret type: ${secretType}`)\n }\n\n if (secret.length !== expectedLength) {\n throw new Error(`Expected unwrapped ${secretType} to be ${expectedLength} bytes, got ${secret.length}.`)\n }\n}\n\nconst throwWrapUnwrapErrors = (operationError: unknown, wrapError: unknown, operationName: string): never => {\n throw new AggregateError(\n [operationError, wrapError],\n `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`,\n )\n}\n\nfunction rawSign(extendedSecretKey: Uint8Array, data: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32))\n\n const kR = extendedSecretKey.slice(32, 64)\n\n // (1): pubKey = scalar * G\n const publicKey = rawPubkey(extendedSecretKey)\n\n // (2): h = hash(kR || msg) mod q\n const rHash = sha512(new Uint8Array([...kR, ...data]))\n const r = mod(bytesToNumberLE(rHash), ed25519.Point.Fn.ORDER)\n\n // (4): R = r * G\n const R = ed25519.Point.BASE.multiply(r)\n\n // h = hash(R || pubKey || msg) mod q\n const hHash = sha512(new Uint8Array([...R.toBytes(), ...publicKey, ...data]))\n const h = mod(bytesToNumberLE(hHash), ed25519.Point.Fn.ORDER)\n\n // (5): S = (r + h * k) mod q\n const S = mod(r + h * scalar, ed25519.Point.Fn.ORDER)\n\n return new Uint8Array([...R.toBytes(), ...numberToBytesLE(S, 32)])\n}\n\nfunction rawPubkey(extendedSecretKey: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32))\n const clearedTopBitScalar = scalar & ((1n << 255n) - 1n)\n const reducedScalar = mod(clearedTopBitScalar, ed25519.Point.Fn.ORDER)\n\n // pubKey = scalar * G\n const publicKey = ed25519.Point.BASE.multiply(reducedScalar)\n return publicKey.toBytes()\n}\n\n/**\n * Creates an Ed25519 signing key from a wrapped secret using the @noble/ed25519 implementation.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the Ed25519 secret.\n * @returns A promise that resolves to an Ed25519 signing key containing the public key and raw signer.\n */\nexport const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap: WrappedEd25519Secret): Promise<Ed25519SigningKey> => {\n let wrapFunction: () => Promise<void>\n if ('wrapEd25519Seed' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapEd25519Seed\n } else if ('wrapHdExtendedPrivateKey' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapHdExtendedPrivateKey\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing wrap function')\n }\n\n const signer = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n let secret: Uint8Array | undefined = undefined\n let signature: Uint8Array | undefined = undefined\n let signingError: unknown\n let wrapError: unknown\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n signature = await ed.signAsync(bytesToSign, secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n signature = rawSign(secret.slice(0, 64), bytesToSign)\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n signingError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (signingError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(signingError, wrapError, 'Signing')\n }\n\n if (signingError !== undefined) {\n throw signingError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (signature === undefined) {\n throw new Error('Signing failed unexpectedly without an error.')\n }\n\n return signature\n }\n\n let pubkey: Uint8Array | undefined = undefined\n let pubkeyError: unknown\n let wrapError: unknown\n let secret: Uint8Array | undefined = undefined\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n pubkey = await ed.getPublicKeyAsync(secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n pubkey = rawPubkey(secret.slice(0, 64))\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n pubkeyError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (pubkeyError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(pubkeyError, wrapError, 'Deriving Ed25519 public key')\n }\n\n if (pubkeyError !== undefined) {\n throw pubkeyError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (pubkey === undefined) {\n throw new Error('Deriving Ed25519 public key failed unexpectedly without an error.')\n }\n\n return {\n ed25519Pubkey: pubkey,\n rawEd25519Signer: signer,\n }\n}\n\n/**\n * Creates an ed25519 signing key from a wrapped secret using the default ed25519 implementation (currently @noble/ed25519).\n * The implementation may change in the future. To explicitly use the @noble/ed25519 implementation, use `nobleEd25519SigningKeyFromWrappedSecret`.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the ed25519 secret.\n * @returns A promise that resolves to an ed25519 signing key with public key and raw signer.\n */\nexport const ed25519SigningKeyFromWrappedSecret = nobleEd25519SigningKeyFromWrappedSecret\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ed25519","ed"],"sources":["../../../../packages/crypto/src/index.ts"],"sourcesContent":["import { Ed25519SigningKey, WrappedEd25519Seed } from './ed25519'\nimport * as ed from '@noble/ed25519'\nimport { WrappedHdExtendedPrivateKey } from './hd'\nimport { ed25519 } from '@noble/curves/ed25519.js'\nimport { sha512 } from '@noble/hashes/sha2.js'\nimport { bytesToNumberLE, numberToBytesLE } from '@noble/curves/utils.js'\nimport { mod } from '@noble/curves/abstract/modular.js'\n\nexport * from './ed25519'\nexport * from './hash'\nexport * from './hd'\n\nexport type WrappedEd25519Secret = WrappedEd25519Seed | WrappedHdExtendedPrivateKey\n\nconst ED25519_SEED_LENGTH = 32\nconst ED25519_EXTENDED_PRIVATE_KEY_LENGTH = 96\n\nconst assertEd25519SecretLength = (secret: Uint8Array, secretType: 'ed25519 seed' | 'HD extended key'): void => {\n let expectedLength: number\n switch (secretType) {\n case 'ed25519 seed':\n expectedLength = ED25519_SEED_LENGTH\n break\n case 'HD extended key':\n expectedLength = ED25519_EXTENDED_PRIVATE_KEY_LENGTH\n break\n default:\n throw new Error(`Unknown secret type: ${secretType}`)\n }\n\n if (secret.length !== expectedLength) {\n throw new Error(`Expected unwrapped ${secretType} to be ${expectedLength} bytes, got ${secret.length}.`)\n }\n}\n\nconst throwWrapUnwrapErrors = (operationError: unknown, wrapError: unknown, operationName: string): never => {\n throw new AggregateError(\n [operationError, wrapError],\n `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`,\n )\n}\n\nfunction rawSign(extendedSecretKey: Uint8Array, data: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32))\n\n const kR = extendedSecretKey.subarray(32, 64)\n\n // (1): pubKey = scalar * G\n const publicKey = rawPubkey(extendedSecretKey)\n\n // (2): h = hash(kR || msg) mod q\n const rHash = sha512(new Uint8Array([...kR, ...data]))\n const r = mod(bytesToNumberLE(rHash), ed25519.Point.Fn.ORDER)\n\n // (4): R = r * G\n const R = ed25519.Point.BASE.multiply(r)\n\n // h = hash(R || pubKey || msg) mod q\n const hHash = sha512(new Uint8Array([...R.toBytes(), ...publicKey, ...data]))\n const h = mod(bytesToNumberLE(hHash), ed25519.Point.Fn.ORDER)\n\n // (5): S = (r + h * k) mod q\n const S = mod(r + h * scalar, ed25519.Point.Fn.ORDER)\n\n return new Uint8Array([...R.toBytes(), ...numberToBytesLE(S, 32)])\n}\n\nfunction rawPubkey(extendedSecretKey: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32))\n if ((scalar & (1n << 255n)) !== 0n) {\n throw new Error(\n 'Invalid HD-expanded Ed25519 secret scalar: most-significant bit (bit 255) of the 32-byte scalar must be 0 for rawSign/rawPubkey inputs.',\n )\n }\n const reducedScalar = mod(scalar, ed25519.Point.Fn.ORDER)\n\n // pubKey = scalar * G\n const publicKey = ed25519.Point.BASE.multiply(reducedScalar)\n return publicKey.toBytes()\n}\n\n/**\n * Creates an Ed25519 signing key from a wrapped secret using the @noble/ed25519 implementation.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the Ed25519 secret.\n * @returns A promise that resolves to an Ed25519 signing key containing the public key and raw signer.\n */\nexport const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap: WrappedEd25519Secret): Promise<Ed25519SigningKey> => {\n let wrapFunction: () => Promise<void>\n if ('wrapEd25519Seed' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapEd25519Seed\n } else if ('wrapHdExtendedPrivateKey' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapHdExtendedPrivateKey\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing wrap function')\n }\n\n const signer = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n let secret: Uint8Array | undefined = undefined\n let signature: Uint8Array | undefined = undefined\n let signingError: unknown\n let wrapError: unknown\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n signature = await ed.signAsync(bytesToSign, secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n signature = rawSign(secret.subarray(0, 64), bytesToSign)\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n signingError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (signingError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(signingError, wrapError, 'Signing')\n }\n\n if (signingError !== undefined) {\n throw signingError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (signature === undefined) {\n throw new Error('Signing failed unexpectedly without an error.')\n }\n\n return signature\n }\n\n let pubkey: Uint8Array | undefined = undefined\n let pubkeyError: unknown\n let wrapError: unknown\n let secret: Uint8Array | undefined = undefined\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n pubkey = await ed.getPublicKeyAsync(secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n pubkey = rawPubkey(secret.subarray(0, 64))\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n pubkeyError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (pubkeyError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(pubkeyError, wrapError, 'Deriving Ed25519 public key')\n }\n\n if (pubkeyError !== undefined) {\n throw pubkeyError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (pubkey === undefined) {\n throw new Error('Deriving Ed25519 public key failed unexpectedly without an error.')\n }\n\n return {\n ed25519Pubkey: pubkey,\n rawEd25519Signer: signer,\n }\n}\n\n/**\n * Creates an ed25519 signing key from a wrapped secret using the default ed25519 implementation (currently @noble/ed25519).\n * The implementation may change in the future. To explicitly use the @noble/ed25519 implementation, use `nobleEd25519SigningKeyFromWrappedSecret`.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the ed25519 secret.\n * @returns A promise that resolves to an ed25519 signing key with public key and raw signer.\n */\nexport const ed25519SigningKeyFromWrappedSecret = nobleEd25519SigningKeyFromWrappedSecret\n"],"mappings":"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"}
@@ -27,8 +27,8 @@ const throwWrapUnwrapErrors = (operationError, wrapError, operationName) => {
27
27
  throw new AggregateError([operationError, wrapError], `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`);
28
28
  };
29
29
  function rawSign(extendedSecretKey, data) {
30
- const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32));
31
- const kR = extendedSecretKey.slice(32, 64);
30
+ const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32));
31
+ const kR = extendedSecretKey.subarray(32, 64);
32
32
  const publicKey = rawPubkey(extendedSecretKey);
33
33
  const r = mod(bytesToNumberLE(sha512(new Uint8Array([...kR, ...data]))), ed25519.Point.Fn.ORDER);
34
34
  const R = ed25519.Point.BASE.multiply(r);
@@ -40,7 +40,9 @@ function rawSign(extendedSecretKey, data) {
40
40
  return new Uint8Array([...R.toBytes(), ...numberToBytesLE(S, 32)]);
41
41
  }
42
42
  function rawPubkey(extendedSecretKey) {
43
- const reducedScalar = mod(bytesToNumberLE(extendedSecretKey.slice(0, 32)) & (1n << 255n) - 1n, ed25519.Point.Fn.ORDER);
43
+ const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32));
44
+ if ((scalar & 1n << 255n) !== 0n) throw new Error("Invalid HD-expanded Ed25519 secret scalar: most-significant bit (bit 255) of the 32-byte scalar must be 0 for rawSign/rawPubkey inputs.");
45
+ const reducedScalar = mod(scalar, ed25519.Point.Fn.ORDER);
44
46
  return ed25519.Point.BASE.multiply(reducedScalar).toBytes();
45
47
  }
46
48
  /**
@@ -69,7 +71,7 @@ const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap) => {
69
71
  } else if ("unwrapHdExtendedPrivateKey" in wrapUnwrap) {
70
72
  secret = await wrapUnwrap.unwrapHdExtendedPrivateKey();
71
73
  assertEd25519SecretLength(secret, "HD extended key");
72
- signature = rawSign(secret.slice(0, 64), bytesToSign);
74
+ signature = rawSign(secret.subarray(0, 64), bytesToSign);
73
75
  } else throw new Error("Invalid WrappedEd25519Secret: missing unwrap function");
74
76
  } catch (error) {
75
77
  signingError = error;
@@ -100,7 +102,7 @@ const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap) => {
100
102
  } else if ("unwrapHdExtendedPrivateKey" in wrapUnwrap) {
101
103
  secret = await wrapUnwrap.unwrapHdExtendedPrivateKey();
102
104
  assertEd25519SecretLength(secret, "HD extended key");
103
- pubkey = rawPubkey(secret.slice(0, 64));
105
+ pubkey = rawPubkey(secret.subarray(0, 64));
104
106
  } else throw new Error("Invalid WrappedEd25519Secret: missing unwrap function");
105
107
  } catch (error) {
106
108
  pubkeyError = error;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../packages/crypto/src/index.ts"],"sourcesContent":["import { Ed25519SigningKey, WrappedEd25519Seed } from './ed25519'\nimport * as ed from '@noble/ed25519'\nimport { WrappedHdExtendedPrivateKey } from './hd'\nimport { ed25519 } from '@noble/curves/ed25519.js'\nimport { sha512 } from '@noble/hashes/sha2.js'\nimport { bytesToNumberLE, numberToBytesLE } from '@noble/curves/utils.js'\nimport { mod } from '@noble/curves/abstract/modular.js'\n\nexport * from './ed25519'\nexport * from './hash'\nexport * from './hd'\n\nexport type WrappedEd25519Secret = WrappedEd25519Seed | WrappedHdExtendedPrivateKey\n\nconst ED25519_SEED_LENGTH = 32\nconst ED25519_EXTENDED_PRIVATE_KEY_LENGTH = 96\n\nconst assertEd25519SecretLength = (secret: Uint8Array, secretType: 'ed25519 seed' | 'HD extended key'): void => {\n let expectedLength: number\n switch (secretType) {\n case 'ed25519 seed':\n expectedLength = ED25519_SEED_LENGTH\n break\n case 'HD extended key':\n expectedLength = ED25519_EXTENDED_PRIVATE_KEY_LENGTH\n break\n default:\n throw new Error(`Unknown secret type: ${secretType}`)\n }\n\n if (secret.length !== expectedLength) {\n throw new Error(`Expected unwrapped ${secretType} to be ${expectedLength} bytes, got ${secret.length}.`)\n }\n}\n\nconst throwWrapUnwrapErrors = (operationError: unknown, wrapError: unknown, operationName: string): never => {\n throw new AggregateError(\n [operationError, wrapError],\n `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`,\n )\n}\n\nfunction rawSign(extendedSecretKey: Uint8Array, data: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32))\n\n const kR = extendedSecretKey.slice(32, 64)\n\n // (1): pubKey = scalar * G\n const publicKey = rawPubkey(extendedSecretKey)\n\n // (2): h = hash(kR || msg) mod q\n const rHash = sha512(new Uint8Array([...kR, ...data]))\n const r = mod(bytesToNumberLE(rHash), ed25519.Point.Fn.ORDER)\n\n // (4): R = r * G\n const R = ed25519.Point.BASE.multiply(r)\n\n // h = hash(R || pubKey || msg) mod q\n const hHash = sha512(new Uint8Array([...R.toBytes(), ...publicKey, ...data]))\n const h = mod(bytesToNumberLE(hHash), ed25519.Point.Fn.ORDER)\n\n // (5): S = (r + h * k) mod q\n const S = mod(r + h * scalar, ed25519.Point.Fn.ORDER)\n\n return new Uint8Array([...R.toBytes(), ...numberToBytesLE(S, 32)])\n}\n\nfunction rawPubkey(extendedSecretKey: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.slice(0, 32))\n const clearedTopBitScalar = scalar & ((1n << 255n) - 1n)\n const reducedScalar = mod(clearedTopBitScalar, ed25519.Point.Fn.ORDER)\n\n // pubKey = scalar * G\n const publicKey = ed25519.Point.BASE.multiply(reducedScalar)\n return publicKey.toBytes()\n}\n\n/**\n * Creates an Ed25519 signing key from a wrapped secret using the @noble/ed25519 implementation.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the Ed25519 secret.\n * @returns A promise that resolves to an Ed25519 signing key containing the public key and raw signer.\n */\nexport const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap: WrappedEd25519Secret): Promise<Ed25519SigningKey> => {\n let wrapFunction: () => Promise<void>\n if ('wrapEd25519Seed' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapEd25519Seed\n } else if ('wrapHdExtendedPrivateKey' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapHdExtendedPrivateKey\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing wrap function')\n }\n\n const signer = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n let secret: Uint8Array | undefined = undefined\n let signature: Uint8Array | undefined = undefined\n let signingError: unknown\n let wrapError: unknown\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n signature = await ed.signAsync(bytesToSign, secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n signature = rawSign(secret.slice(0, 64), bytesToSign)\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n signingError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (signingError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(signingError, wrapError, 'Signing')\n }\n\n if (signingError !== undefined) {\n throw signingError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (signature === undefined) {\n throw new Error('Signing failed unexpectedly without an error.')\n }\n\n return signature\n }\n\n let pubkey: Uint8Array | undefined = undefined\n let pubkeyError: unknown\n let wrapError: unknown\n let secret: Uint8Array | undefined = undefined\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n pubkey = await ed.getPublicKeyAsync(secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n pubkey = rawPubkey(secret.slice(0, 64))\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n pubkeyError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (pubkeyError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(pubkeyError, wrapError, 'Deriving Ed25519 public key')\n }\n\n if (pubkeyError !== undefined) {\n throw pubkeyError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (pubkey === undefined) {\n throw new Error('Deriving Ed25519 public key failed unexpectedly without an error.')\n }\n\n return {\n ed25519Pubkey: pubkey,\n rawEd25519Signer: signer,\n }\n}\n\n/**\n * Creates an ed25519 signing key from a wrapped secret using the default ed25519 implementation (currently @noble/ed25519).\n * The implementation may change in the future. To explicitly use the @noble/ed25519 implementation, use `nobleEd25519SigningKeyFromWrappedSecret`.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the ed25519 secret.\n * @returns A promise that resolves to an ed25519 signing key with public key and raw signer.\n */\nexport const ed25519SigningKeyFromWrappedSecret = nobleEd25519SigningKeyFromWrappedSecret\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../packages/crypto/src/index.ts"],"sourcesContent":["import { Ed25519SigningKey, WrappedEd25519Seed } from './ed25519'\nimport * as ed from '@noble/ed25519'\nimport { WrappedHdExtendedPrivateKey } from './hd'\nimport { ed25519 } from '@noble/curves/ed25519.js'\nimport { sha512 } from '@noble/hashes/sha2.js'\nimport { bytesToNumberLE, numberToBytesLE } from '@noble/curves/utils.js'\nimport { mod } from '@noble/curves/abstract/modular.js'\n\nexport * from './ed25519'\nexport * from './hash'\nexport * from './hd'\n\nexport type WrappedEd25519Secret = WrappedEd25519Seed | WrappedHdExtendedPrivateKey\n\nconst ED25519_SEED_LENGTH = 32\nconst ED25519_EXTENDED_PRIVATE_KEY_LENGTH = 96\n\nconst assertEd25519SecretLength = (secret: Uint8Array, secretType: 'ed25519 seed' | 'HD extended key'): void => {\n let expectedLength: number\n switch (secretType) {\n case 'ed25519 seed':\n expectedLength = ED25519_SEED_LENGTH\n break\n case 'HD extended key':\n expectedLength = ED25519_EXTENDED_PRIVATE_KEY_LENGTH\n break\n default:\n throw new Error(`Unknown secret type: ${secretType}`)\n }\n\n if (secret.length !== expectedLength) {\n throw new Error(`Expected unwrapped ${secretType} to be ${expectedLength} bytes, got ${secret.length}.`)\n }\n}\n\nconst throwWrapUnwrapErrors = (operationError: unknown, wrapError: unknown, operationName: string): never => {\n throw new AggregateError(\n [operationError, wrapError],\n `${operationName} failed and failed to re-wrap Ed25519 secret. Check both errors for details.`,\n )\n}\n\nfunction rawSign(extendedSecretKey: Uint8Array, data: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32))\n\n const kR = extendedSecretKey.subarray(32, 64)\n\n // (1): pubKey = scalar * G\n const publicKey = rawPubkey(extendedSecretKey)\n\n // (2): h = hash(kR || msg) mod q\n const rHash = sha512(new Uint8Array([...kR, ...data]))\n const r = mod(bytesToNumberLE(rHash), ed25519.Point.Fn.ORDER)\n\n // (4): R = r * G\n const R = ed25519.Point.BASE.multiply(r)\n\n // h = hash(R || pubKey || msg) mod q\n const hHash = sha512(new Uint8Array([...R.toBytes(), ...publicKey, ...data]))\n const h = mod(bytesToNumberLE(hHash), ed25519.Point.Fn.ORDER)\n\n // (5): S = (r + h * k) mod q\n const S = mod(r + h * scalar, ed25519.Point.Fn.ORDER)\n\n return new Uint8Array([...R.toBytes(), ...numberToBytesLE(S, 32)])\n}\n\nfunction rawPubkey(extendedSecretKey: Uint8Array): Uint8Array {\n const scalar = bytesToNumberLE(extendedSecretKey.subarray(0, 32))\n if ((scalar & (1n << 255n)) !== 0n) {\n throw new Error(\n 'Invalid HD-expanded Ed25519 secret scalar: most-significant bit (bit 255) of the 32-byte scalar must be 0 for rawSign/rawPubkey inputs.',\n )\n }\n const reducedScalar = mod(scalar, ed25519.Point.Fn.ORDER)\n\n // pubKey = scalar * G\n const publicKey = ed25519.Point.BASE.multiply(reducedScalar)\n return publicKey.toBytes()\n}\n\n/**\n * Creates an Ed25519 signing key from a wrapped secret using the @noble/ed25519 implementation.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the Ed25519 secret.\n * @returns A promise that resolves to an Ed25519 signing key containing the public key and raw signer.\n */\nexport const nobleEd25519SigningKeyFromWrappedSecret = async (wrapUnwrap: WrappedEd25519Secret): Promise<Ed25519SigningKey> => {\n let wrapFunction: () => Promise<void>\n if ('wrapEd25519Seed' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapEd25519Seed\n } else if ('wrapHdExtendedPrivateKey' in wrapUnwrap) {\n wrapFunction = wrapUnwrap.wrapHdExtendedPrivateKey\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing wrap function')\n }\n\n const signer = async (bytesToSign: Uint8Array): Promise<Uint8Array> => {\n let secret: Uint8Array | undefined = undefined\n let signature: Uint8Array | undefined = undefined\n let signingError: unknown\n let wrapError: unknown\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n signature = await ed.signAsync(bytesToSign, secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n signature = rawSign(secret.subarray(0, 64), bytesToSign)\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n signingError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (signingError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(signingError, wrapError, 'Signing')\n }\n\n if (signingError !== undefined) {\n throw signingError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (signature === undefined) {\n throw new Error('Signing failed unexpectedly without an error.')\n }\n\n return signature\n }\n\n let pubkey: Uint8Array | undefined = undefined\n let pubkeyError: unknown\n let wrapError: unknown\n let secret: Uint8Array | undefined = undefined\n try {\n if ('unwrapEd25519Seed' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapEd25519Seed()\n assertEd25519SecretLength(secret, 'ed25519 seed')\n pubkey = await ed.getPublicKeyAsync(secret)\n } else if ('unwrapHdExtendedPrivateKey' in wrapUnwrap) {\n secret = await wrapUnwrap.unwrapHdExtendedPrivateKey()\n assertEd25519SecretLength(secret, 'HD extended key')\n pubkey = rawPubkey(secret.subarray(0, 64))\n } else {\n throw new Error('Invalid WrappedEd25519Secret: missing unwrap function')\n }\n } catch (error) {\n pubkeyError = error\n } finally {\n try {\n await wrapFunction()\n } catch (error) {\n wrapError = error\n } finally {\n secret?.fill(0)\n }\n }\n\n if (pubkeyError !== undefined && wrapError !== undefined) {\n throwWrapUnwrapErrors(pubkeyError, wrapError, 'Deriving Ed25519 public key')\n }\n\n if (pubkeyError !== undefined) {\n throw pubkeyError\n }\n\n if (wrapError !== undefined) {\n throw wrapError\n }\n\n if (pubkey === undefined) {\n throw new Error('Deriving Ed25519 public key failed unexpectedly without an error.')\n }\n\n return {\n ed25519Pubkey: pubkey,\n rawEd25519Signer: signer,\n }\n}\n\n/**\n * Creates an ed25519 signing key from a wrapped secret using the default ed25519 implementation (currently @noble/ed25519).\n * The implementation may change in the future. To explicitly use the @noble/ed25519 implementation, use `nobleEd25519SigningKeyFromWrappedSecret`.\n *\n * NOTE: This function will zero out the unwrapped secret after the wrap function is called.\n *\n * @param wrapUnwrap - The wrapped secret provider that unwraps and re-wraps the ed25519 secret.\n * @returns A promise that resolves to an ed25519 signing key with public key and raw signer.\n */\nexport const ed25519SigningKeyFromWrappedSecret = nobleEd25519SigningKeyFromWrappedSecret\n"],"mappings":"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"}