diff --git a/packages/boot/test/bootstrapTests/orchestration.test.ts b/packages/boot/test/bootstrapTests/orchestration.test.ts
index 1e22fe8dea8..5deaca784a1 100644
--- a/packages/boot/test/bootstrapTests/orchestration.test.ts
+++ b/packages/boot/test/bootstrapTests/orchestration.test.ts
@@ -2,12 +2,12 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js';
import { Fail } from '@agoric/assert';
import { AmountMath } from '@agoric/ertp';
+import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js';
import type { CosmosValidatorAddress } from '@agoric/orchestration';
import type { start as startStakeIca } from '@agoric/orchestration/src/examples/stakeIca.contract.js';
import type { Instance } from '@agoric/zoe/src/zoeService/utils.js';
import { M, matches } from '@endo/patterns';
import type { TestFn } from 'ava';
-import { documentStorageSchema } from '@agoric/internal/src/storage-test-utils.js';
import {
makeWalletFactoryContext,
type WalletFactoryTestContext,
@@ -231,3 +231,35 @@ test.serial('stakeAtom - smart wallet', async t => {
'delegate fails with invalid validator',
);
});
+
+// XXX rely on .serial to be in sequence, and keep this one last
+test.serial('revise chain info', async t => {
+ const {
+ buildProposal,
+ evalProposal,
+ runUtils: { EV },
+ } = t.context;
+
+ const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames');
+
+ await t.throwsAsync(EV(agoricNames).lookup('chain', 'hot'), {
+ message: '"nameKey" not found: "hot"',
+ });
+
+ // Revise chain info in agoricNames with the fixture in this script
+ await evalProposal(
+ buildProposal('@agoric/builders/scripts/testing/append-chain-info.js'),
+ );
+
+ const hotchain = await EV(agoricNames).lookup('chain', 'hot');
+ t.deepEqual(hotchain, { allegedName: 'Hot New Chain', chainId: 'hot-1' });
+
+ const connection = await EV(agoricNames).lookup(
+ 'chainConnection',
+ 'cosmoshub-4_hot-1',
+ );
+ t.like(connection, {
+ id: 'connection-99',
+ client_id: '07-tendermint-3',
+ });
+});
diff --git a/packages/builders/scripts/testing/append-chain-info.js b/packages/builders/scripts/testing/append-chain-info.js
new file mode 100644
index 00000000000..f141fe49074
--- /dev/null
+++ b/packages/builders/scripts/testing/append-chain-info.js
@@ -0,0 +1,50 @@
+///
+import { makeHelpers } from '@agoric/deploy-script-support';
+
+/** @type {Record} */
+const chainInfo = {
+ hot: {
+ allegedName: 'Hot New Chain',
+ chainId: 'hot-1',
+ connections: {
+ 'cosmoshub-4': {
+ id: 'connection-99',
+ client_id: '07-tendermint-3',
+ counterparty: {
+ client_id: '07-tendermint-2',
+ connection_id: 'connection-1',
+ prefix: {
+ key_prefix: '',
+ },
+ },
+ state: 3 /* IBCConnectionState.STATE_OPEN */,
+ transferChannel: {
+ portId: 'transfer',
+ channelId: 'channel-1',
+ counterPartyChannelId: 'channel-1',
+ counterPartyPortId: 'transfer',
+ ordering: 1 /* Order.ORDER_UNORDERED */,
+ state: 3 /* IBCConnectionState.STATE_OPEN */,
+ version: 'ics20-1',
+ },
+ },
+ },
+ },
+};
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
+export const defaultProposalBuilder = async () =>
+ harden({
+ sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js',
+ getManifestCall: [
+ 'getManifestForReviseChains',
+ {
+ chainInfo,
+ },
+ ],
+ });
+
+export default async (homeP, endowments) => {
+ const { writeCoreEval } = await makeHelpers(homeP, endowments);
+ await writeCoreEval('revise-chain-info', defaultProposalBuilder);
+};
diff --git a/packages/builders/scripts/testing/tweak-chain-info.js b/packages/builders/scripts/testing/tweak-chain-info.js
new file mode 100644
index 00000000000..922300ea7c0
--- /dev/null
+++ b/packages/builders/scripts/testing/tweak-chain-info.js
@@ -0,0 +1,53 @@
+///
+import { makeHelpers } from '@agoric/deploy-script-support';
+
+/** @type {Record} */
+const chainInfo = {
+ agoric: {
+ chainId: 'agoric-4',
+ },
+ hot: {
+ allegedName: 'Hot New Chain',
+ chainId: 'hot-1',
+ connections: {
+ 'cosmoshub-4': {
+ id: 'connection-99',
+ client_id: '07-tendermint-3',
+ counterparty: {
+ client_id: '07-tendermint-2',
+ connection_id: 'connection-1',
+ prefix: {
+ key_prefix: '',
+ },
+ },
+ state: 3 /* IBCConnectionState.STATE_OPEN */,
+ transferChannel: {
+ portId: 'transfer',
+ channelId: 'channel-1',
+ counterPartyChannelId: 'channel-1',
+ counterPartyPortId: 'transfer',
+ ordering: 1 /* Order.ORDER_UNORDERED */,
+ state: 3 /* IBCConnectionState.STATE_OPEN */,
+ version: 'ics20-1',
+ },
+ },
+ },
+ },
+};
+
+/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */
+export const defaultProposalBuilder = async () =>
+ harden({
+ sourceSpec: '@agoric/orchestration/src/proposals/revise-chain-info.js',
+ getManifestCall: [
+ 'getManifestForReviseChains',
+ {
+ chainInfo,
+ },
+ ],
+ });
+
+export default async (homeP, endowments) => {
+ const { writeCoreEval } = await makeHelpers(homeP, endowments);
+ await writeCoreEval('revise-chain-info', defaultProposalBuilder);
+};
diff --git a/packages/orchestration/src/proposals/revise-chain-info.js b/packages/orchestration/src/proposals/revise-chain-info.js
new file mode 100644
index 00000000000..b864bfedfc1
--- /dev/null
+++ b/packages/orchestration/src/proposals/revise-chain-info.js
@@ -0,0 +1,44 @@
+import { makeTracer } from '@agoric/internal';
+import { registerChain } from '../chain-info.js';
+
+const trace = makeTracer('ReviseChainInfo', true);
+
+/** @import {CosmosChainInfo} from '../types.js'; */
+
+/**
+ * This will add news values AND overwrite any existing values. Voters on a
+ * proposal of core-eval must be careful not to overwrite any values operating
+ * in production.
+ *
+ * @param {BootstrapPowers} powers
+ * @param {{ options: { chainInfo: Record } }} opt
+ */
+export const reviseChainInfo = async (
+ { consume: { agoricNamesAdmin } },
+ { options: { chainInfo } },
+) => {
+ trace('init-chainInfo');
+
+ assert(chainInfo, 'chainInfo is required');
+
+ trace(chainInfo);
+
+ // Now register the names
+ for await (const [name, info] of Object.entries(chainInfo)) {
+ await registerChain(agoricNamesAdmin, name, info, trace);
+ }
+};
+harden(reviseChainInfo);
+
+export const getManifestForReviseChains = (_powers, { chainInfo }) => ({
+ manifest: {
+ [reviseChainInfo.name]: {
+ consume: {
+ agoricNamesAdmin: true,
+ },
+ },
+ },
+ options: {
+ chainInfo,
+ },
+});