diff --git a/.changeset/olive-maps-applaud.md b/.changeset/olive-maps-applaud.md new file mode 100644 index 0000000000..1562fca151 --- /dev/null +++ b/.changeset/olive-maps-applaud.md @@ -0,0 +1,6 @@ +--- +'@hyperlane-xyz/utils': patch +'@hyperlane-xyz/sdk': patch +--- + +Supported non-32 byte non-EVM recipients when sending warps from Sealevel diff --git a/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts index 8287fa07b8..1df0d86375 100644 --- a/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts +++ b/typescript/sdk/src/token/adapters/SealevelTokenAdapter.ts @@ -21,6 +21,7 @@ import { addressToBytes, eqAddress, median, + padBytesToLength, } from '@hyperlane-xyz/utils'; import { BaseSealevelAdapter } from '../../app/MultiProtocolApp.js'; @@ -295,7 +296,7 @@ export abstract class SealevelHypTokenAdapter instruction: SealevelHypTokenInstruction.TransferRemote, data: new SealevelTransferRemoteInstruction({ destination_domain: destination, - recipient: addressToBytes(recipient), + recipient: padBytesToLength(addressToBytes(recipient), 32), amount_or_id: BigInt(weiAmountOrId), }), }); diff --git a/typescript/utils/src/addresses.test.ts b/typescript/utils/src/addresses.test.ts index d25e33cf8a..2313ce384c 100644 --- a/typescript/utils/src/addresses.test.ts +++ b/typescript/utils/src/addresses.test.ts @@ -4,6 +4,7 @@ import { addressToBytes, bytesToProtocolAddress, isZeroishAddress, + padBytesToLength, } from './addresses.js'; import { ProtocolType } from './types.js'; @@ -42,6 +43,17 @@ describe('Address utilities', () => { }); }); + describe('padBytesToLength', () => { + it('Pads bytes to a given length', () => { + const bytes = Buffer.from([1, 2, 3]); + expect(padBytesToLength(bytes, 5).equals(Buffer.from([0, 0, 1, 2, 3]))); + }); + it('Rejects bytes that exceed the target length', () => { + const bytes = Buffer.from([1, 2, 3]); + expect(() => padBytesToLength(bytes, 2)).to.throw(Error); + }); + }); + describe('bytesToProtocolAddress', () => { it('Converts bytes to address', () => { expect( diff --git a/typescript/utils/src/addresses.ts b/typescript/utils/src/addresses.ts index 88532464fb..01f9fdb107 100644 --- a/typescript/utils/src/addresses.ts +++ b/typescript/utils/src/addresses.ts @@ -316,6 +316,14 @@ export function bytesToBytes32(bytes: Uint8Array): string { ); } +// Pad bytes to a certain length, padding with 0s at the start +export function padBytesToLength(bytes: Uint8Array, length: number) { + if (bytes.length > length) { + throw new Error(`bytes must be ${length} bytes or less`); + } + return Buffer.concat([Buffer.alloc(length - bytes.length), bytes]); +} + export function bytesToAddressEvm(bytes: Uint8Array): Address { return bytes32ToAddress(Buffer.from(bytes).toString('hex')); } diff --git a/typescript/utils/src/index.ts b/typescript/utils/src/index.ts index 0c18543dd6..0c82c6782a 100644 --- a/typescript/utils/src/index.ts +++ b/typescript/utils/src/index.ts @@ -35,6 +35,7 @@ export { normalizeAddressCosmos, normalizeAddressEvm, normalizeAddressSealevel, + padBytesToLength, shortenAddress, strip0x, } from './addresses.js';