diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 875b3162..569a8b19 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,7 +25,7 @@ jobs: cache: 'yarn' - name: Install dependencies - run: yarn --immutable --immutable-cache + run: yarn --immutable --immutable-cache --ignore-engines - run: yarn ${{ matrix.command }} @@ -41,7 +41,7 @@ jobs: cache: 'yarn' - name: Install dependencies - run: yarn --immutable --immutable-cache + run: yarn --immutable --immutable-cache --ignore-engines - name: Run tests run: yarn test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 91a5be34..6be85c41 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: node-version-file: .nvmrc - name: Install dependencies - run: yarn --immutable --immutable-cache + run: yarn --immutable --immutable-cache --ignore-engines - name: Build run: yarn build diff --git a/examples/esm/index.mjs b/examples/esm/index.mjs index 91163212..c6e7a881 100644 --- a/examples/esm/index.mjs +++ b/examples/esm/index.mjs @@ -1,7 +1,9 @@ import { ANT, + ArNSEventEmitter, ArweaveSigner, IO, + createAoSigner, ioDevnetProcessId, spawnANT, } from '@ar.io/sdk'; @@ -66,10 +68,14 @@ import Arweave from 'arweave'; }); const jwk = await arweave.wallets.generate(); - - const processId = await spawnANT({ - signer: new ArweaveSigner(jwk), - }); + let processId; + try { + processId = await spawnANT({ + signer: createAoSigner(new ArweaveSigner(jwk)), + }); + } catch (error) { + console.log(error); + } const ant = ANT.init({ processId, @@ -92,7 +98,7 @@ import Arweave from 'arweave'; // fetching ants owned by a wallet using an event emitter const address = 'ZjmB2vEUlHlJ7-rgJkYP09N5IzLPhJyStVrK5u9dDEo'; - const processEmitter = new ArNSNameEmitter({ contract: arIO }); + const processEmitter = new ArNSEventEmitter({ contract: arIO }); processEmitter.on('error', (e) => { console.error(e); }); diff --git a/package.json b/package.json index 37848e79..dc86cb31 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "@types/sinon": "^10.0.15", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^6.4.0", + "arconnect": "^1.0.3", "dotenv": "^16.4.5", "dotenv-cli": "^7.4.2", "esbuild": "^0.19.2", @@ -118,7 +119,7 @@ "vite-plugin-node-polyfills": "^0.22.0" }, "dependencies": { - "@permaweb/aoconnect": "^0.0.55", + "@permaweb/aoconnect": "^0.0.57", "arbundles": "0.11.0", "arweave": "1.14.4", "axios": "1.7.2", diff --git a/src/common.ts b/src/common.ts index 79a7ac04..afab1946 100644 --- a/src/common.ts +++ b/src/common.ts @@ -23,7 +23,7 @@ import { spawn, unmonitor, } from '@permaweb/aoconnect'; -import { ArconnectSigner, ArweaveSigner } from 'arbundles'; +import { Signer } from 'arbundles'; import { AllowedProtocols, @@ -41,7 +41,7 @@ export type TransactionId = string; export type ProcessId = string; // TODO: append this with other configuration options (e.g. local vs. remote evaluation) -export type ContractSigner = ArweaveSigner | ArconnectSigner; +export type ContractSigner = Signer | Window['arweaveWallet']; export type WithSigner> = { signer: ContractSigner; } & T; // TODO: optionally allow JWK in place of signer diff --git a/src/common/ant.ts b/src/common/ant.ts index 03ec7ea8..1a658b5d 100644 --- a/src/common/ant.ts +++ b/src/common/ant.ts @@ -20,7 +20,7 @@ import { AoANTState, AoANTWrite, AoMessageResult, - ContractSigner, + AoSigner, OptionalSigner, ProcessConfiguration, WalletAddress, @@ -28,6 +28,7 @@ import { isProcessConfiguration, isProcessIdConfiguration, } from '../types.js'; +import { createAoSigner } from '../utils/ao.js'; import { AOProcess, InvalidContractConfigurationError } from './index.js'; export class ANT { @@ -227,14 +228,14 @@ export class AoANTReadable implements AoANTRead { } export class AoANTWriteable extends AoANTReadable implements AoANTWrite { - private signer: ContractSigner; + private signer: AoSigner; constructor({ signer, ...config }: WithSigner>) { super(config); - this.signer = signer; + this.signer = createAoSigner(signer); } /** diff --git a/src/common/contracts/ao-process.ts b/src/common/contracts/ao-process.ts index caed56b2..3ed4a61c 100644 --- a/src/common/contracts/ao-process.ts +++ b/src/common/contracts/ao-process.ts @@ -15,9 +15,8 @@ * along with this program. If not, see . */ import { connect } from '@permaweb/aoconnect'; -import { createData } from 'arbundles'; -import { AOContract, AoClient, ContractSigner } from '../../types.js'; +import { AOContract, AoClient, AoSigner } from '../../types.js'; import { safeDecode } from '../../utils/json.js'; import { version } from '../../version.js'; import { WriteInteractionError } from '../error.js'; @@ -42,34 +41,6 @@ export class AOProcess implements AOContract { this.ao = ao; } - // TODO: could abstract into our own interface that constructs different signers - static async createAoSigner( - signer: ContractSigner, - ): Promise< - (args: { - data: string | Buffer; - tags?: { name: string; value: string }[]; - target?: string; - anchor?: string; - }) => Promise<{ id: string; raw: ArrayBuffer }> - > { - // ensure appropriate permissions are granted with injected signers. - if (signer.publicKey === undefined && 'setPublicKey' in signer) { - await signer.setPublicKey(); - } - - const aoSigner = async ({ data, tags, target, anchor }) => { - const dataItem = createData(data, signer, { tags, target, anchor }); - const signedData = dataItem.sign(signer).then(async () => ({ - id: await dataItem.id, - raw: await dataItem.getRaw(), - })); - return signedData; - }; - - return aoSigner; - } - async read({ tags, retries = 3, @@ -137,7 +108,7 @@ export class AOProcess implements AOContract { }: { tags: Array<{ name: string; value: string }>; data?: I; - signer: ContractSigner; + signer: AoSigner; retries?: number; }): Promise<{ id: string; result?: K }> { // main purpose of retries is to handle network errors/new process delays @@ -158,7 +129,7 @@ export class AOProcess implements AOContract { // TODO: any other default tags we want to add? tags: [...tags, { name: 'AR-IO-SDK', value: version }], data: typeof data !== 'string' ? JSON.stringify(data) : data, - signer: await AOProcess.createAoSigner(signer), + signer, }); this.logger.debug(`Sent message to process`, { diff --git a/src/common/io.ts b/src/common/io.ts index a8fb8581..5877ccef 100644 --- a/src/common/io.ts +++ b/src/common/io.ts @@ -34,7 +34,7 @@ import { isProcessConfiguration, isProcessIdConfiguration, } from '../io.js'; -import { mIOToken } from '../token.js'; +import { AoSigner, mIOToken } from '../token.js'; import { AoArNSNameDataWithName, AoBalanceWithAddress, @@ -52,6 +52,7 @@ import { WithSigner, WriteOptions, } from '../types.js'; +import { createAoSigner } from '../utils/ao.js'; import { defaultArweave } from './arweave.js'; import { AOProcess } from './contracts/ao-process.js'; import { InvalidContractConfigurationError } from './error.js'; @@ -578,7 +579,7 @@ export class IOReadable implements AoIORead { export class IOWriteable extends IOReadable implements AoIOWrite { protected declare process: AOProcess; - private signer: ContractSigner; + private signer: AoSigner; constructor({ signer, ...config @@ -594,17 +595,17 @@ export class IOWriteable extends IOReadable implements AoIOWrite { processId: IO_TESTNET_PROCESS_ID, }), }); - this.signer = signer; + this.signer = createAoSigner(signer); } else if (isProcessConfiguration(config)) { super({ process: config.process }); - this.signer = signer; + this.signer = createAoSigner(signer); } else if (isProcessIdConfiguration(config)) { super({ process: new AOProcess({ processId: config.processId, }), }); - this.signer = signer; + this.signer = createAoSigner(signer); } else { throw new InvalidContractConfigurationError(); } diff --git a/src/io.ts b/src/io.ts index 9f48ea68..27c36553 100644 --- a/src/io.ts +++ b/src/io.ts @@ -26,11 +26,10 @@ import { VaultData, WeightedObserver, } from './contract-state.js'; -import { mIOToken } from './token.js'; +import { AoSigner, mIOToken } from './token.js'; import { AoMessageResult, BlockHeight, - ContractSigner, JoinNetworkParams, ProcessId, Timestamp, @@ -111,7 +110,7 @@ export interface AOContract { }: { tags: { name: string; value: string }[]; data: I; - signer: ContractSigner; + signer: AoSigner; }): Promise<{ id: string; result?: K }>; } diff --git a/src/token.ts b/src/token.ts index c9ff0553..16fbcc14 100644 --- a/src/token.ts +++ b/src/token.ts @@ -153,3 +153,10 @@ export class mIOToken extends PositiveFiniteInteger { return new IOToken(this.valueOf() / MIO_PER_IO); } } + +export type AoSigner = (args: { + data: string | Buffer; + tags?: { name: string; value: string }[]; + target?: string; + anchor?: string; +}) => Promise<{ id: string; raw: ArrayBuffer }>; diff --git a/src/utils/ao.ts b/src/utils/ao.ts index c8718ffd..723a97d5 100644 --- a/src/utils/ao.ts +++ b/src/utils/ao.ts @@ -14,7 +14,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { connect } from '@permaweb/aoconnect'; +import { connect, createDataItemSigner } from '@permaweb/aoconnect'; +import { createData } from 'arbundles'; import { defaultArweave } from '../common/arweave.js'; import { AOProcess } from '../common/index.js'; @@ -24,7 +25,7 @@ import { DEFAULT_SCHEDULER_ID, } from '../constants.js'; import { ANTState } from '../contract-state.js'; -import { AoClient, ContractSigner } from '../types.js'; +import { AoClient, AoSigner, ContractSigner } from '../types.js'; export async function spawnANT({ signer, @@ -35,7 +36,7 @@ export async function spawnANT({ state, stateContractTxId, }: { - signer: ContractSigner; + signer: AoSigner; module?: string; luaCodeTxId?: string; ao?: AoClient; @@ -52,7 +53,7 @@ export async function spawnANT({ const processId = await ao.spawn({ module, scheduler, - signer: await AOProcess.createAoSigner(signer), + signer, }); const aosClient = new AOProcess({ @@ -92,7 +93,7 @@ export async function evolveANT({ luaCodeTxId = ANT_LUA_ID, ao = connect(), }: { - signer: ContractSigner; + signer: AoSigner; processId: string; luaCodeTxId?: string; ao?: AoClient; @@ -120,3 +121,28 @@ export async function evolveANT({ return id; } + +export function createAoSigner(signer: ContractSigner): AoSigner { + if (!('publicKey' in signer)) { + return createDataItemSigner(signer) as any; + } + + const aoSigner = async ({ data, tags, target, anchor }) => { + // ensure appropriate permissions are granted with injected signers. + if ( + signer.publicKey === undefined && + 'setPublicKey' in signer && + typeof signer.setPublicKey === 'function' + ) { + await signer.setPublicKey(); + } + const dataItem = createData(data, signer, { tags, target, anchor }); + const signedData = dataItem.sign(signer).then(async () => ({ + id: await dataItem.id, + raw: await dataItem.getRaw(), + })); + return signedData; + }; + + return aoSigner; +} diff --git a/yarn.lock b/yarn.lock index 2f7d412b..b4c91904 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1701,28 +1701,28 @@ dependencies: "@octokit/openapi-types" "^22.2.0" -"@permaweb/ao-scheduler-utils@~0.0.16": - version "0.0.19" - resolved "https://registry.yarnpkg.com/@permaweb/ao-scheduler-utils/-/ao-scheduler-utils-0.0.19.tgz#69d35c19583624ace3f500f53b4b4d73fca883e1" - integrity sha512-xwIe9FqQ1UZxEYWvSGJDONz0xr4vDq2Ny1NeRUiO0dKYoonShN+oI1ULgrHocKOjOPNEgRX70vMCKGLe+3x70A== +"@permaweb/ao-scheduler-utils@~0.0.20": + version "0.0.20" + resolved "https://registry.yarnpkg.com/@permaweb/ao-scheduler-utils/-/ao-scheduler-utils-0.0.20.tgz#5cee9650ef9234a01ecf3a57e8e0870f1f431076" + integrity sha512-bJkcmnQm/rCGqklJt46q5TnHfWkFzSBcSf9Z3uy8ylHRAheS9NyR1BJMAj3EXDjHCpg7JfnLRo6Uc3Xdw1lmOA== dependencies: lru-cache "^10.2.2" ramda "^0.30.0" zod "^3.23.5" -"@permaweb/aoconnect@^0.0.55": - version "0.0.55" - resolved "https://registry.yarnpkg.com/@permaweb/aoconnect/-/aoconnect-0.0.55.tgz#d856a078d3702154ac58541d09478d25ed3acf2c" - integrity sha512-W2GtLZedVseuDkCKk4CmM9SFmi0DdrMKqvhMBm9xo65z+Mzr/t1TEjMJKRNzEA2qh5IdwM43sWJ5fmbBYLg6TQ== +"@permaweb/aoconnect@^0.0.57": + version "0.0.57" + resolved "https://registry.yarnpkg.com/@permaweb/aoconnect/-/aoconnect-0.0.57.tgz#dd779563e1b994e78509251b74df64dc89ea62ea" + integrity sha512-l1+47cZuQ8pOIMOdRXymcegCmefXjqR8Bc2MY6jIzWv9old/tG6mfCue2W1QviGyhjP3zEVQgr7YofkY2lq35Q== dependencies: - "@permaweb/ao-scheduler-utils" "~0.0.16" + "@permaweb/ao-scheduler-utils" "~0.0.20" buffer "^6.0.3" - debug "^4.3.4" + debug "^4.3.5" hyper-async "^1.1.2" mnemonist "^0.39.8" - ramda "^0.29.1" + ramda "^0.30.1" warp-arbundles "^1.0.4" - zod "^3.22.4" + zod "^3.23.8" "@pkgjs/parseargs@^0.11.0": version "0.11.0" @@ -2604,6 +2604,11 @@ arconnect@^0.4.2: dependencies: arweave "^1.10.13" +arconnect@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arconnect/-/arconnect-1.0.3.tgz#8650ee6fbbcaa492cc31e3feba547dcc1706b97e" + integrity sha512-A4BTa1hl8SIbAMVUOsIiLwavmCvIMpbEFSem64klDBuBOMoIuEMUPxP5AoUfUxJZwUdL3NhNj584lCWUSGtdyA== + are-we-there-yet@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" @@ -3732,6 +3737,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" @@ -8283,16 +8295,16 @@ quick-lru@^4.0.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== -ramda@^0.29.1: - version "0.29.1" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.29.1.tgz#408a6165b9555b7ba2fc62555804b6c5a2eca196" - integrity sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA== - ramda@^0.30.0: version "0.30.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.30.0.tgz#3cc4f0ddddfa6334dad2f371bd72c33237d92cd0" integrity sha512-13Y0iMhIQuAm/wNGBL/9HEqIfRGmNmjKnTPlKWfA9f7dnDkr8d45wQ+S7+ZLh/Pq9PdcGxkqKUEA7ySu1QSd9Q== +ramda@^0.30.1: + version "0.30.1" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.30.1.tgz#7108ac95673062b060025052cd5143ae8fc605bf" + integrity sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -9075,16 +9087,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -9153,14 +9156,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -9936,16 +9932,7 @@ wordwrap@^1.0.0: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -10061,7 +10048,7 @@ yocto-queue@^1.0.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251" integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g== -zod@^3.22.4, zod@^3.23.5: +zod@^3.23.5, zod@^3.23.8: version "3.23.8" resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==