Skip to content

Commit

Permalink
fixup! feat(vats): first cut of Address Hooks in JS
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelfig committed Dec 10, 2024
1 parent aca8aa6 commit 6bbd799
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 11 deletions.
38 changes: 28 additions & 10 deletions packages/cosmic-proto/src/address-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,23 @@ const ADDRESS_HOOK_MAGIC = new Uint8Array([
0x70 | ADDRESS_HOOK_VERSION,
]);

// The default maximum number of characters in a bech32-encoded hooked address.
/**
* The default maximum number of characters in a bech32-encoded hooked address.
*/
export const DEFAULT_HOOKED_ADDRESS_CHAR_LIMIT = 1024;

/**
* @typedef {Record<string, string | (string | null)[] | null>} HookQuery
* @typedef {Record<string, string | (string | null)[] | null>} HookQuery A
* record of query keys mapped to query values. `null` values denote valueless
* keys. Array values denote multiple occurrences of a key:
*
* { key: null } // '?key'
* { key: 'value' } // '?key=value'
* { key: ['value1', 'value2', 'value3'] } // '?key=value1&key=value2&key=value3'
* { key: ['value1', null, 'value3'] } // '?key=value1&key&key=value3'
*/

export const BASE_ADDRESS_LENGTH_BYTES = 2;
export const MAX_BASE_ADDRESS_LENGTH =
(1 << (BASE_ADDRESS_LENGTH_BYTES * 8 - 1)) + 1;

/**
* @param {string} specimen
Expand Down Expand Up @@ -119,22 +126,33 @@ export const joinHookedAddress = (
const { prefix, bytes } = decodeBech32(baseAddress, charLimit);

const baseAddressLength = bytes.length;
if (baseAddressLength > MAX_BASE_ADDRESS_LENGTH) {
const b = baseAddressLength;
const hd = hookData.length;

const maxBaseAddressLength = 2 ** (BASE_ADDRESS_LENGTH_BYTES * 8);
if (b >= maxBaseAddressLength) {
throw RangeError(
`Base address length 0x${baseAddressLength.toString(16)} exceeds maximum 0x${MAX_BASE_ADDRESS_LENGTH.toString(16)}`,
`Base address length 0x${b.toString(16)} exceeds maximum 0x${maxBaseAddressLength.toString(16)}`,
);
}
const b = baseAddressLength;

if (!Number.isSafeInteger(hd) || hd < 0) {
throw RangeError(`Hook data length ${hd} is not a non-negative integer`);
}

const magicLength = ADDRESS_HOOK_MAGIC.length;
const hookBuf = new Uint8Array(
magicLength + bytes.length + hookData.length + BASE_ADDRESS_LENGTH_BYTES,
magicLength + b + hd + BASE_ADDRESS_LENGTH_BYTES,
);
hookBuf.set(ADDRESS_HOOK_MAGIC);
hookBuf.set(ADDRESS_HOOK_MAGIC, 0);
hookBuf.set(bytes, magicLength);
hookBuf.set(hookData, magicLength + b);

// Append the big-endian address length.
// Append the address length bytes, since we've already ensured these do not
// exceed maxBaseAddressLength above. These are big-endian because the length
// is at the end of the payload, so if we want to support more bytes for the
// length, we just need encroach further into the payload. We can do that
// without changing the meaning of the bytes at the end of existing payloads.
let len = b;
for (let i = 0; i < BASE_ADDRESS_LENGTH_BYTES; i += 1) {
hookBuf[hookBuf.length - 1 - i] = len & 0xff;
Expand Down
30 changes: 29 additions & 1 deletion packages/cosmic-proto/test/address-hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import rawTest from '@endo/ses-ava/prepare-endo.js';
import bundleSourceAmbient from '@endo/bundle-source';
import { importBundle } from '@endo/import-bundle';

import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);

/**
* @type {import('ava').TestFn<{
* addressHooks: import('../src/address-hooks.js');
Expand All @@ -11,9 +15,11 @@ import { importBundle } from '@endo/import-bundle';
const test = rawTest;

const makeTestContext = async () => {
// Do all this work so that we test bundling and evaluation of the module in a
// fresh compartment.
const bundleSource = bundleSourceAmbient;
const loadBundle = async specifier => {
const modulePath = new URL(specifier, import.meta.url).pathname;
const modulePath = require.resolve(specifier);
const bundle = await bundleSource(modulePath);
return bundle;
};
Expand Down Expand Up @@ -212,3 +218,25 @@ test(
},
'cosmos10rchqqplv3ehg0tpyej8xapavgnxgum5843jvetkv4e8jargd9hxwqqp4vx73n',
);

test(
'slideshow hook',
addressHookMacro,
'agoric1qqp0e5ys',
{
stake: 'TIA',
strat: 'compound',
holder: 'agoric1adjbkubiukd',
},
'agoric10rchqqpldphkcer9wg7kzem0wf5kxvtpv34xy6m4vf5h26myyeehgcttv574gj2pyeehgunpws7kxmmdwphh2mnyqqqsc2lz8v',
);

test(
'Fast USDC hook',
addressHookMacro,
'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek',
{
EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men',
},
'agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423padaek6me38qekget2vdhx66mtvy6kg7nrw5uhsaekd4uhwufswqex6dtsv44hxv3cd4jkuqpqvduyhf',
);

0 comments on commit 6bbd799

Please sign in to comment.