Skip to content

Commit

Permalink
Fix infinite loop in address parsing (#746)
Browse files Browse the repository at this point in the history
* fix potential inifinite loop

* simple example file showing how to parse addresses

* toNative can handle a UniversalAddress value

* add unit tests to document and test this behavior

* handle Uint8Array too

* check it starts with 0x

* test
  • Loading branch information
artursapek authored Dec 3, 2024
1 parent 9105de2 commit d4b2fea
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 6 deletions.
2 changes: 1 addition & 1 deletion core/definitions/__tests__/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ describe("UniversalAddress tests", function () {
const ua = new UniversalAddress(appId, "algorandAppId");
expect(ua.toString()).toEqual(appAddress)
});
});
});
17 changes: 14 additions & 3 deletions core/definitions/src/address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,20 @@ export function toNative<C extends Chain>(
}

return nativeAddress;
} catch (_) {
// try to parse it as a universal address
return (UniversalAddress.instanceof(ua) ? ua : new UniversalAddress(ua)).toNative(chain);
} catch (e: any) {
const err = `Error parsing address as a native ${chain} address: ${e.message}`;

if (UniversalAddress.instanceof(ua)) {
throw err;
} else {
// If we were given a string or Uint8Array value, which is ambiguously either a
// NativeAddress or UniversalAddress, and it failed to parse directly
// as a NativeAddress, we try one more time to parse it as a UniversalAddress
// first and then convert that to a NativeAddress.
console.error(err);
console.error('Attempting to parse as UniversalAddress');
return (new UniversalAddress(ua)).toNative(chain);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion core/definitions/src/universalAddress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export class UniversalAddress implements Address {
}

toNative<T extends Parameters<typeof toNative>[0]>(chainOrPlatform: T): NativeAddress<T> {
return toNative(chainOrPlatform, this.toUint8Array());
return toNative(chainOrPlatform, this);
}

unwrap(): Uint8Array {
Expand Down
3 changes: 2 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"wrapped": "tsx src/createWrapped.ts",
"tb": "tsx src/tokenBridge.ts",
"cctp": "tsx src/cctp.ts",
"parseAddress": "tsx src/parseAddress.ts",
"demo": "tsx src/index.ts",
"cosmos": "tsx src/cosmos.ts",
"msg": "tsx src/messaging.ts",
Expand All @@ -53,4 +54,4 @@
"dependencies": {
"@wormhole-foundation/sdk": "1.0.3"
}
}
}
20 changes: 20 additions & 0 deletions examples/src/parseAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { toNative, toUniversal } from "@wormhole-foundation/sdk";

const ETHEREUM_ADDRESS = '0xaaee1a9723aadb7afa2810263653a34ba2c21c7a';
const ETHEREUM_ADDRESS_UNIVERSAL = toUniversal('Ethereum', ETHEREUM_ADDRESS).toString();

(async function () {
// We can parse an Ethereum address from its native or universal format
const parsedEthereumAddr1 = toNative('Ethereum', ETHEREUM_ADDRESS);
const parsedEthereumAddr2 = toNative('Ethereum', ETHEREUM_ADDRESS_UNIVERSAL);
console.log(parsedEthereumAddr1);
console.log(parsedEthereumAddr2);

// Parsing a Sui address as Ethereum will throw:
try {
toNative('Ethereum', '0xabd62c91e3bd89243c592b93b9f45cf9f584be3df4574e05ae31d02fcfef67fc');
} catch (e) {
console.error(e);
}
})();

24 changes: 24 additions & 0 deletions platforms/evm/__tests__/unit/platform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import {
chains,
} from '@wormhole-foundation/sdk-connect';

import {
toNative,
} from '@wormhole-foundation/sdk-definitions';

import '@wormhole-foundation/sdk-evm-core';
import '@wormhole-foundation/sdk-evm-tokenbridge';
import { EvmPlatform } from '../../src/platform.js';
Expand All @@ -38,6 +42,26 @@ const configs = CONFIG[network].chains;
// const satisfiesInterface: PlatformUtils<typeof network> = EvmPlatform;

describe('EVM Platform Tests', () => {
describe("Parse Ethereum address", function () {
test("should correctly parse Ethereum addresses", () => {
expect(() =>
toNative('Ethereum', '0xaaee1a9723aadb7afa2810263653a34ba2c21c7a')
).toBeTruthy();
});

test("should correctly handle zero-padded Ethereum addresses (in universal address format)", () => {
expect(() =>
toNative('Ethereum', '0x000000000000000000000000aaee1a9723aadb7afa2810263653a34ba2c21c7a')
).toBeTruthy();
});

test("should throw when parsing an invalid Ethereum addresses", () => {
expect(() =>
toNative('Ethereum', '0xabd62c91e3bd89243c592b93b9f45cf9f584be3df4574e05ae31d02fcfef67fc')
).toThrow();
});
});

describe('Get Token Bridge', () => {
test('No RPC', async () => {
const p = new EvmPlatform(network, {});
Expand Down

0 comments on commit d4b2fea

Please sign in to comment.