diff --git a/docker-compose.yml b/docker-compose.yml index a684119fb7..c8668f4c03 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ version: '3' services: node: - image: aeternity/aeternity:master@sha256:dac4a3b032ee05f2e0d4b4ce5b0da5c639f95e849fe0332e393f87ca01da0df2 + image: aeternity/aeternity:master@sha256:c4883366073e732d47727bde5dc4372ea154fe20e4724d9d82e043d79a1500f9 hostname: node ports: ["3013:3013", "3113:3113", "3014:3014", "3114:3114"] volumes: diff --git a/docs/guides/aens.md b/docs/guides/aens.md index 0c6069ba46..b2d1f7ca9f 100644 --- a/docs/guides/aens.md +++ b/docs/guides/aens.md @@ -170,19 +170,19 @@ Note: ## 2. Update a name Now that you own your AENS name you might want to update it in order to: -- Set pointers to `accounts`, `oracles`, `contracts` or `channels`. +- Set pointers to `accounts`, `oracles`, `contracts`, `channels`, or store binary data. - Extend the TTL before it expires. - By default a name will have a TTL of 180000 key blocks (~375 days). It cannot be extended longer than 180000 key blocks. ### Set pointers & update TTL ```js -import { getDefaultPointerKey } from '@aeternity/aepp-sdk' +import { getDefaultPointerKey, encode, Encoding } from '@aeternity/aepp-sdk' const name = 'testNameForTheGuide.chain' const oracle = 'ok_2519mBsgjJEVEFoRgno1ryDsn3BEaCZGRbXPEjThWYLX9MTpmk' const pointers = { account_pubkey: 'ak_2519mBsgjJEVEFoRgno1ryDsn3BEaCZGRbXPEjThWYLX9MTpmk', - customKey: 'ak_2519mBsgjJEVEFoRgno1ryDsn3BEaCZGRbXPEjThWYLX9MTpmk', + customKey: encode(Buffer.from('example data'), Encoding.Bytearray), [getDefaultPointerKey(oracle)]: oracle, // the same as `oracle_pubkey: oracle,` contract_pubkey: 'ct_2519mBsgjJEVEFoRgno1ryDsn3BEaCZGRbXPEjThWYLX9MTpmk', channel: 'ch_2519mBsgjJEVEFoRgno1ryDsn3BEaCZGRbXPEjThWYLX9MTpmk', diff --git a/package-lock.json b/package-lock.json index ce04662f73..64571758c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "13.2.2", "license": "ISC", "dependencies": { - "@aeternity/aepp-calldata": "github:aeternity/aepp-calldata-js#aens_v2", + "@aeternity/aepp-calldata": "github:aeternity/aepp-calldata-js#8e9c8b8e1b394a01be1c84b13cf76271f7624d38", "@aeternity/argon2": "^0.0.1", "@aeternity/uuid": "^0.0.1", "@azure/core-client": "1.6.0", @@ -106,7 +106,8 @@ }, "node_modules/@aeternity/aepp-calldata": { "version": "1.5.1", - "resolved": "git+ssh://git@github.com/aeternity/aepp-calldata-js.git#1cf5c74188568d069c9df95110faf5c61e602e3a", + "resolved": "git+ssh://git@github.com/aeternity/aepp-calldata-js.git#8e9c8b8e1b394a01be1c84b13cf76271f7624d38", + "integrity": "sha512-pDJBAfyOMfi5lBr+4M0V8edXAJ1dkNMdBuQNt6+opPgZgLSUmO/Cl4Qhp8mMfXm+fPJiTrc52dcZvot/Hx9KRQ==", "license": "ISC", "dependencies": { "blakejs": "^1.2.1", diff --git a/package.json b/package.json index 8a26d45586..c0f93a9370 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "SDK" ], "dependencies": { - "@aeternity/aepp-calldata": "github:aeternity/aepp-calldata-js#aens_v2", + "@aeternity/aepp-calldata": "github:aeternity/aepp-calldata-js#8e9c8b8e1b394a01be1c84b13cf76271f7624d38", "@aeternity/argon2": "^0.0.1", "@aeternity/uuid": "^0.0.1", "@azure/core-client": "1.6.0", diff --git a/src/aens.ts b/src/aens.ts index c736c530b1..0d0cbc68b2 100644 --- a/src/aens.ts +++ b/src/aens.ts @@ -7,10 +7,11 @@ */ import BigNumber from 'bignumber.js'; -import { genSalt } from './utils/crypto'; +import { genSalt, isAddressValid } from './utils/crypto'; import { commitmentHash, isAuctionName } from './tx/builder/helpers'; -import { Tag, AensName } from './tx/builder/constants'; -import { Encoded } from './utils/encoder'; +import { Tag, AensName, ConsensusProtocolVersion } from './tx/builder/constants'; +import { Encoded, Encoding } from './utils/encoder'; +import { UnsupportedProtocolError } from './utils/errors'; import { sendTransaction, SendTransactionOptions, getName } from './chain'; import { buildTxAsync, BuildTxOptions } from './tx/builder'; import { TransformNodeType } from './Node'; @@ -19,7 +20,7 @@ import AccountBase from './account/Base'; import { AddressEncodings } from './tx/builder/field-types/address'; interface KeyPointers { - [key: string]: Encoded.Generic; + [key: string]: Encoded.Generic; } /** @@ -101,9 +102,18 @@ export async function aensUpdate( ...pointers, }; + const hasRawPointers = Object.values(allPointers) + .some((v) => isAddressValid(v, Encoding.Bytearray)); + const isIris = (await options.onNode.getNodeInfo()) + .consensusProtocolVersion === ConsensusProtocolVersion.Iris; + if (hasRawPointers && isIris) { + throw new UnsupportedProtocolError('Raw pointers are available only in Ceres, the current protocol is Iris'); + } + const nameUpdateTx = await buildTxAsync({ ...options, tag: Tag.NameUpdateTx, + version: hasRawPointers ? 2 : 1, nameId: name, accountId: options.onAccount.address, pointers: Object.entries(allPointers) diff --git a/src/tx/builder/field-types/index.ts b/src/tx/builder/field-types/index.ts index 908d83d58b..39c1ad8a9e 100644 --- a/src/tx/builder/field-types/index.ts +++ b/src/tx/builder/field-types/index.ts @@ -18,6 +18,7 @@ export { default as nameFee } from './name-fee'; export { default as nameId } from './name-id'; export { default as nonce } from './nonce'; export { default as pointers } from './pointers'; +export { default as pointers2 } from './pointers2'; export { default as queryFee } from './query-fee'; export { default as raw } from './raw'; export { default as shortUInt } from './short-u-int'; diff --git a/src/tx/builder/field-types/pointers2.ts b/src/tx/builder/field-types/pointers2.ts new file mode 100644 index 0000000000..fe849ab3ef --- /dev/null +++ b/src/tx/builder/field-types/pointers2.ts @@ -0,0 +1,62 @@ +import { NamePointer as NamePointerString } from '../../../apis/node'; +import { toBytes } from '../../../utils/bytes'; +import { + Encoded, Encoding, decode, encode, +} from '../../../utils/encoder'; +import { isAddressValid } from '../../../utils/crypto'; +import { IllegalArgumentError, DecodeError, ArgumentError } from '../../../utils/errors'; +import address, { AddressEncodings, idTagToEncoding } from './address'; + +const ID_TAG = Buffer.from([1]); +const DATA_TAG = Buffer.from([2]); +const DATA_LENGTH_MAX = 1024; +const addressAny = address(...idTagToEncoding); + +// TODO: remove after fixing node types +type NamePointer = NamePointerString & { + id: Encoded.Generic; +}; + +export default { + /** + * Helper function to build pointers for name update TX + * @param pointers - Array of pointers + * `([ { key: 'account_pubkey', id: 'ak_32klj5j23k23j5423l434l2j3423'} ])` + * @returns Serialized pointers array + */ + serialize(pointers: NamePointer[]): Buffer[][] { + if (pointers.length > 32) { + throw new IllegalArgumentError(`Expected 32 pointers or less, got ${pointers.length} instead`); + } + return pointers.map(({ key, id }) => { + let payload; + if (isAddressValid(id, ...idTagToEncoding)) payload = [ID_TAG, addressAny.serialize(id)]; + if (isAddressValid(id, Encoding.Bytearray)) { + const data = decode(id); + if (data.length > DATA_LENGTH_MAX) { + throw new ArgumentError('Raw pointer', `shorter than ${DATA_LENGTH_MAX + 1} bytes`, `${data.length} bytes`); + } + payload = [DATA_TAG, data]; + } + if (payload == null) throw new DecodeError(`Unknown AENS pointer value: ${id}`); + return [toBytes(key), Buffer.concat(payload)]; + }); + }, + + /** + * Helper function to read pointers from name update TX + * @param pointers - Array of pointers + * @returns Deserialize pointer array + */ + deserialize(pointers: Array<[key: Buffer, id: Buffer]>): NamePointer[] { + return pointers.map(([bKey, bId]) => { + const tag = bId.subarray(0, 1); + const payload = bId.subarray(1); + let id; + if (tag.equals(ID_TAG)) id = addressAny.deserialize(payload); + if (tag.equals(DATA_TAG)) id = encode(payload, Encoding.Bytearray); + if (id == null) throw new DecodeError(`Unknown AENS pointer tag: ${tag}`); + return { key: bKey.toString(), id }; + }); + }, +}; diff --git a/src/tx/builder/schema.ts b/src/tx/builder/schema.ts index 4441ab37dd..7933622d92 100644 --- a/src/tx/builder/schema.ts +++ b/src/tx/builder/schema.ts @@ -7,8 +7,8 @@ import { Tag } from './constants'; import SchemaTypes from './SchemaTypes'; import { - uInt, shortUInt, coinAmount, name, nameId, nameFee, gasLimit, gasPrice, fee, - address, pointers, queryFee, entry, enumeration, mptree, shortUIntConst, string, encoded, raw, + uInt, shortUInt, coinAmount, name, nameId, nameFee, gasLimit, gasPrice, fee, address, pointers, + pointers2, queryFee, entry, enumeration, mptree, shortUIntConst, string, encoded, raw, array, boolean, ctVersion, abiVersion, ttl, nonce, map, withDefault, withFormatting, wrapped, } from './field-types'; import { Encoded, Encoding } from '../../utils/encoder'; @@ -129,6 +129,19 @@ interface MapOracles { const mapOracles = map(Encoding.OracleAddress, Tag.Oracle) as unknown as MapOracles; +// TODO: inline after dropping Iris compatibility +const clientTtl = withDefault(60 * 60, shortUInt); +// https://github.com/aeternity/protocol/blob/fd17982/AENS.md#update +const nameTtl = withFormatting( + (value) => { + const NAME_TTL = 180000; + value ??= NAME_TTL; + if (value >= 1 && value <= NAME_TTL) return value; + throw new ArgumentError('nameTtl', `a number between 1 and ${NAME_TTL} blocks`, value); + }, + shortUInt, +); + /** * @see {@link https://github.com/aeternity/protocol/blob/c007deeac4a01e401238412801ac7084ac72d60e/serializations.md#accounts-version-1-basic-accounts} */ @@ -193,18 +206,20 @@ export const txSchema = [{ accountId: address(Encoding.AccountAddress), nonce: nonce('accountId'), nameId, - // https://github.com/aeternity/protocol/blob/fd17982/AENS.md#update - nameTtl: withFormatting( - (nameTtl) => { - const NAME_TTL = 180000; - nameTtl ??= NAME_TTL; - if (nameTtl >= 1 && nameTtl <= NAME_TTL) return nameTtl; - throw new ArgumentError('nameTtl', `a number between 1 and ${NAME_TTL} blocks`, nameTtl); - }, - shortUInt, - ), + nameTtl, pointers, - clientTtl: withDefault(60 * 60, shortUInt), + clientTtl, + fee, + ttl, +}, { + tag: shortUIntConst(Tag.NameUpdateTx), + version: shortUIntConst(2), + accountId: address(Encoding.AccountAddress), + nonce: nonce('accountId'), + nameId, + nameTtl, + pointers: pointers2, + clientTtl, fee, ttl, }, { diff --git a/test/integration/aens.ts b/test/integration/aens.ts index c281bc40c7..3fa4009f48 100644 --- a/test/integration/aens.ts +++ b/test/integration/aens.ts @@ -145,14 +145,23 @@ describe('Aens', () => { }); const address = generateKeyPair().publicKey; - const pointers = { - myKey: address, - account_pubkey: address, - oracle_pubkey: encode(decode(address), Encoding.OracleAddress), - channel: encode(decode(address), Encoding.Channel), - contract_pubkey: buildContractId(address, 13), - }; - const pointersNode = Object.entries(pointers).map(([key, id]) => ({ key, id })); + let pointers: Parameters[1]; + let pointersNode: Array<{ key: string; id: typeof pointers[string] }>; + let isIris: boolean; + + before(async () => { + isIris = (await aeSdk.api.getNodeInfo()) + .consensusProtocolVersion === ConsensusProtocolVersion.Iris; + pointers = { + myKey: address, + ...!isIris && { 'my raw key': encode(Buffer.from('my raw value'), Encoding.Bytearray) }, + account_pubkey: address, + oracle_pubkey: encode(decode(address), Encoding.OracleAddress), + channel: encode(decode(address), Encoding.Channel), + contract_pubkey: buildContractId(address, 13), + }; + pointersNode = Object.entries(pointers).map(([key, id]) => ({ key, id })); + }); it('updates', async () => { const nameObject = await aeSdk.aensQuery(name); @@ -188,6 +197,14 @@ describe('Aens', () => { .to.be.rejectedWith('Expected 32 pointers or less, got 33 instead'); }); + it('throws error on setting too long raw pointer', async () => { + const nameObject = await aeSdk.aensQuery(name); + const pointersRaw = { raw: encode(Buffer.from('t'.repeat(1025)), Encoding.Bytearray) }; + await expect(nameObject.update(pointersRaw)).to.be.rejectedWith(isIris + ? 'Raw pointers are available only in Ceres, the current protocol is Iris' + : 'Raw pointer should be shorter than 1025 bytes, got 1025 bytes instead'); + }); + it('Extend name ttl', async () => { const nameObject = await aeSdk.aensQuery(name); const extendResult: Awaited> = await nameObject diff --git a/test/integration/contract-aci.ts b/test/integration/contract-aci.ts index b3003a3976..20ca1ce803 100644 --- a/test/integration/contract-aci.ts +++ b/test/integration/contract-aci.ts @@ -17,6 +17,7 @@ import { AE_AMOUNT_FORMATS, Tag, NoSuchContractFunctionError, + ConsensusProtocolVersion, } from '../../src'; import { getSdk } from '.'; import { @@ -36,7 +37,7 @@ namespace TestLib = function sum(x: int, y: int) = x + y `; -const testContractSourceCode = ` +const getTestContractSourceCode = (isIris: boolean): string => ` namespace Test = function double(x: int) = x * 2 @@ -86,7 +87,7 @@ contract StateContract = entrypoint hashFn(s: hash) = s entrypoint signatureFn(s: signature) = s entrypoint bytesFn(s: bytes(32)) = s - entrypoint bytesAnySizeFn(s: bytes) = s + ${isIris ? '' : 'entrypoint bytesAnySizeFn(s: bytes) = s'} entrypoint bitsFn(s: bits) = s @@ -101,6 +102,8 @@ contract StateContract = entrypoint chainTtlFn(t: Chain.ttl) = t + ${isIris ? '' : 'entrypoint aensV2Name(name: AENSv2.name) = name'} + stateful entrypoint recursion(t: string) = put(state{value = t}) recursion(t) @@ -113,6 +116,17 @@ const notExistingContractAddress = 'ct_ptREMvyDbSh1d38t4WgYgac5oLsa2v9xwYFnG7eUW type DateUnit = { Year: [] } | { Month: [] } | { Day: [] }; type OneOrBoth = { Left: [First] } | { Both: [First, Second] } | { Right: [Second] }; +interface AENSv2Name { + 'AENSv2.Name': [ + Encoded.AccountAddress, + ChainTtl, + Map, + ]; +} + interface TestContractApi extends ContractMethodsBase { init: (value: string, key: InputNumber, testOption?: string) => void; retrieve: () => [string, bigint]; @@ -165,11 +179,15 @@ interface TestContractApi extends ContractMethodsBase { chainTtlFn: (t: ChainTtl) => ChainTtl; + aensV2Name: (name: AENSv2Name) => AENSv2Name; + recursion: (t: string) => string; } describe('Contract instance', () => { let aeSdk: AeSdk; + let isIris: boolean; + let testContractSourceCode: string; let testContract: Contract; let testContractAddress: Encoded.ContractAddress; let testContractAci: Aci; @@ -177,6 +195,9 @@ describe('Contract instance', () => { before(async () => { aeSdk = await getSdk(2); + isIris = (await aeSdk.api.getNodeInfo()) + .consensusProtocolVersion === ConsensusProtocolVersion.Iris; + testContractSourceCode = getTestContractSourceCode(isIris); const res = await aeSdk.compilerApi.compileBySourceCode(testContractSourceCode, fileSystem); testContractAci = res.aci; testContractBytecode = res.bytecode; @@ -1045,11 +1066,13 @@ describe('Contract instance', () => { describe('Bytes any size', () => { it('Invalid type', async () => { + if (isIris) return; await expect(testContract.bytesAnySizeFn({} as any)) .to.be.rejectedWith('Should be one of: Array, ArrayBuffer, hex string, Number, BigInt; got [object Object] instead'); }); it('Valid', async () => { + if (isIris) return; const decoded = Buffer.from('0xdeadbeef', 'hex'); const { decodedResult: hashAsBuffer } = await testContract.bytesAnySizeFn(decoded); const { decodedResult: hashAsHex } = await testContract.bytesAnySizeFn(decoded.toString('hex')); @@ -1082,6 +1105,29 @@ describe('Contract instance', () => { expect((await testContract.chainTtlFn(value)).decodedResult).to.be.eql(value); }); }); + + describe('AENSv2.name', () => { + it('Invalid', async () => { + if (isIris) return; + await expect(testContract.aensV2Name({ 'AENSv2.Name': ['test'] } as any)) + .to.be.rejectedWith('"AENSv2.Name" variant constructor expects 3 argument(s) but got 1 instead'); + }); + + it('Valid', async () => { + if (isIris) return; + const value: AENSv2Name = { + 'AENSv2.Name': [ + 'ak_nRqnePWC6yGWBmR4wfN3AvQnqbv2TizxKJdvGXj8p7YZrUZ5J', + { FixedTTL: [180205n] }, + new Map([ + ['oracle', { 'AENSv2.OraclePt': ['ak_nRqnePWC6yGWBmR4wfN3AvQnqbv2TizxKJdvGXj8p7YZrUZ5J'] }], + ['test key', { 'AENSv2.DataPt': [Buffer.from('test value')] }], + ]), + ], + }; + expect((await testContract.aensV2Name(value)).decodedResult).to.be.eql(value); + }); + }); }); describe('Call contract', () => { diff --git a/test/integration/delegation.ts b/test/integration/delegation.ts index 2bb814b5c1..d617b6a0c1 100644 --- a/test/integration/delegation.ts +++ b/test/integration/delegation.ts @@ -20,6 +20,12 @@ describe('Operation delegation', () => { }); describe('AENS', () => { + interface Pointee { + 'AENS.OraclePt'?: readonly [Encoded.AccountAddress]; + 'AENSv2.OraclePt'?: readonly [Encoded.AccountAddress]; + 'AENSv2.DataPt'?: readonly [Uint8Array]; + } + const name = randomName(15); const salt = genSalt(); let owner: Encoded.AccountAddress; @@ -50,10 +56,7 @@ describe('Operation delegation', () => { owner: Encoded.AccountAddress, name: string, key: string, - pt: { - 'AENS.OraclePt'?: readonly [Encoded.Any]; - 'AENSv2.OraclePt'?: readonly [Encoded.Any]; - }, + pt: Pointee, sign: Uint8Array ) => void; }>; @@ -115,15 +118,8 @@ contract DelegateTest = result.returnType.should.be.equal('ok'); }); - it('gets', async () => { - const nameEntry = (await contract.getName(name)).decodedResult[`${aens}.Name`]; - expect(nameEntry[0]).to.be.equal(owner); - expect(nameEntry[1].FixedTTL[0]).to.be.a('bigint'); - expect(nameEntry[2]).to.be.eql(new Map()); - }); - it('updates', async () => { - const pointee = { [`${aens}.OraclePt`]: [newOwner] as const }; + const pointee: Pointee = { [`${aens}.OraclePt`]: [newOwner] }; const { result } = await contract .signedUpdate(owner, name, 'oracle', pointee, delegationSignature); assertNotNull(result); @@ -134,6 +130,32 @@ contract DelegateTest = }]); }); + const dataPt = new Uint8Array(Buffer.from('test value')); + + it('updates with raw pointer', async () => { + if (isIris) return; + const pointee: Pointee = { 'AENSv2.DataPt': [dataPt] }; + await contract.signedUpdate(owner, name, 'test key', pointee, delegationSignature); + expect((await aeSdk.aensQuery(name)).pointers[0]).to.be.eql({ + key: 'test key', + id: encode(dataPt, Encoding.Bytearray), + }); + }); + + it('gets', async () => { + const nameEntry = (await contract.getName(name)).decodedResult[`${aens}.Name`]; + const ttl = nameEntry[1].FixedTTL[0]; + expect(ttl).to.be.a('bigint'); + expect(nameEntry).to.be.eql([ + owner, + { FixedTTL: [ttl] }, + new Map([ + ['oracle', { [`${aens}.OraclePt`]: [newOwner] }], + ...isIris ? [] : [['test key', { 'AENSv2.DataPt': [dataPt] }]] as const, + ]), + ]); + }); + it('transfers', async () => { const { result } = await contract .signedTransfer(owner, newOwner, name, delegationSignature); @@ -164,7 +186,7 @@ contract DelegateTest = await contract.signedClaim(owner, n, salt, 20e18, allNamesDelSig); - const pointee = { 'AENSv2.OraclePt': [newOwner] as const }; + const pointee: Pointee = { 'AENSv2.OraclePt': [newOwner] }; await contract.signedUpdate(owner, n, 'oracle', pointee, allNamesDelSig); const nameEntry = (await contract.getName(n)).decodedResult['AENSv2.Name']; @@ -183,6 +205,7 @@ contract DelegateTest = }); it('claims without preclaim', async () => { + if (isIris) return; const n = randomName(15); const nameFee = 20e18; const dlgSig = await aeSdk.createDelegationSignature(contractAddress, [n]); diff --git a/test/integration/transaction.ts b/test/integration/transaction.ts index 34f0e126d6..bac2bb47f5 100644 --- a/test/integration/transaction.ts +++ b/test/integration/transaction.ts @@ -97,6 +97,22 @@ describe('Transaction', () => { async () => aeSdk.buildTx({ tag: Tag.NameUpdateTx, accountId: senderId, nonce, nameId, nameTtl, pointers, clientTtl, }), + ], [ + 'name update v2', + 'tx_+JwiAqEB4TK48d23oE5jt/qWR5pUu8UlpTGn8bwM5JISGQMGf7ABoQL1zlEz+3+D5h4MF9POub3zp5zJ2fj6VUWGMNOhCyMYPAH4SfKOYWNjb3VudF9wdWJrZXmiAQHhMrjx3begTmO3+pZHmlS7xSWlMafxvAzkkhIZAwZ/sNWIdGVzdCBrZXmLAnRlc3QgdmFsdWUBhhCENFlgAABtaPdX', + async () => aeSdk.buildTx({ + tag: Tag.NameUpdateTx, + version: 2, + accountId: senderId, + nonce, + nameId, + nameTtl, + pointers: [ + ...pointers, + { key: 'test key', id: encode(Buffer.from('test value'), Encoding.Bytearray) }, + ], + clientTtl, + }), ], [ 'name revoke', 'tx_+E8jAaEB4TK48d23oE5jt/qWR5pUu8UlpTGn8bwM5JISGQMGf7ABoQL1zlEz+3+D5h4MF9POub3zp5zJ2fj6VUWGMNOhCyMYPIYPHaUyOAAA94BVgw==', diff --git a/tooling/fetch-aesophia-cli-8.mjs b/tooling/fetch-aesophia-cli-8.mjs index 7bb3dd67f9..72f148f1a3 100644 --- a/tooling/fetch-aesophia-cli-8.mjs +++ b/tooling/fetch-aesophia-cli-8.mjs @@ -3,7 +3,7 @@ import { dirname } from 'path'; import { writeFileSync, readFileSync, mkdirSync } from 'fs'; const path = './bin/aesophia_cli_8'; -const hash = 'tZdsd7XH1e4C10MIzM0TY0IFcpkPBZqZMPdJ1ln9GDVsgjVCCK86YKCK5KtKqQzhNKSXaE01ZjAfTEYOSV7uIg=='; +const hash = 'HWWFD9mdaW/7n1cc3dDZzE01JKSVFHSIPC9DPeCTpAh3QZMpdGI1TTGI0ZpZfK1dC/Hexvs/1o6My60v6a7m4Q=='; function ensureBinaryCorrect() { const buffer = readFileSync(path); @@ -16,7 +16,7 @@ try { } catch { console.log('Fetching aesophia_cli_8'); const request = await fetch( - 'https://github.com/aeternity/aesophia_cli/raw/df63ff9f4fdcfc437c90b90914fd1a7081d2bbbe/aesophia_cli', + 'https://github.com/aeternity/aepp-calldata-js/raw/3d98ab7ac8180f080753c8ab2046ad7291054132/bin/aesophia_cli', ); const body = Buffer.from(await request.arrayBuffer()); mkdirSync(dirname(path), { recursive: true });