@metaplex-foundation/umi-uploader-irys 0.8.11

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createIrysUploader.mjs","sources":["../../src/createIrysUploader.ts"],"sourcesContent":["// eslint-disable-next-line import/no-named-default\nimport type { default as NodeIrys, WebIrys } from '@irys/sdk';\nimport {\n Commitment,\n Context,\n GenericFile,\n GenericFileTag,\n Keypair,\n Signer,\n SolAmount,\n UploaderInterface,\n base58,\n createGenericFileFromJson,\n createSignerFromKeypair,\n isKeypairSigner,\n lamports,\n publicKey,\n signTransaction,\n} from '@metaplex-foundation/umi';\nimport {\n fromWeb3JsKeypair,\n fromWeb3JsLegacyTransaction,\n toWeb3JsLegacyTransaction,\n toWeb3JsPublicKey,\n} from '@metaplex-foundation/umi-web3js-adapters';\nimport {\n Connection as Web3JsConnection,\n Keypair as Web3JsKeypair,\n PublicKey as Web3JsPublicKey,\n SendOptions as Web3JsSendOptions,\n Signer as Web3JsSigner,\n Transaction as Web3JsTransaction,\n TransactionSignature as Web3JsTransactionSignature,\n} from '@solana/web3.js';\nimport BigNumber from 'bignumber.js';\nimport { Buffer } from 'buffer';\nimport {\n AssetUploadFailedError,\n IrysWithdrawError,\n FailedToConnectToIrysAddressError,\n FailedToInitializeIrysError,\n} from './errors';\n\n/**\n * This method is necessary to import the Irys package on both ESM and CJS modules.\n * Without this, we get a different structure on each module:\n * - CJS: { default: [Getter], WebIrys: [Getter] }\n * - ESM: { default: { default: [Getter], WebIrys: [Getter] } }\n * This method fixes this by ensure there is not double default in the imported package.\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nfunction _removeDoubleDefault<T>(pkg: T): T {\n if (\n pkg &&\n typeof pkg === 'object' &&\n 'default' in pkg &&\n 'default' in (pkg as any).default\n ) {\n return (pkg as any).default;\n }\n\n return pkg;\n}\n\nexport type IrysUploader = UploaderInterface & {\n irys: () => Promise<NodeIrys | WebIrys>;\n getUploadPriceFromBytes: (bytes: number) => Promise<SolAmount>;\n getBalance: () => Promise<SolAmount>;\n fund: (amount: SolAmount, skipBalanceCheck: boolean) => Promise<void>;\n withdrawAll: (amount: SolAmount) => Promise<void>;\n withdraw: (amount: SolAmount) => Promise<void>;\n};\n\nexport type IrysUploaderOptions = {\n address?: string;\n timeout?: number;\n providerUrl?: string;\n priceMultiplier?: number;\n payer?: Signer;\n};\n\nexport type IrysWalletAdapter = {\n publicKey: Web3JsPublicKey | null;\n signMessage?: (message: Uint8Array) => Promise<Uint8Array>;\n signTransaction?: (\n transaction: Web3JsTransaction\n ) => Promise<Web3JsTransaction>;\n signAllTransactions?: (\n transactions: Web3JsTransaction[]\n ) => Promise<Web3JsTransaction[]>;\n sendTransaction: (\n transaction: Web3JsTransaction,\n connection: Web3JsConnection,\n options?: Web3JsSendOptions & { signers?: Web3JsSigner[] }\n ) => Promise<Web3JsTransactionSignature>;\n};\n\n// Size of Irys transaction header.\nconst HEADER_SIZE = 2_000;\n\n// Minimum file size for cost calculation.\nconst MINIMUM_SIZE = 80_000;\n\nexport function createIrysUploader(\n context: Pick<Context, 'rpc' | 'payer' | 'eddsa'>,\n options: IrysUploaderOptions = {}\n): IrysUploader {\n // eslint-disable-next-line @typescript-eslint/naming-convention\n let _irys: WebIrys | NodeIrys | null = null;\n options = {\n providerUrl: context.rpc.getEndpoint(),\n ...options,\n };\n\n const getUploadPriceFromBytes = async (bytes: number): Promise<SolAmount> => {\n const irys = await getIrys();\n const price = await irys.getPrice(bytes);\n\n return bigNumberToAmount(\n price.multipliedBy(options.priceMultiplier ?? 1.1)\n );\n };\n\n const getUploadPrice = async (files: GenericFile[]): Promise<SolAmount> => {\n const bytes: number = files.reduce(\n (sum, file) =>\n sum + HEADER_SIZE + Math.max(MINIMUM_SIZE, file.buffer.byteLength),\n 0\n );\n\n return getUploadPriceFromBytes(bytes);\n };\n\n const upload = async (files: GenericFile[]): Promise<string[]> => {\n const irys = await getIrys();\n const amount = await getUploadPrice(files);\n await fund(amount);\n\n const promises = files.map(async (file) => {\n const buffer = Buffer.from(file.buffer);\n const irysTx = irys.createTransaction(buffer, {\n tags: getGenericFileTagsWithContentType(file),\n });\n await irysTx.sign();\n\n const { status, data } = await irys.uploader.uploadTransaction(irysTx);\n\n if (status >= 300) {\n throw new AssetUploadFailedError(status);\n }\n\n return `https://arweave.net/${data.id}`;\n });\n\n return Promise.all(promises);\n };\n\n const uploadJson = async <T>(json: T): Promise<string> => {\n const file = createGenericFileFromJson(json);\n const uris = await upload([file]);\n return uris[0];\n };\n\n const getBalance = async (): Promise<SolAmount> => {\n const irys = await getIrys();\n const balance = await irys.getLoadedBalance();\n\n return bigNumberToAmount(balance);\n };\n\n const fund = async (\n amount: SolAmount,\n skipBalanceCheck = false\n ): Promise<void> => {\n const irys = await getIrys();\n let toFund = amountToBigNumber(amount);\n\n if (!skipBalanceCheck) {\n const balance = await irys.getLoadedBalance();\n\n toFund = toFund.isGreaterThan(balance)\n ? toFund.minus(balance)\n : new BigNumber(0);\n }\n\n if (toFund.isLessThanOrEqualTo(0)) {\n return;\n }\n\n await irys.fund(toFund);\n };\n\n const withdrawAll = async (): Promise<void> => {\n // TODO(loris): Replace with \"withdrawAll\" when available on Irys.\n const irys = await getIrys();\n const balance = await irys.getLoadedBalance();\n const minimumBalance = new BigNumber(5000);\n\n if (balance.isLessThan(minimumBalance)) {\n return;\n }\n\n const balanceToWithdraw = balance.minus(minimumBalance);\n await withdraw(bigNumberToAmount(balanceToWithdraw));\n };\n\n const withdraw = async (amount: SolAmount): Promise<void> => {\n const irys = await getIrys();\n try {\n await irys.withdrawBalance(amountToBigNumber(amount));\n } catch (e: any) {\n throw new IrysWithdrawError(\n e instanceof Error ? e.message : e.toString()\n );\n }\n };\n\n const getIrys = async (): Promise<WebIrys | NodeIrys> => {\n const oldPayer = _irys?.getSigner().publicKey;\n const newPayer = options.payer ?? context.payer;\n if (\n oldPayer &&\n publicKey(new Uint8Array(oldPayer)) !== newPayer.publicKey\n ) {\n _irys = null;\n }\n\n if (!_irys) {\n _irys = await initIrys();\n }\n\n return _irys;\n };\n\n const initIrys = async (): Promise<WebIrys | NodeIrys> => {\n const currency = 'solana';\n const defaultAddress =\n context.rpc.getCluster() === 'devnet'\n ? 'https://devnet.irys.xyz'\n : 'https://node1.irys.xyz';\n const address = options?.address ?? defaultAddress;\n const irysOptions = {\n timeout: options.timeout,\n providerUrl: options.providerUrl,\n };\n\n const payer: Signer = options.payer ?? context.payer;\n\n // If in node use node irys, else use web irys.\n const isNode =\n // eslint-disable-next-line no-prototype-builtins\n typeof window === 'undefined' || window.process?.hasOwnProperty('type');\n\n let irys;\n if (isNode && isKeypairSigner(payer))\n irys = await initNodeIrys(address, currency, payer, irysOptions);\n else {\n irys = await initWebIrys(address, currency, payer, irysOptions);\n }\n\n try {\n // Check for valid irys node.\n await irys.utils.getBundlerAddress(currency);\n } catch (error) {\n throw new FailedToConnectToIrysAddressError(address, error as Error);\n }\n\n return irys;\n };\n\n const initNodeIrys = async (\n address: string,\n currency: string,\n keypair: Keypair,\n options: any\n ): Promise<NodeIrys> => {\n const bPackage = _removeDoubleDefault(await import('@irys/sdk'));\n // eslint-disable-next-line new-cap\n return new bPackage.default({\n url: address,\n token: currency,\n key: keypair.secretKey,\n config: options,\n });\n };\n\n const initWebIrys = async (\n address: string,\n currency: string,\n payer: Signer,\n options: any\n ): Promise<WebIrys> => {\n const wallet: IrysWalletAdapter = {\n publicKey: toWeb3JsPublicKey(payer.publicKey),\n signMessage: (message: Uint8Array) => payer.signMessage(message),\n signTransaction: async (web3JsTransaction: Web3JsTransaction) =>\n toWeb3JsLegacyTransaction(\n await payer.signTransaction(\n fromWeb3JsLegacyTransaction(web3JsTransaction)\n )\n ),\n signAllTransactions: async (web3JsTransactions: Web3JsTransaction[]) => {\n const transactions = web3JsTransactions.map(\n fromWeb3JsLegacyTransaction\n );\n const signedTransactions = await payer.signAllTransactions(\n transactions\n );\n return signedTransactions.map(toWeb3JsLegacyTransaction);\n },\n sendTransaction: async (\n web3JsTransaction: Web3JsTransaction,\n connection: Web3JsConnection,\n options: Web3JsSendOptions & { signers?: Web3JsSigner[] } = {}\n ): Promise<Web3JsTransactionSignature> => {\n const { signers: web3JsSigners = [], ...sendOptions } = options;\n const signers = web3JsSigners.map((web3JsSigner) =>\n createSignerFromKeypair(\n context,\n fromWeb3JsKeypair(\n Web3JsKeypair.fromSecretKey(web3JsSigner.secretKey)\n )\n )\n );\n\n let transaction = fromWeb3JsLegacyTransaction(web3JsTransaction);\n transaction = await signTransaction(transaction, [payer, ...signers]);\n\n const signature = await context.rpc.sendTransaction(transaction, {\n ...sendOptions,\n preflightCommitment: sendOptions.preflightCommitment as Commitment,\n });\n\n return base58.deserialize(signature)[0];\n },\n };\n\n const bPackage = _removeDoubleDefault(await import('@irys/sdk'));\n const irys = new bPackage.WebIrys({\n url: address,\n token: currency,\n wallet: { provider: wallet },\n config: options,\n });\n\n try {\n // Try to initiate irys.\n await irys.ready();\n } catch (error) {\n throw new FailedToInitializeIrysError(error as Error);\n }\n\n return irys;\n };\n\n return {\n getUploadPriceFromBytes,\n getUploadPrice,\n upload,\n uploadJson,\n getBalance,\n fund,\n withdrawAll,\n withdraw,\n irys: getIrys,\n };\n}\n\nexport const isIrysUploader = (\n uploader: UploaderInterface\n): uploader is IrysUploader =>\n 'irys' in uploader &&\n 'getBalance' in uploader &&\n 'fund' in uploader &&\n 'withdrawAll' in uploader;\n\nconst bigNumberToAmount = (bigNumber: BigNumber): SolAmount =>\n lamports(bigNumber.decimalPlaces(0).toString());\n\nconst amountToBigNumber = (amount: SolAmount): BigNumber =>\n new BigNumber(amount.basisPoints.toString());\n\nconst getGenericFileTagsWithContentType = (\n file: GenericFile\n): GenericFileTag[] => {\n if (!file.contentType) {\n return file.tags;\n }\n\n return [{ name: 'Content-Type', value: file.contentType }, ...file.tags];\n};\n"],"names":["_removeDoubleDefault","pkg","default","HEADER_SIZE","MINIMUM_SIZE","createIrysUploader","context","options","_irys","providerUrl","rpc","getEndpoint","getUploadPriceFromBytes","bytes","irys","getIrys","price","getPrice","bigNumberToAmount","multipliedBy","priceMultiplier","getUploadPrice","files","reduce","sum","file","Math","max","buffer","byteLength","upload","amount","fund","promises","map","Buffer","from","irysTx","createTransaction","tags","getGenericFileTagsWithContentType","sign","status","data","uploader","uploadTransaction","AssetUploadFailedError","id","Promise","all","uploadJson","json","createGenericFileFromJson","uris","getBalance","balance","getLoadedBalance","skipBalanceCheck","toFund","amountToBigNumber","isGreaterThan","minus","BigNumber","isLessThanOrEqualTo","withdrawAll","minimumBalance","isLessThan","balanceToWithdraw","withdraw","withdrawBalance","e","IrysWithdrawError","Error","message","toString","oldPayer","getSigner","publicKey","newPayer","payer","Uint8Array","initIrys","currency","defaultAddress","getCluster","address","irysOptions","timeout","isNode","window","process","hasOwnProperty","isKeypairSigner","initNodeIrys","initWebIrys","utils","getBundlerAddress","error","FailedToConnectToIrysAddressError","keypair","bPackage","url","token","key","secretKey","config","wallet","toWeb3JsPublicKey","signMessage","signTransaction","web3JsTransaction","toWeb3JsLegacyTransaction","fromWeb3JsLegacyTransaction","signAllTransactions","web3JsTransactions","transactions","signedTransactions","sendTransaction","connection","signers","web3JsSigners","sendOptions","web3JsSigner","createSignerFromKeypair","fromWeb3JsKeypair","Web3JsKeypair","fromSecretKey","transaction","signature","preflightCommitment","base58","deserialize","WebIrys","provider","ready","FailedToInitializeIrysError","isIrysUploader","bigNumber","lamports","decimalPlaces","basisPoints","contentType","name","value"],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { UmiError } from '@metaplex-foundation/umi';
2
+
3
+ class IrysError extends UmiError {
4
+ name = 'IrysError';
5
+ constructor(message, cause) {
6
+ super(message, 'plugin', 'Irys', cause);
7
+ }
8
+ }
9
+ class FailedToInitializeIrysError extends IrysError {
10
+ name = 'FailedToInitializeIrysError';
11
+ constructor(cause) {
12
+ const message = 'Irys could not be initialized. ' + 'Please check the underlying error below for more details.';
13
+ super(message, cause);
14
+ }
15
+ }
16
+ class FailedToConnectToIrysAddressError extends IrysError {
17
+ name = 'FailedToConnectToIrysAddressError';
18
+ constructor(address, cause) {
19
+ const message = `Irys could not connect to the provided address [${address}]. ` + 'Please ensure the provided address is valid. Some valid addresses include: ' + '"https://node1.irys.xyz" for mainnet and "https://devnet.irys.xyz" for devnet';
20
+ super(message, cause);
21
+ }
22
+ }
23
+ class AssetUploadFailedError extends IrysError {
24
+ name = 'AssetUploadFailedError';
25
+ constructor(status) {
26
+ const message = `The asset could not be uploaded to the Irys network and ` + `returned the following status code [${status}].`;
27
+ super(message);
28
+ }
29
+ }
30
+ class IrysWithdrawError extends IrysError {
31
+ name = 'IrysWithdrawError';
32
+ constructor(error) {
33
+ const message = `The balance could not be withdrawn from the Irys network and ` + `returned the following error: ${error}.`;
34
+ super(message);
35
+ }
36
+ }
37
+
38
+ export { AssetUploadFailedError, FailedToConnectToIrysAddressError, FailedToInitializeIrysError, IrysError, IrysWithdrawError };
39
+ //# sourceMappingURL=errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.mjs","sources":["../../src/errors.ts"],"sourcesContent":["import { UmiError } from '@metaplex-foundation/umi';\n\nexport class IrysError extends UmiError {\n readonly name: string = 'IrysError';\n\n constructor(message: string, cause?: Error) {\n super(message, 'plugin', 'Irys', cause);\n }\n}\n\nexport class FailedToInitializeIrysError extends IrysError {\n readonly name: string = 'FailedToInitializeIrysError';\n\n constructor(cause: Error) {\n const message =\n 'Irys could not be initialized. ' +\n 'Please check the underlying error below for more details.';\n super(message, cause);\n }\n}\n\nexport class FailedToConnectToIrysAddressError extends IrysError {\n readonly name: string = 'FailedToConnectToIrysAddressError';\n\n constructor(address: string, cause: Error) {\n const message =\n `Irys could not connect to the provided address [${address}]. ` +\n 'Please ensure the provided address is valid. Some valid addresses include: ' +\n '\"https://node1.irys.xyz\" for mainnet and \"https://devnet.irys.xyz\" for devnet';\n super(message, cause);\n }\n}\n\nexport class AssetUploadFailedError extends IrysError {\n readonly name: string = 'AssetUploadFailedError';\n\n constructor(status: number) {\n const message =\n `The asset could not be uploaded to the Irys network and ` +\n `returned the following status code [${status}].`;\n super(message);\n }\n}\n\nexport class IrysWithdrawError extends IrysError {\n readonly name: string = 'IrysWithdrawError';\n\n constructor(error: string) {\n const message =\n `The balance could not be withdrawn from the Irys network and ` +\n `returned the following error: ${error}.`;\n super(message);\n }\n}\n"],"names":["IrysError","UmiError","name","constructor","message","cause","FailedToInitializeIrysError","FailedToConnectToIrysAddressError","address","AssetUploadFailedError","status","IrysWithdrawError","error"],"mappings":";;AAEO,MAAMA,SAAS,SAASC,QAAQ,CAAC;AAC7BC,EAAAA,IAAI,GAAW,WAAW,CAAA;AAEnCC,EAAAA,WAAW,CAACC,OAAe,EAAEC,KAAa,EAAE;IAC1C,KAAK,CAACD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAEC,KAAK,CAAC,CAAA;AACzC,GAAA;AACF,CAAA;AAEO,MAAMC,2BAA2B,SAASN,SAAS,CAAC;AAChDE,EAAAA,IAAI,GAAW,6BAA6B,CAAA;EAErDC,WAAW,CAACE,KAAY,EAAE;AACxB,IAAA,MAAMD,OAAO,GACX,iCAAiC,GACjC,2DAA2D,CAAA;AAC7D,IAAA,KAAK,CAACA,OAAO,EAAEC,KAAK,CAAC,CAAA;AACvB,GAAA;AACF,CAAA;AAEO,MAAME,iCAAiC,SAASP,SAAS,CAAC;AACtDE,EAAAA,IAAI,GAAW,mCAAmC,CAAA;AAE3DC,EAAAA,WAAW,CAACK,OAAe,EAAEH,KAAY,EAAE;IACzC,MAAMD,OAAO,GACV,CAAkDI,gDAAAA,EAAAA,OAAQ,KAAI,GAC/D,6EAA6E,GAC7E,+EAA+E,CAAA;AACjF,IAAA,KAAK,CAACJ,OAAO,EAAEC,KAAK,CAAC,CAAA;AACvB,GAAA;AACF,CAAA;AAEO,MAAMI,sBAAsB,SAAST,SAAS,CAAC;AAC3CE,EAAAA,IAAI,GAAW,wBAAwB,CAAA;EAEhDC,WAAW,CAACO,MAAc,EAAE;AAC1B,IAAA,MAAMN,OAAO,GACV,CAAA,wDAAA,CAAyD,GACzD,CAAA,oCAAA,EAAsCM,MAAO,CAAG,EAAA,CAAA,CAAA;IACnD,KAAK,CAACN,OAAO,CAAC,CAAA;AAChB,GAAA;AACF,CAAA;AAEO,MAAMO,iBAAiB,SAASX,SAAS,CAAC;AACtCE,EAAAA,IAAI,GAAW,mBAAmB,CAAA;EAE3CC,WAAW,CAACS,KAAa,EAAE;AACzB,IAAA,MAAMR,OAAO,GACV,CAAA,6DAAA,CAA8D,GAC9D,CAAA,8BAAA,EAAgCQ,KAAM,CAAE,CAAA,CAAA,CAAA;IAC3C,KAAK,CAACR,OAAO,CAAC,CAAA;AAChB,GAAA;AACF;;;;"}
@@ -0,0 +1,4 @@
1
+ export { createIrysUploader, isIrysUploader } from './createIrysUploader.mjs';
2
+ export { AssetUploadFailedError, FailedToConnectToIrysAddressError, FailedToInitializeIrysError, IrysError, IrysWithdrawError } from './errors.mjs';
3
+ export { irysUploader } from './plugin.mjs';
4
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -0,0 +1,10 @@
1
+ import { createIrysUploader } from './createIrysUploader.mjs';
2
+
3
+ const irysUploader = options => ({
4
+ install(umi) {
5
+ umi.uploader = createIrysUploader(umi, options);
6
+ }
7
+ });
8
+
9
+ export { irysUploader };
10
+ //# sourceMappingURL=plugin.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.mjs","sources":["../../src/plugin.ts"],"sourcesContent":["import type { UmiPlugin } from '@metaplex-foundation/umi';\nimport { IrysUploaderOptions, createIrysUploader } from './createIrysUploader';\n\nexport const irysUploader = (options?: IrysUploaderOptions): UmiPlugin => ({\n install(umi) {\n umi.uploader = createIrysUploader(umi, options);\n },\n});\n"],"names":["irysUploader","options","install","umi","uploader","createIrysUploader"],"mappings":";;AAGaA,MAAAA,YAAY,GAAIC,OAA6B,KAAiB;EACzEC,OAAO,CAACC,GAAG,EAAE;IACXA,GAAG,CAACC,QAAQ,GAAGC,kBAAkB,CAACF,GAAG,EAAEF,OAAO,CAAC,CAAA;AACjD,GAAA;AACF,CAAC;;;;"}
@@ -0,0 +1,29 @@
1
+ import type { default as NodeIrys, WebIrys } from '@irys/sdk';
2
+ import { Context, Signer, SolAmount, UploaderInterface } from '@metaplex-foundation/umi';
3
+ import { Connection as Web3JsConnection, PublicKey as Web3JsPublicKey, SendOptions as Web3JsSendOptions, Signer as Web3JsSigner, Transaction as Web3JsTransaction, TransactionSignature as Web3JsTransactionSignature } from '@solana/web3.js';
4
+ export type IrysUploader = UploaderInterface & {
5
+ irys: () => Promise<NodeIrys | WebIrys>;
6
+ getUploadPriceFromBytes: (bytes: number) => Promise<SolAmount>;
7
+ getBalance: () => Promise<SolAmount>;
8
+ fund: (amount: SolAmount, skipBalanceCheck: boolean) => Promise<void>;
9
+ withdrawAll: (amount: SolAmount) => Promise<void>;
10
+ withdraw: (amount: SolAmount) => Promise<void>;
11
+ };
12
+ export type IrysUploaderOptions = {
13
+ address?: string;
14
+ timeout?: number;
15
+ providerUrl?: string;
16
+ priceMultiplier?: number;
17
+ payer?: Signer;
18
+ };
19
+ export type IrysWalletAdapter = {
20
+ publicKey: Web3JsPublicKey | null;
21
+ signMessage?: (message: Uint8Array) => Promise<Uint8Array>;
22
+ signTransaction?: (transaction: Web3JsTransaction) => Promise<Web3JsTransaction>;
23
+ signAllTransactions?: (transactions: Web3JsTransaction[]) => Promise<Web3JsTransaction[]>;
24
+ sendTransaction: (transaction: Web3JsTransaction, connection: Web3JsConnection, options?: Web3JsSendOptions & {
25
+ signers?: Web3JsSigner[];
26
+ }) => Promise<Web3JsTransactionSignature>;
27
+ };
28
+ export declare function createIrysUploader(context: Pick<Context, 'rpc' | 'payer' | 'eddsa'>, options?: IrysUploaderOptions): IrysUploader;
29
+ export declare const isIrysUploader: (uploader: UploaderInterface) => uploader is IrysUploader;
@@ -0,0 +1,21 @@
1
+ import { UmiError } from '@metaplex-foundation/umi';
2
+ export declare class IrysError extends UmiError {
3
+ readonly name: string;
4
+ constructor(message: string, cause?: Error);
5
+ }
6
+ export declare class FailedToInitializeIrysError extends IrysError {
7
+ readonly name: string;
8
+ constructor(cause: Error);
9
+ }
10
+ export declare class FailedToConnectToIrysAddressError extends IrysError {
11
+ readonly name: string;
12
+ constructor(address: string, cause: Error);
13
+ }
14
+ export declare class AssetUploadFailedError extends IrysError {
15
+ readonly name: string;
16
+ constructor(status: number);
17
+ }
18
+ export declare class IrysWithdrawError extends IrysError {
19
+ readonly name: string;
20
+ constructor(error: string);
21
+ }
@@ -0,0 +1,3 @@
1
+ export * from './createIrysUploader';
2
+ export * from './errors';
3
+ export * from './plugin';
@@ -0,0 +1,3 @@
1
+ import type { UmiPlugin } from '@metaplex-foundation/umi';
2
+ import { IrysUploaderOptions } from './createIrysUploader';
3
+ export declare const irysUploader: (options?: IrysUploaderOptions) => UmiPlugin;
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@metaplex-foundation/umi-uploader-irys",
3
+ "version": "0.8.11",
4
+ "description": "An uploader implementation relying on Irys",
5
+ "license": "MIT",
6
+ "sideEffects": false,
7
+ "module": "dist/esm/index.mjs",
8
+ "main": "dist/cjs/index.cjs",
9
+ "types": "dist/types/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/types/index.d.ts",
13
+ "import": "./dist/esm/index.mjs",
14
+ "require": "./dist/cjs/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "/dist/cjs",
19
+ "/dist/esm",
20
+ "/dist/types",
21
+ "/src"
22
+ ],
23
+ "dependencies": {
24
+ "@irys/sdk": "^0.0.2",
25
+ "bignumber.js": "^9.0.2",
26
+ "buffer": "^6.0.3",
27
+ "@metaplex-foundation/umi-web3js-adapters": "^0.8.10"
28
+ },
29
+ "peerDependencies": {
30
+ "@solana/web3.js": "^1.72.0",
31
+ "@metaplex-foundation/umi": "^0.8.10"
32
+ },
33
+ "devDependencies": {
34
+ "@ava/typescript": "^3.0.1",
35
+ "@solana/web3.js": "^1.72.0",
36
+ "ava": "^5.1.0",
37
+ "@metaplex-foundation/umi": "^0.8.10",
38
+ "@metaplex-foundation/umi-downloader-http": "^0.8.10",
39
+ "@metaplex-foundation/umi-eddsa-web3js": "^0.8.10",
40
+ "@metaplex-foundation/umi-rpc-web3js": "^0.8.10",
41
+ "@metaplex-foundation/umi-http-fetch": "^0.8.10"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "author": "Metaplex Maintainers <contact@metaplex.com>",
47
+ "homepage": "https://metaplex.com",
48
+ "repository": {
49
+ "url": "https://github.com/metaplex-foundation/umi.git"
50
+ },
51
+ "typedoc": {
52
+ "entryPoint": "./src/index.ts",
53
+ "readmeFile": "./README.md",
54
+ "displayName": "umi-uploader-irys"
55
+ },
56
+ "ava": {
57
+ "typescript": {
58
+ "compile": false,
59
+ "rewritePaths": {
60
+ "src/": "dist/test/src/",
61
+ "test/": "dist/test/test/"
62
+ }
63
+ }
64
+ },
65
+ "scripts": {
66
+ "lint": "eslint --ext js,ts,tsx src",
67
+ "lint:fix": "eslint --fix --ext js,ts,tsx src",
68
+ "clean": "rimraf dist",
69
+ "build": "pnpm clean && tsc && tsc -p test/tsconfig.json && rollup -c",
70
+ "test": "ava"
71
+ }
72
+ }
@@ -0,0 +1,391 @@
1
+ // eslint-disable-next-line import/no-named-default
2
+ import type { default as NodeIrys, WebIrys } from '@irys/sdk';
3
+ import {
4
+ Commitment,
5
+ Context,
6
+ GenericFile,
7
+ GenericFileTag,
8
+ Keypair,
9
+ Signer,
10
+ SolAmount,
11
+ UploaderInterface,
12
+ base58,
13
+ createGenericFileFromJson,
14
+ createSignerFromKeypair,
15
+ isKeypairSigner,
16
+ lamports,
17
+ publicKey,
18
+ signTransaction,
19
+ } from '@metaplex-foundation/umi';
20
+ import {
21
+ fromWeb3JsKeypair,
22
+ fromWeb3JsLegacyTransaction,
23
+ toWeb3JsLegacyTransaction,
24
+ toWeb3JsPublicKey,
25
+ } from '@metaplex-foundation/umi-web3js-adapters';
26
+ import {
27
+ Connection as Web3JsConnection,
28
+ Keypair as Web3JsKeypair,
29
+ PublicKey as Web3JsPublicKey,
30
+ SendOptions as Web3JsSendOptions,
31
+ Signer as Web3JsSigner,
32
+ Transaction as Web3JsTransaction,
33
+ TransactionSignature as Web3JsTransactionSignature,
34
+ } from '@solana/web3.js';
35
+ import BigNumber from 'bignumber.js';
36
+ import { Buffer } from 'buffer';
37
+ import {
38
+ AssetUploadFailedError,
39
+ IrysWithdrawError,
40
+ FailedToConnectToIrysAddressError,
41
+ FailedToInitializeIrysError,
42
+ } from './errors';
43
+
44
+ /**
45
+ * This method is necessary to import the Irys package on both ESM and CJS modules.
46
+ * Without this, we get a different structure on each module:
47
+ * - CJS: { default: [Getter], WebIrys: [Getter] }
48
+ * - ESM: { default: { default: [Getter], WebIrys: [Getter] } }
49
+ * This method fixes this by ensure there is not double default in the imported package.
50
+ */
51
+ // eslint-disable-next-line @typescript-eslint/naming-convention
52
+ function _removeDoubleDefault<T>(pkg: T): T {
53
+ if (
54
+ pkg &&
55
+ typeof pkg === 'object' &&
56
+ 'default' in pkg &&
57
+ 'default' in (pkg as any).default
58
+ ) {
59
+ return (pkg as any).default;
60
+ }
61
+
62
+ return pkg;
63
+ }
64
+
65
+ export type IrysUploader = UploaderInterface & {
66
+ irys: () => Promise<NodeIrys | WebIrys>;
67
+ getUploadPriceFromBytes: (bytes: number) => Promise<SolAmount>;
68
+ getBalance: () => Promise<SolAmount>;
69
+ fund: (amount: SolAmount, skipBalanceCheck: boolean) => Promise<void>;
70
+ withdrawAll: (amount: SolAmount) => Promise<void>;
71
+ withdraw: (amount: SolAmount) => Promise<void>;
72
+ };
73
+
74
+ export type IrysUploaderOptions = {
75
+ address?: string;
76
+ timeout?: number;
77
+ providerUrl?: string;
78
+ priceMultiplier?: number;
79
+ payer?: Signer;
80
+ };
81
+
82
+ export type IrysWalletAdapter = {
83
+ publicKey: Web3JsPublicKey | null;
84
+ signMessage?: (message: Uint8Array) => Promise<Uint8Array>;
85
+ signTransaction?: (
86
+ transaction: Web3JsTransaction
87
+ ) => Promise<Web3JsTransaction>;
88
+ signAllTransactions?: (
89
+ transactions: Web3JsTransaction[]
90
+ ) => Promise<Web3JsTransaction[]>;
91
+ sendTransaction: (
92
+ transaction: Web3JsTransaction,
93
+ connection: Web3JsConnection,
94
+ options?: Web3JsSendOptions & { signers?: Web3JsSigner[] }
95
+ ) => Promise<Web3JsTransactionSignature>;
96
+ };
97
+
98
+ // Size of Irys transaction header.
99
+ const HEADER_SIZE = 2_000;
100
+
101
+ // Minimum file size for cost calculation.
102
+ const MINIMUM_SIZE = 80_000;
103
+
104
+ export function createIrysUploader(
105
+ context: Pick<Context, 'rpc' | 'payer' | 'eddsa'>,
106
+ options: IrysUploaderOptions = {}
107
+ ): IrysUploader {
108
+ // eslint-disable-next-line @typescript-eslint/naming-convention
109
+ let _irys: WebIrys | NodeIrys | null = null;
110
+ options = {
111
+ providerUrl: context.rpc.getEndpoint(),
112
+ ...options,
113
+ };
114
+
115
+ const getUploadPriceFromBytes = async (bytes: number): Promise<SolAmount> => {
116
+ const irys = await getIrys();
117
+ const price = await irys.getPrice(bytes);
118
+
119
+ return bigNumberToAmount(
120
+ price.multipliedBy(options.priceMultiplier ?? 1.1)
121
+ );
122
+ };
123
+
124
+ const getUploadPrice = async (files: GenericFile[]): Promise<SolAmount> => {
125
+ const bytes: number = files.reduce(
126
+ (sum, file) =>
127
+ sum + HEADER_SIZE + Math.max(MINIMUM_SIZE, file.buffer.byteLength),
128
+ 0
129
+ );
130
+
131
+ return getUploadPriceFromBytes(bytes);
132
+ };
133
+
134
+ const upload = async (files: GenericFile[]): Promise<string[]> => {
135
+ const irys = await getIrys();
136
+ const amount = await getUploadPrice(files);
137
+ await fund(amount);
138
+
139
+ const promises = files.map(async (file) => {
140
+ const buffer = Buffer.from(file.buffer);
141
+ const irysTx = irys.createTransaction(buffer, {
142
+ tags: getGenericFileTagsWithContentType(file),
143
+ });
144
+ await irysTx.sign();
145
+
146
+ const { status, data } = await irys.uploader.uploadTransaction(irysTx);
147
+
148
+ if (status >= 300) {
149
+ throw new AssetUploadFailedError(status);
150
+ }
151
+
152
+ return `https://arweave.net/${data.id}`;
153
+ });
154
+
155
+ return Promise.all(promises);
156
+ };
157
+
158
+ const uploadJson = async <T>(json: T): Promise<string> => {
159
+ const file = createGenericFileFromJson(json);
160
+ const uris = await upload([file]);
161
+ return uris[0];
162
+ };
163
+
164
+ const getBalance = async (): Promise<SolAmount> => {
165
+ const irys = await getIrys();
166
+ const balance = await irys.getLoadedBalance();
167
+
168
+ return bigNumberToAmount(balance);
169
+ };
170
+
171
+ const fund = async (
172
+ amount: SolAmount,
173
+ skipBalanceCheck = false
174
+ ): Promise<void> => {
175
+ const irys = await getIrys();
176
+ let toFund = amountToBigNumber(amount);
177
+
178
+ if (!skipBalanceCheck) {
179
+ const balance = await irys.getLoadedBalance();
180
+
181
+ toFund = toFund.isGreaterThan(balance)
182
+ ? toFund.minus(balance)
183
+ : new BigNumber(0);
184
+ }
185
+
186
+ if (toFund.isLessThanOrEqualTo(0)) {
187
+ return;
188
+ }
189
+
190
+ await irys.fund(toFund);
191
+ };
192
+
193
+ const withdrawAll = async (): Promise<void> => {
194
+ // TODO(loris): Replace with "withdrawAll" when available on Irys.
195
+ const irys = await getIrys();
196
+ const balance = await irys.getLoadedBalance();
197
+ const minimumBalance = new BigNumber(5000);
198
+
199
+ if (balance.isLessThan(minimumBalance)) {
200
+ return;
201
+ }
202
+
203
+ const balanceToWithdraw = balance.minus(minimumBalance);
204
+ await withdraw(bigNumberToAmount(balanceToWithdraw));
205
+ };
206
+
207
+ const withdraw = async (amount: SolAmount): Promise<void> => {
208
+ const irys = await getIrys();
209
+ try {
210
+ await irys.withdrawBalance(amountToBigNumber(amount));
211
+ } catch (e: any) {
212
+ throw new IrysWithdrawError(
213
+ e instanceof Error ? e.message : e.toString()
214
+ );
215
+ }
216
+ };
217
+
218
+ const getIrys = async (): Promise<WebIrys | NodeIrys> => {
219
+ const oldPayer = _irys?.getSigner().publicKey;
220
+ const newPayer = options.payer ?? context.payer;
221
+ if (
222
+ oldPayer &&
223
+ publicKey(new Uint8Array(oldPayer)) !== newPayer.publicKey
224
+ ) {
225
+ _irys = null;
226
+ }
227
+
228
+ if (!_irys) {
229
+ _irys = await initIrys();
230
+ }
231
+
232
+ return _irys;
233
+ };
234
+
235
+ const initIrys = async (): Promise<WebIrys | NodeIrys> => {
236
+ const currency = 'solana';
237
+ const defaultAddress =
238
+ context.rpc.getCluster() === 'devnet'
239
+ ? 'https://devnet.irys.xyz'
240
+ : 'https://node1.irys.xyz';
241
+ const address = options?.address ?? defaultAddress;
242
+ const irysOptions = {
243
+ timeout: options.timeout,
244
+ providerUrl: options.providerUrl,
245
+ };
246
+
247
+ const payer: Signer = options.payer ?? context.payer;
248
+
249
+ // If in node use node irys, else use web irys.
250
+ const isNode =
251
+ // eslint-disable-next-line no-prototype-builtins
252
+ typeof window === 'undefined' || window.process?.hasOwnProperty('type');
253
+
254
+ let irys;
255
+ if (isNode && isKeypairSigner(payer))
256
+ irys = await initNodeIrys(address, currency, payer, irysOptions);
257
+ else {
258
+ irys = await initWebIrys(address, currency, payer, irysOptions);
259
+ }
260
+
261
+ try {
262
+ // Check for valid irys node.
263
+ await irys.utils.getBundlerAddress(currency);
264
+ } catch (error) {
265
+ throw new FailedToConnectToIrysAddressError(address, error as Error);
266
+ }
267
+
268
+ return irys;
269
+ };
270
+
271
+ const initNodeIrys = async (
272
+ address: string,
273
+ currency: string,
274
+ keypair: Keypair,
275
+ options: any
276
+ ): Promise<NodeIrys> => {
277
+ const bPackage = _removeDoubleDefault(await import('@irys/sdk'));
278
+ // eslint-disable-next-line new-cap
279
+ return new bPackage.default({
280
+ url: address,
281
+ token: currency,
282
+ key: keypair.secretKey,
283
+ config: options,
284
+ });
285
+ };
286
+
287
+ const initWebIrys = async (
288
+ address: string,
289
+ currency: string,
290
+ payer: Signer,
291
+ options: any
292
+ ): Promise<WebIrys> => {
293
+ const wallet: IrysWalletAdapter = {
294
+ publicKey: toWeb3JsPublicKey(payer.publicKey),
295
+ signMessage: (message: Uint8Array) => payer.signMessage(message),
296
+ signTransaction: async (web3JsTransaction: Web3JsTransaction) =>
297
+ toWeb3JsLegacyTransaction(
298
+ await payer.signTransaction(
299
+ fromWeb3JsLegacyTransaction(web3JsTransaction)
300
+ )
301
+ ),
302
+ signAllTransactions: async (web3JsTransactions: Web3JsTransaction[]) => {
303
+ const transactions = web3JsTransactions.map(
304
+ fromWeb3JsLegacyTransaction
305
+ );
306
+ const signedTransactions = await payer.signAllTransactions(
307
+ transactions
308
+ );
309
+ return signedTransactions.map(toWeb3JsLegacyTransaction);
310
+ },
311
+ sendTransaction: async (
312
+ web3JsTransaction: Web3JsTransaction,
313
+ connection: Web3JsConnection,
314
+ options: Web3JsSendOptions & { signers?: Web3JsSigner[] } = {}
315
+ ): Promise<Web3JsTransactionSignature> => {
316
+ const { signers: web3JsSigners = [], ...sendOptions } = options;
317
+ const signers = web3JsSigners.map((web3JsSigner) =>
318
+ createSignerFromKeypair(
319
+ context,
320
+ fromWeb3JsKeypair(
321
+ Web3JsKeypair.fromSecretKey(web3JsSigner.secretKey)
322
+ )
323
+ )
324
+ );
325
+
326
+ let transaction = fromWeb3JsLegacyTransaction(web3JsTransaction);
327
+ transaction = await signTransaction(transaction, [payer, ...signers]);
328
+
329
+ const signature = await context.rpc.sendTransaction(transaction, {
330
+ ...sendOptions,
331
+ preflightCommitment: sendOptions.preflightCommitment as Commitment,
332
+ });
333
+
334
+ return base58.deserialize(signature)[0];
335
+ },
336
+ };
337
+
338
+ const bPackage = _removeDoubleDefault(await import('@irys/sdk'));
339
+ const irys = new bPackage.WebIrys({
340
+ url: address,
341
+ token: currency,
342
+ wallet: { provider: wallet },
343
+ config: options,
344
+ });
345
+
346
+ try {
347
+ // Try to initiate irys.
348
+ await irys.ready();
349
+ } catch (error) {
350
+ throw new FailedToInitializeIrysError(error as Error);
351
+ }
352
+
353
+ return irys;
354
+ };
355
+
356
+ return {
357
+ getUploadPriceFromBytes,
358
+ getUploadPrice,
359
+ upload,
360
+ uploadJson,
361
+ getBalance,
362
+ fund,
363
+ withdrawAll,
364
+ withdraw,
365
+ irys: getIrys,
366
+ };
367
+ }
368
+
369
+ export const isIrysUploader = (
370
+ uploader: UploaderInterface
371
+ ): uploader is IrysUploader =>
372
+ 'irys' in uploader &&
373
+ 'getBalance' in uploader &&
374
+ 'fund' in uploader &&
375
+ 'withdrawAll' in uploader;
376
+
377
+ const bigNumberToAmount = (bigNumber: BigNumber): SolAmount =>
378
+ lamports(bigNumber.decimalPlaces(0).toString());
379
+
380
+ const amountToBigNumber = (amount: SolAmount): BigNumber =>
381
+ new BigNumber(amount.basisPoints.toString());
382
+
383
+ const getGenericFileTagsWithContentType = (
384
+ file: GenericFile
385
+ ): GenericFileTag[] => {
386
+ if (!file.contentType) {
387
+ return file.tags;
388
+ }
389
+
390
+ return [{ name: 'Content-Type', value: file.contentType }, ...file.tags];
391
+ };