diff --git a/packages/ensjs/src/functions/wallet/setAbiRecord.test.ts b/packages/ensjs/src/functions/wallet/setAbiRecord.test.ts index 0b095497..34701364 100644 --- a/packages/ensjs/src/functions/wallet/setAbiRecord.test.ts +++ b/packages/ensjs/src/functions/wallet/setAbiRecord.test.ts @@ -136,21 +136,34 @@ it('should allow an abi record to be set with uri content type', async () => { expect(response!.decoded).toBe(true) }) -it('should allow an abi record to be set to blank', async () => { - const tx = await setAbiRecord(walletClient, { - name: 'with-type-1-abi.eth', - encodedAbi: null, - resolverAddress: (await getResolver(publicClient, { - name: 'test123.eth', - }))!, - account: accounts[1], - }) - expect(tx).toBeTruthy() - const receipt = await waitForTransaction(tx) - expect(receipt.status).toBe('success') +type EncodeAs = Parameters[0]['encodeAs'] +it.each([ + ['json', 'with-type-1-abi.eth'], + ['zlib', 'with-type-2-abi.eth'], + ['cbor', 'with-type-4-abi.eth'], + ['uri', 'with-type-8-abi.eth'], +] as [EncodeAs, string][])( + `should allow an abi record to be set to null with %s content type`, + async (encodeAs, name) => { + const encodedAbi = await encodeAbi({ + encodeAs, + data: null, + }) + const tx = await setAbiRecord(walletClient, { + name, + encodedAbi, + resolverAddress: (await getResolver(publicClient, { + name, + }))!, + account: accounts[1], + }) + expect(tx).toBeTruthy() + const receipt = await waitForTransaction(tx) + expect(receipt.status).toBe('success') - const response = await getAbiRecord(publicClient, { - name: 'test123.eth', - }) - expect(response).toBeNull() -}) + const response = await getAbiRecord(publicClient, { + name, + }) + expect(response).toBeNull() + }, +) diff --git a/packages/ensjs/src/functions/wallet/setAbiRecord.ts b/packages/ensjs/src/functions/wallet/setAbiRecord.ts index 59f096c6..2f4bbd1e 100644 --- a/packages/ensjs/src/functions/wallet/setAbiRecord.ts +++ b/packages/ensjs/src/functions/wallet/setAbiRecord.ts @@ -22,7 +22,7 @@ export type SetAbiRecordDataParameters = { /** Name to set ABI for */ name: string /** Encoded ABI data to set */ - encodedAbi: EncodedAbi | null + encodedAbi: EncodedAbi /** Resolver address to set ABI on */ resolverAddress: Address } @@ -47,12 +47,11 @@ export const makeFunctionData = < _wallet: WalletWithEns, { name, encodedAbi, resolverAddress }: SetAbiRecordDataParameters, ): SetAbiRecordDataReturnType => { - const encodedAbi_ = encodedAbi || { contentType: 0, encodedData: null } return { to: resolverAddress, data: encodeSetAbi({ namehash: namehash(name), - ...encodedAbi_, + ...encodedAbi, } as EncodeSetAbiParameters), } } diff --git a/packages/ensjs/src/functions/wallet/setRecords.test.ts b/packages/ensjs/src/functions/wallet/setRecords.test.ts index 7415e51c..e4e0c6ea 100644 --- a/packages/ensjs/src/functions/wallet/setRecords.test.ts +++ b/packages/ensjs/src/functions/wallet/setRecords.test.ts @@ -91,6 +91,59 @@ it('should return a transaction to the resolver and set successfully', async () ] `) }) +it('should return a transaction to the resolver and delete successfully', async () => { + const setupTx = await setRecords(walletClient, { + name: 'test123.eth', + resolverAddress: (await getResolver(publicClient, { + name: 'test123.eth', + }))!, + coins: [ + { + coin: 'etcLegacy', + value: '0x42D63ae25990889E35F215bC95884039Ba354115', + }, + ], + texts: [{ key: 'foo', value: 'bar' }], + abi: await encodeAbi({ encodeAs: 'json', data: dummyABI }), + account: accounts[1], + }) + await waitForTransaction(setupTx) + const checkRecords = await getRecords(publicClient, { + name: 'test123.eth', + coins: ['etcLegacy'], + texts: ['foo'], + abi: true, + }) + expect(checkRecords.abi!.abi).not.toBeNull() + expect(checkRecords.coins).toHaveLength(1) + expect(checkRecords.texts).toHaveLength(1) + const tx = await setRecords(walletClient, { + name: 'test123.eth', + resolverAddress: (await getResolver(publicClient, { + name: 'test123.eth', + }))!, + coins: [ + { + coin: 'etcLegacy', + value: '', + }, + ], + texts: [{ key: 'foo', value: '' }], + abi: await encodeAbi({ encodeAs: 'json', data: null }), + account: accounts[1], + }) + await waitForTransaction(tx) + + const records = await getRecords(publicClient, { + name: 'test123.eth', + coins: ['etcLegacy'], + texts: ['foo'], + abi: true, + }) + expect(records.abi).toBeNull() + expect(records.coins).toHaveLength(0) + expect(records.texts).toHaveLength(0) +}) it('should error if there are no records to set', async () => { await expect( setRecords(walletClient, { diff --git a/packages/ensjs/src/utils/encoders/encodeAbi.test.ts b/packages/ensjs/src/utils/encoders/encodeAbi.test.ts index dd0a3c3f..b4e6a246 100644 --- a/packages/ensjs/src/utils/encoders/encodeAbi.test.ts +++ b/packages/ensjs/src/utils/encoders/encodeAbi.test.ts @@ -12,6 +12,13 @@ describe('encodeAbi', () => { expect(result.encodedData).toEqual('0x7b22666f6f223a22626172227d') }) + // Null JSON data + it('encodes null JSON data', async () => { + const result = await encodeAbi({ encodeAs: 'json', data: null }) + expect(result.contentType).toEqual(1) + expect(result.encodedData).toEqual('0x') + }) + it('encodes data as zlib', async () => { const data = { foo: 'bar' } const result = await encodeAbi({ encodeAs: 'zlib', data }) @@ -21,6 +28,13 @@ describe('encodeAbi', () => { ) }) + // Null zlib data + it('encodes null zlib data', async () => { + const result = await encodeAbi({ encodeAs: 'zlib', data: null }) + expect(result.contentType).toEqual(2) + expect(result.encodedData).toEqual('0x') + }) + it('encodes data as cbor', async () => { const data = { foo: 'bar' } const result = await encodeAbi({ encodeAs: 'cbor', data }) @@ -28,12 +42,26 @@ describe('encodeAbi', () => { expect(result.encodedData).toEqual('0xa163666f6f63626172') }) + // Null CBOR data + it('encodes null CBOR data', async () => { + const result = await encodeAbi({ encodeAs: 'cbor', data: null }) + expect(result.contentType).toEqual(4) + expect(result.encodedData).toEqual('0x') + }) + it('encodes data as uri', async () => { const data = 'foo=bar' const result = await encodeAbi({ encodeAs: 'uri', data }) expect(result.contentType).toEqual(8) expect(result.encodedData).toEqual('0x666f6f3d626172') }) + + // Null URI data + it('encodes null URI data', async () => { + const result = await encodeAbi({ encodeAs: 'uri', data: null }) + expect(result.contentType).toEqual(8) + expect(result.encodedData).toEqual('0x') + }) }) describe('encodeAsToContentType', () => { diff --git a/packages/ensjs/src/utils/encoders/encodeAbi.ts b/packages/ensjs/src/utils/encoders/encodeAbi.ts index 2cd13c3e..a976e69e 100644 --- a/packages/ensjs/src/utils/encoders/encodeAbi.ts +++ b/packages/ensjs/src/utils/encoders/encodeAbi.ts @@ -20,11 +20,11 @@ export type EncodeAbiParameters = TEncodeAs extends 'uri' ? { encodeAs: TEncodeAs - data: string + data: string | null } : { encodeAs: TEncodeAs - data: Record + data: Record | null } export type EncodedAbi = { @@ -72,27 +72,31 @@ export const encodeAbi = async < Prettify> > => { let contentType: AbiContentType - let encodedData: Hex + let encodedData: Hex = '0x' switch (encodeAs) { case 'json': contentType = 1 - encodedData = stringToHex(JSON.stringify(data)) + if (data) encodedData = stringToHex(JSON.stringify(data)) break case 'zlib': { contentType = 2 - const { deflate } = await import('pako/dist/pako_deflate.min.js') - encodedData = bytesToHex(deflate(JSON.stringify(data))) + if (data) { + const { deflate } = await import('pako/dist/pako_deflate.min.js') + encodedData = bytesToHex(deflate(JSON.stringify(data))) + } break } case 'cbor': { contentType = 4 - const { cborEncode } = await import('@ensdomains/address-encoder/utils') - encodedData = bytesToHex(new Uint8Array(cborEncode(data))) + if (data) { + const { cborEncode } = await import('@ensdomains/address-encoder/utils') + encodedData = bytesToHex(new Uint8Array(cborEncode(data))) + } break } default: { contentType = 8 - encodedData = stringToHex(data as string) + if (data) encodedData = stringToHex(data as string) break } } diff --git a/packages/ensjs/src/utils/encoders/encodeSetAbi.test.ts b/packages/ensjs/src/utils/encoders/encodeSetAbi.test.ts index 044f5774..046d95f8 100644 --- a/packages/ensjs/src/utils/encoders/encodeSetAbi.test.ts +++ b/packages/ensjs/src/utils/encoders/encodeSetAbi.test.ts @@ -4,8 +4,8 @@ import { encodeSetAbi, type EncodeSetAbiParameters } from './encodeSetAbi.js' describe('encodeSetAbi', () => { const namehash = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' - const contentType = 0 - const encodedData = null + const contentType = 1 + const encodedData = '0x' const parameters: EncodeSetAbiParameters = { namehash, @@ -13,9 +13,9 @@ describe('encodeSetAbi', () => { encodedData, } - it('encodes the setAbi function data correctly', () => { + it('encodes the setAbi function data correctly with null encodedData', async () => { const expected = - '0x623195b01234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000' + '0x623195b01234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000' const result = encodeSetAbi(parameters) expect(result).toEqual(expected) }) diff --git a/packages/ensjs/src/utils/encoders/encodeSetAbi.ts b/packages/ensjs/src/utils/encoders/encodeSetAbi.ts index ea263e85..460583ed 100644 --- a/packages/ensjs/src/utils/encoders/encodeSetAbi.ts +++ b/packages/ensjs/src/utils/encoders/encodeSetAbi.ts @@ -4,7 +4,7 @@ import type { EncodedAbi } from './encodeAbi.js' export type EncodeSetAbiParameters = { namehash: Hex -} & (EncodedAbi | { contentType: 0; encodedData: null }) +} & EncodedAbi export type EncodeSetAbiReturnType = Hex @@ -16,6 +16,6 @@ export const encodeSetAbi = ({ return encodeFunctionData({ abi: publicResolverSetAbiSnippet, functionName: 'setABI', - args: [namehash, BigInt(contentType), encodedData ?? '0x'], + args: [namehash, BigInt(contentType), encodedData], }) } diff --git a/packages/ensjs/src/utils/generateRecordCallArray.test.ts b/packages/ensjs/src/utils/generateRecordCallArray.test.ts index 5dd3cd54..e50f21ef 100644 --- a/packages/ensjs/src/utils/generateRecordCallArray.test.ts +++ b/packages/ensjs/src/utils/generateRecordCallArray.test.ts @@ -1,4 +1,5 @@ import { generateRecordCallArray } from './generateRecordCallArray.js' +import { encodeAbi } from './index.js' import { namehash } from './normalise.js' it('generates a record call array', () => { @@ -44,18 +45,6 @@ it('adds contentHash call when contentHash is defined', () => { ] `) }) -it('adds abi call when abi is null', () => { - expect( - generateRecordCallArray({ - namehash: namehash('test.eth'), - abi: null, - }), - ).toMatchInlineSnapshot(` - [ - "0x623195b0eb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", - ] - `) -}) it('does not add abi call when abi is undefined', () => { expect( generateRecordCallArray({ @@ -90,3 +79,29 @@ it('adds coin calls when coins array is defined and not empty', () => { ] `) }) +it('adds abi call when data is null', async () => { + const result = await encodeAbi({ encodeAs: 'uri', data: null }) + expect( + generateRecordCallArray({ + namehash: namehash('test.eth'), + abi: result, + }), + ).toMatchInlineSnapshot(` + [ + "0x623195b0eb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f1000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000", + ] + `) +}) +it('adds abi call when data is not empty', async () => { + const result = await encodeAbi({ encodeAs: 'json', data: { foo: 'bar' } }) + expect( + generateRecordCallArray({ + namehash: namehash('test.eth'), + abi: result, + }), + ).toMatchInlineSnapshot(` + [ + "0x623195b0eb4f647bea6caa36333c816d7b46fdcb05f9466ecacc140ea8c66faf15b3d9f100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000d7b22666f6f223a22626172227d00000000000000000000000000000000000000", + ] + `) +}) diff --git a/packages/ensjs/src/utils/generateRecordCallArray.ts b/packages/ensjs/src/utils/generateRecordCallArray.ts index 83b0ec6d..61656375 100644 --- a/packages/ensjs/src/utils/generateRecordCallArray.ts +++ b/packages/ensjs/src/utils/generateRecordCallArray.ts @@ -26,7 +26,7 @@ export type RecordOptions = Prettify<{ /** Array of coin records */ coins?: Omit[] /** ABI value */ - abi?: EncodedAbi | null + abi?: EncodedAbi }> export const generateRecordCallArray = ({ @@ -49,8 +49,7 @@ export const generateRecordCallArray = ({ } if (abi !== undefined) { - const abi_ = abi ?? { contentType: 0, encodedData: null } - const data = encodeSetAbi({ namehash, ...abi_ } as EncodeSetAbiParameters) + const data = encodeSetAbi({ namehash, ...abi } as EncodeSetAbiParameters) if (data) calls.push(data) }