From ab3fcb5646e27b1906732f2b496dcdd939cd8046 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Mon, 16 Dec 2024 15:00:28 -0600 Subject: [PATCH 01/65] build(deps): use backport of cosmos-sdk v0.46.15 --- golang/cosmos/e2e_test/go.mod | 28 +++++++++++++++++++++++++--- golang/cosmos/e2e_test/go.sum | 26 +++++++++++++------------- golang/cosmos/go.mod | 2 +- golang/cosmos/go.sum | 4 ++-- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/golang/cosmos/e2e_test/go.mod b/golang/cosmos/e2e_test/go.mod index a6e8cd0e16c..9943ffa2948 100644 --- a/golang/cosmos/e2e_test/go.mod +++ b/golang/cosmos/e2e_test/go.mod @@ -6,7 +6,7 @@ require ( github.com/agoric-labs/interchaintest/v6 v6.0.1-agoriclabs github.com/cosmos/cosmos-sdk v0.46.13 github.com/cosmos/ibc-go/v6 v6.2.0 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.26.0 ) @@ -17,7 +17,7 @@ require ( cloud.google.com/go/iam v1.1.1 // indirect cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/errors v1.0.0-beta.7 // indirect - cosmossdk.io/math v1.0.0-rc.0 // indirect + cosmossdk.io/math v1.4.0 // indirect filippo.io/edwards25519 v1.0.0-rc.1 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect @@ -200,7 +200,7 @@ require ( modernc.org/sqlite v1.23.1 // indirect modernc.org/strutil v1.1.3 // indirect modernc.org/token v1.0.1 // indirect - sigs.k8s.io/yaml v1.3.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) // Some replace copied from https://github.com/gjermundgaraba/ibctest/blob/110aa579a5a889b2af760bed4f3d90e0d2475e7a/go.mod @@ -215,3 +215,25 @@ replace ( github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.27 github.com/vedhavyas/go-subkey => github.com/strangelove-ventures/go-subkey v1.0.7 ) + +// Agoric-specific replacements: +replace ( + // We need a fork of cosmos-sdk until all of the differences are merged. + github.com/cosmos/cosmos-sdk => github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5 + + // Pick up an IAVL race fix. + github.com/cosmos/iavl => github.com/cosmos/iavl v0.19.7 + + // Use a version of ibc-go that is compatible with the above forks. + github.com/cosmos/ibc-go/v6 => github.com/agoric-labs/ibc-go/v6 v6.3.1-alpha.agoric.2 + +// use cometbft +// Use our fork at least until post-v0.34.14 is released with +// https://github.com/tendermint/tendermint/issue/6899 resolved. +// github.com/tendermint/tendermint => github.com/agoric-labs/cometbft v0.34.30-alpha.agoric.1 + +// For testing against a local cosmos-sdk, ibc-go, or cometbft +// github.com/cosmos/cosmos-sdk => ../../../forks/cosmos-sdk +// github.com/cosmos/ibc-go/v6 => ../../../forks/ibc-go/v6 +// github.com/tendermint/tendermint => ../../../forks/cometbft +) diff --git a/golang/cosmos/e2e_test/go.sum b/golang/cosmos/e2e_test/go.sum index fafb4941d6f..976eb7d51a3 100644 --- a/golang/cosmos/e2e_test/go.sum +++ b/golang/cosmos/e2e_test/go.sum @@ -51,8 +51,8 @@ cloud.google.com/go/storage v1.30.1/go.mod h1:NfxhC0UJE1aXSx7CIIbCf7y9HKT7Biccwk collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w= cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE= -cosmossdk.io/math v1.0.0-rc.0 h1:ml46ukocrAAoBpYKMidF0R2tQJ1Uxfns0yH8wqgMAFc= -cosmossdk.io/math v1.0.0-rc.0/go.mod h1:Ygz4wBHrgc7g0N+8+MrnTfS9LLn9aaTGa9hKopuym5k= +cosmossdk.io/math v1.4.0 h1:XbgExXFnXmF/CccPPEto40gOO7FpWu9yWNAZPN3nkNQ= +cosmossdk.io/math v1.4.0/go.mod h1:O5PkD4apz2jZs4zqFdTr16e1dcaQCc5z6lkEnrrppuk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -85,6 +85,10 @@ github.com/StirlingMarketingGroup/go-namecase v1.0.0/go.mod h1:ZsoSKcafcAzuBx+sn github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/Workiva/go-datastructures v1.0.53 h1:J6Y/52yX10Xc5JjXmGtWoSSxs3mZnGSaq37xZZh7Yig= +github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5 h1:cwbONQaVbGEPzfVqvTY9PGcLZptlR9LTPunZ9La0QCg= +github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5/go.mod h1:Yny/YE+GJ+y/++UgvraITGzfLhXCnwETSWw3dAY5NDg= +github.com/agoric-labs/ibc-go/v6 v6.3.1-alpha.agoric.2 h1:vEzy4JaExzlWNHV3ZSVXEVZcRE9loEFUjieE2TXwDdI= +github.com/agoric-labs/ibc-go/v6 v6.3.1-alpha.agoric.2/go.mod h1:L1xcBjCLIHN7Wd9j6cAQvZertn56pq+eRGFZjRO5bsY= github.com/agoric-labs/interchaintest/v6 v6.0.1-agoriclabs h1:OG3Z7F9YsqFKCi2w/JZVhMWs+VWNsAEujy39/I2Clxo= github.com/agoric-labs/interchaintest/v6 v6.0.1-agoriclabs/go.mod h1:B/KLzyRfuZI+uFKDQe+AXrvjJKRBjl5gds27iOwT9mM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -179,17 +183,13 @@ github.com/cosmos/btcutil v1.0.5 h1:t+ZFcX77LpKtDBhjucvnOH8C2l2ioGsBNEQ3jef8xFk= github.com/cosmos/btcutil v1.0.5/go.mod h1:IyB7iuqZMJlthe2tkIFL33xPyzbFYP0XVdS8P5lUPis= github.com/cosmos/cosmos-proto v1.0.0-alpha8 h1:d3pCRuMYYvGA5bM0ZbbjKn+AoQD4A7dyNG2wzwWalUw= github.com/cosmos/cosmos-proto v1.0.0-alpha8/go.mod h1:6/p+Bc4O8JKeZqe0VqUGTX31eoYqemTT4C1hLCWsO7I= -github.com/cosmos/cosmos-sdk v0.46.13 h1:LhL6WDBadczqBuCW0t5BHUzGQR3vbujdOYOfU0ORt+o= -github.com/cosmos/cosmos-sdk v0.46.13/go.mod h1:EfY521ATNEla8eJ6oJuZBdgP5+p360s7InnRqX+TWdM= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gorocksdb v1.2.0 h1:d0l3jJG8M4hBouIZq0mDUHZ+zjOx044J3nGRskwTb4Y= github.com/cosmos/gorocksdb v1.2.0/go.mod h1:aaKvKItm514hKfNJpUJXnnOWeBnk2GL4+Qw9NHizILw= -github.com/cosmos/iavl v0.19.6 h1:XY78yEeNPrEYyNCKlqr9chrwoeSDJ0bV2VjocTk//OU= -github.com/cosmos/iavl v0.19.6/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= -github.com/cosmos/ibc-go/v6 v6.2.0 h1:HKS5WNxQrlmjowHb73J9LqlNJfvTnvkbhXZ9QzNTU7Q= -github.com/cosmos/ibc-go/v6 v6.2.0/go.mod h1:+S3sxcNwOhgraYDJAhIFDg5ipXHaUnJrg7tOQqGyWlc= +github.com/cosmos/iavl v0.19.7 h1:ij32FaEnwxfEurtK0QKDNhTWFnz6NUmrI5gky/WnoY0= +github.com/cosmos/iavl v0.19.7/go.mod h1:X9PKD3J0iFxdmgNLa7b2LYWdsGd90ToV5cAONApkEPw= github.com/cosmos/ledger-cosmos-go v0.12.4 h1:drvWt+GJP7Aiw550yeb3ON/zsrgW0jgh5saFCr7pDnw= github.com/cosmos/ledger-cosmos-go v0.12.4/go.mod h1:fjfVWRf++Xkygt9wzCsjEBdjcf7wiiY35fv3ctT+k4M= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= @@ -752,8 +752,8 @@ github.com/strangelove-ventures/go-subkey v1.0.7/go.mod h1:E34izOIEm+sZ1YmYawYRq github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -766,8 +766,8 @@ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1F github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= @@ -1319,5 +1319,5 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= -sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/golang/cosmos/go.mod b/golang/cosmos/go.mod index 1e0919c6a99..1c871ea598c 100644 --- a/golang/cosmos/go.mod +++ b/golang/cosmos/go.mod @@ -187,7 +187,7 @@ replace ( // Agoric-specific replacements: replace ( // We need a fork of cosmos-sdk until all of the differences are merged. - github.com/cosmos/cosmos-sdk => github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.4 + github.com/cosmos/cosmos-sdk => github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5 // Pick up an IAVL race fix. github.com/cosmos/iavl => github.com/cosmos/iavl v0.19.7 diff --git a/golang/cosmos/go.sum b/golang/cosmos/go.sum index 3428b14eeb3..de2b7576df7 100644 --- a/golang/cosmos/go.sum +++ b/golang/cosmos/go.sum @@ -232,8 +232,8 @@ github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBA github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agoric-labs/cometbft v0.34.30-alpha.agoric.1 h1:tqCNL72pQXdUmBzgv1md5SN2U3K/PaYQ4qZ5pFv8v6w= github.com/agoric-labs/cometbft v0.34.30-alpha.agoric.1/go.mod h1:myvkihZD8eg9jKE3WFaugkNoL5nvEqlP7Jbjg98pCek= -github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.4 h1:i5IgChQjTyWulV/y5NpVBB5qBJETQ59hYglod6vhok0= -github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.4/go.mod h1:d7e4h+w7FNBNmE6ysp6duBVuQg67pqMtvsLwpT9ca3E= +github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5 h1:cwbONQaVbGEPzfVqvTY9PGcLZptlR9LTPunZ9La0QCg= +github.com/agoric-labs/cosmos-sdk v0.46.16-alpha.agoric.2.5/go.mod h1:Yny/YE+GJ+y/++UgvraITGzfLhXCnwETSWw3dAY5NDg= github.com/agoric-labs/cosmos-sdk/ics23/go v0.8.0-alpha.agoric.1 h1:2jvHI/2d+psWAZy6FQ0vXJCHUtfU3ZbbW+pQFL04arQ= github.com/agoric-labs/cosmos-sdk/ics23/go v0.8.0-alpha.agoric.1/go.mod h1:E45NqnlpxGnpfTWL/xauN7MRwEE28T4Dd4uraToOaKg= github.com/agoric-labs/ibc-go/v6 v6.3.1-alpha.agoric.2 h1:vEzy4JaExzlWNHV3ZSVXEVZcRE9loEFUjieE2TXwDdI= From c025cb7fad64b8bff26b35000cee1846a0b3ae20 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Mon, 16 Dec 2024 15:50:10 -0600 Subject: [PATCH 02/65] fix(cosmic-swingset): expect chain --halt-height exit status > 1 --- packages/cosmic-swingset/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cosmic-swingset/Makefile b/packages/cosmic-swingset/Makefile index 52908818da4..a83d831fc78 100644 --- a/packages/cosmic-swingset/Makefile +++ b/packages/cosmic-swingset/Makefile @@ -161,7 +161,9 @@ BLOCKS_TO_RUN=3 scenario2-run-chain-to-halt: t1/decentral-economy-config.json CHAIN_BOOTSTRAP_VAT_CONFIG="$$PWD/t1/decentral-economy-config.json" \ $(AGC) --home=t1/n0 start --log_level=warn --halt-height=$$(($(INITIAL_HEIGHT) + $(BLOCKS_TO_RUN))); \ - test "$$?" -eq 98 + status=$$?; \ + echo "chain halt status=$$status"; \ + test "$$status" -gt 1 echo ran to $(INITIAL_HEIGHT) + $(BLOCKS_TO_RUN) # Blow away all client state to try again without resetting the chain. From 092056be6609b4309282436288e99b63321c58b7 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 22:59:47 -0500 Subject: [PATCH 03/65] test: advance and settle as a macro - include `agoric` and `noble` EUD destinations --- .../test/fast-usdc/fast-usdc.test.ts | 225 +++++++++--------- 1 file changed, 116 insertions(+), 109 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 8997384e031..103948a4118 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -34,7 +34,7 @@ const accounts = [...keys(oracleMnemonics), 'lp']; const contractName = 'fastUsdc'; const contractBuilder = '../packages/builders/scripts/fast-usdc/init-fast-usdc.js'; -const LP_DEPOSIT_AMOUNT = 10_000_000n; +const LP_DEPOSIT_AMOUNT = 8_000n * 10n ** 6n; test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); @@ -79,7 +79,7 @@ test.before(async t => { // save an LP in test context const lpUser = await provisionSmartWallet(wallets['lp'], { - USDC: 100n, + USDC: 8_000n, BLD: 100n, }); @@ -187,129 +187,136 @@ test.serial('lp deposits', async t => { ); }); -test.serial('advance and settlement', async t => { - const { - nobleTools, - nobleAgoricChannelId, - oracleWds, - retryUntilCondition, - useChain, - usdcOnOsmosis, - vstorageClient, - } = t.context; - - // EUD wallet on osmosis - const eudWallet = await createWallet(useChain('osmosis').chain.bech32_prefix); - const EUD = (await eudWallet.getAccounts())[0].address; - - // parameterize agoric address - const { settlementAccount } = await vstorageClient.queryData( - `published.${contractName}`, - ); - t.log('settlementAccount address', settlementAccount); +const advanceAndSettleScenario = test.macro({ + title: (_, mintAmt: bigint, eudChain: string) => + `advance ${mintAmt} uusdc to ${eudChain} and settle`, + exec: async (t, mintAmt: bigint, eudChain: string) => { + const { + nobleTools, + nobleAgoricChannelId, + oracleWds, + retryUntilCondition, + useChain, + usdcOnOsmosis, + vstorageClient, + } = t.context; + + // EUD wallet on the specified chain + const eudWallet = await createWallet( + useChain(eudChain).chain.bech32_prefix, + ); + const EUD = (await eudWallet.getAccounts())[0].address; + t.log(`EUD wallet created: ${EUD}`); - const recipientAddress = encodeAddressHook(settlementAccount, { EUD }); - t.log('recipientAddress', recipientAddress); + // parameterize agoric address + const { settlementAccount } = await vstorageClient.queryData( + `published.${contractName}`, + ); + t.log('settlementAccount address', settlementAccount); - // register forwarding address on noble - const txRes = nobleTools.registerForwardingAcct( - nobleAgoricChannelId, - recipientAddress, - ); - t.is(txRes?.code, 0, 'registered forwarding account'); + const recipientAddress = encodeAddressHook(settlementAccount, { EUD }); + t.log('recipientAddress', recipientAddress); - const { address: userForwardingAddr } = nobleTools.queryForwardingAddress( - nobleAgoricChannelId, - recipientAddress, - ); - t.log('got forwardingAddress', userForwardingAddr); - - const mintAmount = 800_000n; - - // TODO export CctpTxEvidence type - const evidence = harden({ - blockHash: - '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665', - blockNumber: 21037663n, - txHash: `0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617${makeRandomDigits(makeRandomNumber(), 2n)}`, - tx: { - amount: mintAmount, - forwardingAddress: userForwardingAddr, - }, - aux: { - forwardingChannel: nobleAgoricChannelId, + // register forwarding address on noble + const txRes = nobleTools.registerForwardingAcct( + nobleAgoricChannelId, recipientAddress, - }, - chainId: 42161, - }); - - console.log('User initiates evm mint', evidence.txHash); - - // submit evidences - await Promise.all( - oracleWds.map(makeDoOffer).map((doOffer, i) => - doOffer({ - id: `${Date.now()}-evm-evidence`, - invitationSpec: { - source: 'continuing', - previousOffer: toOracleOfferId(i), - invitationMakerName: 'SubmitEvidence', - invitationArgs: [evidence], - }, - proposal: {}, - }), - ), - ); - - const queryClient = makeQueryClient( - await useChain('osmosis').getRestEndpoint(), - ); + ); + t.is(txRes?.code, 0, 'registered forwarding account'); - await t.notThrowsAsync(() => - retryUntilCondition( - () => queryClient.queryBalance(EUD, usdcOnOsmosis), - ({ balance }) => !!balance?.amount && BigInt(balance.amount) < mintAmount, - `${EUD} advance available from fast-usdc`, - { - // this resolves quickly, so _decrease_ the interval so the timing is more apparent - retryIntervalMs: 500, + const { address: userForwardingAddr } = nobleTools.queryForwardingAddress( + nobleAgoricChannelId, + recipientAddress, + ); + t.log('got forwardingAddress', userForwardingAddr); + + // TODO export CctpTxEvidence type + const evidence = harden({ + blockHash: + '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665', + blockNumber: 21037663n, + txHash: `0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff3875527617${makeRandomDigits(makeRandomNumber(), 2n)}`, + tx: { + amount: mintAmt, + forwardingAddress: userForwardingAddr, }, - ), - ); + aux: { + forwardingChannel: nobleAgoricChannelId, + recipientAddress, + }, + chainId: 42161, + }); + + console.log('User initiates evm mint:', evidence.txHash); + + // submit evidences + await Promise.all( + oracleWds.map(makeDoOffer).map((doOffer, i) => + doOffer({ + id: `${Date.now()}-evm-evidence`, + invitationSpec: { + source: 'continuing', + previousOffer: toOracleOfferId(i), + invitationMakerName: 'SubmitEvidence', + invitationArgs: [evidence], + }, + proposal: {}, + }), + ), + ); - const queryTxStatus = async () => - vstorageClient.queryData( - `published.${contractName}.status.${evidence.txHash}`, + const queryClient = makeQueryClient( + await useChain(eudChain).getRestEndpoint(), ); - const assertTxStatus = async (status: string) => - t.notThrowsAsync(() => + await t.notThrowsAsync(() => retryUntilCondition( - () => queryTxStatus(), - txStatus => { - console.log('tx status', txStatus); - return txStatus === status; - }, - `${evidence.txHash} is ${status}`, + () => queryClient.queryBalance(EUD, usdcOnOsmosis), + ({ balance }) => !!balance?.amount && BigInt(balance.amount) < mintAmt, + `${EUD} advance available from fast-usdc`, + // this resolves quickly, so _decrease_ the interval so the timing is more apparent + { retryIntervalMs: 500 }, ), ); - await assertTxStatus('ADVANCED'); - console.log('Advance completed, waiting for mint...'); - - nobleTools.mockCctpMint(mintAmount, userForwardingAddr); - await t.notThrowsAsync(() => - retryUntilCondition( - () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), - ({ encumberedBalance }) => - encumberedBalance && isEmpty(encumberedBalance), - 'encumberedBalance returns to 0', - ), - ); + const queryTxStatus = async () => + vstorageClient.queryData( + `published.${contractName}.status.${evidence.txHash}`, + ); + + const assertTxStatus = async (status: string) => + t.notThrowsAsync(() => + retryUntilCondition( + () => queryTxStatus(), + txStatus => { + console.log('tx status', txStatus); + return txStatus === status; + }, + `${evidence.txHash} is ${status}`, + ), + ); + + await assertTxStatus('ADVANCED'); + console.log('Advance completed, waiting for mint...'); + + nobleTools.mockCctpMint(mintAmt, userForwardingAddr); + await t.notThrowsAsync(() => + retryUntilCondition( + () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + ({ encumberedBalance }) => + encumberedBalance && isEmpty(encumberedBalance), + 'encumberedBalance returns to 0', + ), + ); - await assertTxStatus('DISBURSED'); + await assertTxStatus('DISBURSED'); + }, }); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 4n, 'osmosis'); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 8n, 'noble'); +test.serial(advanceAndSettleScenario, LP_DEPOSIT_AMOUNT / 5n, 'agoric'); + test.serial('lp withdraws', async t => { const { lpUser, From 1eb9eb163775ac03e3a1e049cc21aa702e11ad17 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 23:32:20 -0500 Subject: [PATCH 04/65] chore: "oracles accept" handles already accepted invs - mainly to facilitate active development; allows test to be run more than once --- .../test/fast-usdc/fast-usdc.test.ts | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 103948a4118..92b493fdccd 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -103,13 +103,33 @@ const toOracleOfferId = (idx: number) => `oracle${idx + 1}-accept`; test.serial('oracles accept', async t => { const { oracleWds, retryUntilCondition, vstorageClient, wallets } = t.context; + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const { Invitation } = Object.fromEntries(brands); - const instances = await vstorageClient.queryData( - 'published.agoricNames.instance', - ); - const instance = fromEntries(instances)[contractName]; + const description = 'oracle operator invitation'; + + // ensure we have an unused (or used) oracle invitation in each purse + let hasAccepted = false; + for (const name of keys(oracleMnemonics)) { + const { offerToUsedInvitation, purses } = await vstorageClient.queryData( + `published.wallet.${wallets[name]}.current`, + ); + const { value: invitations } = balancesFromPurses(purses)[Invitation]; + const hasInvitation = invitations.some(x => x.description === description); + const usedInvitation = offerToUsedInvitation?.[0]?.[0] === `${name}-accept`; + t.log({ name, hasInvitation, usedInvitation }); + t.true(hasInvitation || usedInvitation, 'has or accepted invitation'); + if (usedInvitation) hasAccepted = true; + } + // if the oracles have already accepted, skip the rest of the test this is + // primarily to facilitate active development but could support testing on + // images where operator invs are already accepted + if (hasAccepted) return t.pass(); // accept oracle operator invitations + const instance = fromEntries( + await vstorageClient.queryData('published.agoricNames.instance'), + )[contractName]; await Promise.all( oracleWds.map(makeDoOffer).map((doOffer, i) => doOffer({ @@ -117,7 +137,7 @@ test.serial('oracles accept', async t => { invitationSpec: { source: 'purse', instance, - description: 'oracle operator invitation', // TODO export/import INVITATION_MAKERS_DESC + description, }, proposal: {}, }), @@ -387,3 +407,7 @@ test.serial('lp withdraws', async t => { ), ); }); + +test.todo('insufficient LP funds; forward path'); +test.todo('mint while Advancing; still Disbursed'); +test.todo('transfer failed (e.g. to cosmos, not in env)'); From 4ce154090fc3340e6685104c576fa702bfc184d4 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Mon, 16 Dec 2024 17:07:27 -0600 Subject: [PATCH 05/65] test(acceptance): skip make proposal and vote; seems flaky --- a3p-integration/proposals/z:acceptance/governance.test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index 353590370eb..eaad279754d 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -16,7 +16,10 @@ const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; const delay = ms => new Promise(resolve => setTimeout(() => resolve(undefined), ms)); -test.serial( +const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines + +// z:acceptance governance fails/flakes: No quorum #10708 +testSkipXXX( 'economic committee can make governance proposal and vote on it', async t => { const { waitUntil } = makeTimerUtils({ setTimeout }); From 1eb858dabddcaff5df597bb167dad9c5a42ea620 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 2 Dec 2024 11:05:10 +0000 Subject: [PATCH 06/65] chore(vaultFactory): add core-eval for null upgrade vaultFactory --- .../scripts/testing/upgrade-vaultFactory.js | 21 ++++ .../upgrade-vaultFactory-proposal.js | 118 ++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 packages/builders/scripts/testing/upgrade-vaultFactory.js create mode 100644 packages/vats/src/proposals/upgrade-vaultFactory-proposal.js diff --git a/packages/builders/scripts/testing/upgrade-vaultFactory.js b/packages/builders/scripts/testing/upgrade-vaultFactory.js new file mode 100644 index 00000000000..fa12d22ddcc --- /dev/null +++ b/packages/builders/scripts/testing/upgrade-vaultFactory.js @@ -0,0 +1,21 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }) => + harden({ + sourceSpec: '@agoric/vats/src/proposals/upgrade-vaultFactory-proposal.js', + getManifestCall: [ + 'getManifestForVaultFactoryUpgrade', + { + contractRef: publishRef( + install('@agoric/inter-protocol/src/vaultFactory/vaultFactory.js'), + ), + }, + ], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('upgrade-vaults', defaultProposalBuilder); +}; diff --git a/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js new file mode 100644 index 00000000000..c3accf3078a --- /dev/null +++ b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js @@ -0,0 +1,118 @@ +import { E } from '@endo/far'; +import { makeTracer } from '@agoric/internal/src/index.js'; +import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; + +const trace = makeTracer('upgrade Vaults proposal'); + +export const upgradeVaultFactory = async (powers, options) => { + trace('Initiate VaultFactory contract upgrade'); + + const { + consume: { + zoe, + vaultFactoryKit, + reserveKit, + auctioneerKit, + economicCommitteeCreatorFacet, + }, + } = powers; + + const { + options: { contractRef }, + } = options; + + const { adminFacet, privateArgs, publicFacet, instance } = + await vaultFactoryKit; + + const allBrands = await E(zoe).getBrands(instance); + const { Minted: _istBrand, ...vaultBrands } = allBrands; + + const initialPoserInvitation = await E( + economicCommitteeCreatorFacet, + ).getPoserInvitation(); + + const initialShortfallInvitation = await E( + E.get(reserveKit).creatorFacet, + ).makeShortfallReportingInvitation(); + + const auctioneerInstance = await E.get(auctioneerKit).instance; + + const readCurrentDirectorParams = async () => { + await null; + + const subscription = E(publicFacet).getElectorateSubscription(); + const notifier = makeNotifierFromAsyncIterable(subscription); + const { updateCount } = await notifier.getUpdateSince(); + + // subscribeAfter() retrieves the latest value. + const after = await E(subscription).subscribeAfter(updateCount); + const { current } = after.head.value; + return harden({ + MinInitialDebt: current.MinInitialDebt.value, + ReferencedUI: current.ReferencedUI.value, + RecordingPeriod: current.RecordingPeriod.value, + ChargingPeriod: current.ChargingPeriod.value, + }); + }; + + const directorParamOverrides = await readCurrentDirectorParams(); + trace({ directorParamOverrides }); + + const readManagerParams = async () => { + await null; + + const params = {}; + for (const kwd of Object.keys(vaultBrands)) { + const collateralBrand = vaultBrands[kwd]; + + /** @type {any} */ + const governedParams = await E(publicFacet).getGovernedParams({ + collateralBrand, + }); + params[kwd] = harden({ + brand: collateralBrand, + debtLimit: governedParams.DebtLimit.value, + interestRate: governedParams.InterestRate.value, + liquidationMargin: governedParams.LiquidationMargin.value, + liquidationPadding: governedParams.LiquidationPadding.value, + liquidationPenalty: governedParams.LiquidationPenalty.value, + mintFee: governedParams.MintFee.value, + }); + trace(kwd, params[kwd]); + } + return params; + }; + const managerParams = await readManagerParams(); + + const newPrivateArgs = harden({ + ...privateArgs, + auctioneerInstance, + initialPoserInvitation, + initialShortfallInvitation, + managerParams, + directorParamOverrides, + }); + + await E(adminFacet).upgradeContract(contractRef.bundleID, newPrivateArgs); + + trace('VaultFactory contract upgraded!'); +}; + +export const getManifestForVaultFactoryUpgrade = ( + { restoreRef }, + { contractRef }, +) => ({ + manifest: { + [upgradeVaultFactory.name]: { + consume: { + zoe: true, + vaultFactoryKit: true, + reserveKit: true, + auctioneerKit: true, + economicCommitteeCreatorFacet: true, + }, + }, + }, + installations: { vaultFactory: restoreRef(contractRef) }, + options: { contractRef }, +}); From 662fa2ca2ed6d9067125a8512be18a43c9a8a6f6 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 2 Dec 2024 11:10:02 +0000 Subject: [PATCH 07/65] chore(a3p): add new submissions from governance acceptance tests --- a3p-integration/proposals/z:acceptance/.gitignore | 2 ++ a3p-integration/proposals/z:acceptance/package.json | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/a3p-integration/proposals/z:acceptance/.gitignore b/a3p-integration/proposals/z:acceptance/.gitignore index 7f5da265d56..dc7df2c53f4 100644 --- a/a3p-integration/proposals/z:acceptance/.gitignore +++ b/a3p-integration/proposals/z:acceptance/.gitignore @@ -3,3 +3,5 @@ restart-valueVow start-valueVow localchaintest-submission recorded-instances-submission +upgrade-vaultFactory +upgrade-provisionPool diff --git a/a3p-integration/proposals/z:acceptance/package.json b/a3p-integration/proposals/z:acceptance/package.json index fd4b89562ae..9afa351d90a 100644 --- a/a3p-integration/proposals/z:acceptance/package.json +++ b/a3p-integration/proposals/z:acceptance/package.json @@ -5,7 +5,9 @@ "testing/start-valueVow.js start-valueVow", "testing/recorded-retired-instances.js recorded-instances-submission", "vats/test-localchain.js localchaintest-submission", - "testing/restart-valueVow.js restart-valueVow" + "testing/restart-valueVow.js restart-valueVow", + "testing/upgrade-vaultFactory.js upgrade-vaultFactory", + "vats/upgrade-provisionPool.js upgrade-provisionPool" ] }, "type": "module", From 75c8a1205e52601449164a90683f0d935f54ee7c Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 9 Dec 2024 20:15:57 +0000 Subject: [PATCH 08/65] chore(governance):Refactor makeGovernanceDriver methods to be contract agnostic --- .../proposals/z:acceptance/governance.test.js | 68 +++--------- .../z:acceptance/test-lib/governance.js | 102 ++++++++++++++++-- .../z:acceptance/test-lib/psm-lib.js | 2 +- 3 files changed, 105 insertions(+), 67 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index eaad279754d..ce43f7da0fb 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -1,20 +1,16 @@ -/* global fetch setTimeout */ +/* global fetch */ import test from 'ava'; -import { makeWalletUtils } from '@agoric/client-utils'; import { GOV1ADDR, GOV2ADDR } from '@agoric/synthetic-chain'; import { makeGovernanceDriver } from './test-lib/governance.js'; -import { networkConfig } from './test-lib/index.js'; -import { makeTimerUtils } from './test-lib/utils.js'; +import { networkConfig, walletUtils } from './test-lib/index.js'; const GOV4ADDR = 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy'; const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; -// TODO test-lib export `walletUtils` with this ambient authority like s:stake-bld has -/** @param {number} ms */ -const delay = ms => - new Promise(resolve => setTimeout(() => resolve(undefined), ms)); +const { getLastUpdate } = walletUtils; +const governanceDriver = await makeGovernanceDriver(fetch, networkConfig); const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines @@ -22,35 +18,22 @@ const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformattin testSkipXXX( 'economic committee can make governance proposal and vote on it', async t => { - const { waitUntil } = makeTimerUtils({ setTimeout }); - const { readLatestHead, getLastUpdate, getCurrentWalletRecord } = - await makeWalletUtils({ delay, fetch }, networkConfig); - const governanceDriver = await makeGovernanceDriver(fetch, networkConfig); - - /** @type {any} */ - const instance = await readLatestHead(`published.agoricNames.instance`); - const instances = Object.fromEntries(instance); - - const wallet = await getCurrentWalletRecord(governanceAddresses[0]); - const usedInvitations = wallet.offerToUsedInvitation; - - const charterInvitation = usedInvitations.find( - v => - v[1].value[0].instance.getBoardId() === - instances.econCommitteeCharter.getBoardId(), + const charterInvitation = await governanceDriver.getCharterInvitation( + governanceAddresses[0], ); - assert(charterInvitation, 'missing charter invitation'); const params = { ChargingPeriod: 400n, }; const path = { paramPath: { key: 'governedParams' } }; t.log('Proposing param change', { params, path }); + const instanceName = 'VaultFactory'; - await governanceDriver.proposeVaultDirectorParamChange( + await governanceDriver.proposeParamChange( governanceAddresses[0], params, path, + instanceName, charterInvitation[0], ); @@ -62,22 +45,9 @@ testSkipXXX( t.log('Voting on param change'); for (const address of governanceAddresses) { - const voteWallet = - /** @type {import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord} */ ( - await readLatestHead(`published.wallet.${address}.current`) - ); - - const usedInvitationsForVoter = voteWallet.offerToUsedInvitation; + const committeeInvitationForVoter = + await governanceDriver.getCommitteeInvitation(address); - const committeeInvitationForVoter = usedInvitationsForVoter.find( - v => - v[1].value[0].instance.getBoardId() === - instances.economicCommittee.getBoardId(), - ); - assert( - committeeInvitationForVoter, - `${address} must have committee invitation`, - ); await governanceDriver.voteOnProposedChanges( address, committeeInvitationForVoter[0], @@ -90,21 +60,7 @@ testSkipXXX( }); } - const latestQuestion = - /** @type {import('@agoric/governance/src/types.js').QuestionSpec} */ ( - await readLatestHead( - 'published.committees.Economic_Committee.latestQuestion', - ) - ); - t.log('Waiting for deadline', latestQuestion); - /** @type {bigint} */ - // @ts-expect-error assume POSIX seconds since epoch - const deadline = latestQuestion.closingRule.deadline; - await waitUntil(deadline); - - const latestOutcome = await readLatestHead( - 'published.committees.Economic_Committee.latestOutcome', - ); + const { latestOutcome } = await governanceDriver.getLatestQuestion(); t.log('Verifying latest outcome', latestOutcome); t.like(latestOutcome, { outcome: 'win' }); }, diff --git a/a3p-integration/proposals/z:acceptance/test-lib/governance.js b/a3p-integration/proposals/z:acceptance/test-lib/governance.js index 27c881c0ed2..6e9304a23bd 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/governance.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/governance.js @@ -1,5 +1,18 @@ +/* global fetch setTimeout */ + import { agops, agoric, executeOffer } from '@agoric/synthetic-chain'; -import { makeVstorageKit } from '@agoric/client-utils'; +import { + boardSlottingMarshaller, + makeFromBoard, + makeVstorageKit, + retryUntilCondition, +} from '@agoric/client-utils'; +import { makeVStorage } from './rpc.js'; +import { walletUtils } from './index.js'; +import { + checkCommitteeElectionResult, + fetchLatestEcQuestion, +} from './psm-lib.js'; /** * @param {typeof window.fetch} fetch @@ -11,6 +24,8 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { networkConfig, ); + let deadline; + /** @param {string} previousOfferId */ const generateVoteOffer = async previousOfferId => { const latestQuestionRecord = @@ -63,7 +78,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { }; /** - * Generates a vault director parameter change proposal as a `executeOffer` message + * Generates a parameter change proposal as a `executeOffer` message * body. * * @param {string} previousOfferId - the `id` of the offer that this proposal is @@ -72,13 +87,15 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { * be open for (in seconds) * @param {any} params * @param {{ paramPath: any; }} paramsPath + * @param {string} instanceName * @returns {Promise} - the `executeOffer` message body as a JSON string */ - const generateVaultDirectorParamChange = async ( + const generateParamChange = async ( previousOfferId, voteDur, params, paramsPath, + instanceName, ) => { const instancesRaw = await agoric.follow( '-lF', @@ -89,12 +106,12 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { const instances = Object.fromEntries( marshaller.fromCapData(JSON.parse(instancesRaw)), ); - const { VaultFactory } = instances; - assert(VaultFactory); + const instance = instances[instanceName]; + assert(instance); const msSinceEpoch = Date.now(); const id = `propose-${msSinceEpoch}`; - const deadline = BigInt(Math.ceil(msSinceEpoch / 1000)) + BigInt(voteDur); + deadline = BigInt(Math.ceil(msSinceEpoch / 1000)) + BigInt(voteDur); const body = { method: 'executeOffer', offer: { @@ -106,7 +123,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { }, offerArgs: { deadline, - instance: VaultFactory, + instance, params, path: paramsPath, }, @@ -123,12 +140,14 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { * @param {string} address * @param {any} params * @param {{paramPath: any}} path + * @param {string} instanceName * @param {string} charterAcceptOfferId */ - const proposeVaultDirectorParamChange = async ( + const proposeParamChange = async ( address, params, path, + instanceName, charterAcceptOfferId, ) => { await null; @@ -144,12 +163,75 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { return executeOffer( address, - generateVaultDirectorParamChange(offerId, 10, params, path), + generateParamChange(offerId, 30, params, path, instanceName), + ); + }; + + const getCharterInvitation = async address => { + const { getCurrentWalletRecord } = walletUtils; + + /** @type {any} */ + const instance = await readLatestHead(`published.agoricNames.instance`); + const instances = Object.fromEntries(instance); + + const wallet = await getCurrentWalletRecord(address); + const usedInvitations = wallet.offerToUsedInvitation; + + const charterInvitation = usedInvitations.find( + v => + v[1].value[0].instance.getBoardId() === + instances.econCommitteeCharter.getBoardId(), ); + assert(charterInvitation, 'missing charter invitation'); + + return charterInvitation; + }; + + const getCommitteeInvitation = async address => { + /** @type {any} */ + const instance = await readLatestHead(`published.agoricNames.instance`); + const instances = Object.fromEntries(instance); + + const voteWallet = + /** @type {import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord} */ ( + await readLatestHead(`published.wallet.${address}.current`) + ); + + const usedInvitationsForVoter = voteWallet.offerToUsedInvitation; + + const committeeInvitationForVoter = usedInvitationsForVoter.find( + v => + v[1].value[0].instance.getBoardId() === + instances.economicCommittee.getBoardId(), + ); + assert( + committeeInvitationForVoter, + `${address} must have committee invitation`, + ); + + return committeeInvitationForVoter; + }; + + const getLatestQuestion = async () => { + const { latestOutcome, latestQuestion } = await await retryUntilCondition( + () => fetchLatestEcQuestion({ follow: agoric.follow }), + electionResult => + checkCommitteeElectionResult(electionResult, { + outcome: 'win', + deadline, + }), + 'Governed param change election failed', + { setTimeout, retryIntervalMs: 5000, maxRetries: 15 }, + ); + + return { latestOutcome, latestQuestion }; }; return { voteOnProposedChanges, - proposeVaultDirectorParamChange, + proposeParamChange, + getCharterInvitation, + getCommitteeInvitation, + getLatestQuestion, }; }; diff --git a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js index 74763e6f401..24c6a89ff88 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js @@ -218,7 +218,7 @@ export const fetchLatestEcQuestion = async io => { return { latestOutcome, latestQuestion }; }; -const checkCommitteeElectionResult = ( +export const checkCommitteeElectionResult = ( /** @type {{ latestOutcome: { outcome: any; question: any; }; latestQuestion: { closingRule: { deadline: any; }; questionHandle: any; }; }} */ electionResult, /** @type {{ outcome: any; deadline: any; }} */ expectedResult, ) => { From c9bd9a40a49fbabb15f4599602ff8b72f8825778 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 11 Dec 2024 16:13:03 +0000 Subject: [PATCH 09/65] fix(a3p): change test execution order rel #10574 --- a3p-integration/proposals/z:acceptance/test.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/test.sh b/a3p-integration/proposals/z:acceptance/test.sh index e45cced45d1..60ea686e238 100755 --- a/a3p-integration/proposals/z:acceptance/test.sh +++ b/a3p-integration/proposals/z:acceptance/test.sh @@ -21,18 +21,18 @@ yarn ava kread.test.js echo ACCEPTANCE TESTING valueVow yarn ava valueVow.test.js -echo ACCEPTANCE TESTING state sync -./state-sync-snapshots-test.sh -./genesis-test.sh - echo ACCEPTANCE TESTING wallet yarn ava wallet.test.js echo ACCEPTANCE TESTING psm yarn ava psm.test.js +echo ACCEPTANCE TESTING vaults +yarn ava vaults.test.js + echo ACCEPTANCE TESTING governance yarn ava governance.test.js -echo ACCEPTANCE TESTING vaults -yarn ava vaults.test.js +echo ACCEPTANCE TESTING state sync +./state-sync-snapshots-test.sh +./genesis-test.sh \ No newline at end of file From 4b660fd36ffd22b58782e3f7a42fcb3ef683d82c Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 11 Dec 2024 16:13:38 +0000 Subject: [PATCH 10/65] test(a3p): extend governance testing coverage --- .../proposals/z:acceptance/governance.test.js | 124 +++++++++++++++++- .../z:acceptance/test-lib/governance.js | 10 +- .../proposals/z:acceptance/test-lib/utils.js | 28 ++++ 3 files changed, 153 insertions(+), 9 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index ce43f7da0fb..aa72e5fd062 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -5,11 +5,12 @@ import test from 'ava'; import { GOV1ADDR, GOV2ADDR } from '@agoric/synthetic-chain'; import { makeGovernanceDriver } from './test-lib/governance.js'; import { networkConfig, walletUtils } from './test-lib/index.js'; +import { upgradeContract } from './test-lib/utils.js'; const GOV4ADDR = 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy'; const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; -const { getLastUpdate } = walletUtils; +const { getLastUpdate, readLatestHead } = walletUtils; const governanceDriver = await makeGovernanceDriver(fetch, networkConfig); const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines @@ -65,3 +66,124 @@ testSkipXXX( t.like(latestOutcome, { outcome: 'win' }); }, ); + +test.serial( + 'VaultFactory governed parameters are intact following contract upgrade', + async t => { + /** @type {any} */ + const vaultFactoryParamsBefore = await readLatestHead( + 'published.vaultFactory.governance', + ); + + /* + * At the previous test ('economic committee can make governance proposal and vote on it') + * The value of ChargingPeriod was updated to 400 + * The 'published.vaultFactory.governance' node should reflect that change. + */ + t.is( + vaultFactoryParamsBefore.current.ChargingPeriod.value, + 400n, + 'vaultFactory ChargingPeriod parameter value is not the expected ', + ); + + await upgradeContract('upgrade-vaultFactory', 'zcf-b1-6c08a-vaultFactory'); + + const vaultFactoryParamsAfter = await readLatestHead( + 'published.vaultFactory.governance', + ); + + t.deepEqual( + vaultFactoryParamsAfter, + vaultFactoryParamsBefore, + 'vaultFactory governed parameters did not match', + ); + }, +); + +test.serial( + 'economic committee can make governance proposal for ProvisionPool', + async t => { + const charterInvitation = await governanceDriver.getCharterInvitation( + governanceAddresses[0], + ); + + /** @type {any} */ + const brand = await readLatestHead(`published.agoricNames.brand`); + const brands = Object.fromEntries(brand); + + const params = { + PerAccountInitialAmount: { brand: brands.IST, value: 100_000n }, + }; + const path = { paramPath: { key: 'governedParams' } }; + const instanceName = 'provisionPool'; + + await governanceDriver.proposeParamChange( + governanceAddresses[0], + params, + path, + instanceName, + charterInvitation[0], + ); + + const questionUpdate = await getLastUpdate(governanceAddresses[0]); + t.like(questionUpdate, { + status: { numWantsSatisfied: 1 }, + }); + + for (const address of governanceAddresses) { + const committeeInvitationForVoter = + await governanceDriver.getCommitteeInvitation(address); + + await governanceDriver.voteOnProposedChanges( + address, + committeeInvitationForVoter[0], + ); + + const voteUpdate = await getLastUpdate(address); + t.like(voteUpdate, { + status: { numWantsSatisfied: 1 }, + }); + } + + const { latestOutcome } = await governanceDriver.getLatestQuestion(); + t.log('Verifying latest outcome', latestOutcome); + t.like(latestOutcome, { outcome: 'win' }); + }, +); + +test.serial( + 'ProvisionPool governed parameters are intact following contract upgrade', + async t => { + /** @type {any} */ + const provisionPoolParamsBefore = await readLatestHead( + 'published.provisionPool.governance', + ); + + /* + * At the previous test ('economic committee can make governance proposal and vote on it') + * The value of ChargingPeriod was updated to 400 + * The 'published.vaultFactory.governance' node should reflect that change. + */ + t.is( + provisionPoolParamsBefore.current.PerAccountInitialAmount.value.value, + 100_000n, + 'provisionPool PerAccountInitialAmount parameter value is not the expected ', + ); + + await upgradeContract( + 'upgrade-provisionPool', + 'zcf-b1-db93f-provisionPool', + ); + + /** @type {any} */ + const provisionPoolParamsAfter = await readLatestHead( + 'published.provisionPool.governance', + ); + + t.deepEqual( + provisionPoolParamsAfter.current.PerAccountInitialAmount, + provisionPoolParamsBefore.current.PerAccountInitialAmount, + 'provisionPool governed parameters did not match', + ); + }, +); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/governance.js b/a3p-integration/proposals/z:acceptance/test-lib/governance.js index 6e9304a23bd..6a98bad448d 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/governance.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/governance.js @@ -1,13 +1,7 @@ -/* global fetch setTimeout */ +/* global setTimeout */ import { agops, agoric, executeOffer } from '@agoric/synthetic-chain'; -import { - boardSlottingMarshaller, - makeFromBoard, - makeVstorageKit, - retryUntilCondition, -} from '@agoric/client-utils'; -import { makeVStorage } from './rpc.js'; +import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils'; import { walletUtils } from './index.js'; import { checkCommitteeElectionResult, diff --git a/a3p-integration/proposals/z:acceptance/test-lib/utils.js b/a3p-integration/proposals/z:acceptance/test-lib/utils.js index 0826daa3660..a2705f48e6d 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/utils.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/utils.js @@ -3,7 +3,9 @@ import { LOCAL_CONFIG, makeStargateClient, makeVstorageKit, + retryUntilCondition, } from '@agoric/client-utils'; +import { evalBundles, getDetailsMatchingVats } from '@agoric/synthetic-chain'; import { readFile, writeFile } from 'node:fs/promises'; export const stargateClientP = makeStargateClient(LOCAL_CONFIG, { fetch }); @@ -93,3 +95,29 @@ export const makeTimerUtils = ({ setTimeout }) => { waitUntil, }; }; + +/** + * This function solves the limitation of getIncarnation when multiple Vats + * are returned for the provided vatName and does not return the incarnation + * of the desired Vat (e.g. zcf-mintHolder-USDC) + * @param {string} vatName + * @returns {Promise} + */ +const getIncarnationFromDetails = async vatName => { + const matchingVats = await getDetailsMatchingVats(vatName); + const expectedVat = matchingVats.find(vat => vat.vatName === vatName); + console.log('Vat: ', expectedVat); + return expectedVat.incarnation; +}; + +export const upgradeContract = async (submissionPath, vatName) => { + const incarnationBefore = await getIncarnationFromDetails(vatName); + await evalBundles(submissionPath); + + return retryUntilCondition( + async () => getIncarnationFromDetails(vatName), + value => value === incarnationBefore + 1, + `${vatName} upgrade not processed yet`, + { setTimeout, retryIntervalMs: 5000, maxRetries: 15 }, + ); +}; From 938d61512d9fbdd79d3192937a4482c470d2e3a5 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 11 Dec 2024 20:17:26 +0000 Subject: [PATCH 11/65] chore(a3p): refactor makeVStorage to be aligned with batchQuery.js rel: #10574 --- .../proposals/z:acceptance/test-lib/rpc.js | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 a3p-integration/proposals/z:acceptance/test-lib/rpc.js diff --git a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js b/a3p-integration/proposals/z:acceptance/test-lib/rpc.js new file mode 100644 index 00000000000..c8aa7f5fcda --- /dev/null +++ b/a3p-integration/proposals/z:acceptance/test-lib/rpc.js @@ -0,0 +1,291 @@ +/** @file copied from packages/agoric-cli */ +// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109 +// @ts-check + +import { + boardSlottingMarshaller, + makeBoardRemote, +} from '@agoric/internal/src/marshal.js'; +import { E, Far } from '@endo/far'; +import { Fail } from '@endo/errors'; + +export { boardSlottingMarshaller }; + +/** @type {(val: any) => string} */ +export const boardValToSlot = val => { + if ('getBoardId' in val) { + return val.getBoardId(); + } + throw Fail`unknown obj in boardSlottingMarshaller.valToSlot ${val}`; +}; + +/** @param {string} agoricNetSubdomain */ +export const networkConfigUrl = agoricNetSubdomain => + `https://${agoricNetSubdomain}.agoric.net/network-config`; +/** @param {string} agoricNetSubdomain */ +export const rpcUrl = agoricNetSubdomain => + `https://${agoricNetSubdomain}.rpc.agoric.net:443`; + +/** + * @typedef {{ rpcAddrs: string[], chainName: string, apiAddress: string }} MinimalNetworkConfig + */ + +/** @type {MinimalNetworkConfig} */ +const networkConfig = { + rpcAddrs: ['http://0.0.0.0:26657'], + chainName: 'agoriclocal', + apiAddress: 'http://localhost:1317', +}; +export { networkConfig }; +// console.warn('networkConfig', networkConfig); + +/** + * gRPC-gateway REST API access + * + * @see {@link https://docs.cosmos.network/v0.45/core/grpc_rest.html#rest-server Cosmos SDK REST Server} + * + * Note: avoid Legacy REST routes, per + * {@link https://docs.cosmos.network/v0.45/migrations/rest.html Cosmos SDK REST Endpoints Migration}. + * + * @param {string} apiAddress nodes default to port 1317 + * @param {object} io + * @param {typeof fetch} io.fetch + */ +const makeAPI = (apiAddress, { fetch }) => { + assert.typeof(apiAddress, 'string'); + + /** + * @param {string} href + * @param {object} [options] + * @param {Record} [options.headers] + */ + const getJSON = (href, options = {}) => { + const opts = { + keepalive: true, + headers: { + 'Content-Type': 'application/json', + ...options.headers, + }, + }; + const url = `${apiAddress}${href}`; + return fetch(url, opts).then(r => { + if (!r.ok) throw Error(r.statusText); + return r.json().then(data => { + return data; + }); + }); + }; + + return Far('LCD', { + getJSON, + latestBlock: () => getJSON(`/cosmos/base/tendermint/v1beta1/blocks/latest`), + }); +}; +/** @typedef {ReturnType} LCD */ + +/** + * @template T + * @param {(value: string) => T} f + * @param {AsyncGenerator} chunks + */ +async function* mapHistory(f, chunks) { + for await (const chunk of chunks) { + if (chunk === undefined) continue; + for (const value of chunk.reverse()) { + yield f(value); + } + } +} + +/** + * @param {LCD} lcd + */ +export const makeVStorage = lcd => { + const getJSON = (href, options) => E(lcd).getJSON(href, options); + + // height=0 is the same as omitting height and implies the highest block + const href = (path = 'published', { kind = 'data' } = {}) => + `/agoric/vstorage/${kind}/${path}`; + const headers = height => + height ? { 'x-cosmos-block-height': `${height}` } : undefined; + + const readStorage = ( + path = 'published', + { kind = 'data', height = 0 } = {}, + ) => + getJSON(href(path, { kind }), { headers: headers(height) }).catch(err => { + throw Error(`cannot read ${kind} of ${path}: ${err.message}`); + }); + const readCell = (path, opts) => + readStorage(path, opts) + .then(data => data.value) + .then(s => (s === '' ? {} : JSON.parse(s))); + + /** + * Read values going back as far as available + * + * @param {string} path + * @param {number | string} [minHeight] + */ + async function* readHistory(path, minHeight = undefined) { + // undefined the first iteration, to query at the highest + let blockHeight; + await null; + do { + // console.debug('READING', { blockHeight }); + /** @type {string[]} */ + let values = []; + try { + ({ blockHeight, values } = await readCell(path, { + kind: 'data', + height: blockHeight && Number(blockHeight) - 1, + })); + // console.debug('readAt returned', { blockHeight }); + } catch (err) { + if (err.message.match(/unknown request/)) { + // XXX FIXME + // console.error(err); + break; + } + throw err; + } + yield values; + // console.debug('PUSHED', values); + // console.debug('NEW', { blockHeight, minHeight }); + if (minHeight && Number(blockHeight) <= Number(minHeight)) break; + } while (blockHeight > 0); + } + + /** + * @template T + * @param {(value: string) => T} f + * @param {string} path + * @param {number | string} [minHeight] + */ + const readHistoryBy = (f, path, minHeight) => + mapHistory(f, readHistory(path, minHeight)); + + return { + lcd, + readLatest: readStorage, + readCell, + readHistory, + readHistoryBy, + }; +}; +/** @typedef {ReturnType} VStorage */ + +export const makeFromBoard = () => { + const cache = new Map(); + /** @type {(boardId: string, iface?: string) => ReturnType} */ + const convertSlotToVal = (boardId, iface) => { + if (cache.has(boardId)) { + return cache.get(boardId); + } + const val = makeBoardRemote({ boardId, iface }); + cache.set(boardId, val); + return val; + }; + return harden({ convertSlotToVal }); +}; +/** @typedef {ReturnType} IdMap */ + +export const storageHelper = { + parseCapData: txt => { + /** @type {{ value: string }} */ + const { value } = txt; + assert(typeof value === 'string', typeof value); + const specimen = JSON.parse(value); + const { blockHeight, values } = specimen; + assert(values, `empty values in specimen ${value}`); + const capDatas = storageHelper.parseMany(values); + return { blockHeight, capDatas }; + }, + /** + * @param {string} txt + * @param {IdMap} ctx + */ + unserializeTxt: (txt, ctx) => { + const { capDatas } = storageHelper.parseCapData(txt); + return capDatas.map(capData => + boardSlottingMarshaller(ctx.convertSlotToVal).fromCapData(capData), + ); + }, + /** @param {string[]} capDataStrings array of stringified capData */ + parseMany: capDataStrings => { + assert(capDataStrings && capDataStrings.length); + /** @type {{ body: string, slots: string[] }[]} */ + const capDatas = capDataStrings.map(s => JSON.parse(s)); + for (const capData of capDatas) { + assert(typeof capData === 'object' && capData !== null); + assert('body' in capData && 'slots' in capData); + assert(typeof capData.body === 'string'); + assert(Array.isArray(capData.slots)); + } + return capDatas; + }, +}; +harden(storageHelper); + +/** + * @param {IdMap} ctx + * @param {VStorage} vstorage + * @returns {Promise} + */ +export const makeAgoricNames = async (ctx, vstorage) => { + /** @type {Record} */ + const reverse = {}; + const entries = await Promise.all( + ['brand', 'instance', 'vbankAsset'].map(async kind => { + const content = await vstorage.readLatest( + `published.agoricNames.${kind}`, + ); + /** @type {Array<[string, import('@agoric/vats/tools/board-utils.js').BoardRemote]>} */ + const parts = storageHelper.unserializeTxt(content, ctx).at(-1); + for (const [name, remote] of parts) { + if ('getBoardId' in remote) { + reverse[/** @type {string} */ (remote.getBoardId())] = name; + } + } + return [kind, Object.fromEntries(parts)]; + }), + ); + return { ...Object.fromEntries(entries), reverse }; +}; + +/** + * @param {{ fetch: typeof window.fetch }} io + * @param {MinimalNetworkConfig} config + */ +export const makeVstorageKit = async ({ fetch }, config = networkConfig) => { + await null; + try { + const lcd = await makeAPI(networkConfig.apiAddress, { fetch }); + const vstorage = makeVStorage(lcd); + + const fromBoard = makeFromBoard(); + const agoricNames = await makeAgoricNames(fromBoard, vstorage); + + const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); + + /** @type {(txt: string) => unknown} */ + const unserializeHead = txt => + storageHelper.unserializeTxt(txt, fromBoard).at(-1); + + /** @type {(path: string) => Promise} */ + const readLatestHead = path => + vstorage.readLatest(path).then(unserializeHead); + + return { + agoricNames, + fromBoard, + marshaller, + readLatestHead, + unserializeHead, + vstorage, + }; + } catch (err) { + throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`); + } +}; +/** @typedef {Awaited>} RpcUtils */ From dccf7bc512fdf95369397b8485692fcc47762ca4 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Fri, 13 Dec 2024 18:04:15 +0000 Subject: [PATCH 12/65] test(a3p): extend governance test with proposals history --- .../proposals/z:acceptance/governance.test.js | 53 +++++++++++++++++-- .../z:acceptance/test-lib/governance.js | 29 ++++++++-- .../proposals/z:acceptance/test.sh | 2 +- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index aa72e5fd062..902dbccea26 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -4,13 +4,14 @@ import test from 'ava'; import { GOV1ADDR, GOV2ADDR } from '@agoric/synthetic-chain'; import { makeGovernanceDriver } from './test-lib/governance.js'; -import { networkConfig, walletUtils } from './test-lib/index.js'; +import { agdWalletUtils } from './test-lib/index.js'; import { upgradeContract } from './test-lib/utils.js'; +import { networkConfig } from './test-lib/rpc.js'; const GOV4ADDR = 'agoric1c9gyu460lu70rtcdp95vummd6032psmpdx7wdy'; const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; -const { getLastUpdate, readLatestHead } = walletUtils; +const { getLastUpdate, readLatestHead } = agdWalletUtils; const governanceDriver = await makeGovernanceDriver(fetch, networkConfig); const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines @@ -146,7 +147,6 @@ test.serial( } const { latestOutcome } = await governanceDriver.getLatestQuestion(); - t.log('Verifying latest outcome', latestOutcome); t.like(latestOutcome, { outcome: 'win' }); }, ); @@ -187,3 +187,50 @@ test.serial( ); }, ); + +test.serial('Governance proposals history is visible', async t => { + /* + * List ordered from most recent to latest of Economic Committee + * parameter changes proposed prior to the execution of this test. + * + * XXX a dynamic solution should replace this hardcoded list to ensure + * the acceptance tests scalability + */ + const expectedParametersChanges = [ + ['PerAccountInitialAmount'], // z:acceptance/governance.test.js + ['ChargingPeriod'], // z:acceptance/governance.test.js + ['DebtLimit'], // z:acceptance/vaults.test.js + ['GiveMintedFee', 'MintLimit', 'WantMintedFee'], // z:acceptance/psm.test.js + ['DebtLimit'], // z:acceptance/scripts/test-vaults.mts + ['ClockStep', 'PriceLockPeriod', 'StartFrequency'], // z:acceptance/scripts/test-vaults.mts + ['DebtLimit'], // agoric-3-proposals/proposals/34:upgrade-10/performActions.js + ['ClockStep', 'PriceLockPeriod', 'StartFrequency'], // agoric-3-proposals/proposals/34:upgrade-10/performActions.js + ]; + + // history of Economic Committee parameters changes proposed since block height 0 + const history = await governanceDriver.getLatestQuestionHistory(); + t.true( + history.length > 0, + 'published.committees.Economic_Committee.latestQuestion node should not be empty', + ); + + const changedParameters = history.map(changes => Object.keys(changes)); + + /* + * In case you see the error message bellow and you + * executed an VoteOnParamChange offer prior to this test, + * please make sure to update the expectedParametersChanges list. + */ + if ( + !( + JSON.stringify(changedParameters) === + JSON.stringify(expectedParametersChanges) + ) + ) { + console.error( + `ERROR: Economic_Committee parameters changes history does not match with the expected list`, + ); + t.log('Economic_Committee parameters changes history: ', changedParameters); + t.log('Expected parameters changes history: ', expectedParametersChanges); + } +}); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/governance.js b/a3p-integration/proposals/z:acceptance/test-lib/governance.js index 6a98bad448d..e9152ace34c 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/governance.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/governance.js @@ -1,19 +1,20 @@ /* global setTimeout */ import { agops, agoric, executeOffer } from '@agoric/synthetic-chain'; -import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils'; -import { walletUtils } from './index.js'; +import { retryUntilCondition } from '@agoric/client-utils'; +import { agdWalletUtils } from './index.js'; import { checkCommitteeElectionResult, fetchLatestEcQuestion, } from './psm-lib.js'; +import { makeVstorageKit } from './rpc.js'; /** * @param {typeof window.fetch} fetch - * @param {import('@agoric/client-utils').MinimalNetworkConfig} networkConfig + * @param {import('./rpc.js').MinimalNetworkConfig} networkConfig */ export const makeGovernanceDriver = async (fetch, networkConfig) => { - const { readLatestHead, marshaller } = await makeVstorageKit( + const { readLatestHead, marshaller, vstorage } = await makeVstorageKit( { fetch }, networkConfig, ); @@ -162,7 +163,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { }; const getCharterInvitation = async address => { - const { getCurrentWalletRecord } = walletUtils; + const { getCurrentWalletRecord } = agdWalletUtils; /** @type {any} */ const instance = await readLatestHead(`published.agoricNames.instance`); @@ -221,11 +222,29 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { return { latestOutcome, latestQuestion }; }; + const getLatestQuestionHistory = async () => { + const nodePath = 'published.committees.Economic_Committee.latestQuestion'; + + const historyIterator = await vstorage.readHistory(nodePath); + const history = []; + + for await (const data of historyIterator) { + if (data) { + const question = marshaller.fromCapData(JSON.parse(data[0])); + const changes = question.positions[0].changes; + history.push(changes); + } + } + + return history; + }; + return { voteOnProposedChanges, proposeParamChange, getCharterInvitation, getCommitteeInvitation, getLatestQuestion, + getLatestQuestionHistory, }; }; diff --git a/a3p-integration/proposals/z:acceptance/test.sh b/a3p-integration/proposals/z:acceptance/test.sh index 60ea686e238..78e9c2d09fa 100755 --- a/a3p-integration/proposals/z:acceptance/test.sh +++ b/a3p-integration/proposals/z:acceptance/test.sh @@ -35,4 +35,4 @@ yarn ava governance.test.js echo ACCEPTANCE TESTING state sync ./state-sync-snapshots-test.sh -./genesis-test.sh \ No newline at end of file +./genesis-test.sh From dc7388c6fff0754bd856bfa293d355a8a84489ad Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 16 Dec 2024 11:58:56 +0000 Subject: [PATCH 13/65] chore(vaultFactory): include insightful comments --- packages/inter-protocol/src/proposals/upgrade-vaults.js | 6 ++++++ .../vats/src/proposals/upgrade-vaultFactory-proposal.js | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/packages/inter-protocol/src/proposals/upgrade-vaults.js b/packages/inter-protocol/src/proposals/upgrade-vaults.js index febaa8cfa35..b92961d871f 100644 --- a/packages/inter-protocol/src/proposals/upgrade-vaults.js +++ b/packages/inter-protocol/src/proposals/upgrade-vaults.js @@ -1,3 +1,9 @@ +/** + * @file this core-eval proposal is specific to the upgrade-18 scenario, + * handling tasks beyond generic Vault Factory null upgrade. For a reusable + * proposal, see upgrade-vaultFactory-proposal.js. + */ + import { E } from '@endo/far'; import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; import { makeTracer } from '@agoric/internal/src/index.js'; diff --git a/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js index c3accf3078a..20c1a408d18 100644 --- a/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js +++ b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js @@ -1,3 +1,9 @@ +/** + * @file this core-eval proposal is a generic and reusable script for executing + * a Vault Factory null upgrade. In contrast, upgrade-vaults.js is a specific + * implementation tailored to the upgrade-18. + */ + import { E } from '@endo/far'; import { makeTracer } from '@agoric/internal/src/index.js'; import { makeNotifierFromAsyncIterable } from '@agoric/notifier'; From ecddebd33aece167155c6224b1f10f90f3ecd874 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 16 Dec 2024 12:00:09 +0000 Subject: [PATCH 14/65] fix(a3p): minor fixes to governance test and helpers --- .../proposals/z:acceptance/governance.test.js | 2 +- .../proposals/z:acceptance/test-lib/rpc.js | 13 +++++++++++-- .../proposals/z:acceptance/test-lib/utils.js | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index 902dbccea26..9136e9f2786 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -190,7 +190,7 @@ test.serial( test.serial('Governance proposals history is visible', async t => { /* - * List ordered from most recent to latest of Economic Committee + * List ordered from most recent to earliest of Economic Committee * parameter changes proposed prior to the execution of this test. * * XXX a dynamic solution should replace this hardcoded list to ensure diff --git a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js b/a3p-integration/proposals/z:acceptance/test-lib/rpc.js index c8aa7f5fcda..1a401875f86 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/rpc.js @@ -1,5 +1,14 @@ -/** @file copied from packages/agoric-cli */ -// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109 +/** + * @file This file implements methods currently available in + * packages/client-utils . + * + * With the exceptions of: + * - makeVstorage and mapHistory: copied from `multichain-testing/tools/batchQuery.js`. + * - makeAPI: copied from `multichain-testing/tools/makeHttpClient.js`. + * + * These modifications were made to address the issue described in #10574. + */ + // @ts-check import { diff --git a/a3p-integration/proposals/z:acceptance/test-lib/utils.js b/a3p-integration/proposals/z:acceptance/test-lib/utils.js index a2705f48e6d..603e7cb8d2c 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/utils.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/utils.js @@ -106,7 +106,7 @@ export const makeTimerUtils = ({ setTimeout }) => { const getIncarnationFromDetails = async vatName => { const matchingVats = await getDetailsMatchingVats(vatName); const expectedVat = matchingVats.find(vat => vat.vatName === vatName); - console.log('Vat: ', expectedVat); + assert(expectedVat, `No matching Vat was found for ${vatName}`); return expectedVat.incarnation; }; From bc1f87a802f68d629972874c6bb60339c3933de4 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 16 Dec 2024 18:02:50 +0000 Subject: [PATCH 15/65] fix(vaultFactory): fix proposal description Co-authored-by: Chris Hibbert --- packages/vats/src/proposals/upgrade-vaultFactory-proposal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js index 20c1a408d18..242bdd6ae93 100644 --- a/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js +++ b/packages/vats/src/proposals/upgrade-vaultFactory-proposal.js @@ -1,6 +1,6 @@ /** * @file this core-eval proposal is a generic and reusable script for executing - * a Vault Factory null upgrade. In contrast, upgrade-vaults.js is a specific + * a Vault Factory upgrade. In contrast, upgrade-vaults.js is a specific * implementation tailored to the upgrade-18. */ From cc4c1a2df8f27d8789f154aae824edc565b5d34b Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 17 Dec 2024 09:20:00 +0000 Subject: [PATCH 16/65] fix(a3p): remove duplicated await --- a3p-integration/proposals/z:acceptance/test-lib/governance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a3p-integration/proposals/z:acceptance/test-lib/governance.js b/a3p-integration/proposals/z:acceptance/test-lib/governance.js index e9152ace34c..7b841be4101 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/governance.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/governance.js @@ -208,7 +208,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { }; const getLatestQuestion = async () => { - const { latestOutcome, latestQuestion } = await await retryUntilCondition( + const { latestOutcome, latestQuestion } = await retryUntilCondition( () => fetchLatestEcQuestion({ follow: agoric.follow }), electionResult => checkCommitteeElectionResult(electionResult, { From 28b4884f1ec0e718bc9dd37eb6dcdbdf62690705 Mon Sep 17 00:00:00 2001 From: anilhelvaci Date: Tue, 17 Dec 2024 14:32:12 +0300 Subject: [PATCH 17/65] chore: switch using waitForElectionResult, eliminate flakiness refs: https://github.com/Agoric/agoric-sdk/issues/10708 --- .../proposals/z:acceptance/governance.test.js | 24 ++++-------------- .../z:acceptance/test-lib/governance.js | 25 ++++++++++++++++--- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/governance.test.js b/a3p-integration/proposals/z:acceptance/governance.test.js index 9136e9f2786..e63a3271030 100644 --- a/a3p-integration/proposals/z:acceptance/governance.test.js +++ b/a3p-integration/proposals/z:acceptance/governance.test.js @@ -14,16 +14,9 @@ const governanceAddresses = [GOV4ADDR, GOV2ADDR, GOV1ADDR]; const { getLastUpdate, readLatestHead } = agdWalletUtils; const governanceDriver = await makeGovernanceDriver(fetch, networkConfig); -const testSkipXXX = test.skip; // same lenth as test.serial to avoid reformatting all lines - -// z:acceptance governance fails/flakes: No quorum #10708 -testSkipXXX( +test.serial( 'economic committee can make governance proposal and vote on it', async t => { - const charterInvitation = await governanceDriver.getCharterInvitation( - governanceAddresses[0], - ); - const params = { ChargingPeriod: 400n, }; @@ -36,7 +29,7 @@ testSkipXXX( params, path, instanceName, - charterInvitation[0], + 30, ); const questionUpdate = await getLastUpdate(governanceAddresses[0]); @@ -62,9 +55,7 @@ testSkipXXX( }); } - const { latestOutcome } = await governanceDriver.getLatestQuestion(); - t.log('Verifying latest outcome', latestOutcome); - t.like(latestOutcome, { outcome: 'win' }); + await governanceDriver.waitForElection(); }, ); @@ -104,10 +95,6 @@ test.serial( test.serial( 'economic committee can make governance proposal for ProvisionPool', async t => { - const charterInvitation = await governanceDriver.getCharterInvitation( - governanceAddresses[0], - ); - /** @type {any} */ const brand = await readLatestHead(`published.agoricNames.brand`); const brands = Object.fromEntries(brand); @@ -123,7 +110,7 @@ test.serial( params, path, instanceName, - charterInvitation[0], + 30, ); const questionUpdate = await getLastUpdate(governanceAddresses[0]); @@ -146,8 +133,7 @@ test.serial( }); } - const { latestOutcome } = await governanceDriver.getLatestQuestion(); - t.like(latestOutcome, { outcome: 'win' }); + await governanceDriver.waitForElection(); }, ); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/governance.js b/a3p-integration/proposals/z:acceptance/test-lib/governance.js index 7b841be4101..a93d14411bd 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/governance.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/governance.js @@ -1,7 +1,10 @@ /* global setTimeout */ import { agops, agoric, executeOffer } from '@agoric/synthetic-chain'; -import { retryUntilCondition } from '@agoric/client-utils'; +import { + retryUntilCondition, + waitUntilElectionResult, +} from '@agoric/client-utils'; import { agdWalletUtils } from './index.js'; import { checkCommitteeElectionResult, @@ -136,13 +139,15 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { * @param {any} params * @param {{paramPath: any}} path * @param {string} instanceName - * @param {string} charterAcceptOfferId + * @param {number} votingDuration + * @param {string} [charterAcceptOfferId] */ const proposeParamChange = async ( address, params, path, instanceName, + votingDuration, charterAcceptOfferId, ) => { await null; @@ -158,7 +163,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { return executeOffer( address, - generateParamChange(offerId, 30, params, path, instanceName), + generateParamChange(offerId, votingDuration, params, path, instanceName), ); }; @@ -222,6 +227,19 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { return { latestOutcome, latestQuestion }; }; + const waitForElection = () => + waitUntilElectionResult( + 'published.committees.Economic_Committee', + { outcome: 'win', deadline }, + // @ts-expect-error vstorage casting + { vstorage: { readLatestHead }, log: console.log, setTimeout }, + { + errorMessage: 'Governed param change election failed', + retryIntervalMs: 5000, + maxRetries: 15, + }, + ); + const getLatestQuestionHistory = async () => { const nodePath = 'published.committees.Economic_Committee.latestQuestion'; @@ -245,6 +263,7 @@ export const makeGovernanceDriver = async (fetch, networkConfig) => { getCharterInvitation, getCommitteeInvitation, getLatestQuestion, + waitForElection, getLatestQuestionHistory, }; }; From 293ac50cf5bbfa8a40e214bd1fb1e8f8eac13ce3 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 13:43:57 -0800 Subject: [PATCH 18/65] lint: tsc checkJs --- multichain-testing/tsconfig.json | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/multichain-testing/tsconfig.json b/multichain-testing/tsconfig.json index 8915139d881..c0b1b588fec 100644 --- a/multichain-testing/tsconfig.json +++ b/multichain-testing/tsconfig.json @@ -1,11 +1,8 @@ { "extends": "../tsconfig.json", "include": [ - "src", - "tools", - "test" - ], - "compilerOptions": { - "checkJs": false - } + "src", + "tools", + "test" + ] } From 3c63de25c7a48c10b6ce8d8464f2f49c26abcc55 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 13:44:23 -0800 Subject: [PATCH 19/65] chore(deps): link agoric-sdk --- multichain-testing/README.md | 2 + multichain-testing/package.json | 50 +- multichain-testing/yarn.lock | 2218 ++++++++++++++++++++++++++++++- 3 files changed, 2207 insertions(+), 63 deletions(-) diff --git a/multichain-testing/README.md b/multichain-testing/README.md index 5a43a2aff24..949b1aeab8d 100644 --- a/multichain-testing/README.md +++ b/multichain-testing/README.md @@ -21,6 +21,8 @@ Install the relevant dependencies: yarn install ``` +(Note that the '@agoric/*' deps will come from the parent directory due to `yarn link --relative .. --all`) + Ensure you have Kubernetes available. See https://docs.cosmology.zone/starship/get-started/step-2. The following will install `kubectl`, `kind`, `helm`, and `yq` as needed: diff --git a/multichain-testing/package.json b/multichain-testing/package.json index 78949330c11..f73af9bbeb5 100644 --- a/multichain-testing/package.json +++ b/multichain-testing/package.json @@ -18,6 +18,7 @@ "packageManager": "yarn@4.5.3", "devDependencies": { "@agoric/cosmic-proto": "dev", + "@agoric/fast-usdc": "dev", "@cosmjs/crypto": "^0.32.4", "@cosmjs/proto-signing": "^0.32.4", "@cosmjs/stargate": "^0.32.4", @@ -41,7 +42,54 @@ "typescript": "~5.7.2" }, "resolutions": { - "axios": "1.6.7" + "axios": "1.6.7", + "@agoric/cosmos": "portal:../golang/cosmos", + "@agoric/ertp": "portal:../packages/ERTP", + "@agoric/swingset-vat": "portal:../packages/SwingSet", + "@agoric/access-token": "portal:../packages/access-token", + "agoric": "portal:../packages/agoric-cli", + "@agoric/async-flow": "portal:../packages/async-flow", + "@agoric/base-zone": "portal:../packages/base-zone", + "@agoric/builders": "portal:../packages/builders", + "@agoric/cache": "portal:../packages/cache", + "@agoric/casting": "portal:../packages/casting", + "@agoric/client-utils": "portal:../packages/client-utils", + "@agoric/cosmic-proto": "portal:../packages/cosmic-proto", + "@agoric/cosmic-swingset": "portal:../packages/cosmic-swingset", + "@agoric/create-dapp": "portal:../packages/create-dapp", + "@agoric/deploy-script-support": "portal:../packages/deploy-script-support", + "@agoric/eslint-config": "portal:../packages/eslint-config", + "@agoric/fast-usdc": "portal:../packages/fast-usdc", + "@agoric/governance": "portal:../packages/governance", + "@agoric/import-manager": "portal:../packages/import-manager", + "@agoric/inter-protocol": "portal:../packages/inter-protocol", + "@agoric/internal": "portal:../packages/internal", + "@agoric/kmarshal": "portal:../packages/kmarshal", + "@agoric/network": "portal:../packages/network", + "@agoric/notifier": "portal:../packages/notifier", + "@agoric/orchestration": "portal:../packages/orchestration", + "@agoric/pegasus": "portal:../packages/pegasus", + "@agoric/smart-wallet": "portal:../packages/smart-wallet", + "@agoric/solo": "portal:../packages/solo", + "@agoric/sparse-ints": "portal:../packages/sparse-ints", + "@agoric/spawner": "portal:../packages/spawner", + "@agoric/stat-logger": "portal:../packages/stat-logger", + "@agoric/store": "portal:../packages/store", + "@agoric/swing-store": "portal:../packages/swing-store", + "@agoric/swingset-liveslots": "portal:../packages/swingset-liveslots", + "@agoric/swingset-xsnap-supervisor": "portal:../packages/swingset-xsnap-supervisor", + "@agoric/telemetry": "portal:../packages/telemetry", + "@agoric/time": "portal:../packages/time", + "@agoric/vat-data": "portal:../packages/vat-data", + "@agoric/vats": "portal:../packages/vats", + "@agoric/vm-config": "portal:../packages/vm-config", + "@agoric/vow": "portal:../packages/vow", + "@agoric/wallet": "portal:../packages/wallet", + "@agoric/wallet-backend": "portal:../packages/wallet/api", + "@agoric/xsnap": "portal:../packages/xsnap", + "@agoric/xsnap-lockdown": "portal:../packages/xsnap-lockdown", + "@agoric/zoe": "portal:../packages/zoe", + "@agoric/zone": "portal:../packages/zone" }, "eslintConfig": { "root": true, diff --git a/multichain-testing/yarn.lock b/multichain-testing/yarn.lock index fd3e9510370..8f909306465 100644 --- a/multichain-testing/yarn.lock +++ b/multichain-testing/yarn.lock @@ -5,15 +5,555 @@ __metadata: version: 8 cacheKey: 10c0 -"@agoric/cosmic-proto@npm:dev": - version: 0.4.1-dev-bdf5c17.0 - resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-bdf5c17.0" +"@adraffy/ens-normalize@npm:1.10.1": + version: 1.10.1 + resolution: "@adraffy/ens-normalize@npm:1.10.1" + checksum: 10c0/fdd647604e8fac6204921888aaf5a6bc65eabf0d2921bc5f93b64d01f4bc33ead167c1445f7de05468d05cd92ac31b74c68d2be840c62b79d73693308f885c06 + languageName: node + linkType: hard + +"@agoric/async-flow@portal:../packages/async-flow::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/async-flow@portal:../packages/async-flow::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@agoric/internal": "npm:^0.3.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/vow": "npm:^0.1.0" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/marshal": "npm:^1.6.2" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/babel-generator@npm:^7.17.6": + version: 7.17.6 + resolution: "@agoric/babel-generator@npm:7.17.6" + dependencies: + "@babel/types": "npm:^7.17.0" + jsesc: "npm:^2.5.1" + source-map: "npm:^0.5.0" + checksum: 10c0/59db151ae737bd9b1f21c1589df4c7da9cbf484de5b5cc8352052825c2d977283d975303f55acb54d0210c176cb405da263073ceba1d3a6db65c6e21cc6e663f + languageName: node + linkType: hard + +"@agoric/base-zone@portal:../packages/base-zone::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/base-zone@portal:../packages/base-zone::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/store": "npm:^0.9.2" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/far": "npm:^1.1.9" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + languageName: node + linkType: soft + +"@agoric/casting@portal:../packages/casting::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/casting@portal:../packages/casting::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@cosmjs/encoding": "npm:^0.32.3" + "@cosmjs/proto-signing": "npm:^0.32.3" + "@cosmjs/stargate": "npm:^0.32.3" + "@cosmjs/tendermint-rpc": "npm:^0.32.3" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/init": "npm:^1.1.7" + "@endo/lockdown": "npm:^1.0.13" + "@endo/marshal": "npm:^1.6.2" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/client-utils@portal:../packages/client-utils::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/client-utils@portal:../packages/client-utils::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/casting": "npm:^0.4.2" + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/smart-wallet": "npm:^0.5.3" + "@agoric/vats": "npm:^0.15.1" + "@cosmjs/stargate": "npm:^0.32.3" + "@cosmjs/tendermint-rpc": "npm:^0.32.3" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/marshal": "npm:^1.6.2" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/cosmic-proto@portal:../packages/cosmic-proto::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/cosmic-proto@portal:../packages/cosmic-proto::locator=root-workspace-0b6124%40workspace%3A." dependencies: "@endo/base64": "npm:^1.0.9" "@endo/init": "npm:^1.1.7" bech32: "npm:^2.0.0" query-string: "npm:^9.1.1" - checksum: 10c0/20d4f8763a091b0b741c754fcceb82d666c4eb55bab2eaaef8821f8f7da644e2ee70c1134ef0e1cf90cc940150d61437d935913549d0da8ea17a8f0c80f2d36c + languageName: node + linkType: soft + +"@agoric/ertp@portal:../packages/ERTP::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/ertp@portal:../packages/ERTP::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/zone": "npm:^0.2.2" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/fast-usdc@portal:../packages/fast-usdc::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/fast-usdc@portal:../packages/fast-usdc::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/client-utils": "npm:^0.1.0" + "@agoric/cosmic-proto": "npm:^0.4.0" + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/orchestration": "npm:^0.1.0" + "@agoric/store": "npm:^0.9.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/vow": "npm:^0.1.0" + "@agoric/zoe": "npm:^0.26.2" + "@cosmjs/proto-signing": "npm:^0.32.4" + "@cosmjs/stargate": "npm:^0.32.4" + "@endo/base64": "npm:^1.0.9" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/init": "npm:^1.1.7" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + "@nick134-bit/noblejs": "npm:0.0.2" + bech32: "npm:^2.0.0" + commander: "npm:^12.1.0" + ethers: "npm:^6.13.4" + bin: + fast-usdc: ./src/cli/bin.js + languageName: node + linkType: soft + +"@agoric/governance@portal:../packages/governance::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/governance@portal:../packages/governance::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/time": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/zoe": "npm:^0.26.2" + "@endo/bundle-source": "npm:^3.5.0" + "@endo/captp": "npm:^4.4.3" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/promise-kit": "npm:^1.1.8" + import-meta-resolve: "npm:^2.2.1" + languageName: node + linkType: soft + +"@agoric/internal@portal:../packages/internal::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/internal@portal:../packages/internal::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/init": "npm:^1.1.7" + "@endo/marshal": "npm:^1.6.2" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + "@endo/stream": "npm:^1.2.8" + anylogger: "npm:^0.21.0" + jessie.js: "npm:^0.3.4" + languageName: node + linkType: soft + +"@agoric/kmarshal@portal:../packages/kmarshal::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/kmarshal@portal:../packages/kmarshal::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + languageName: node + linkType: soft + +"@agoric/network@portal:../packages/network::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/network@portal:../packages/network::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/vat-data": "npm:^0.5.2" + "@endo/base64": "npm:^1.0.9" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/notifier@portal:../packages/notifier::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/notifier@portal:../packages/notifier::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/orchestration@portal:../packages/orchestration::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/orchestration@portal:../packages/orchestration::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/async-flow": "npm:^0.1.0" + "@agoric/cosmic-proto": "npm:^0.4.0" + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/network": "npm:^0.1.0" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/time": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/vats": "npm:^0.15.1" + "@agoric/vow": "npm:^0.1.0" + "@agoric/zoe": "npm:^0.26.2" + "@agoric/zone": "npm:^0.2.2" + "@endo/base64": "npm:^1.0.9" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + "@endo/patterns": "npm:^1.4.7" + "@noble/hashes": "npm:^1.5.0" + languageName: node + linkType: soft + +"@agoric/smart-wallet@portal:../packages/smart-wallet::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/smart-wallet@portal:../packages/smart-wallet::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/vats": "npm:^0.15.1" + "@agoric/vow": "npm:^0.1.0" + "@agoric/zoe": "npm:^0.26.2" + "@agoric/zone": "npm:^0.2.2" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/store@portal:../packages/store::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/store@portal:../packages/store::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@endo/errors": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/marshal": "npm:^1.6.2" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + languageName: node + linkType: soft + +"@agoric/swing-store@portal:../packages/swing-store::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/swing-store@portal:../packages/swing-store::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@endo/base64": "npm:^1.0.9" + "@endo/bundle-source": "npm:^3.5.0" + "@endo/check-bundle": "npm:^1.0.12" + "@endo/errors": "npm:^1.2.8" + "@endo/nat": "npm:^5.0.13" + better-sqlite3: "npm:^9.1.1" + languageName: node + linkType: soft + +"@agoric/swingset-liveslots@portal:../packages/swingset-liveslots::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/swingset-liveslots@portal:../packages/swingset-liveslots::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@agoric/store": "npm:^0.9.2" + "@endo/env-options": "npm:^1.1.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/far": "npm:^1.1.9" + "@endo/init": "npm:^1.1.7" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/swingset-vat@portal:../packages/SwingSet::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/swingset-vat@portal:../packages/SwingSet::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/internal": "npm:^0.3.2" + "@agoric/kmarshal": "npm:^0.1.0" + "@agoric/store": "npm:^0.9.2" + "@agoric/swing-store": "npm:^0.9.1" + "@agoric/swingset-liveslots": "npm:^0.10.2" + "@agoric/swingset-xsnap-supervisor": "npm:^0.10.2" + "@agoric/time": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/xsnap-lockdown": "npm:^0.14.0" + "@endo/base64": "npm:^1.0.9" + "@endo/bundle-source": "npm:^3.5.0" + "@endo/captp": "npm:^4.4.3" + "@endo/check-bundle": "npm:^1.0.12" + "@endo/compartment-mapper": "npm:^1.4.0" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/import-bundle": "npm:^1.3.2" + "@endo/init": "npm:^1.1.7" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + "@endo/ses-ava": "npm:^1.2.8" + "@endo/stream": "npm:^1.2.8" + "@endo/zip": "npm:^1.0.9" + ansi-styles: "npm:^6.2.1" + anylogger: "npm:^0.21.0" + better-sqlite3: "npm:^9.1.1" + import-meta-resolve: "npm:^2.2.1" + microtime: "npm:^3.1.0" + semver: "npm:^6.3.0" + tmp: "npm:^0.2.1" + yargs-parser: "npm:^21.1.1" + peerDependencies: + "@agoric/xsnap": ^0.14.2 + ava: ^5.3.0 + bin: + vat: bin/vat + languageName: node + linkType: soft + +"@agoric/swingset-xsnap-supervisor@portal:../packages/swingset-xsnap-supervisor::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/swingset-xsnap-supervisor@portal:../packages/swingset-xsnap-supervisor::locator=root-workspace-0b6124%40workspace%3A." + languageName: node + linkType: soft + +"@agoric/time@portal:../packages/time::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/time@portal:../packages/time::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/store": "npm:^0.9.2" + "@endo/errors": "npm:^1.2.8" + "@endo/nat": "npm:^5.0.13" + "@endo/patterns": "npm:^1.4.7" + languageName: node + linkType: soft + +"@agoric/vat-data@portal:../packages/vat-data::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/vat-data@portal:../packages/vat-data::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@agoric/store": "npm:^0.9.2" + "@agoric/swingset-liveslots": "npm:^0.10.2" + "@endo/errors": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/patterns": "npm:^1.4.7" + languageName: node + linkType: soft + +"@agoric/vats@portal:../packages/vats::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/vats@portal:../packages/vats::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/cosmic-proto": "npm:^0.4.0" + "@agoric/ertp": "npm:^0.16.2" + "@agoric/governance": "npm:^0.10.3" + "@agoric/internal": "npm:^0.3.2" + "@agoric/network": "npm:^0.1.0" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/swingset-vat": "npm:^0.32.2" + "@agoric/time": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/vow": "npm:^0.1.0" + "@agoric/zoe": "npm:^0.26.2" + "@agoric/zone": "npm:^0.2.2" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/import-bundle": "npm:^1.3.2" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + import-meta-resolve: "npm:^2.2.1" + jessie.js: "npm:^0.3.4" + languageName: node + linkType: soft + +"@agoric/vow@portal:../packages/vow::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/vow@portal:../packages/vow::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@agoric/internal": "npm:^0.3.2" + "@endo/env-options": "npm:^1.1.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + languageName: node + linkType: soft + +"@agoric/xsnap-lockdown@portal:../packages/xsnap-lockdown::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/xsnap-lockdown@portal:../packages/xsnap-lockdown::locator=root-workspace-0b6124%40workspace%3A." + languageName: node + linkType: soft + +"@agoric/zoe@portal:../packages/zoe::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/zoe@portal:../packages/zoe::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@agoric/ertp": "npm:^0.16.2" + "@agoric/internal": "npm:^0.3.2" + "@agoric/notifier": "npm:^0.6.2" + "@agoric/store": "npm:^0.9.2" + "@agoric/swingset-liveslots": "npm:^0.10.2" + "@agoric/swingset-vat": "npm:^0.32.2" + "@agoric/time": "npm:^0.3.2" + "@agoric/vat-data": "npm:^0.5.2" + "@agoric/vow": "npm:^0.1.0" + "@agoric/zone": "npm:^0.2.2" + "@endo/bundle-source": "npm:^3.5.0" + "@endo/captp": "npm:^4.4.3" + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/far": "npm:^1.1.9" + "@endo/import-bundle": "npm:^1.3.2" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + yargs-parser: "npm:^21.1.1" + languageName: node + linkType: soft + +"@agoric/zone@portal:../packages/zone::locator=root-workspace-0b6124%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@agoric/zone@portal:../packages/zone::locator=root-workspace-0b6124%40workspace%3A." + dependencies: + "@agoric/base-zone": "npm:^0.1.0" + "@agoric/vat-data": "npm:^0.5.2" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/pass-style": "npm:^1.4.7" + languageName: node + linkType: soft + +"@babel/code-frame@npm:^7.25.9, @babel/code-frame@npm:^7.26.2": + version: 7.26.2 + resolution: "@babel/code-frame@npm:7.26.2" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.25.9" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10c0/7d79621a6849183c415486af99b1a20b84737e8c11cd55b6544f688c51ce1fd710e6d869c3dd21232023da272a79b91efb3e83b5bc2dc65c1187c5fcd1b72ea8 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/generator@npm:7.26.3" + dependencies: + "@babel/parser": "npm:^7.26.3" + "@babel/types": "npm:^7.26.3" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^3.0.2" + checksum: 10c0/54f260558e3e4ec8942da3cde607c35349bb983c3a7c5121243f96893fba3e8cd62e1f1773b2051f936f8c8a10987b758d5c7d76dbf2784e95bb63ab4843fa00 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-string-parser@npm:7.25.9" + checksum: 10c0/7244b45d8e65f6b4338a6a68a8556f2cb161b782343e97281a5f2b9b93e420cad0d9f5773a59d79f61d0c448913d06f6a2358a87f2e203cf112e3c5b53522ee6 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-validator-identifier@npm:7.25.9" + checksum: 10c0/4fc6f830177b7b7e887ad3277ddb3b91d81e6c4a24151540d9d1023e8dc6b1c0505f0f0628ae653601eb4388a8db45c1c14b2c07a9173837aef7e4116456259d + languageName: node + linkType: hard + +"@babel/parser@npm:^7.23.6, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/parser@npm:7.26.3" + dependencies: + "@babel/types": "npm:^7.26.3" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/48f736374e61cfd10ddbf7b80678514ae1f16d0e88bc793d2b505d73d9b987ea786fc8c2f7ee8f8b8c467df062030eb07fd0eb2168f0f541ca1f542775852cad languageName: node linkType: hard @@ -21,8 +561,44 @@ __metadata: version: 7.24.7 resolution: "@babel/runtime@npm:7.24.7" dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + regenerator-runtime: "npm:^0.14.0" + checksum: 10c0/b6fa3ec61a53402f3c1d75f4d808f48b35e0dfae0ec8e2bb5c6fc79fb95935da75766e0ca534d0f1c84871f6ae0d2ebdd950727cfadb745a2cdbef13faef5513 + languageName: node + linkType: hard + +"@babel/template@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/template@npm:7.25.9" + dependencies: + "@babel/code-frame": "npm:^7.25.9" + "@babel/parser": "npm:^7.25.9" + "@babel/types": "npm:^7.25.9" + checksum: 10c0/ebe677273f96a36c92cc15b7aa7b11cc8bc8a3bb7a01d55b2125baca8f19cae94ff3ce15f1b1880fb8437f3a690d9f89d4e91f16fc1dc4d3eb66226d128983ab + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.23.6": + version: 7.26.4 + resolution: "@babel/traverse@npm:7.26.4" + dependencies: + "@babel/code-frame": "npm:^7.26.2" + "@babel/generator": "npm:^7.26.3" + "@babel/parser": "npm:^7.26.3" + "@babel/template": "npm:^7.25.9" + "@babel/types": "npm:^7.26.3" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/cf25d0eda9505daa0f0832ad786b9e28c9d967e823aaf7fbe425250ab198c656085495aa6bed678b27929e095c84eea9fd778b851a31803da94c9bc4bf4eaef7 + languageName: node + linkType: hard + +"@babel/types@npm:^7.17.0, @babel/types@npm:^7.24.0, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.3": + version: 7.26.3 + resolution: "@babel/types@npm:7.26.3" + dependencies: + "@babel/helper-string-parser": "npm:^7.25.9" + "@babel/helper-validator-identifier": "npm:^7.25.9" + checksum: 10c0/966c5242c5e55c8704bf7a7418e7be2703a0afa4d19a8480999d5a4ef13d095dd60686615fe5983cb7593b4b06ba3a7de8d6ca501c1d78bdd233a10d90be787b languageName: node linkType: hard @@ -76,7 +652,19 @@ __metadata: languageName: node linkType: hard -"@cosmjs/amino@npm:^0.32.4": +"@cosmjs/amino@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/amino@npm:0.32.3" + dependencies: + "@cosmjs/crypto": "npm:^0.32.3" + "@cosmjs/encoding": "npm:^0.32.3" + "@cosmjs/math": "npm:^0.32.3" + "@cosmjs/utils": "npm:^0.32.3" + checksum: 10c0/6f3da2ba6d88257d6717898af798aad9f2a51bb2c0d0b61cd40cf103c86a1431f4fa5086df350f81371d3282b8a28bcbc4f97c6d9eb83a9831fad473ae1ab492 + languageName: node + linkType: hard + +"@cosmjs/amino@npm:^0.32.3, @cosmjs/amino@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/amino@npm:0.32.4" dependencies: @@ -88,7 +676,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/crypto@npm:^0.32.4": +"@cosmjs/crypto@npm:^0.32.3, @cosmjs/crypto@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/crypto@npm:0.32.4" dependencies: @@ -103,7 +691,18 @@ __metadata: languageName: node linkType: hard -"@cosmjs/encoding@npm:^0.32.4": +"@cosmjs/encoding@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/encoding@npm:0.32.3" + dependencies: + base64-js: "npm:^1.3.0" + bech32: "npm:^1.1.4" + readonly-date: "npm:^1.0.0" + checksum: 10c0/3c3d4b610093c2c8ca13437664e4736d60cdfb309bf2671f492388c59a9bca20f1a75ab4686a7b73d48aa6208f454bee56c84c0fe780015473ea53353a70266a + languageName: node + linkType: hard + +"@cosmjs/encoding@npm:^0.32.3, @cosmjs/encoding@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/encoding@npm:0.32.4" dependencies: @@ -124,7 +723,16 @@ __metadata: languageName: node linkType: hard -"@cosmjs/math@npm:^0.32.4": +"@cosmjs/math@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/math@npm:0.32.3" + dependencies: + bn.js: "npm:^5.2.0" + checksum: 10c0/cad8b13a0db739ef4a416b334e39ea9f55874315ebdf91dc38772676c2ead6caccaf8a28b9e8803fc48680a72cf5a9fde97564f5efbfbe9a9073c95665f31294 + languageName: node + linkType: hard + +"@cosmjs/math@npm:^0.32.3, @cosmjs/math@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/math@npm:0.32.4" dependencies: @@ -133,7 +741,21 @@ __metadata: languageName: node linkType: hard -"@cosmjs/proto-signing@npm:^0.32.4": +"@cosmjs/proto-signing@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/proto-signing@npm:0.32.3" + dependencies: + "@cosmjs/amino": "npm:^0.32.3" + "@cosmjs/crypto": "npm:^0.32.3" + "@cosmjs/encoding": "npm:^0.32.3" + "@cosmjs/math": "npm:^0.32.3" + "@cosmjs/utils": "npm:^0.32.3" + cosmjs-types: "npm:^0.9.0" + checksum: 10c0/d44511d3a50489c1a3f61f28f68ca8cac87d6bdbb69e434cb0916dfc1d79e6a68ca0c09e074d4be73624f26fbb215024848225b862201b7f8d1d6a44014fd819 + languageName: node + linkType: hard + +"@cosmjs/proto-signing@npm:^0.32.3, @cosmjs/proto-signing@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/proto-signing@npm:0.32.4" dependencies: @@ -159,7 +781,25 @@ __metadata: languageName: node linkType: hard -"@cosmjs/stargate@npm:^0.32.4": +"@cosmjs/stargate@npm:0.32.3": + version: 0.32.3 + resolution: "@cosmjs/stargate@npm:0.32.3" + dependencies: + "@confio/ics23": "npm:^0.6.8" + "@cosmjs/amino": "npm:^0.32.3" + "@cosmjs/encoding": "npm:^0.32.3" + "@cosmjs/math": "npm:^0.32.3" + "@cosmjs/proto-signing": "npm:^0.32.3" + "@cosmjs/stream": "npm:^0.32.3" + "@cosmjs/tendermint-rpc": "npm:^0.32.3" + "@cosmjs/utils": "npm:^0.32.3" + cosmjs-types: "npm:^0.9.0" + xstream: "npm:^11.14.0" + checksum: 10c0/c82db0355f4b15ca988f0452f8142102b44840319fe48d44c8dc9c1a316cbe3c9e765eb90970348bd5b5fddd6d9452d5a556e14dbbbd93eda6a6c92ceb616241 + languageName: node + linkType: hard + +"@cosmjs/stargate@npm:^0.32.3, @cosmjs/stargate@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/stargate@npm:0.32.4" dependencies: @@ -177,7 +817,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/stream@npm:^0.32.4": +"@cosmjs/stream@npm:^0.32.3, @cosmjs/stream@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/stream@npm:0.32.4" dependencies: @@ -186,7 +826,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/tendermint-rpc@npm:^0.32.4": +"@cosmjs/tendermint-rpc@npm:^0.32.3, @cosmjs/tendermint-rpc@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/tendermint-rpc@npm:0.32.4" dependencies: @@ -204,7 +844,7 @@ __metadata: languageName: node linkType: hard -"@cosmjs/utils@npm:^0.32.4": +"@cosmjs/utils@npm:^0.32.3, @cosmjs/utils@npm:^0.32.4": version: 0.32.4 resolution: "@cosmjs/utils@npm:0.32.4" checksum: 10c0/d5ff8b235094be1150853a715116049f73eb5cdfeea8ce8e22ecccc61ec99792db457404d4307782b1a2f935dcf438f5c485beabfcfbc1dc5df26eb6e6da9062 @@ -218,6 +858,83 @@ __metadata: languageName: node linkType: hard +"@endo/bundle-source@npm:^3.5.0": + version: 3.5.0 + resolution: "@endo/bundle-source@npm:3.5.0" + dependencies: + "@endo/base64": "npm:^1.0.9" + "@endo/compartment-mapper": "npm:^1.4.0" + "@endo/evasive-transform": "npm:^1.3.3" + "@endo/init": "npm:^1.1.7" + "@endo/promise-kit": "npm:^1.1.8" + "@endo/where": "npm:^1.0.9" + "@rollup/plugin-commonjs": "npm:^19.0.0" + "@rollup/plugin-json": "npm:^6.1.0" + "@rollup/plugin-node-resolve": "npm:^13.0.0" + acorn: "npm:^8.2.4" + rollup: "npm:^2.79.1" + ts-blank-space: "npm:^0.4.1" + bin: + bundle-source: ./src/tool.js + checksum: 10c0/7f97194c97eb28abbde6655f7de4410d5aae5d6a2a3d712e1418b9b4fd20823333b7fe8956401c2f201280340731e51e28d9c4fbe3b5a787b0abd00e3ac13b52 + languageName: node + linkType: hard + +"@endo/captp@npm:^4.4.3": + version: 4.4.3 + resolution: "@endo/captp@npm:4.4.3" + dependencies: + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/marshal": "npm:^1.6.2" + "@endo/nat": "npm:^5.0.13" + "@endo/promise-kit": "npm:^1.1.8" + checksum: 10c0/0647dd6acc39c7a54a42d9f168861d11dc28248321be72529dd8574b52989957be8f7a5ec9985fc76a24b37cd6b6d190e5bfbbc1481594e367c8517c31fce0e2 + languageName: node + linkType: hard + +"@endo/check-bundle@npm:^1.0.12": + version: 1.0.12 + resolution: "@endo/check-bundle@npm:1.0.12" + dependencies: + "@endo/base64": "npm:^1.0.9" + "@endo/compartment-mapper": "npm:^1.4.0" + "@endo/errors": "npm:^1.2.8" + checksum: 10c0/73e146d9d4d5ee23936b0df368e51ebb3658eecc5efe308a1894f70339502e6de8fa065185e8518d1445bf8fbc4c5fae54fc7dab8794f02397f6694a7ab9af9c + languageName: node + linkType: hard + +"@endo/cjs-module-analyzer@npm:^1.0.9": + version: 1.0.9 + resolution: "@endo/cjs-module-analyzer@npm:1.0.9" + checksum: 10c0/cb8c56d108b175f2f211c8292bac6cda35c44b9c16fb2763ab9a32b545895e1721633938b440bfe7a06f69e1f168e9b248ef103631a1d4c63fda8cbe580ca185 + languageName: node + linkType: hard + +"@endo/common@npm:^1.2.8": + version: 1.2.8 + resolution: "@endo/common@npm:1.2.8" + dependencies: + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/promise-kit": "npm:^1.1.8" + checksum: 10c0/c9465721095d9f06278b6550909a02c330c7a69223f11aff29759067586d41b86054127639fa2c2c0345d0d0aa43518e5b72d5c547b67bfe8e802cd21756d87b + languageName: node + linkType: hard + +"@endo/compartment-mapper@npm:^1.4.0": + version: 1.4.0 + resolution: "@endo/compartment-mapper@npm:1.4.0" + dependencies: + "@endo/cjs-module-analyzer": "npm:^1.0.9" + "@endo/module-source": "npm:^1.1.2" + "@endo/trampoline": "npm:^1.0.3" + "@endo/zip": "npm:^1.0.9" + ses: "npm:^1.10.0" + checksum: 10c0/2c4999962016f57c0f3a40ce1445a064b826eb101a972d26ba56d9dba6d3d8f66744912e3f7e24754018bd2c633663a00ea5ab0d7658c4907c9372ddd3e56464 + languageName: node + linkType: hard + "@endo/env-options@npm:^1.1.8": version: 1.1.8 resolution: "@endo/env-options@npm:1.1.8" @@ -234,6 +951,18 @@ __metadata: languageName: node linkType: hard +"@endo/evasive-transform@npm:^1.3.3": + version: 1.3.3 + resolution: "@endo/evasive-transform@npm:1.3.3" + dependencies: + "@agoric/babel-generator": "npm:^7.17.6" + "@babel/parser": "npm:^7.23.6" + "@babel/traverse": "npm:^7.23.6" + source-map-js: "npm:^1.2.0" + checksum: 10c0/34fae4789ab3142ab73a5c94a46954908737bbc72f1e302c338941ca2556ab2127505ecee57a1c0d11e0b9c7070b4a579ce4e7e60585990161cec64ce0955211 + languageName: node + linkType: hard + "@endo/eventual-send@npm:^1.2.8": version: 1.2.8 resolution: "@endo/eventual-send@npm:1.2.8" @@ -243,7 +972,22 @@ __metadata: languageName: node linkType: hard -"@endo/far@npm:^1.1.9": +"@endo/exo@npm:^1.5.7": + version: 1.5.7 + resolution: "@endo/exo@npm:1.5.7" + dependencies: + "@endo/common": "npm:^1.2.8" + "@endo/env-options": "npm:^1.1.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/pass-style": "npm:^1.4.7" + "@endo/patterns": "npm:^1.4.7" + checksum: 10c0/0193de0606a7f07f207f3dd8bb71ec6be0acfb0ff5ef570f03cbbcaed888db68e451082c34764de8ee301f8d2d175e6c5a5405e76367c27151d644536bdf57a4 + languageName: node + linkType: hard + +"@endo/far@npm:^1.0.0, @endo/far@npm:^1.1.9": version: 1.1.9 resolution: "@endo/far@npm:1.1.9" dependencies: @@ -254,6 +998,19 @@ __metadata: languageName: node linkType: hard +"@endo/import-bundle@npm:^1.3.2": + version: 1.3.2 + resolution: "@endo/import-bundle@npm:1.3.2" + dependencies: + "@endo/base64": "npm:^1.0.9" + "@endo/compartment-mapper": "npm:^1.4.0" + "@endo/errors": "npm:^1.2.8" + "@endo/where": "npm:^1.0.9" + ses: "npm:^1.10.0" + checksum: 10c0/cc38bb7858c4b3a3d1cfbf70b0af3b05b527019452eb922313b4adf87e5590f5cacf4ff5dbd7a44c172d3c220de41edc3fa8895551f76071c85f1450ff94b09a + languageName: node + linkType: hard + "@endo/init@npm:^1.1.7": version: 1.1.7 resolution: "@endo/init@npm:1.1.7" @@ -275,6 +1032,33 @@ __metadata: languageName: node linkType: hard +"@endo/marshal@npm:^1.6.2": + version: 1.6.2 + resolution: "@endo/marshal@npm:1.6.2" + dependencies: + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/nat": "npm:^5.0.13" + "@endo/pass-style": "npm:^1.4.7" + "@endo/promise-kit": "npm:^1.1.8" + checksum: 10c0/bdb634a77c2147c1359792531822aabe642a5e4d39f496dd57bb97367617a2f2d72edaaa50c51ed6a2ec1f2c08deab6a571c3dd8ffa260d441d25f53606902b1 + languageName: node + linkType: hard + +"@endo/module-source@npm:^1.1.2": + version: 1.1.2 + resolution: "@endo/module-source@npm:1.1.2" + dependencies: + "@agoric/babel-generator": "npm:^7.17.6" + "@babel/parser": "npm:^7.23.6" + "@babel/traverse": "npm:^7.23.6" + "@babel/types": "npm:^7.24.0" + ses: "npm:^1.10.0" + checksum: 10c0/3d64ff5430f288531a00e124ae0620e137dab0fdaba00f2d41066b8307eb2da30e3987d84fe450d55d844e0f96feafa36a825cecc615c05d96224a209832c95c + languageName: node + linkType: hard + "@endo/nat@npm:^5.0.13": version: 5.0.13 resolution: "@endo/nat@npm:5.0.13" @@ -295,6 +1079,19 @@ __metadata: languageName: node linkType: hard +"@endo/patterns@npm:^1.4.7": + version: 1.4.7 + resolution: "@endo/patterns@npm:1.4.7" + dependencies: + "@endo/common": "npm:^1.2.8" + "@endo/errors": "npm:^1.2.8" + "@endo/eventual-send": "npm:^1.2.8" + "@endo/marshal": "npm:^1.6.2" + "@endo/promise-kit": "npm:^1.1.8" + checksum: 10c0/358720438a019847406dfad9f23fc9b565c955ffd86d75693cea994c492dd46efaf189502f04b04f8870e6d50ffcb44ffa1e1dd3a0d6b2dfbbe57edeb994b83b + languageName: node + linkType: hard + "@endo/promise-kit@npm:^1.1.8": version: 1.1.8 resolution: "@endo/promise-kit@npm:1.1.8" @@ -317,6 +1114,38 @@ __metadata: languageName: node linkType: hard +"@endo/stream@npm:^1.2.8": + version: 1.2.8 + resolution: "@endo/stream@npm:1.2.8" + dependencies: + "@endo/eventual-send": "npm:^1.2.8" + "@endo/promise-kit": "npm:^1.1.8" + ses: "npm:^1.10.0" + checksum: 10c0/f435f7650020b32c10bb4cb139910b363b4d4f22bcf9e7a659d3d2eae694a3ea43c3af49c80370760a573370429e5fbe1619dec631251578d4c5eba9ff161613 + languageName: node + linkType: hard + +"@endo/trampoline@npm:^1.0.3": + version: 1.0.3 + resolution: "@endo/trampoline@npm:1.0.3" + checksum: 10c0/be0c3784b17f422ae04e28a6722e2abd193a5585a82acf5eb388476094c026aa5e76a383db887bdf6a032ccf0a12c38a967f5f1e71cef44a4659606be789b548 + languageName: node + linkType: hard + +"@endo/where@npm:^1.0.9": + version: 1.0.9 + resolution: "@endo/where@npm:1.0.9" + checksum: 10c0/dd8f8fb601fb54e7cef64d7b32f91595d01151acf1e63c46257c905afb75760d80f2eec5d71cfb1f9251e435990256d56f35d6f8b4851f5e6fbe6b393b535028 + languageName: node + linkType: hard + +"@endo/zip@npm:^1.0.9": + version: 1.0.9 + resolution: "@endo/zip@npm:1.0.9" + checksum: 10c0/3fccea31bd5dad938a3b5f531454d3c49513892d6d5aba1f0af1034ff0ae54c3e28a346a9df08bd9e5201354acccd631e45c9c0e68fa2848a876a3919f3830dc + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" @@ -395,6 +1224,71 @@ __metadata: languageName: node linkType: hard +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: "npm:^7.0.4" + checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 + languageName: node + linkType: hard + +"@jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.8 + resolution: "@jridgewell/gen-mapping@npm:0.3.8" + dependencies: + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/c668feaf86c501d7c804904a61c23c67447b2137b813b9ce03eca82cb9d65ac7006d766c218685d76e3d72828279b6ee26c347aa1119dab23fbaf36aed51585a + languageName: node + linkType: hard + +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e + languageName: node + linkType: hard + +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 + languageName: node + linkType: hard + +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.5.0 + resolution: "@jridgewell/sourcemap-codec@npm:1.5.0" + checksum: 10c0/2eb864f276eb1096c3c11da3e9bb518f6d9fc0023c78344cdc037abadc725172c70314bdb360f2d4b7bffec7f5d657ce006816bc5d4ecb35e61b66132db00c18 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.25": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 + languageName: node + linkType: hard + "@mapbox/node-pre-gyp@npm:^1.0.11": version: 1.0.11 resolution: "@mapbox/node-pre-gyp@npm:1.0.11" @@ -414,6 +1308,36 @@ __metadata: languageName: node linkType: hard +"@nick134-bit/noblejs@npm:0.0.2": + version: 0.0.2 + resolution: "@nick134-bit/noblejs@npm:0.0.2" + dependencies: + "@cosmjs/amino": "npm:0.32.3" + "@cosmjs/encoding": "npm:0.32.3" + "@cosmjs/math": "npm:0.32.3" + "@cosmjs/proto-signing": "npm:0.32.3" + "@cosmjs/stargate": "npm:0.32.3" + typescript: "npm:^5.4.5" + checksum: 10c0/93a0d28459caf9649722d085f8a06f828ad878c2a2948beeb38eb583ebcb305ba15bff5f66ccc712e6068df93fb0cbd1b09bdf7681cc72ef37138f8c5484c287 + languageName: node + linkType: hard + +"@noble/curves@npm:1.2.0": + version: 1.2.0 + resolution: "@noble/curves@npm:1.2.0" + dependencies: + "@noble/hashes": "npm:1.3.2" + checksum: 10c0/0bac7d1bbfb3c2286910b02598addd33243cb97c3f36f987ecc927a4be8d7d88e0fcb12b0f0ef8a044e7307d1844dd5c49bb724bfa0a79c8ec50ba60768c97f6 + languageName: node + linkType: hard + +"@noble/hashes@npm:1.3.2": + version: 1.3.2 + resolution: "@noble/hashes@npm:1.3.2" + checksum: 10c0/2482cce3bce6a596626f94ca296e21378e7a5d4c09597cbc46e65ffacc3d64c8df73111f2265444e36a3168208628258bbbaccba2ef24f65f58b2417638a20e7 + languageName: node + linkType: hard + "@noble/hashes@npm:^1, @noble/hashes@npm:^1.0.0, @noble/hashes@npm:^1.2.0": version: 1.4.0 resolution: "@noble/hashes@npm:1.4.0" @@ -421,6 +1345,13 @@ __metadata: languageName: node linkType: hard +"@noble/hashes@npm:^1.5.0": + version: 1.6.1 + resolution: "@noble/hashes@npm:1.6.1" + checksum: 10c0/27643cd8b551bc933b57cc29aa8c8763d586552fc4c3e06ecf7897f55be3463c0c9dff7f6ebacd88e5ce6d0cdb5415ca4874d0cf4359b5ea4a85be21ada03aab + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -448,6 +1379,35 @@ __metadata: languageName: node linkType: hard +"@npmcli/agent@npm:^3.0.0": + version: 3.0.0 + resolution: "@npmcli/agent@npm:3.0.0" + dependencies: + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.3" + checksum: 10c0/efe37b982f30740ee77696a80c196912c274ecd2cb243bc6ae7053a50c733ce0f6c09fda085145f33ecf453be19654acca74b69e81eaad4c90f00ccffe2f9271 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/fs@npm:4.0.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/c90935d5ce670c87b6b14fab04a965a3b8137e585f8b2a6257263bd7f97756dd736cb165bb470e5156a9e718ecd99413dccc54b1138c1a46d6ec7cf325982fe5 + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd + languageName: node + linkType: hard + "@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2": version: 1.1.2 resolution: "@protobufjs/aspromise@npm:1.1.2" @@ -521,9 +1481,69 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.1.3": - version: 5.1.3 - resolution: "@rollup/pluginutils@npm:5.1.3" +"@rollup/plugin-commonjs@npm:^19.0.0": + version: 19.0.2 + resolution: "@rollup/plugin-commonjs@npm:19.0.2" + dependencies: + "@rollup/pluginutils": "npm:^3.1.0" + commondir: "npm:^1.0.1" + estree-walker: "npm:^2.0.1" + glob: "npm:^7.1.6" + is-reference: "npm:^1.2.1" + magic-string: "npm:^0.25.7" + resolve: "npm:^1.17.0" + peerDependencies: + rollup: ^2.38.3 + checksum: 10c0/9adccf77ad835cbe565da4385212f1e54c3e0dca2be174b5c2cfe89cfaeb240f42c7673e97e49b21b7c66ed901cc1c711552b6727f60b43a953ce996eb2868a7 + languageName: node + linkType: hard + +"@rollup/plugin-json@npm:^6.1.0": + version: 6.1.0 + resolution: "@rollup/plugin-json@npm:6.1.0" + dependencies: + "@rollup/pluginutils": "npm:^5.1.0" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/9400c431b5e0cf3088ba2eb2d038809a2b0fb2a84ed004997da85582f48cd64958ed3168893c4f2c8109e38652400ed68282d0c92bf8ec07a3b2ef2e1ceab0b7 + languageName: node + linkType: hard + +"@rollup/plugin-node-resolve@npm:^13.0.0": + version: 13.3.0 + resolution: "@rollup/plugin-node-resolve@npm:13.3.0" + dependencies: + "@rollup/pluginutils": "npm:^3.1.0" + "@types/resolve": "npm:1.17.1" + deepmerge: "npm:^4.2.2" + is-builtin-module: "npm:^3.1.0" + is-module: "npm:^1.0.0" + resolve: "npm:^1.19.0" + peerDependencies: + rollup: ^2.42.0 + checksum: 10c0/6caa32a8304a20f1c9953111b25e9543f4de7d254958d81ce0158ad909e4493946bc2060c4ace23d9748b560ebc84c920ee7bc1b7d50dbf8ba852ef13c91af58 + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^3.1.0": + version: 3.1.0 + resolution: "@rollup/pluginutils@npm:3.1.0" + dependencies: + "@types/estree": "npm:0.0.39" + estree-walker: "npm:^1.0.1" + picomatch: "npm:^2.2.2" + peerDependencies: + rollup: ^1.20.0||^2.0.0 + checksum: 10c0/7151753160d15ba2b259461a6c25b3932150994ea52dba8fd3144f634c7647c2e56733d986e2c15de67c4d96a9ee7d6278efa6d2e626a7169898fd64adc0f90c + languageName: node + linkType: hard + +"@rollup/pluginutils@npm:^5.1.0, @rollup/pluginutils@npm:^5.1.3": + version: 5.1.4 + resolution: "@rollup/pluginutils@npm:5.1.4" dependencies: "@types/estree": "npm:^1.0.0" estree-walker: "npm:^2.0.2" @@ -533,7 +1553,7 @@ __metadata: peerDependenciesMeta: rollup: optional: true - checksum: 10c0/ba46ad588733fb01d184ee3bc7a127d626158bc840b5874a94c129ff62689d12f16f537530709c54da6f3b71f67d705c4e09235b1dc9542e9d47ee8f2d0b8b9e + checksum: 10c0/6d58fbc6f1024eb4b087bc9bf59a1d655a8056a60c0b4021d3beaeec3f0743503f52467fd89d2cf0e7eccf2831feb40a05ad541a17637ea21ba10b21c2004deb languageName: node linkType: hard @@ -575,6 +1595,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:0.0.39": + version: 0.0.39 + resolution: "@types/estree@npm:0.0.39" + checksum: 10c0/f0af6c95ac1988c4827964bd9d3b51d24da442e2188943f6dfcb1e1559103d5d024d564b2e9d3f84c53714a02a0a7435c7441138eb63d9af5de4dfc66cdc0d92 + languageName: node + linkType: hard + "@types/fs-extra@npm:^11": version: 11.0.4 resolution: "@types/fs-extra@npm:11.0.4" @@ -617,6 +1644,24 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:22.7.5": + version: 22.7.5 + resolution: "@types/node@npm:22.7.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10c0/cf11f74f1a26053ec58066616e3a8685b6bcd7259bc569738b8f752009f9f0f7f85a1b2d24908e5b0f752482d1e8b6babdf1fbb25758711ec7bb9500bfcd6e60 + languageName: node + linkType: hard + +"@types/resolve@npm:1.17.1": + version: 1.17.1 + resolution: "@types/resolve@npm:1.17.1" + dependencies: + "@types/node": "npm:*" + checksum: 10c0/6eeb9c27d99bf4b393bf168d43208f63e78cefca5644662a0bdb2bdbf8352386f4f3aca66add138fc41bce5f66fd48a0de430a1473f11b612fbed0375ae78031 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^8.17.0": version: 8.17.0 resolution: "@typescript-eslint/eslint-plugin@npm:8.17.0" @@ -781,6 +1826,13 @@ __metadata: languageName: node linkType: hard +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 + languageName: node + linkType: hard + "acorn-import-attributes@npm:^1.9.5": version: 1.9.5 resolution: "acorn-import-attributes@npm:1.9.5" @@ -808,7 +1860,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.11.0, acorn@npm:^8.13.0, acorn@npm:^8.6.0, acorn@npm:^8.9.0": +"acorn@npm:^8.11.0, acorn@npm:^8.13.0, acorn@npm:^8.2.4, acorn@npm:^8.6.0, acorn@npm:^8.9.0": version: 8.14.0 resolution: "acorn@npm:8.14.0" bin: @@ -817,6 +1869,13 @@ __metadata: languageName: node linkType: hard +"aes-js@npm:4.0.0-beta.5": + version: 4.0.0-beta.5 + resolution: "aes-js@npm:4.0.0-beta.5" + checksum: 10c0/444f4eefa1e602cbc4f2a3c644bc990f93fd982b148425fee17634da510586fc09da940dcf8ace1b2d001453c07ff042e55f7a0482b3cc9372bf1ef75479090c + languageName: node + linkType: hard + "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -826,6 +1885,13 @@ __metadata: languageName: node linkType: hard +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.3 + resolution: "agent-base@npm:7.1.3" + checksum: 10c0/6192b580c5b1d8fb399b9c62bf8343d76654c2dd62afcb9a52b2cf44a8b6ace1e3b704d3fe3547d91555c857d3df02603341ff2cb961b9cfe2b12f9f3c38ee11 + languageName: node + linkType: hard + "ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -861,13 +1927,20 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.2.1": +"ansi-styles@npm:^6.0.0, ansi-styles@npm:^6.1.0, ansi-styles@npm:^6.2.1": version: 6.2.1 resolution: "ansi-styles@npm:6.2.1" checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c languageName: node linkType: hard +"anylogger@npm:^0.21.0": + version: 0.21.0 + resolution: "anylogger@npm:0.21.0" + checksum: 10c0/1ca7fcf5bc2b78d1e1d9b8c8cc7ce50b5c6cc67a8da5a28c9c975b7b46fff255a04abab02de38a5139190c9d8b34b3d6c59af6724521b077f7d7dfbad9b47a9c + languageName: node + linkType: hard + "aproba@npm:^1.0.3 || ^2.0.0": version: 2.0.0 resolution: "aproba@npm:2.0.0" @@ -1016,7 +2089,7 @@ __metadata: languageName: node linkType: hard -"base64-js@npm:^1.3.0": +"base64-js@npm:^1.3.0, base64-js@npm:^1.3.1": version: 1.5.1 resolution: "base64-js@npm:1.5.1" checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf @@ -1037,6 +2110,17 @@ __metadata: languageName: node linkType: hard +"better-sqlite3@npm:^9.1.1": + version: 9.6.0 + resolution: "better-sqlite3@npm:9.6.0" + dependencies: + bindings: "npm:^1.5.0" + node-gyp: "npm:latest" + prebuild-install: "npm:^7.1.1" + checksum: 10c0/8db9b38f414e26a56d4c40fc16e94a253118491dae0e2c054338a9e470f1a883c7eb4cb330f2f5737db30f704d4f2e697c59071ca04e03364ee9fe04375aa9c8 + languageName: node + linkType: hard + "bfs-path@npm:^1.0.2": version: 1.0.2 resolution: "bfs-path@npm:1.0.2" @@ -1051,7 +2135,7 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.4.0": +"bindings@npm:^1.4.0, bindings@npm:^1.5.0": version: 1.5.0 resolution: "bindings@npm:1.5.0" dependencies: @@ -1064,8 +2148,19 @@ __metadata: version: 3.1.0 resolution: "bip39@npm:3.1.0" dependencies: - "@noble/hashes": "npm:^1.2.0" - checksum: 10c0/68f9673a0d6a851e9635f3af8a85f2a1ecef9066c76d77e6f0d58d274b5bf22a67f429da3997e07c0d2cf153a4d7321f9273e656cac0526f667575ddee28ef71 + "@noble/hashes": "npm:^1.2.0" + checksum: 10c0/68f9673a0d6a851e9635f3af8a85f2a1ecef9066c76d77e6f0d58d274b5bf22a67f429da3997e07c0d2cf153a4d7321f9273e656cac0526f667575ddee28ef71 + languageName: node + linkType: hard + +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: "npm:^5.5.0" + inherits: "npm:^2.0.4" + readable-stream: "npm:^3.4.0" + checksum: 10c0/02847e1d2cb089c9dc6958add42e3cdeaf07d13f575973963335ac0fdece563a50ac770ac4c8fa06492d2dd276f6cc3b7f08c7cd9c7a7ad0f8d388b2a28def5f languageName: node linkType: hard @@ -1125,6 +2220,43 @@ __metadata: languageName: node linkType: hard +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: "npm:^1.3.1" + ieee754: "npm:^1.1.13" + checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e + languageName: node + linkType: hard + +"builtin-modules@npm:^3.3.0": + version: 3.3.0 + resolution: "builtin-modules@npm:3.3.0" + checksum: 10c0/2cb3448b4f7306dc853632a4fcddc95e8d4e4b9868c139400027b71938fc6806d4ff44007deffb362ac85724bd40c2c6452fb6a0aa4531650eeddb98d8e5ee8a + languageName: node + linkType: hard + +"cacache@npm:^19.0.1": + version: 19.0.1 + resolution: "cacache@npm:19.0.1" + dependencies: + "@npmcli/fs": "npm:^4.0.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^7.0.2" + ssri: "npm:^12.0.0" + tar: "npm:^7.4.3" + unique-filename: "npm:^4.0.0" + checksum: 10c0/01f2134e1bd7d3ab68be851df96c8d63b492b1853b67f2eecb2c37bb682d37cb70bb858a16f2f0554d3c0071be6dfe21456a1ff6fa4b7eed996570d6a25ffe9c + languageName: node + linkType: hard + "call-bind@npm:^1.0.5": version: 1.0.7 resolution: "call-bind@npm:1.0.7" @@ -1178,6 +2310,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: 10c0/ed57952a84cc0c802af900cf7136de643d3aba2eecb59d29344bc2f3f9bf703a301b9d84cdc71f82c3ffc9ccde831b0d92f5b45f91727d6c9da62f23aef9d9db + languageName: node + linkType: hard + "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" @@ -1185,6 +2324,13 @@ __metadata: languageName: node linkType: hard +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 + languageName: node + linkType: hard + "chunkd@npm:^2.0.1": version: 2.0.1 resolution: "chunkd@npm:2.0.1" @@ -1277,6 +2423,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 + languageName: node + linkType: hard + "common-path-prefix@npm:^3.0.0": version: 3.0.0 resolution: "common-path-prefix@npm:3.0.0" @@ -1284,6 +2437,13 @@ __metadata: languageName: node linkType: hard +"commondir@npm:^1.0.1": + version: 1.0.1 + resolution: "commondir@npm:1.0.1" + checksum: 10c0/33a124960e471c25ee19280c9ce31ccc19574b566dc514fe4f4ca4c34fa8b0b57cf437671f5de380e11353ea9426213fca17687dd2ef03134fea2dbc53809fd6 + languageName: node + linkType: hard + "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" @@ -1337,14 +2497,14 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" dependencies: path-key: "npm:^3.1.0" shebang-command: "npm:^2.0.0" which: "npm:^2.0.1" - checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 + checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 languageName: node linkType: hard @@ -1385,6 +2545,22 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: "npm:^3.1.0" + checksum: 10c0/bd89d23141b96d80577e70c54fb226b2f40e74a6817652b80a116d7befb8758261ad073a8895648a29cc0a5947021ab66705cb542fa9c143c82022b27c5b175e + languageName: node + linkType: hard + +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -1392,6 +2568,13 @@ __metadata: languageName: node linkType: hard +"deepmerge@npm:^4.2.2": + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044 + languageName: node + linkType: hard + "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -1444,6 +2627,13 @@ __metadata: languageName: node linkType: hard +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 + languageName: node + linkType: hard + "elliptic@npm:^6.5.4": version: 6.5.7 resolution: "elliptic@npm:6.5.7" @@ -1480,6 +2670,45 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 + languageName: node + linkType: hard + +"encoding@npm:^0.1.13": + version: 0.1.13 + resolution: "encoding@npm:0.1.13" + dependencies: + iconv-lite: "npm:^0.6.2" + checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.4 + resolution: "end-of-stream@npm:1.4.4" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 + languageName: node + linkType: hard + +"err-code@npm:^2.0.2": + version: 2.0.3 + resolution: "err-code@npm:2.0.3" + checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 + languageName: node + linkType: hard + "es-define-property@npm:^1.0.0": version: 1.0.0 resolution: "es-define-property@npm:1.0.0" @@ -1653,13 +2882,20 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:2.0.2, estree-walker@npm:^2.0.2": +"estree-walker@npm:2.0.2, estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af languageName: node linkType: hard +"estree-walker@npm:^1.0.1": + version: 1.0.1 + resolution: "estree-walker@npm:1.0.1" + checksum: 10c0/fa9e5f8c1bbe8d01e314c0f03067b64a4f22d4c58410fc5237060d0c15b81e58c23921c41acc60abbdab490f1fdfcbd6408ede2d03ca704454272e0244d61a55 + languageName: node + linkType: hard + "esutils@npm:^2.0.2, esutils@npm:^2.0.3": version: 2.0.3 resolution: "esutils@npm:2.0.3" @@ -1667,6 +2903,21 @@ __metadata: languageName: node linkType: hard +"ethers@npm:^6.13.4": + version: 6.13.4 + resolution: "ethers@npm:6.13.4" + dependencies: + "@adraffy/ens-normalize": "npm:1.10.1" + "@noble/curves": "npm:1.2.0" + "@noble/hashes": "npm:1.3.2" + "@types/node": "npm:22.7.5" + aes-js: "npm:4.0.0-beta.5" + tslib: "npm:2.7.0" + ws: "npm:8.17.1" + checksum: 10c0/efcf9f39f841e38af68ec23cdbd745432c239c256aac4929842d1af04e55d7be0ff65e462f1cf3e93586f43f7bdcc0098fd56f2f7234f36d73e466521a5766ce + languageName: node + linkType: hard + "execa@npm:9.1.0": version: 9.1.0 resolution: "execa@npm:9.1.0" @@ -1687,6 +2938,20 @@ __metadata: languageName: node linkType: hard +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 10c0/1c9e7afe9acadf9d373301d27f6a47b34e89b3391b1ef38b7471d381812537ef2457e620ae7f819d2642ce9c43b189b3583813ec395e2938319abe356a9b2f51 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 + languageName: node + linkType: hard + "fast-check@npm:^3.0.0": version: 3.19.0 resolution: "fast-check@npm:3.19.0" @@ -1841,6 +3106,16 @@ __metadata: languageName: node linkType: hard +"foreground-child@npm:^3.1.0": + version: 3.3.0 + resolution: "foreground-child@npm:3.3.0" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2 + languageName: node + linkType: hard + "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -1852,6 +3127,13 @@ __metadata: languageName: node linkType: hard +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 10c0/a0cde99085f0872f4d244e83e03a46aa387b74f5a5af750896c6b05e9077fac00e9932fdf5aef84f2f16634cd473c63037d7a512576da7d5c2b9163d1909f3a8 + languageName: node + linkType: hard + "fs-extra@npm:^11.2.0": version: 11.2.0 resolution: "fs-extra@npm:11.2.0" @@ -1884,6 +3166,15 @@ __metadata: languageName: node linkType: hard +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 + languageName: node + linkType: hard + "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" @@ -1891,6 +3182,25 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:~2.3.2": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 + conditions: os=darwin + languageName: node + linkType: hard + +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "function-bind@npm:^1.1.2": version: 1.1.2 resolution: "function-bind@npm:1.1.2" @@ -1952,6 +3262,13 @@ __metadata: languageName: node linkType: hard +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 10c0/737ee3f52d0a27e26332cde85b533c21fcdc0b09fb716c3f8e522cfaa9c600d4a631dec9fcde179ec9d47cca89017b7848ed4d6ae6b6b78f936c06825b1fcc12 + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -1970,7 +3287,23 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3": +"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": + version: 10.4.5 + resolution: "glob@npm:10.4.5" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + package-json-from-dist: "npm:^1.0.0" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/19a9759ea77b8e3ca0a43c2f07ecddc2ad46216b786bb8f993c445aee80d345925a21e5280c7b7c6c59e860a0154b84e4b2b60321fea92cd3c56b4a7489f160e + languageName: node + linkType: hard + +"glob@npm:^7.1.3, glob@npm:^7.1.6": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -1984,6 +3317,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 + languageName: node + linkType: hard + "globals@npm:^13.19.0": version: 13.24.0 resolution: "globals@npm:13.24.0" @@ -2026,7 +3366,7 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.9": +"graceful-fs@npm:^4.1.11, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -2087,7 +3427,7 @@ __metadata: languageName: node linkType: hard -"hasown@npm:^2.0.0": +"hasown@npm:^2.0.0, hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" dependencies: @@ -2107,6 +3447,23 @@ __metadata: languageName: node linkType: hard +"http-cache-semantics@npm:^4.1.1": + version: 4.1.1 + resolution: "http-cache-semantics@npm:4.1.1" + checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + "https-proxy-agent@npm:^5.0.0": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" @@ -2117,6 +3474,16 @@ __metadata: languageName: node linkType: hard +"https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:4" + checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac + languageName: node + linkType: hard + "human-signals@npm:^7.0.0": version: 7.0.0 resolution: "human-signals@npm:7.0.0" @@ -2124,6 +3491,22 @@ __metadata: languageName: node linkType: hard +"iconv-lite@npm:^0.6.2": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb + languageName: node + linkType: hard + "ignore-by-default@npm:^2.1.0": version: 2.1.0 resolution: "ignore-by-default@npm:2.1.0" @@ -2148,6 +3531,13 @@ __metadata: languageName: node linkType: hard +"import-meta-resolve@npm:^2.2.1": + version: 2.2.2 + resolution: "import-meta-resolve@npm:2.2.2" + checksum: 10c0/80873aebf0d2a66e824e278fb6cbb16a6660f86df49b367404e5de80928720ecb44f643243b46dc5c5fae506abb666ef54d6f281b45ee0f1034951acb2261eb5 + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -2179,6 +3569,23 @@ __metadata: languageName: node linkType: hard +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" + dependencies: + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc + languageName: node + linkType: hard + "irregular-plurals@npm:^3.3.0": version: 3.5.0 resolution: "irregular-plurals@npm:3.5.0" @@ -2186,6 +3593,24 @@ __metadata: languageName: node linkType: hard +"is-builtin-module@npm:^3.1.0": + version: 3.2.1 + resolution: "is-builtin-module@npm:3.2.1" + dependencies: + builtin-modules: "npm:^3.3.0" + checksum: 10c0/5a66937a03f3b18803381518f0ef679752ac18cdb7dd53b5e23ee8df8d440558737bd8dcc04d2aae555909d2ecb4a81b5c0d334d119402584b61e6a003e31af1 + languageName: node + linkType: hard + +"is-core-module@npm:^2.16.0": + version: 2.16.0 + resolution: "is-core-module@npm:2.16.0" + dependencies: + hasown: "npm:^2.0.2" + checksum: 10c0/57e3b4bf3503a5ace3e61ef030a2eefa03d27827647b22968456e3e4befffed7c7aa849eea2e029f4f74a119a2d53cc391d5bad59c9352ecc9b79be3fd2acf79 + languageName: node + linkType: hard + "is-docker@npm:^2.0.0": version: 2.2.1 resolution: "is-docker@npm:2.2.1" @@ -2225,6 +3650,13 @@ __metadata: languageName: node linkType: hard +"is-module@npm:^1.0.0": + version: 1.0.0 + resolution: "is-module@npm:1.0.0" + checksum: 10c0/795a3914bcae7c26a1c23a1e5574c42eac13429625045737bf3e324ce865c0601d61aee7a5afbca1bee8cb300c7d9647e7dc98860c9bdbc3b7fdc51d8ac0bffc + languageName: node + linkType: hard + "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" @@ -2260,6 +3692,15 @@ __metadata: languageName: node linkType: hard +"is-reference@npm:^1.2.1": + version: 1.2.1 + resolution: "is-reference@npm:1.2.1" + dependencies: + "@types/estree": "npm:*" + checksum: 10c0/7dc819fc8de7790264a0a5d531164f9f5b9ef5aa1cd05f35322d14db39c8a2ec78fd5d4bf57f9789f3ddd2b3abeea7728432b759636157a42db12a9e8c3b549b + languageName: node + linkType: hard + "is-stream@npm:^4.0.1": version: 4.0.1 resolution: "is-stream@npm:4.0.1" @@ -2297,6 +3738,13 @@ __metadata: languageName: node linkType: hard +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 + languageName: node + linkType: hard + "isomorphic-ws@npm:^4.0.1": version: 4.0.1 resolution: "isomorphic-ws@npm:4.0.1" @@ -2306,6 +3754,28 @@ __metadata: languageName: node linkType: hard +"jackspeak@npm:^3.1.2": + version: 3.4.3 + resolution: "jackspeak@npm:3.4.3" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 + languageName: node + linkType: hard + +"jessie.js@npm:^0.3.4": + version: 0.3.4 + resolution: "jessie.js@npm:0.3.4" + dependencies: + "@endo/far": "npm:^1.0.0" + checksum: 10c0/853ab3f8a0e30df11742882f5e11479d1303033a5a203a247d8ffbf4c6f3f3d4bcbefa53084ae4632e6ab106e348f23dc988280486cbeaaf5d16487fa3d40e96 + languageName: node + linkType: hard + "js-string-escape@npm:^1.0.1": version: 1.0.1 resolution: "js-string-escape@npm:1.0.1" @@ -2313,6 +3783,13 @@ __metadata: languageName: node linkType: hard +"js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + "js-yaml@npm:^3.14.1": version: 3.14.1 resolution: "js-yaml@npm:3.14.1" @@ -2336,6 +3813,31 @@ __metadata: languageName: node linkType: hard +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 + languageName: node + linkType: hard + +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" + bin: + jsesc: bin/jsesc + checksum: 10c0/dbf59312e0ebf2b4405ef413ec2b25abb5f8f4d9bc5fb8d9f90381622ebca5f2af6a6aa9a8578f65903f9e33990a6dc798edd0ce5586894bf0e9e31803a1de88 + languageName: node + linkType: hard + +"jsesc@npm:^3.0.2": + version: 3.1.0 + resolution: "jsesc@npm:3.1.0" + bin: + jsesc: bin/jsesc + checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -2470,6 +3972,22 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb + languageName: node + linkType: hard + +"magic-string@npm:^0.25.7": + version: 0.25.9 + resolution: "magic-string@npm:0.25.9" + dependencies: + sourcemap-codec: "npm:^1.4.8" + checksum: 10c0/37f5e01a7e8b19a072091f0b45ff127cda676232d373ce2c551a162dd4053c575ec048b9cbb4587a1f03adb6c5d0fd0dd49e8ab070cd2c83a4992b2182d9cb56 + languageName: node + linkType: hard + "make-dir@npm:^3.1.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" @@ -2479,6 +3997,25 @@ __metadata: languageName: node linkType: hard +"make-fetch-happen@npm:^14.0.3": + version: 14.0.3 + resolution: "make-fetch-happen@npm:14.0.3" + dependencies: + "@npmcli/agent": "npm:^3.0.0" + cacache: "npm:^19.0.1" + http-cache-semantics: "npm:^4.1.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^4.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^1.0.0" + proc-log: "npm:^5.0.0" + promise-retry: "npm:^2.0.1" + ssri: "npm:^12.0.0" + checksum: 10c0/c40efb5e5296e7feb8e37155bde8eb70bc57d731b1f7d90e35a092fde403d7697c56fb49334d92d330d6f1ca29a98142036d6480a12681133a0a1453164cb2f0 + languageName: node + linkType: hard + "matcher@npm:^5.0.0": version: 5.0.0 resolution: "matcher@npm:5.0.0" @@ -2523,6 +4060,17 @@ __metadata: languageName: node linkType: hard +"microtime@npm:^3.1.0": + version: 3.1.1 + resolution: "microtime@npm:3.1.1" + dependencies: + node-addon-api: "npm:^5.0.0" + node-gyp: "npm:latest" + node-gyp-build: "npm:^4.4.0" + checksum: 10c0/02512993de914c6f71424d3b8b28ce53de44ba5895b904a213420fd4fc86a084c1d08ec0876ac60cdae6427022766e1b9b86d9b3442bf408701120bd61455e26 + languageName: node + linkType: hard + "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" @@ -2546,6 +4094,13 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 10c0/0d6f07ce6e03e9e4445bee655202153bdb8a98d67ee8dc965ac140900d7a2688343e6b4c9a72cfc9ef2f7944dfd76eef4ab2482eb7b293a68b84916bac735362 + languageName: node + linkType: hard + "minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1": version: 1.0.1 resolution: "minimalistic-assert@npm:1.0.1" @@ -2560,28 +4115,79 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.2 + resolution: "minimatch@npm:3.1.2" + dependencies: + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + languageName: node + linkType: hard + +"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.6": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e + languageName: node + linkType: hard + +"minipass-fetch@npm:^4.0.0": + version: 4.0.0 + resolution: "minipass-fetch@npm:4.0.0" + dependencies: + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^3.0.1" + dependenciesMeta: + encoding: + optional: true + checksum: 10c0/7fa30ce7c373fb6f94c086b374fff1589fd7e78451855d2d06c2e2d9df936d131e73e952163063016592ed3081444bd8d1ea608533313b0149156ce23311da4b + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd languageName: node linkType: hard -"minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 languageName: node linkType: hard -"minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 +"minipass-sized@npm:^1.0.3": + version: 1.0.3 + resolution: "minipass-sized@npm:1.0.3" + dependencies: + minipass: "npm:^3.0.0" + checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb languageName: node linkType: hard @@ -2601,6 +4207,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + "minizlib@npm:^2.1.1": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -2611,6 +4224,23 @@ __metadata: languageName: node linkType: hard +"minizlib@npm:^3.0.1": + version: 3.0.1 + resolution: "minizlib@npm:3.0.1" + dependencies: + minipass: "npm:^7.0.4" + rimraf: "npm:^5.0.5" + checksum: 10c0/82f8bf70da8af656909a8ee299d7ed3b3372636749d29e105f97f20e88971be31f5ed7642f2e898f00283b68b701cc01307401cdc209b0efc5dd3818220e5093 + languageName: node + linkType: hard + +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 10c0/95371d831d196960ddc3833cc6907e6b8f67ac5501a6582f47dfae5eb0f092e9f8ce88e0d83afcae95d6e2b61a01741ba03714eeafb6f7a6e9dcc158ac85b168 + languageName: node + linkType: hard + "mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" @@ -2620,6 +4250,15 @@ __metadata: languageName: node linkType: hard +"mkdirp@npm:^3.0.1": + version: 3.0.1 + resolution: "mkdirp@npm:3.0.1" + bin: + mkdirp: dist/cjs/src/bin.js + checksum: 10c0/9f2b975e9246351f5e3a40dcfac99fcd0baa31fbfab615fe059fb11e51f10e4803c63de1f384c54d656e4db31d000e4767e9ef076a22e12a641357602e31d57d + languageName: node + linkType: hard + "ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" @@ -2627,6 +4266,13 @@ __metadata: languageName: node linkType: hard +"napi-build-utils@npm:^1.0.1": + version: 1.0.2 + resolution: "napi-build-utils@npm:1.0.2" + checksum: 10c0/37fd2cd0ff2ad20073ce78d83fd718a740d568b225924e753ae51cb69d68f330c80544d487e5e5bd18e28702ed2ca469c2424ad948becd1862c1b0209542b2e9 + languageName: node + linkType: hard + "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -2634,6 +4280,31 @@ __metadata: languageName: node linkType: hard +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b + languageName: node + linkType: hard + +"node-abi@npm:^3.3.0": + version: 3.71.0 + resolution: "node-abi@npm:3.71.0" + dependencies: + semver: "npm:^7.3.5" + checksum: 10c0/dbd0792ea729329cd9d099f28a5681ff9e8a6db48cf64e1437bf6a7fd669009d1e758a784619a1c4cc8bfd1ed17162f042c787654edf19a1f64b5018457c9c1f + languageName: node + linkType: hard + +"node-addon-api@npm:^5.0.0": + version: 5.1.0 + resolution: "node-addon-api@npm:5.1.0" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/0eb269786124ba6fad9df8007a149e03c199b3e5a3038125dfb3e747c2d5113d406a4e33f4de1ea600aa2339be1f137d55eba1a73ee34e5fff06c52a5c296d1d + languageName: node + linkType: hard + "node-fetch@npm:^2.6.12, node-fetch@npm:^2.6.7, node-fetch@npm:^2.6.9": version: 2.7.0 resolution: "node-fetch@npm:2.7.0" @@ -2648,14 +4319,34 @@ __metadata: languageName: node linkType: hard -"node-gyp-build@npm:^4.2.2": - version: 4.8.1 - resolution: "node-gyp-build@npm:4.8.1" +"node-gyp-build@npm:^4.2.2, node-gyp-build@npm:^4.4.0": + version: 4.8.4 + resolution: "node-gyp-build@npm:4.8.4" bin: node-gyp-build: bin.js node-gyp-build-optional: optional.js node-gyp-build-test: build-test.js - checksum: 10c0/e36ca3d2adf2b9cca316695d7687207c19ac6ed326d6d7c68d7112cebe0de4f82d6733dff139132539fcc01cf5761f6c9082a21864ab9172edf84282bc849ce7 + checksum: 10c0/444e189907ece2081fe60e75368784f7782cfddb554b60123743dfb89509df89f1f29c03bbfa16b3a3e0be3f48799a4783f487da6203245fa5bed239ba7407e1 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 11.0.0 + resolution: "node-gyp@npm:11.0.0" + dependencies: + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^14.0.3" + nopt: "npm:^8.0.0" + proc-log: "npm:^5.0.0" + semver: "npm:^7.3.5" + tar: "npm:^7.4.3" + which: "npm:^5.0.0" + bin: + node-gyp: bin/node-gyp.js + checksum: 10c0/a3b885bbee2d271f1def32ba2e30ffcf4562a3db33af06b8b365e053153e2dd2051b9945783c3c8e852d26a0f20f65b251c7e83361623383a99635c0280ee573 languageName: node linkType: hard @@ -2677,6 +4368,17 @@ __metadata: languageName: node linkType: hard +"nopt@npm:^8.0.0": + version: 8.0.0 + resolution: "nopt@npm:8.0.0" + dependencies: + abbrev: "npm:^2.0.0" + bin: + nopt: bin/nopt.js + checksum: 10c0/19cb986f79abaca2d0f0b560021da7b32ee6fcc3de48f3eaeb0c324d36755c17754f886a754c091f01f740c17caf7d6aea8237b7fbaf39f476ae5e30a249f18f + languageName: node + linkType: hard + "npm-run-path@npm:^5.2.0": version: 5.3.0 resolution: "npm-run-path@npm:5.3.0" @@ -2712,7 +4414,7 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0": +"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -2787,6 +4489,13 @@ __metadata: languageName: node linkType: hard +"package-json-from-dist@npm:^1.0.0": + version: 1.0.1 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 10c0/62ba2785eb655fec084a257af34dbe24292ab74516d6aecef97ef72d4897310bc6898f6c85b5cd22770eaa1ce60d55a0230e150fb6a966e3ecd6c511e23d164b + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -2856,6 +4565,23 @@ __metadata: languageName: node linkType: hard +"path-parse@npm:^1.0.7": + version: 1.0.7 + resolution: "path-parse@npm:1.0.7" + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + languageName: node + linkType: hard + +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d + languageName: node + linkType: hard + "path-type@npm:^5.0.0": version: 5.0.0 resolution: "path-type@npm:5.0.0" @@ -2863,7 +4589,14 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.3.1": +"picocolors@npm:^1.0.0": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 + languageName: node + linkType: hard + +"picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be @@ -2886,6 +4619,28 @@ __metadata: languageName: node linkType: hard +"prebuild-install@npm:^7.1.1": + version: 7.1.2 + resolution: "prebuild-install@npm:7.1.2" + dependencies: + detect-libc: "npm:^2.0.0" + expand-template: "npm:^2.0.3" + github-from-package: "npm:0.0.0" + minimist: "npm:^1.2.3" + mkdirp-classic: "npm:^0.5.3" + napi-build-utils: "npm:^1.0.1" + node-abi: "npm:^3.3.0" + pump: "npm:^3.0.0" + rc: "npm:^1.2.7" + simple-get: "npm:^4.0.0" + tar-fs: "npm:^2.0.0" + tunnel-agent: "npm:^0.6.0" + bin: + prebuild-install: bin.js + checksum: 10c0/e64868ba9ef2068fd7264f5b03e5298a901e02a450acdb1f56258d88c09dea601eefdb3d1dfdff8513fdd230a92961712be0676192626a3b4d01ba154d48bdd3 + languageName: node + linkType: hard + "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" @@ -2902,6 +4657,23 @@ __metadata: languageName: node linkType: hard +"proc-log@npm:^5.0.0": + version: 5.0.0 + resolution: "proc-log@npm:5.0.0" + checksum: 10c0/bbe5edb944b0ad63387a1d5b1911ae93e05ce8d0f60de1035b218cdcceedfe39dbd2c697853355b70f1a090f8f58fe90da487c85216bf9671f9499d1a897e9e3 + languageName: node + linkType: hard + +"promise-retry@npm:^2.0.1": + version: 2.0.1 + resolution: "promise-retry@npm:2.0.1" + dependencies: + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 + languageName: node + linkType: hard + "protobufjs@npm:^6.8.8": version: 6.11.4 resolution: "protobufjs@npm:6.11.4" @@ -2933,6 +4705,16 @@ __metadata: languageName: node linkType: hard +"pump@npm:^3.0.0": + version: 3.0.2 + resolution: "pump@npm:3.0.2" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/5ad655cb2a7738b4bcf6406b24ad0970d680649d996b55ad20d1be8e0c02394034e4c45ff7cd105d87f1e9b96a0e3d06fd28e11fae8875da26e7f7a8e2c9726f + languageName: node + linkType: hard + "punycode@npm:^2.1.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" @@ -2965,7 +4747,21 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.6.0": +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0": version: 3.6.2 resolution: "readable-stream@npm:3.6.2" dependencies: @@ -3020,6 +4816,39 @@ __metadata: languageName: node linkType: hard +"resolve@npm:^1.17.0, resolve@npm:^1.19.0": + version: 1.22.9 + resolution: "resolve@npm:1.22.9" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/314cea2c47f956743f106256854203bd43a60a3ec6fb85ee6894e75cf4b16004952e4280319bfeb4c6fb1246e3ecd27f2699abb2e2b316b7c5727ec6491505c9 + languageName: node + linkType: hard + +"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin": + version: 1.22.9 + resolution: "resolve@patch:resolve@npm%3A1.22.9#optional!builtin::version=1.22.9&hash=c3c19d" + dependencies: + is-core-module: "npm:^2.16.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10c0/dadd8c85040784fdc18d6edc0cc27f7f35776c5d904b030ea67485ab9a5607568187afcfaf157e6fa9db9274481d155356bc42ca578c5578be25965b880d1e80 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe + languageName: node + linkType: hard + "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" @@ -3049,11 +4878,37 @@ __metadata: languageName: node linkType: hard +"rimraf@npm:^5.0.5": + version: 5.0.10 + resolution: "rimraf@npm:5.0.10" + dependencies: + glob: "npm:^10.3.7" + bin: + rimraf: dist/esm/bin.mjs + checksum: 10c0/7da4fd0e15118ee05b918359462cfa1e7fe4b1228c7765195a45b55576e8c15b95db513b8466ec89129666f4af45ad978a3057a02139afba1a63512a2d9644cc + languageName: node + linkType: hard + +"rollup@npm:^2.79.1": + version: 2.79.2 + resolution: "rollup@npm:2.79.2" + dependencies: + fsevents: "npm:~2.3.2" + dependenciesMeta: + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/bc3746c988d903c2211266ddc539379d53d92689b9cc5c2b4e3ae161689de9af491957a567c629b6cc81f48d0928a7591fc4c383fba68a48d2966c9fb8a2bce9 + languageName: node + linkType: hard + "root-workspace-0b6124@workspace:.": version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: "@agoric/cosmic-proto": "npm:dev" + "@agoric/fast-usdc": "npm:dev" "@cosmjs/crypto": "npm:^0.32.4" "@cosmjs/proto-signing": "npm:^0.32.4" "@cosmjs/stargate": "npm:^0.32.4" @@ -3094,7 +4949,14 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.0.0": +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 + languageName: node + linkType: hard + +"semver@npm:^6.0.0, semver@npm:^6.3.0": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -3193,6 +5055,24 @@ __metadata: languageName: node linkType: hard +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 10c0/62f7508e674414008910b5397c1811941d457dfa0db4fd5aa7fa0409eb02c3609608dfcd7508cace75b3a0bf67a2a77990711e32cd213d2c76f4fd12ee86d776 + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: "npm:^6.0.0" + once: "npm:^1.3.1" + simple-concat: "npm:^1.0.0" + checksum: 10c0/b0649a581dbca741babb960423248899203165769747142033479a7dc5e77d7b0fced0253c731cd57cf21e31e4d77c9157c3069f4448d558ebc96cf9e1eebcf0 + languageName: node + linkType: hard + "slash@npm:^2.0.0": version: 2.0.0 resolution: "slash@npm:2.0.0" @@ -3217,6 +5097,55 @@ __metadata: languageName: node linkType: hard +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: "npm:^7.1.2" + debug: "npm:^4.3.4" + socks: "npm:^2.8.3" + checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.3 + resolution: "socks@npm:2.8.3" + dependencies: + ip-address: "npm:^9.0.5" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 + languageName: node + linkType: hard + +"source-map-js@npm:^1.2.0": + version: 1.2.1 + resolution: "source-map-js@npm:1.2.1" + checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf + languageName: node + linkType: hard + +"source-map@npm:^0.5.0": + version: 0.5.7 + resolution: "source-map@npm:0.5.7" + checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599 + languageName: node + linkType: hard + +"sourcemap-codec@npm:^1.4.8": + version: 1.4.8 + resolution: "sourcemap-codec@npm:1.4.8" + checksum: 10c0/f099279fdaae070ff156df7414bbe39aad69cdd615454947ed3e19136bfdfcb4544952685ee73f56e17038f4578091e12b17b283ed8ac013882916594d95b9e6 + languageName: node + linkType: hard + "split-on-first@npm:^3.0.0": version: 3.0.0 resolution: "split-on-first@npm:3.0.0" @@ -3224,6 +5153,13 @@ __metadata: languageName: node linkType: hard +"sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec + languageName: node + linkType: hard + "sprintf-js@npm:~1.0.2": version: 1.0.3 resolution: "sprintf-js@npm:1.0.3" @@ -3231,6 +5167,15 @@ __metadata: languageName: node linkType: hard +"ssri@npm:^12.0.0": + version: 12.0.0 + resolution: "ssri@npm:12.0.0" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/caddd5f544b2006e88fa6b0124d8d7b28208b83c72d7672d5ade44d794525d23b540f3396108c4eb9280dcb7c01f0bef50682f5b4b2c34291f7c5e211fd1417d + languageName: node + linkType: hard + "stack-utils@npm:^2.0.6": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -3252,7 +5197,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -3263,6 +5208,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" + dependencies: + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca + languageName: node + linkType: hard + "string-width@npm:^7.0.0": version: 7.1.0 resolution: "string-width@npm:7.1.0" @@ -3283,7 +5239,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: @@ -3315,6 +5271,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + "supertap@npm:^3.0.1": version: 3.0.1 resolution: "supertap@npm:3.0.1" @@ -3336,6 +5299,13 @@ __metadata: languageName: node linkType: hard +"supports-preserve-symlinks-flag@npm:^1.0.0": + version: 1.0.0 + resolution: "supports-preserve-symlinks-flag@npm:1.0.0" + checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 + languageName: node + linkType: hard + "symbol-observable@npm:^2.0.3": version: 2.0.3 resolution: "symbol-observable@npm:2.0.3" @@ -3343,6 +5313,31 @@ __metadata: languageName: node linkType: hard +"tar-fs@npm:^2.0.0": + version: 2.1.1 + resolution: "tar-fs@npm:2.1.1" + dependencies: + chownr: "npm:^1.1.1" + mkdirp-classic: "npm:^0.5.2" + pump: "npm:^3.0.0" + tar-stream: "npm:^2.1.4" + checksum: 10c0/871d26a934bfb7beeae4c4d8a09689f530b565f79bd0cf489823ff0efa3705da01278160da10bb006d1a793fa0425cf316cec029b32a9159eacbeaff4965fb6d + languageName: node + linkType: hard + +"tar-stream@npm:^2.1.4": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + dependencies: + bl: "npm:^4.0.3" + end-of-stream: "npm:^1.4.1" + fs-constants: "npm:^1.0.0" + inherits: "npm:^2.0.3" + readable-stream: "npm:^3.1.1" + checksum: 10c0/2f4c910b3ee7196502e1ff015a7ba321ec6ea837667220d7bcb8d0852d51cb04b87f7ae471008a6fb8f5b1a1b5078f62f3a82d30c706f20ada1238ac797e7692 + languageName: node + linkType: hard + "tar@npm:^6.1.11": version: 6.2.1 resolution: "tar@npm:6.2.1" @@ -3357,6 +5352,20 @@ __metadata: languageName: node linkType: hard +"tar@npm:^7.4.3": + version: 7.4.3 + resolution: "tar@npm:7.4.3" + dependencies: + "@isaacs/fs-minipass": "npm:^4.0.0" + chownr: "npm:^3.0.0" + minipass: "npm:^7.1.2" + minizlib: "npm:^3.0.1" + mkdirp: "npm:^3.0.1" + yallist: "npm:^5.0.0" + checksum: 10c0/d4679609bb2a9b48eeaf84632b6d844128d2412b95b6de07d53d8ee8baf4ca0857c9331dfa510390a0727b550fd543d4d1a10995ad86cdf078423fbb8d99831d + languageName: node + linkType: hard + "temp-dir@npm:^3.0.0": version: 3.0.0 resolution: "temp-dir@npm:3.0.0" @@ -3387,6 +5396,13 @@ __metadata: languageName: node linkType: hard +"tmp@npm:^0.2.1": + version: 0.2.3 + resolution: "tmp@npm:0.2.3" + checksum: 10c0/3e809d9c2f46817475b452725c2aaa5d11985cf18d32a7a970ff25b568438e2c076c2e8609224feef3b7923fa9749b74428e3e634f6b8e520c534eef2fd24125 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -3412,7 +5428,7 @@ __metadata: languageName: node linkType: hard -"ts-blank-space@npm:^0.4.4": +"ts-blank-space@npm:^0.4.1, ts-blank-space@npm:^0.4.4": version: 0.4.4 resolution: "ts-blank-space@npm:0.4.4" dependencies: @@ -3421,6 +5437,22 @@ __metadata: languageName: node linkType: hard +"tslib@npm:2.7.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 + languageName: node + linkType: hard + +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: "npm:^5.0.1" + checksum: 10c0/4c7a1b813e7beae66fdbf567a65ec6d46313643753d0beefb3c7973d66fcec3a1e7f39759f0a0b4465883499c6dc8b0750ab8b287399af2e583823e40410a17a + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -3444,7 +5476,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:5.1.6 - 5.7.x, typescript@npm:~5.7.2": +"typescript@npm:5.1.6 - 5.7.x, typescript@npm:^5.4.5, typescript@npm:~5.7.2": version: 5.7.2 resolution: "typescript@npm:5.7.2" bin: @@ -3454,7 +5486,7 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A5.1.6 - 5.7.x#optional!builtin, typescript@patch:typescript@npm%3A~5.7.2#optional!builtin": +"typescript@patch:typescript@npm%3A5.1.6 - 5.7.x#optional!builtin, typescript@patch:typescript@npm%3A^5.4.5#optional!builtin, typescript@patch:typescript@npm%3A~5.7.2#optional!builtin": version: 5.7.2 resolution: "typescript@patch:typescript@npm%3A5.7.2#optional!builtin::version=5.7.2&hash=5786d5" bin: @@ -3478,6 +5510,24 @@ __metadata: languageName: node linkType: hard +"unique-filename@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-filename@npm:4.0.0" + dependencies: + unique-slug: "npm:^5.0.0" + checksum: 10c0/38ae681cceb1408ea0587b6b01e29b00eee3c84baee1e41fd5c16b9ed443b80fba90c40e0ba69627e30855570a34ba8b06702d4a35035d4b5e198bf5a64c9ddc + languageName: node + linkType: hard + +"unique-slug@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-slug@npm:5.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10c0/d324c5a44887bd7e105ce800fcf7533d43f29c48757ac410afd42975de82cc38ea2035c0483f4de82d186691bf3208ef35c644f73aa2b1b20b8e651be5afd293 + languageName: node + linkType: hard + "universalify@npm:^2.0.0": version: 2.0.1 resolution: "universalify@npm:2.0.1" @@ -3536,6 +5586,17 @@ __metadata: languageName: node linkType: hard +"which@npm:^5.0.0": + version: 5.0.0 + resolution: "which@npm:5.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10c0/e556e4cd8b7dbf5df52408c9a9dd5ac6518c8c5267c8953f5b0564073c66ed5bf9503b14d876d0e9c7844d4db9725fb0dcf45d6e911e17e26ab363dc3965ae7b + languageName: node + linkType: hard + "wide-align@npm:^1.1.2": version: 1.1.5 resolution: "wide-align@npm:1.1.5" @@ -3552,7 +5613,7 @@ __metadata: languageName: node linkType: hard -"wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: @@ -3563,6 +5624,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 + languageName: node + linkType: hard + "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" @@ -3580,6 +5652,21 @@ __metadata: languageName: node linkType: hard +"ws@npm:8.17.1": + version: 8.17.1 + resolution: "ws@npm:8.17.1" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ">=5.0.2" + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/f4a49064afae4500be772abdc2211c8518f39e1c959640457dcee15d4488628620625c783902a52af2dd02f68558da2868fd06e6fd0e67ebcd09e6881b1b5bfe + languageName: node + linkType: hard + "ws@npm:^7": version: 7.5.9 resolution: "ws@npm:7.5.9" @@ -3619,6 +5706,13 @@ __metadata: languageName: node linkType: hard +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 + languageName: node + linkType: hard + "yaml@npm:^2.2.2": version: 2.4.5 resolution: "yaml@npm:2.4.5" From b5698cee87068656cf6cfcbed25925d19fe025fd Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 18:10:44 -0800 Subject: [PATCH 20/65] feat: getValues for sequence nodes --- packages/internal/src/storage-test-utils.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index 143a6bbd444..b467220ae25 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -2,12 +2,12 @@ import { Fail } from '@endo/errors'; import { Far } from '@endo/far'; import { makeMarshal, Remotable } from '@endo/marshal'; -import { unmarshalFromVstorage } from './marshal.js'; import { makeTracer } from './debug.js'; +import { NonNullish } from './errors.js'; import { isStreamCell, makeChainStorageRoot } from './lib-chainStorage.js'; +import { unmarshalFromVstorage } from './marshal.js'; import { bindAllMethods } from './method-tools.js'; import { eventLoopIteration } from './testing-utils.js'; -import { NonNullish } from './errors.js'; /** * @import {TotalMap} from './types.js'; @@ -190,10 +190,24 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { }, ); const rootNode = makeChainStorageRoot(toStorage, rootPath, resolvedOptions); + + /** + * Get the values at a sequence node + * + * @param {string} path + * @returns {unknown[]} + */ + const getValues = path => { + assert(resolvedOptions.sequence); + const wrapper = JSON.parse(data.get(path)); + return wrapper.values; + }; + return { rootNode, // eslint-disable-next-line object-shorthand data: /** @type {Map} */ (data), + getValues, messages, toStorage, }; From fd09c056cf7c1168e5eee7525f0f385385c1c78b Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 Dec 2024 16:26:11 -0800 Subject: [PATCH 21/65] refactor: distinguish NFA address `sender` and `address` are ambiguous in FUC --- packages/fast-usdc/src/exos/settler.js | 34 +++++++------- packages/fast-usdc/src/exos/status-manager.js | 45 ++++++++++--------- .../test/exos/status-manager.test.ts | 2 +- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 931961c01b7..727e02bfbb0 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -143,7 +143,7 @@ export const prepareSettler = ( ); // given the sourceChannel check, we can be certain of this cast - const sender = /** @type {NobleAddress} */ (tx.sender); + const nfa = /** @type {NobleAddress} */ (tx.sender); if (tx.denom !== remoteDenom) { const { denom: actual } = tx; @@ -170,23 +170,23 @@ export const prepareSettler = ( const amount = BigInt(tx.amount); // TODO: what if this throws? const { self } = this.facets; - const found = statusManager.dequeueStatus(sender, amount); - log('dequeued', found, 'for', sender, amount); + const found = statusManager.dequeueStatus(nfa, amount); + log('dequeued', found, 'for', nfa, amount); switch (found?.status) { case PendingTxStatus.Advanced: - return self.disburse(found.txHash, sender, amount); + return self.disburse(found.txHash, nfa, amount); case PendingTxStatus.Advancing: - this.state.mintedEarly.add(makeMintedEarlyKey(sender, amount)); + this.state.mintedEarly.add(makeMintedEarlyKey(nfa, amount)); return; case PendingTxStatus.Observed: case PendingTxStatus.AdvanceFailed: - return self.forward(found.txHash, sender, amount, EUD); + return self.forward(found.txHash, nfa, amount, EUD); case undefined: default: - log('⚠️ tap: no status for ', sender, amount); + log('⚠️ tap: no status for ', nfa, amount); } }, }, @@ -231,10 +231,10 @@ export const prepareSettler = ( self: { /** * @param {EvmHash} txHash - * @param {NobleAddress} sender + * @param {NobleAddress} nfa * @param {NatValue} fullValue */ - async disburse(txHash, sender, fullValue) { + async disburse(txHash, nfa, fullValue) { const { repayer, settlementAccount } = this.state; const received = AmountMath.make(USDC, fullValue); const { zcfSeat: settlingSeat } = zcf.makeEmptySeatKit(); @@ -264,11 +264,11 @@ export const prepareSettler = ( }, /** * @param {EvmHash} txHash - * @param {NobleAddress} sender + * @param {NobleAddress} nfa * @param {NatValue} fullValue * @param {string} EUD */ - forward(txHash, sender, fullValue, EUD) { + forward(txHash, nfa, fullValue, EUD) { const { settlementAccount, intermediateRecipient } = this.state; const dest = chainHub.makeChainAddress(EUD); @@ -281,7 +281,7 @@ export const prepareSettler = ( ); void vowTools.watch(txfrV, this.facets.transferHandler, { txHash, - sender, + nfa, fullValue, }); }, @@ -293,13 +293,13 @@ export const prepareSettler = ( * * @typedef {{ * txHash: EvmHash; - * sender: NobleAddress; + * nfa: NobleAddress; * fullValue: NatValue; * }} SettlerTransferCtx */ onFulfilled(_result, ctx) { - const { txHash, sender, fullValue } = ctx; - statusManager.forwarded(txHash, sender, fullValue); + const { txHash, nfa, fullValue } = ctx; + statusManager.forwarded(txHash, nfa, fullValue); }, /** * @param {unknown} reason @@ -307,8 +307,8 @@ export const prepareSettler = ( */ onRejected(reason, ctx) { log('⚠️ transfer rejected!', reason, ctx); - // const { txHash, sender, amount } = ctx; - // TODO(#10510): statusManager.forwardFailed(txHash, sender, amount); + // const { txHash, nfa, amount } = ctx; + // TODO(#10510): statusManager.forwardFailed(txHash, nfa, amount); }, }, }, diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index ca17487e01b..b3cfebf151d 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -29,13 +29,13 @@ import { PendingTxStatus, TxStatus } from '../constants.js'; * * The key is a composite but not meant to be parsable. * - * @param {NobleAddress} addr + * @param {NobleAddress} nfa Noble Forwarding Account (implies EUD) * @param {bigint} amount * @returns {PendingTxKey} */ -const makePendingTxKey = (addr, amount) => +const makePendingTxKey = (nfa, amount) => // amount can't contain colon - `pendingTx:${amount}:${addr}`; + `pendingTx:${amount}:${nfa}`; /** * Get the key for the pendingTxs MapStore. @@ -86,7 +86,10 @@ export const prepareStatusManager = ( log = makeTracer('Advancer', true), } = /** @type {StatusManagerPowers} */ ({}), ) => { - /** @type {MapStore} */ + /** + * Keyed by a tuple of the Noble Forwarding Account and amount. + * @type {MapStore} + */ const pendingTxs = zone.mapStore('PendingTxs', { keyShape: M.string(), valueShape: M.arrayOf(PendingTxShape), @@ -134,15 +137,15 @@ export const prepareStatusManager = ( /** * Update the pending transaction status. * - * @param {{sender: NobleAddress, amount: bigint}} keyParts + * @param {{nfa: NobleAddress, amount: bigint}} keyParts * @param {PendingTxStatus} status */ - function setPendingTxStatus({ sender, amount }, status) { - const key = makePendingTxKey(sender, amount); - pendingTxs.has(key) || Fail`no advancing tx with ${{ sender, amount }}`; + function setPendingTxStatus({ nfa, amount }, status) { + const key = makePendingTxKey(nfa, amount); + pendingTxs.has(key) || Fail`no advancing tx with ${{ nfa, amount }}`; const pending = pendingTxs.get(key); const ix = pending.findIndex(tx => tx.status === PendingTxStatus.Advancing); - ix >= 0 || Fail`no advancing tx with ${{ sender, amount }}`; + ix >= 0 || Fail`no advancing tx with ${{ nfa, amount }}`; const [prefix, tx, suffix] = [ pending.slice(0, ix), pending[ix], @@ -197,14 +200,14 @@ export const prepareStatusManager = ( /** * Record result of ADVANCING * - * @param {NobleAddress} sender + * @param {NobleAddress} nfa Noble Forwarding Account * @param {import('@agoric/ertp').NatValue} amount * @param {boolean} success - Advanced vs. AdvanceFailed * @throws {Error} if nothing to advance */ - advanceOutcome(sender, amount, success) { + advanceOutcome(nfa, amount, success) { setPendingTxStatus( - { sender, amount }, + { nfa, amount }, success ? PendingTxStatus.Advanced : PendingTxStatus.AdvanceFailed, ); }, @@ -230,13 +233,13 @@ export const prepareStatusManager = ( /** * Remove and return an `ADVANCED` or `OBSERVED` tx waiting to be `SETTLED`. * - * @param {NobleAddress} address + * @param {NobleAddress} nfa * @param {bigint} amount * @returns {Pick | undefined} undefined if nothing * with this address and amount has been marked pending. */ - dequeueStatus(address, amount) { - const key = makePendingTxKey(address, amount); + dequeueStatus(nfa, amount) { + const key = makePendingTxKey(nfa, amount); if (!pendingTxs.has(key)) return undefined; const pending = pendingTxs.get(key); @@ -272,16 +275,16 @@ export const prepareStatusManager = ( * Mark a transaction as `FORWARDED` * * @param {EvmHash | undefined} txHash - undefined in case mint before observed - * @param {NobleAddress} address + * @param {NobleAddress} nfa * @param {bigint} amount */ - forwarded(txHash, address, amount) { + forwarded(txHash, nfa, amount) { if (txHash) { publishStatus(txHash, TxStatus.Forwarded); } else { // TODO store (early) `Minted` transactions to check against incoming evidence log( - `⚠️ Forwarded minted amount ${amount} from account ${address} before it was observed.`, + `⚠️ Forwarded minted amount ${amount} from account ${nfa} before it was observed.`, ); } }, @@ -291,12 +294,12 @@ export const prepareStatusManager = ( * * XXX only used in tests. should we remove? * - * @param {NobleAddress} address + * @param {NobleAddress} nfa * @param {bigint} amount * @returns {PendingTx[]} */ - lookupPending(address, amount) { - const key = makePendingTxKey(address, amount); + lookupPending(nfa, amount) { + const key = makePendingTxKey(nfa, amount); if (!pendingTxs.has(key)) { return harden([]); } diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 71757ea731a..5b61396fdc8 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -200,7 +200,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { const advanceOutcomeFn = () => statusManager.advanceOutcome(e1.tx.forwardingAddress, e1.tx.amount, true); const expectedErrMsg = - 'no advancing tx with {"amount":"[150000000n]","sender":"noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelqkd"}'; + 'no advancing tx with {"amount":"[150000000n]","nfa":"noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelqkd"}'; t.throws(advanceOutcomeFn, { message: expectedErrMsg, From 71b185924d945aafae31c28c28f6826610123b7c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 17:28:21 -0800 Subject: [PATCH 22/65] test: trace logger --- .../test/fast-usdc/fast-usdc.test.ts | 14 +++++++++++--- multichain-testing/tools/e2e-tools.js | 17 +++++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 92b493fdccd..3589f4b7bb3 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -13,6 +13,9 @@ import { commonSetup, type SetupContextWithWallets } from '../support.js'; import { makeFeedPolicy, oracleMnemonics } from './config.js'; import { makeRandomDigits } from '../../tools/random.js'; import { balancesFromPurses } from '../../tools/purse.js'; +import { makeTracer } from '@agoric/internal'; + +const log = makeTracer('MCFU'); const { keys, values, fromEntries } = Object; const { isGTE, isEmpty, make } = AmountMath; @@ -153,6 +156,7 @@ test.serial('oracles accept', async t => { return offerToUsedInvitation[0][0] === `${name}-accept`; }, `${name} invitation used`, + { log }, ), ); } @@ -191,6 +195,7 @@ test.serial('lp deposits', async t => { ({ shareWorth }) => !isGTE(currShareWorth.numerator, shareWorth.numerator), 'share worth numerator increases from deposit', + { log }, ), ); @@ -203,6 +208,7 @@ test.serial('lp deposits', async t => { return currentPoolShares && isGTE(currentPoolShares, poolSharesWanted); }, 'lp has pool shares', + { log }, ), ); }); @@ -267,7 +273,7 @@ const advanceAndSettleScenario = test.macro({ chainId: 42161, }); - console.log('User initiates evm mint:', evidence.txHash); + log('User initiates evm mint:', evidence.txHash); // submit evidences await Promise.all( @@ -309,7 +315,7 @@ const advanceAndSettleScenario = test.macro({ retryUntilCondition( () => queryTxStatus(), txStatus => { - console.log('tx status', txStatus); + log('tx status', txStatus); return txStatus === status; }, `${evidence.txHash} is ${status}`, @@ -317,7 +323,7 @@ const advanceAndSettleScenario = test.macro({ ); await assertTxStatus('ADVANCED'); - console.log('Advance completed, waiting for mint...'); + log('Advance completed, waiting for mint...'); nobleTools.mockCctpMint(mintAmt, userForwardingAddr); await t.notThrowsAsync(() => @@ -393,6 +399,7 @@ test.serial('lp withdraws', async t => { return !currentPoolShares || isEmpty(currentPoolShares); }, 'lp no longer has pool shares', + { log }, ), ); @@ -404,6 +411,7 @@ test.serial('lp withdraws', async t => { BigInt(balance.amount) - BigInt(currentUSDCBalance!.amount!) > LP_DEPOSIT_AMOUNT, "lp's USDC balance increases", + { log }, ), ); }); diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js index 4710761e014..6074a5e1261 100644 --- a/multichain-testing/tools/e2e-tools.js +++ b/multichain-testing/tools/e2e-tools.js @@ -9,12 +9,16 @@ import { makeHttpClient, makeAPI } from './makeHttpClient.js'; import { dedup, makeQueryKit, poll } from './queryKit.js'; import { makeVStorage } from './batchQuery.js'; import { makeRetryUntilCondition } from './sleep.js'; +import { makeTracer } from '@agoric/internal'; /** + * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js'; * @import { EnglishMnemonic } from '@cosmjs/crypto'; * @import { RetryUntilCondition } from './sleep.js'; */ +const trace = makeTracer('E2ET'); + const BLD = '000000ubld'; export const txAbbr = tx => { @@ -223,7 +227,7 @@ export const provisionSmartWallet = async ( const txInfo = await sendAction({ method: 'executeOffer', offer }); console.debug('spendAction', txInfo); for await (const update of updates) { - // console.log('update', address, update); + trace('update', address, update); if (update.updated !== 'offerStatus' || update.status.id !== offer.id) { continue; } @@ -355,7 +359,7 @@ const voteLatestProposalAndWait = async ({ await blockTool.waitForBlock(1, { step: `voting`, on: lastProposalId }) ) { info = await agd.query(['gov', 'proposal', lastProposalId]); - console.log( + trace( `Waiting for proposal ${lastProposalId} to pass (status=${info.status})`, ); } @@ -398,7 +402,7 @@ const runCoreEval = async ( const evalPaths = evals.map(e => [e.permit, e.code]).flat(); log(evalPaths); - console.log('await tx', evalPaths); + trace('await tx', evalPaths); const result = await agd.tx( [ 'gov', @@ -413,7 +417,7 @@ const runCoreEval = async ( // FIXME TypeError#1: unrecognized details 0 // assert(result.code, 0); - console.log('await voteLatestProposalAndWait', evalPaths); + trace('await voteLatestProposalAndWait', evalPaths); const detail = await voteLatestProposalAndWait({ agd, blockTool }); log(detail.proposal_id, detail.voting_end_time, detail.status); @@ -462,7 +466,7 @@ export const makeE2ETools = async ( if (typeof info === 'object' && Object.keys(info).length > 0) { // XXX normally we have the caller pass in the log function // later, but the way blockTool is factored, we have to supply it early. - console.log({ ...info, delay: ms / 1000 }, '...'); + trace({ ...info, delay: ms / 1000 }, '...'); } return delay(ms); }; @@ -605,8 +609,9 @@ export const seatLike = updates => { }); }; -/** @param {Awaited>} wallet */ +/** @param {Awaited>} wallet */ export const makeDoOffer = wallet => { + /** @type {(offer: OfferSpec) => Promise} */ const doOffer = async offer => { const updates = wallet.offers.executeOffer(offer); // const seat = seatLike(updates); From fd05a7ecd0fc2847380506d2a90fe79079511457 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 13 Dec 2024 16:16:31 -0800 Subject: [PATCH 23/65] feat: simplify seenTxs key - no need to support legacy Ethereum txs that do not include chain id in the tx envelope --- packages/fast-usdc/src/exos/status-manager.js | 32 ++++--------------- .../test/exos/status-manager.test.ts | 6 ++-- 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index b3cfebf151d..84b5766d0b0 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -19,9 +19,6 @@ import { PendingTxStatus, TxStatus } from '../constants.js'; /** * @typedef {`pendingTx:${bigint}:${NobleAddress}`} PendingTxKey * The string template is for developer visibility but not meant to ever be parsed. - * - * @typedef {`seenTx:${string}:${EvmHash}`} SeenTxKey - * The string template is for developer visibility but not meant to ever be parsed. */ /** @@ -48,20 +45,6 @@ const pendingTxKeyOf = evidence => { return makePendingTxKey(forwardingAddress, amount); }; -/** - * Get the key for the seenTxs SetStore. - * - * The key is a composite but not meant to be parsable. - * - * @param {CctpTxEvidence} evidence - * @returns {SeenTxKey} - */ -const seenTxKeyOf = evidence => { - const { txHash, chainId } = evidence; - // chainId can't contain colon - return `seenTx:${chainId}:${txHash}`; -}; - /** * @typedef {{ * log?: LogFn; @@ -95,7 +78,7 @@ export const prepareStatusManager = ( valueShape: M.arrayOf(PendingTxShape), }); - /** @type {SetStore} */ + /** @type {SetStore} */ const seenTxs = zone.setStore('SeenTxs', { keyShape: M.string(), }); @@ -120,18 +103,18 @@ export const prepareStatusManager = ( * @param {PendingTxStatus} status */ const initPendingTx = (evidence, status) => { - const seenKey = seenTxKeyOf(evidence); - if (seenTxs.has(seenKey)) { - throw makeError(`Transaction already seen: ${q(seenKey)}`); + const { txHash } = evidence; + if (seenTxs.has(txHash)) { + throw makeError(`Transaction already seen: ${q(txHash)}`); } - seenTxs.add(seenKey); + seenTxs.add(txHash); appendToStoredArray( pendingTxs, pendingTxKeyOf(evidence), harden({ ...evidence, status }), ); - publishStatus(evidence.txHash, status); + publishStatus(txHash, status); }; /** @@ -226,8 +209,7 @@ export const prepareStatusManager = ( * @param {CctpTxEvidence} evidence */ hasBeenObserved(evidence) { - const seenKey = seenTxKeyOf(evidence); - return seenTxs.has(seenKey); + return seenTxs.has(evidence.txHash); }, /** diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 5b61396fdc8..969af7530d5 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -106,18 +106,16 @@ test('cannot process same tx twice', t => { t.throws(() => statusManager.advance(evidence), { message: - 'Transaction already seen: "seenTx:1:0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702"', + 'Transaction already seen: "0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702"', }); t.throws(() => statusManager.observe(evidence), { message: - 'Transaction already seen: "seenTx:1:0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702"', + 'Transaction already seen: "0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702"', }); // new txHash should not throw t.notThrows(() => statusManager.advance({ ...evidence, txHash: '0xtest2' })); - // new chainId with existing txHash should not throw - t.notThrows(() => statusManager.advance({ ...evidence, chainId: 9999 })); }); test('isSeen checks if a tx has been processed', t => { From 6df7f1fa33bc0ac3f979663db97859c90af94e6c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 12:24:39 -0800 Subject: [PATCH 24/65] feat: pureDataMarshaller --- packages/internal/src/index.js | 1 + packages/internal/src/marshal.js | 7 +++++++ .../internal/test/snapshots/exports.test.js.md | 1 + .../test/snapshots/exports.test.js.snap | Bin 642 -> 674 bytes 4 files changed, 9 insertions(+) diff --git a/packages/internal/src/index.js b/packages/internal/src/index.js index d241d8f6ece..662e273110d 100644 --- a/packages/internal/src/index.js +++ b/packages/internal/src/index.js @@ -6,6 +6,7 @@ export * from './config.js'; export * from './debug.js'; export * from './errors.js'; export * from './js-utils.js'; +export { pureDataMarshaller } from './marshal.js'; export * from './method-tools.js'; export * from './ses-utils.js'; export * from './typeCheck.js'; diff --git a/packages/internal/src/marshal.js b/packages/internal/src/marshal.js index 3750b910ad2..ebfaa33d9e6 100644 --- a/packages/internal/src/marshal.js +++ b/packages/internal/src/marshal.js @@ -135,3 +135,10 @@ export const makeHistoryReviver = (entries, slotToVal = undefined) => { return harden({ getItem, children, has }); }; + +/** @param {import('@endo/marshal').CapData} cap */ +const rejectOCap = cap => Fail`${cap} is not pure data`; +export const pureDataMarshaller = makeMarshal(rejectOCap, rejectOCap, { + serializeBodyFormat: 'smallcaps', +}); +harden(pureDataMarshaller); diff --git a/packages/internal/test/snapshots/exports.test.js.md b/packages/internal/test/snapshots/exports.test.js.md index 9da2a6a2453..de3a330db68 100644 --- a/packages/internal/test/snapshots/exports.test.js.md +++ b/packages/internal/test/snapshots/exports.test.js.md @@ -34,6 +34,7 @@ Generated by [AVA](https://avajs.dev). 'mustMatch', 'objectMap', 'objectMetaMap', + 'pureDataMarshaller', 'synchronizedTee', 'untilTrue', 'whileTrue', diff --git a/packages/internal/test/snapshots/exports.test.js.snap b/packages/internal/test/snapshots/exports.test.js.snap index 730293f20f65d419bc68ec17f2329e4c7b2a7f63..8f11be2dad60ab382bc90db406fc1e6d8dbf281c 100644 GIT binary patch literal 674 zcmV;T0$u$j5099kZkURIN8$iCW}y<&3F^2^ z`%MzmfFFwp00000000ARlFL#PK@^7no*6>GU{!lHC5kNr~h*~8x5sS5AEqWIpHLcP#L`! zR`Jpn+S${yEaQ&9NseO7V*0Tsj|N?{AnV$YWLj2;V19VvIsmND8`?^p6EPCcDbzu+Z#Vs%dn(o|QszUESr>+x}@UH7cb^W0F*9SzK6TPQBlEtn&VO) za9L4EKOeGjYst8dl$$gXio$$udE@p_sH`Jpmt3K)KUQuepD=(X9AHgrVBgO&%ak28O5C zLGOg+j4SK9+@<0CRs+(%o9^<`qq|{xSBMegdCVEpoak+7edla^e9~9v2evEjmQ|vHY9OXg?x{_6rYIl7lN6% I!k`2I09e&PBme*a literal 642 zcmV-|0)72KRzVK}^;00000000ARlFe=tF%ZYs`DoITHcgXKzPa)WT#(YxiWZV0B`xBHv!3jl zIQC+DDccLGxbYB(a_C#2J^=5)fdk?dxG{lxS`d+bO0>U!yffoDnT(Z*r|$R@cYW5(Une=Y0>mRw8Q7hWSO|&6!6w(! zZXBCj`(SHS;WMrj_yM2M+4bPsJV`7h+{4Hg+frk)2%*IgTEwRZT;)L3FHvpWIj|lZ zdl>vV(j%*gWiqR^{!IkVjPKKC)L-v%l3 zyJ;L!P}gXB=L$T(q^}3vbcK#nYqUH9F#?+Y4LTYZO{$U2N!=uMm`Vkg)h*h#L+Mjo c6tEUVPXX6Cz58|um5*fh3u#!MhIj-306N?^^#A|> From 01315f10d11239e131a50eea9b53dbf7501252f4 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 12:33:02 -0800 Subject: [PATCH 25/65] test: getPureData helper --- packages/fast-usdc/test/supports.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 7106b0e948a..83f4f979013 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -24,7 +24,10 @@ import { makeWellKnownSpaces } from '@agoric/vats/src/core/utils.js'; import { prepareLocalChainTools } from '@agoric/vats/src/localchain.js'; import { prepareTransferTools } from '@agoric/vats/src/transfer.js'; import { makeFakeBankManagerKit } from '@agoric/vats/tools/bank-utils.js'; -import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js'; +import { + makeFakeBoard, + pureDataMarshaller, +} from '@agoric/vats/tools/board-utils.js'; import { makeFakeLocalchainBridge, makeFakeTransferBridge, @@ -37,6 +40,7 @@ import { makeHeapZone, type Zone } from '@agoric/zone'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { E } from '@endo/far'; import type { ExecutionContext } from 'ava'; +import type { PureData } from '@endo/pass-style'; import { makeTestFeeConfig } from './mocks.js'; export { @@ -44,6 +48,9 @@ export { makeFakeTransferBridge, } from '@agoric/vats/tools/fake-bridge.js'; +const unserializePureData = data => + pureDataMarshaller.fromCapData(JSON.parse(data)); + const assetOn = ( baseDenom: Denom, baseName: string, @@ -152,6 +159,12 @@ export const commonSetup = async (t: ExecutionContext) => { const storage = makeFakeStorageKit('mockChainStorageRoot', { sequence: false, }); + /** + * Read pure data (CapData that has no slots) from the storage path + * @param path + */ + storage.getPureData = (path: string): PureData => + storage.getValues(path).map(unserializePureData); const { portAllocator, setupIBCProtocol, ibcBridge } = setupFakeNetwork( rootZone.subZone('network'), From ebdb5e94e05ad6aa134bc58c767f59ea9085f0ca Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 13:51:54 -0800 Subject: [PATCH 26/65] test: provide smartWalletKit --- multichain-testing/tools/e2e-tools.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js index 6074a5e1261..448f8b81895 100644 --- a/multichain-testing/tools/e2e-tools.js +++ b/multichain-testing/tools/e2e-tools.js @@ -1,5 +1,6 @@ // @ts-check /** global harden */ +import { makeSmartWalletKit, LOCAL_CONFIG } from '@agoric/client-utils'; import { assert } from '@endo/errors'; import { E, Far } from '@endo/far'; import { Nat } from '@endo/nat'; @@ -432,6 +433,8 @@ const runCoreEval = async ( }; /** + * @deprecated use `@agoric/client-utils` instead + * * @param {typeof console.log} log * @param {import('@agoric/swingset-vat/tools/bundleTool.js').BundleCache} bundleCache * @param {object} io @@ -535,10 +538,23 @@ export const makeE2ETools = async ( const copyFiles = makeCopyFiles({ execFileSync, log }); + /** + * @deprecated use `@agoric/client-utils` instead + */ const vstorageClient = makeQueryKit(vstorage).query; + /** @type {import('@agoric/client-utils').SmartWalletKit} */ + const smartWalletKit = await makeSmartWalletKit( + { + fetch, + delay, + }, + LOCAL_CONFIG, + ); + return { vstorageClient, + smartWalletKit, installBundles, runCoreEval: buildAndRunCoreEval, /** From f99e7b8152fe686a100618b9cdfa4a8ced156dd2 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 18:27:08 -0800 Subject: [PATCH 27/65] feat: include 'sender' in CctpTxEvidence --- multichain-testing/test/fast-usdc/fast-usdc.test.ts | 1 + packages/fast-usdc/src/cli/operator-commands.js | 4 +++- packages/fast-usdc/src/type-guards.js | 12 ++++++++++-- packages/fast-usdc/src/types.ts | 2 ++ packages/fast-usdc/test/fixtures.ts | 10 +++++++++- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 3589f4b7bb3..5a131e58335 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -265,6 +265,7 @@ const advanceAndSettleScenario = test.macro({ tx: { amount: mintAmt, forwardingAddress: userForwardingAddr, + sender: '0x9a9eE9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9', }, aux: { forwardingChannel: nobleAgoricChannelId, diff --git a/packages/fast-usdc/src/cli/operator-commands.js b/packages/fast-usdc/src/cli/operator-commands.js index 8f849f760db..6a4db0a1c98 100644 --- a/packages/fast-usdc/src/cli/operator-commands.js +++ b/packages/fast-usdc/src/cli/operator-commands.js @@ -99,6 +99,7 @@ export const addOperatorCommands = ( .requiredOption('--chainId ', 'chain id', Number) .requiredOption('--amount ', 'number', parseNat) .requiredOption('--forwardingAddress ', 'bech32 address', String) + .requiredOption('--sender ', 'Ethereum address initiating', String) .requiredOption('--txHash <0xhexo>', 'hex hash', parseHex) .option('--offerId ', 'Offer id', String, `operatorAttest-${now()}`) .action(async opts => { @@ -109,12 +110,13 @@ export const addOperatorCommands = ( recipientAddress, amount, forwardingAddress, + sender, ...flat } = opts; const evidence = harden({ aux: { forwardingChannel, recipientAddress }, - tx: { amount, forwardingAddress }, + tx: { amount, forwardingAddress, sender }, ...flat, }); mustMatch(evidence, CctpTxEvidenceShape); diff --git a/packages/fast-usdc/src/type-guards.js b/packages/fast-usdc/src/type-guards.js index 5281521ef12..05215f43886 100644 --- a/packages/fast-usdc/src/type-guards.js +++ b/packages/fast-usdc/src/type-guards.js @@ -6,7 +6,7 @@ import { PendingTxStatus } from './constants.js'; * @import {TypedPattern} from '@agoric/internal'; * @import {FastUsdcTerms} from './fast-usdc.contract.js'; * @import {USDCProposalShapes} from './pool-share-math.js'; - * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook} from './types.js'; + * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook, EvmAddress, EvmHash} from './types.js'; */ /** @@ -36,7 +36,14 @@ export const FastUSDCTermsShape = harden({ usdcDenom: M.string(), }); -/** @type {TypedPattern} */ +/** @type {TypedPattern} */ +export const EvmAddressShape = M.string({ + // 0x + 40 hex digits + stringLengthLimit: 42, +}); +harden(EvmAddressShape); + +/** @type {TypedPattern} */ export const EvmHashShape = M.string({ stringLengthLimit: 66, }); @@ -54,6 +61,7 @@ export const CctpTxEvidenceShape = { tx: { amount: M.nat(), forwardingAddress: M.string(), + sender: EvmAddressShape, }, txHash: EvmHashShape, }; diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index 30dd64acbbc..35bbf84da1f 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -11,6 +11,7 @@ import type { PendingTxStatus } from './constants.js'; import type { FastUsdcTerms } from './fast-usdc.contract.js'; export type EvmHash = `0x${string}`; +export type EvmAddress = `0x${string & { length: 40 }}`; export type NobleAddress = `noble1${string}`; export type EvmChainID = number; export type EvmChainName = string; @@ -28,6 +29,7 @@ export interface CctpTxEvidence { tx: { amount: bigint; forwardingAddress: NobleAddress; + sender: EvmAddress; }; txHash: EvmHash; } diff --git a/packages/fast-usdc/test/fixtures.ts b/packages/fast-usdc/test/fixtures.ts index 7ffcedafb73..35ec0c231e2 100644 --- a/packages/fast-usdc/test/fixtures.ts +++ b/packages/fast-usdc/test/fixtures.ts @@ -3,7 +3,7 @@ import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import type { ChainAddress } from '@agoric/orchestration'; import type { VTransferIBCEvent } from '@agoric/vats'; -import type { CctpTxEvidence } from '../src/types.js'; +import type { CctpTxEvidence, EvmAddress } from '../src/types.js'; const mockScenarios = [ 'AGORIC_PLUS_OSMO', @@ -14,6 +14,10 @@ const mockScenarios = [ type MockScenario = (typeof mockScenarios)[number]; +export const Senders = { + default: '0xDefaultFakeEthereumAddress', +} as unknown as Record; + export const MockCctpTxEvidences: Record< MockScenario, (receiverAddress?: string) => CctpTxEvidence @@ -27,6 +31,7 @@ export const MockCctpTxEvidences: Record< tx: { amount: 150000000n, forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelqkd', + sender: Senders.default, }, aux: { forwardingChannel: 'channel-21', @@ -48,6 +53,7 @@ export const MockCctpTxEvidences: Record< tx: { amount: 300000000n, forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelktz', + sender: Senders.default, }, aux: { forwardingChannel: 'channel-21', @@ -69,6 +75,7 @@ export const MockCctpTxEvidences: Record< tx: { amount: 200000000n, forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelyyy', + sender: Senders.default, }, aux: { forwardingChannel: 'channel-21', @@ -87,6 +94,7 @@ export const MockCctpTxEvidences: Record< tx: { amount: 200000000n, forwardingAddress: 'noble1x0ydg69dh6fqvr27xjvp6maqmrldam6yfelyyy', + sender: Senders.default, }, aux: { forwardingChannel: 'channel-21', From aebb4d792317f6964a8150324548b69cec2eb505 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 5 Dec 2024 16:49:00 -0800 Subject: [PATCH 28/65] feat: vstorage status --> txns --- .../test/fast-usdc/fast-usdc.test.ts | 2 +- .../boot/test/fast-usdc/fast-usdc.test.ts | 4 +- .../fast-usdc/snapshots/fast-usdc.test.ts.md | 4 +- .../snapshots/fast-usdc.test.ts.snap | Bin 2198 -> 2193 bytes packages/fast-usdc/src/fast-usdc.contract.js | 9 ++-- packages/fast-usdc/test/exos/advancer.test.ts | 12 +++--- packages/fast-usdc/test/exos/settler.test.ts | 6 +-- .../test/exos/status-manager.test.ts | 39 +++++++++--------- 8 files changed, 39 insertions(+), 37 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 5a131e58335..dc77ee172de 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -308,7 +308,7 @@ const advanceAndSettleScenario = test.macro({ const queryTxStatus = async () => vstorageClient.queryData( - `published.${contractName}.status.${evidence.txHash}`, + `published.${contractName}.txns.${evidence.txHash}`, ); const assertTxStatus = async (status: string) => diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index 6eae95b9ad2..32f3d23354b 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -256,8 +256,8 @@ test.serial('makes usdc advance', async t => { harness?.resetRunPolicy(); const doc = { - node: `fastUsdc.status`, - owner: `the statuses of fast USDC transfers identified by their tx hashes`, + node: `fastUsdc.txns`, + owner: `the Ethereum transactions upon which Fast USDC is acting`, }; await documentStorageSchema(t, storage, doc); }); diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md index f27a41da2c4..f83e7fc388f 100644 --- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md +++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md @@ -161,14 +161,14 @@ Generated by [AVA](https://avajs.dev). ## makes usdc advance -> Under "published", the "fastUsdc.status" node is delegated to the statuses of fast USDC transfers identified by their tx hashes. +> Under "published", the "fastUsdc.txns" node is delegated to the Ethereum transactions upon which Fast USDC is acting. > The example below illustrates the schema of the data published there. > > See also board marshalling conventions (_to appear_). [ [ - 'published.fastUsdc.status.0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', + 'published.fastUsdc.txns.0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', 'ADVANCING', ], ] diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap index 4647d12715fa8bbddbe4a9e3641aa8f369ea9e3a..577839a970dd27509899f00d143c4d6dde03da81 100644 GIT binary patch literal 2193 zcmV;C2yXX5RzVGE^H74iJHDdn zf9H2dKp%?;00000000BsSZ#6=_S(&d}`H+)C( zfR;J8Xwy$Lt8gdqSUso;8C<_<+f1^LYOm-RNBBpQM4JJS1+bTlO_M~y z_t_R9?Wa9^_JE{72*?B>A80%29KafYuf!a+xT6NL8+(a{eMARIOp^!ejgspGRc_Cf zSs*V4wlx=KepV%}rnwbPLc)2BUjz6ZfHwimlh#~gPn523OA@{FI5jl|GKp}C`v|!} z(3x)1sxrq@!5toe>NVqGSB1gDZ6bBMJvCQGqYx%vvSTnkYrYfJ=pw2C)>{!hfbHaubzQUel zfutADuM|}a&ZRC?Ipv$IR(ClqaaU|m$8{Tl^jX-Zp+{gigq@8@jA)n8s zQs+6R%nbxB3Fh0h#{8hlT-Wg`)Dqr0_tf&~q03TGR~LBzRJ%PEX}8^$@TAWyd5%f0 ztm_f0QFfVBqc6E(JZiTMsIxlNa!MFXz4EX{yPqW_BkZxP^K@!pNmL6Yb>4R}NY z&c&h09%w@Yu4=$Dap2O98d9GdDWkfzr2Pc5=on|q?>cuWdk8L7T)+~qZD z+;5sX-j789iIUGeJJz;|b>=p>`bBn=gqg`?G7+H z-rCoVk?N+I(UQG9nls5pe1AEbuWoj|tlx|{vk8*yF38w4*;{a3Ug7r9CjF`~J@pU& zx5VKOZ$})Ov@<{(wmG%oD-BXg&{2VVLjVr61fVX2OKV*Ejui}+fW)P{CIMd^SpxR= zk$^Du$D5g}dA`vRf$`S?ya8Yr0p3f1A_2+-czU=PjH%D>W`w(^xo0(MCGK1=qg=Fq=;rn7EP}YMHBAr&&VoPpLa^8fTi9jY5uf7fRlcPG-_n2|4Of=eHQ)^m(BsrL)&t$I0}tuIBXMY|2l|u_d{PHC z;?Q0?drk+w*5cPebe1IguXNzII`G#xbaDsgyKh7aiPF!qF+eM9V~Ey$@eXEw_6~fX zzXRVJqx&X%1NgH6ATf9sGX;|9_rJ5K1BsDUq~m*b zbl+sp_UwU9LBjq$AF@QytwV{H_Pjb&dm?HI zd`GW9s&(D3HCNlu=TIL}W$L!WEVDI!x>#r(+Et`u10o%MyOB&4YHdKMeiuOMLdBFk zkjniztu6F=sBu5h0K`Q>?;(|AI&e}4%EPzu*L2`>I`Bdq+I!%7Ne6zY18>EtYNDSi zb@9hU*wBS$FSN(*-=Y3pj?)2`(&aVo$(Z{)cPe_H>5Y=Gx7t7SgXy$ly?tX5)(c!A zgAtrFqdRK{w1ZdEuCSQf$~Jv8J@1sP*}CxMykjwS6c?_`{aJHf_;$Dto4>l6Ugv(` z2yZogbT#c*L3U}@Tuslcrnm7$;d$H&8R?X*U{+^fb}6gCRT0QRup=1-YcZ9wZhwr* z#63&cj#p8(x-XtLbZMd9CZi`SvxUnVw1eye1@% z)uAft^IeH|RVQ4)|8-TasW0nvpD!!fMUi9OT-s&ZHNdtzVrxqA7I|ry77x_ll_G6l zAI+sGrSy!D{3z|iYaeSia>24>_|iW<(-+jDi55gf46hygK^;$Wzs7Bc$?d3=`8*=! zr7e1_NfYzJx2jz20UY6}!0Qg94{tcK`b5<9u$u6Y>e5eJBB+Vr@NDQj+miCxHAl`} z37X5j7xo%{jji#3HUitC%w7)MRa z&M1YIONBGVQ)eD+?KS@~bgvnvGT@5ignCDf8kIit0%kSeM58V|x>0qkYUIw_3HN)_ T@hbn@J?MV{5xNl^7aITo-Z@PM literal 2198 zcmV;H2x<30RzVOlNz##;%&pE-_$~`z0tIc&O(OlZyz#A>t3=L{Ja}PX+Zj&*Owc z6(x2>6x9mApwK)W9Y8;dEa{L?W*UgsvDKE$L)3T^i3vR>9NiIR{~cu zVOAJ(%m(*dd&`vE+z^rnw8~uJ(}t*VDX!mi94hHYwU>2FBK(mg(dGbT0qi9cvm{Xr z0=h*==V{NLJs>F%0y0I&2RcqV1F#O@YcWSH?x=z6#$KXfAJIV)v*f`>v+TK|#+-!; z74m{`?1eD%Gb(Y_&8@H#682;K7QpWTyaiy9wELQPvV57@lIY#XnVA`oX@p(eN62}C zZg-H?lJ+gCrqYe+~@PM$BI=RxOS;VeV=(JosKbOw_4`2R?KZ$xvla#b^SKp zAciXDRRUa(=V|oiNmQQCMeXUT}tAFnn;`O(=UvYyvl`i*1yZ##UXqkDN|GD5hEHKmEX_lTd zWsRBX0kbV_`rKirD@=!ZtQyuTTsa}U%6t}3&!oO%s(j`}gV}DywOdQf4Hp~_6!rua z(!6kPwWOBdLh5{tnQW8R8y+*u%;Q%~*Ylb}1~gozp@*<*tWHf{QE%a*G`snRO#xd- zrOq*CQcrNR%xU15bsC5o^*qhTGwKz1@S0GJ|=bu_+unzNi-Sw&DfijxUuvO0VK)+^_|$VO>9uF$t07`MUslFZ@1GsDe*W=LL zJAAco8e`Q>v!W$?X*_3=jrjh0JYU`F`B=Xjvu6t=*;|l_S+ck2d92Euqb>SXVfyMH z{

9k8ejDTC_7n8@4&M87K`>O3+n-dqV&Yv<0BSxo6gy3|w0bmw?2@yCwl&A6o+U z50HQ`^(R`HtA4)K6@ke&0K5rc7XjW&fD!>J1bBM17)+??cQeA>v&^@f^)d^XbDVnA zw_Ei7%LpVTYBXR^@j%v;?X4*FOD?H*oCg8FB9!%Dgh*$VwbYiI6O6SWrz4PQ1v$gH z*EMfNsaToMvIgA}s>-)C;5!=dlhMlZh6cQ;0eYO;CiJZ#cq9%@^+7+T1E11? zD{*K)ojt1q-)QseFgi;T{Wm)Bst)`u4xQeC`R*H&LZbAuVhqs=#~7h?U%G>yzj6n@ z&)tFVjq!bxeR8-X;UOf*_73un( z8Q(YAw>^8HTaa-5o(ow*^y*Netv#=e)Sd|6?VvuP##}g8GEcdmZn};ux57?Mw#n}e z&3UM;In=g!)0ZY~9SPY8;hCsKgeOq|@Ie3{0&ot%Cr62pp~S&$1(+h_nYK(!5%RjX$?y};B+ zfqX~5K&o-wueC-y$mh@iQKjm(!>Z7AcB)itAKF!5D*s6iJ%>O#em zOi1Patkw~FJ=D0LX#nD)p!bo=F&#Le1C`O+_-i`wc^!B@4(&g1y{H2})`8n`s+t<4 zN{a`w+Sa07%g!P2S zr5M9GGrqHSKs$If?QxrW?QGLW(~EA|o^S9#F1j{VM{(|XESR?zdEkWmu*Iuu=?xYL zm-}n!qibo`7TM)_Yb`yumfpsfxbHJNWTcahg4x}M`Q@wv*SL_wU`H|v)@CYY-JXof z#C)4Ou3uHQM!+RsQtfi{{8odhR^hB)sy999UaE`gTKbwAUiX> zb*S;iVo%~d)d>gie_fSpYG$1pFtd_96gkn$r9HM?Lu|Vvww4rckrzj4@lgF;Et#F` zqlJ`dn&xRP*->)9AJ%G!76?ns?=EGN9S$i^SdRTRMNUhS(*j&`PI6NOZ&$p#~e%+M| zmqly1_rhKysMB>O%%*T`lR6vWp{;LY@sWSrwFB*|V;^YO27Eptscedc%%)wi%68t$ z { marshaller, ); - const statusNode = E(storageNode).makeChildNode(STATUS_NODE); - const statusManager = prepareStatusManager(zone, statusNode); + const statusManager = prepareStatusManager( + zone, + E(storageNode).makeChildNode(TXNS_NODE), + ); const { USDC } = terms.brands; const { withdrawToSeat } = tools.zoeTools; diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index b91e52485a9..1f09fbc8484 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -48,7 +48,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const statusManager = prepareStatusManager( rootZone.subZone('status-manager'), - storageNode.makeChildNode('status'), + storageNode.makeChildNode('transactions'), ); const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { @@ -185,7 +185,7 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.status.${mockEvidence.txHash}`), + storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), PendingTxStatus.Advancing, 'ADVANCED status in happy path', ); @@ -259,7 +259,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.status.${mockEvidence.txHash}`), + storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'OBSERVED status on insufficient pool funds', ); @@ -288,7 +288,7 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`mockChainStorageRoot.status.${mockEvidence.txHash}`), + storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'OBSERVED status on makeChainAddress failure', ); @@ -321,7 +321,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.status.${mockEvidence.txHash}`), + storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), PendingTxStatus.Advancing, 'tx is Advancing', ); @@ -368,7 +368,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`mockChainStorageRoot.status.${mockEvidence.txHash}`), + storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 2c8075e9e2f..39dd3e2ecbe 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -47,7 +47,7 @@ const makeTestContext = async t => { const { log, inspectLogs } = makeTestLogger(t.log); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - common.commonPrivateArgs.storageNode.makeChildNode('status'), + common.commonPrivateArgs.storageNode.makeChildNode('txns'), { log }, ); const { zcf, callLog } = mockZcf(zone.subZone('Mock ZCF')); @@ -236,7 +236,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { await eventLoopIteration(); const vstorage = t.context.storage.data; t.is( - vstorage.get(`mockChainStorageRoot.status.${cctpTxEvidence.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${cctpTxEvidence.txHash}`), 'DISBURSED', ); }); @@ -307,7 +307,7 @@ test('slow path: forward to EUD; remove pending tx', async t => { ); const vstorage = t.context.storage.data; t.is( - vstorage.get(`mockChainStorageRoot.status.${cctpTxEvidence.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${cctpTxEvidence.txHash}`), 'FORWARDED', ); }); diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 969af7530d5..6fb5f732715 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -10,7 +10,7 @@ import type { CctpTxEvidence } from '../../src/types.js'; type Common = Awaited>; type TestContext = { - statusNode: ERef; + transactionsNode: ERef; storage: Common['bootstrap']['storage']; }; @@ -19,7 +19,8 @@ const test = anyTest as TestFn; test.beforeEach(async t => { const common = await commonSetup(t); t.context = { - statusNode: common.commonPrivateArgs.storageNode.makeChildNode('status'), + transactionsNode: + common.commonPrivateArgs.storageNode.makeChildNode('txns'), storage: common.bootstrap.storage, }; }); @@ -28,7 +29,7 @@ test('advance creates new entry with ADVANCED status', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -46,7 +47,7 @@ test('ADVANCED transactions are published to vstorage', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -55,7 +56,7 @@ test('ADVANCED transactions are published to vstorage', async t => { const vstorage = t.context.storage.data; t.is( - vstorage.get(`mockChainStorageRoot.status.${evidence.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${evidence.txHash}`), 'ADVANCING', ); }); @@ -64,7 +65,7 @@ test('observe creates new entry with OBSERVED status', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -81,7 +82,7 @@ test('OBSERVED transactions are published to vstorage', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -90,7 +91,7 @@ test('OBSERVED transactions are published to vstorage', async t => { const vstorage = t.context.storage.data; t.is( - vstorage.get(`mockChainStorageRoot.status.${evidence.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${evidence.txHash}`), 'OBSERVED', ); }); @@ -99,7 +100,7 @@ test('cannot process same tx twice', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -122,7 +123,7 @@ test('isSeen checks if a tx has been processed', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -140,7 +141,7 @@ test('dequeueStatus removes entries from PendingTxs', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -192,7 +193,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const advanceOutcomeFn = () => @@ -221,7 +222,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -235,7 +236,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { ]); await eventLoopIteration(); t.is( - vstorage.get(`mockChainStorageRoot.status.${e1.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${e1.txHash}`), PendingTxStatus.Advanced, ); @@ -248,7 +249,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { ]); await eventLoopIteration(); t.is( - vstorage.get(`mockChainStorageRoot.status.${e2.txHash}`), + vstorage.get(`mockChainStorageRoot.txns.${e2.txHash}`), PendingTxStatus.AdvanceFailed, ); }); @@ -257,7 +258,7 @@ test('dequeueStatus returns undefined when nothing is settleable', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -271,7 +272,7 @@ test('dequeueStatus returns first (earliest) matched entry', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -368,7 +369,7 @@ test('lookupPending returns empty array when presented a key it has not seen', t const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); t.deepEqual(statusManager.lookupPending('noble123', 1n), []); }); @@ -377,7 +378,7 @@ test('StatusManagerKey logic handles addresses with hyphens', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.statusNode, + t.context.transactionsNode, ); const evidence: CctpTxEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); evidence.tx.forwardingAddress = 'noble1-foo'; From fc8bb1e77f809acbb7fbe6584134366218215738 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 17:17:06 -0800 Subject: [PATCH 29/65] refactor: txnsNode --- packages/fast-usdc/src/exos/status-manager.js | 6 ++-- .../test/exos/status-manager.test.ts | 31 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 84b5766d0b0..dbffbd07946 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -59,12 +59,12 @@ const pendingTxKeyOf = evidence => { * XXX consider separate facets for `Advancing` and `Settling` capabilities. * * @param {Zone} zone - * @param {ERef} transactionsNode + * @param {ERef} txnsNode * @param {StatusManagerPowers} caps */ export const prepareStatusManager = ( zone, - transactionsNode, + txnsNode, { log = makeTracer('Advancer', true), } = /** @type {StatusManagerPowers} */ ({}), @@ -88,7 +88,7 @@ export const prepareStatusManager = ( * @param {TxStatus} status */ const publishStatus = (hash, status) => { - const txnNodeP = E(transactionsNode).makeChildNode(hash); + const txnNodeP = E(txnsNode).makeChildNode(hash); // Don't await, just writing to vstorage. void E(txnNodeP).setValue(status); }; diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 6fb5f732715..bf8f3c8a67b 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -10,7 +10,7 @@ import type { CctpTxEvidence } from '../../src/types.js'; type Common = Awaited>; type TestContext = { - transactionsNode: ERef; + txnsNode: ERef; storage: Common['bootstrap']['storage']; }; @@ -19,8 +19,7 @@ const test = anyTest as TestFn; test.beforeEach(async t => { const common = await commonSetup(t); t.context = { - transactionsNode: - common.commonPrivateArgs.storageNode.makeChildNode('txns'), + txnsNode: common.commonPrivateArgs.storageNode.makeChildNode('txns'), storage: common.bootstrap.storage, }; }); @@ -29,7 +28,7 @@ test('advance creates new entry with ADVANCED status', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -47,7 +46,7 @@ test('ADVANCED transactions are published to vstorage', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -65,7 +64,7 @@ test('observe creates new entry with OBSERVED status', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -82,7 +81,7 @@ test('OBSERVED transactions are published to vstorage', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -100,7 +99,7 @@ test('cannot process same tx twice', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -123,7 +122,7 @@ test('isSeen checks if a tx has been processed', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -141,7 +140,7 @@ test('dequeueStatus removes entries from PendingTxs', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -193,7 +192,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const advanceOutcomeFn = () => @@ -222,7 +221,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -258,7 +257,7 @@ test('dequeueStatus returns undefined when nothing is settleable', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -272,7 +271,7 @@ test('dequeueStatus returns first (earliest) matched entry', async t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -369,7 +368,7 @@ test('lookupPending returns empty array when presented a key it has not seen', t const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); t.deepEqual(statusManager.lookupPending('noble123', 1n), []); }); @@ -378,7 +377,7 @@ test('StatusManagerKey logic handles addresses with hyphens', t => { const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), - t.context.transactionsNode, + t.context.txnsNode, ); const evidence: CctpTxEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); evidence.tx.forwardingAddress = 'noble1-foo'; From 1637c1d9edef7cfb78ce4c396e4c8bdac2a8a70d Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 16:46:55 -0800 Subject: [PATCH 30/65] test: shorten node path --- packages/fast-usdc/test/exos/advancer.test.ts | 12 +++++------ packages/fast-usdc/test/exos/settler.test.ts | 10 ++-------- .../test/exos/status-manager.test.ts | 20 ++++--------------- packages/fast-usdc/test/supports.ts | 7 ++++--- 4 files changed, 16 insertions(+), 33 deletions(-) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 1f09fbc8484..4e7780bc2c3 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -48,7 +48,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const statusManager = prepareStatusManager( rootZone.subZone('status-manager'), - storageNode.makeChildNode('transactions'), + storageNode.makeChildNode('txns'), ); const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { @@ -185,7 +185,7 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), + storage.data.get(`fun.txns.${mockEvidence.txHash}`), PendingTxStatus.Advancing, 'ADVANCED status in happy path', ); @@ -259,7 +259,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), + storage.data.get(`fun.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'OBSERVED status on insufficient pool funds', ); @@ -288,7 +288,7 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), + storage.data.get(`fun.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'OBSERVED status on makeChainAddress failure', ); @@ -321,7 +321,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t await eventLoopIteration(); t.deepEqual( - storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), + storage.data.get(`fun.txns.${mockEvidence.txHash}`), PendingTxStatus.Advancing, 'tx is Advancing', ); @@ -368,7 +368,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`mockChainStorageRoot.txns.${mockEvidence.txHash}`), + storage.data.get(`fun.txns.${mockEvidence.txHash}`), PendingTxStatus.Observed, 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 39dd3e2ecbe..f224515df1c 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -235,10 +235,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { ); await eventLoopIteration(); const vstorage = t.context.storage.data; - t.is( - vstorage.get(`mockChainStorageRoot.txns.${cctpTxEvidence.txHash}`), - 'DISBURSED', - ); + t.is(vstorage.get(`fun.txns.${cctpTxEvidence.txHash}`), 'DISBURSED'); }); test('slow path: forward to EUD; remove pending tx', async t => { @@ -306,10 +303,7 @@ test('slow path: forward to EUD; remove pending tx', async t => { 'SETTLED entry removed from StatusManger', ); const vstorage = t.context.storage.data; - t.is( - vstorage.get(`mockChainStorageRoot.txns.${cctpTxEvidence.txHash}`), - 'FORWARDED', - ); + t.is(vstorage.get(`fun.txns.${cctpTxEvidence.txHash}`), 'FORWARDED'); }); test('Settlement for unknown transaction', async t => { diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index bf8f3c8a67b..6ea7810903e 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -54,10 +54,7 @@ test('ADVANCED transactions are published to vstorage', async t => { await eventLoopIteration(); const vstorage = t.context.storage.data; - t.is( - vstorage.get(`mockChainStorageRoot.txns.${evidence.txHash}`), - 'ADVANCING', - ); + t.is(vstorage.get(`fun.txns.${evidence.txHash}`), 'ADVANCING'); }); test('observe creates new entry with OBSERVED status', t => { @@ -89,10 +86,7 @@ test('OBSERVED transactions are published to vstorage', async t => { await eventLoopIteration(); const vstorage = t.context.storage.data; - t.is( - vstorage.get(`mockChainStorageRoot.txns.${evidence.txHash}`), - 'OBSERVED', - ); + t.is(vstorage.get(`fun.txns.${evidence.txHash}`), 'OBSERVED'); }); test('cannot process same tx twice', t => { @@ -234,10 +228,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.is( - vstorage.get(`mockChainStorageRoot.txns.${e1.txHash}`), - PendingTxStatus.Advanced, - ); + t.is(vstorage.get(`fun.txns.${e1.txHash}`), PendingTxStatus.Advanced); statusManager.advance(e2); statusManager.advanceOutcome(e2.tx.forwardingAddress, e2.tx.amount, false); @@ -247,10 +238,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.is( - vstorage.get(`mockChainStorageRoot.txns.${e2.txHash}`), - PendingTxStatus.AdvanceFailed, - ); + t.is(vstorage.get(`fun.txns.${e2.txHash}`), PendingTxStatus.AdvanceFailed); }); test('dequeueStatus returns undefined when nothing is settleable', t => { diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 83f4f979013..fe9d83c6448 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -156,9 +156,10 @@ export const commonSetup = async (t: ExecutionContext) => { }); const timer = buildZoeManualTimer(t.log); const marshaller = makeFakeBoard().getReadonlyMarshaller(); - const storage = makeFakeStorageKit('mockChainStorageRoot', { - sequence: false, - }); + const storage = makeFakeStorageKit( + 'fun', // Fast USDC Node + { sequence: false }, + ); /** * Read pure data (CapData that has no slots) from the storage path * @param path From 2916c8f43b23a6c4d38796dd7135e9d712d12f8c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 6 Dec 2024 17:37:00 -0800 Subject: [PATCH 31/65] feat: publish CctpTxEvidence --- packages/fast-usdc/src/exos/status-manager.js | 16 +++++++++++++++- packages/fast-usdc/test/exos/advancer.test.ts | 19 ++++++++++--------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index dbffbd07946..89afafef0bd 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -2,7 +2,7 @@ import { M } from '@endo/patterns'; import { Fail, makeError, q } from '@endo/errors'; import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js'; import { E } from '@endo/eventual-send'; -import { makeTracer } from '@agoric/internal'; +import { makeTracer, pureDataMarshaller } from '@agoric/internal'; import { CctpTxEvidenceShape, EvmHashShape, @@ -83,6 +83,19 @@ export const prepareStatusManager = ( keyShape: M.string(), }); + /** + * @param {CctpTxEvidence['txHash']} hash + * @param {CctpTxEvidence} evidence + */ + const publishEvidence = (hash, evidence) => { + const txNode = E(transactionsNode).makeChildNode(hash); + // Don't await, just writing to vstorage. + void E(txNode).setValue( + // @ts-expect-error XXX CopyRecordI expects an index signature + JSON.stringify(pureDataMarshaller.toCapData(evidence)), + ); + }; + /** * @param {CctpTxEvidence['txHash']} hash * @param {TxStatus} status @@ -114,6 +127,7 @@ export const prepareStatusManager = ( pendingTxKeyOf(evidence), harden({ ...evidence, status }), ); + publishEvidence(txHash, evidence); publishStatus(txHash, status); }; diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 4e7780bc2c3..0f1be85ee9f 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -1,29 +1,30 @@ -import type { TestFn } from 'ava'; import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; + +import { + decodeAddressHook, + encodeAddressHook, +} from '@agoric/cosmic-proto/address-hooks.js'; +import type { NatAmount } from '@agoric/ertp'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { denomHash } from '@agoric/orchestration'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; -import { Far } from '@endo/pass-style'; -import type { NatAmount } from '@agoric/ertp'; import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { q } from '@endo/errors'; -import { - decodeAddressHook, - encodeAddressHook, -} from '@agoric/cosmic-proto/address-hooks.js'; +import { Far } from '@endo/pass-style'; +import type { TestFn } from 'ava'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; +import type { LiquidityPoolKit } from '../../src/types.js'; import { makeFeeTools } from '../../src/utils/fees.js'; -import { commonSetup } from '../supports.js'; import { MockCctpTxEvidences, intermediateRecipient } from '../fixtures.js'; import { makeTestFeeConfig, makeTestLogger, prepareMockOrchAccounts, } from '../mocks.js'; -import type { LiquidityPoolKit } from '../../src/types.js'; +import { commonSetup } from '../supports.js'; const LOCAL_DENOM = `ibc/${denomHash({ denom: 'uusdc', From d82f7e7685f19216bb9689c7dbb88e0c9996b53c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 18:17:03 -0800 Subject: [PATCH 32/65] test: observe node sequence --- packages/fast-usdc/test/exos/advancer.test.ts | 21 +++++++------- packages/fast-usdc/test/exos/settler.test.ts | 18 +++++++++--- .../test/exos/status-manager.test.ts | 29 ++++++++++++++----- packages/fast-usdc/test/supports.ts | 1 - 4 files changed, 47 insertions(+), 22 deletions(-) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 0f1be85ee9f..815727e6bf7 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -12,6 +12,7 @@ import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { q } from '@endo/errors'; import { Far } from '@endo/pass-style'; import type { TestFn } from 'ava'; +import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; @@ -186,8 +187,8 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`fun.txns.${mockEvidence.txHash}`), - PendingTxStatus.Advancing, + storage.getValues(`fun.txns.${mockEvidence.txHash}`), + [stringifyWithBigint(mockEvidence), PendingTxStatus.Advancing], 'ADVANCED status in happy path', ); @@ -260,8 +261,8 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { await eventLoopIteration(); t.deepEqual( - storage.data.get(`fun.txns.${mockEvidence.txHash}`), - PendingTxStatus.Observed, + storage.getValues(`fun.txns.${mockEvidence.txHash}`), + [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], 'OBSERVED status on insufficient pool funds', ); @@ -289,8 +290,8 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`fun.txns.${mockEvidence.txHash}`), - PendingTxStatus.Observed, + storage.getValues(`fun.txns.${mockEvidence.txHash}`), + [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], 'OBSERVED status on makeChainAddress failure', ); @@ -322,8 +323,8 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t await eventLoopIteration(); t.deepEqual( - storage.data.get(`fun.txns.${mockEvidence.txHash}`), - PendingTxStatus.Advancing, + storage.getValues(`fun.txns.${mockEvidence.txHash}`), + [stringifyWithBigint(mockEvidence), PendingTxStatus.Advancing], 'tx is Advancing', ); @@ -369,8 +370,8 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.data.get(`fun.txns.${mockEvidence.txHash}`), - PendingTxStatus.Observed, + storage.getValues(`fun.txns.${mockEvidence.txHash}`), + [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index f224515df1c..d82479479c9 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -4,6 +4,7 @@ import type { TestFn } from 'ava'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import type { Zone } from '@agoric/zone'; +import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareSettler } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; @@ -234,8 +235,13 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { 'SETTLED entry removed from StatusManger', ); await eventLoopIteration(); - const vstorage = t.context.storage.data; - t.is(vstorage.get(`fun.txns.${cctpTxEvidence.txHash}`), 'DISBURSED'); + const { storage } = t.context; + t.deepEqual(storage.getValues(`fun.txns.${cctpTxEvidence.txHash}`), [ + stringifyWithBigint(cctpTxEvidence), + 'ADVANCING', + 'ADVANCED', + 'DISBURSED', + ]); }); test('slow path: forward to EUD; remove pending tx', async t => { @@ -302,8 +308,12 @@ test('slow path: forward to EUD; remove pending tx', async t => { [], 'SETTLED entry removed from StatusManger', ); - const vstorage = t.context.storage.data; - t.is(vstorage.get(`fun.txns.${cctpTxEvidence.txHash}`), 'FORWARDED'); + const { storage } = t.context; + t.deepEqual(storage.getValues(`fun.txns.${cctpTxEvidence.txHash}`), [ + stringifyWithBigint(cctpTxEvidence), + 'OBSERVED', + 'FORWARDED', + ]); }); test('Settlement for unknown transaction', async t => { diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 6ea7810903e..40db60149c9 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -2,6 +2,7 @@ import type { TestFn } from 'ava'; import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { StorageNode } from '@agoric/internal/src/lib-chainStorage.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; +import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; import { commonSetup, provideDurableZone } from '../supports.js'; @@ -53,8 +54,11 @@ test('ADVANCED transactions are published to vstorage', async t => { statusManager.advance(evidence); await eventLoopIteration(); - const vstorage = t.context.storage.data; - t.is(vstorage.get(`fun.txns.${evidence.txHash}`), 'ADVANCING'); + const { storage } = t.context; + t.deepEqual(storage.getValues(`fun.txns.${evidence.txHash}`), [ + stringifyWithBigint(evidence), + 'ADVANCING', + ]); }); test('observe creates new entry with OBSERVED status', t => { @@ -85,8 +89,11 @@ test('OBSERVED transactions are published to vstorage', async t => { statusManager.observe(evidence); await eventLoopIteration(); - const vstorage = t.context.storage.data; - t.is(vstorage.get(`fun.txns.${evidence.txHash}`), 'OBSERVED'); + const { storage } = t.context; + t.deepEqual(storage.getValues(`fun.txns.${evidence.txHash}`), [ + stringifyWithBigint(evidence), + 'OBSERVED', + ]); }); test('cannot process same tx twice', t => { @@ -211,7 +218,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { }); test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { - const vstorage = t.context.storage.data; + const { storage } = t.context; const zone = provideDurableZone('status-test'); const statusManager = prepareStatusManager( zone.subZone('status-manager'), @@ -228,7 +235,11 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.is(vstorage.get(`fun.txns.${e1.txHash}`), PendingTxStatus.Advanced); + t.deepEqual(storage.getValues(`fun.txns.${e1.txHash}`), [ + stringifyWithBigint(e1), + PendingTxStatus.Advancing, + PendingTxStatus.Advanced, + ]); statusManager.advance(e2); statusManager.advanceOutcome(e2.tx.forwardingAddress, e2.tx.amount, false); @@ -238,7 +249,11 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.is(vstorage.get(`fun.txns.${e2.txHash}`), PendingTxStatus.AdvanceFailed); + t.deepEqual(storage.getValues(`fun.txns.${e2.txHash}`), [ + stringifyWithBigint(e2), + PendingTxStatus.Advancing, + PendingTxStatus.AdvanceFailed, + ]); }); test('dequeueStatus returns undefined when nothing is settleable', t => { diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index fe9d83c6448..1cb5284d515 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -158,7 +158,6 @@ export const commonSetup = async (t: ExecutionContext) => { const marshaller = makeFakeBoard().getReadonlyMarshaller(); const storage = makeFakeStorageKit( 'fun', // Fast USDC Node - { sequence: false }, ); /** * Read pure data (CapData that has no slots) from the storage path From f0078ee5668de2f1bba6f0544ea5629ccc8c9d28 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 18:17:59 -0800 Subject: [PATCH 33/65] feat: deleteCompletedTxs --- packages/fast-usdc/src/constants.js | 7 ++- packages/fast-usdc/src/exos/status-manager.js | 41 +++++++++++++++++- packages/fast-usdc/test/exos/settler.test.ts | 10 +++++ .../snapshots/fast-usdc.contract.test.ts.md | 1 + .../snapshots/fast-usdc.contract.test.ts.snap | Bin 5789 -> 5809 bytes 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/packages/fast-usdc/src/constants.js b/packages/fast-usdc/src/constants.js index d341f6c650d..28ab7775db7 100644 --- a/packages/fast-usdc/src/constants.js +++ b/packages/fast-usdc/src/constants.js @@ -21,7 +21,12 @@ export const TxStatus = /** @type {const} */ ({ }); harden(TxStatus); -// TODO: define valid state transitions +// According to the state diagram +export const TerminalTxStatus = { + [TxStatus.Forwarded]: true, + [TxStatus.ForwardFailed]: true, + [TxStatus.Disbursed]: true, +}; /** * Status values for the StatusManager. diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 89afafef0bd..6db165b8b31 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -8,7 +8,7 @@ import { EvmHashShape, PendingTxShape, } from '../type-guards.js'; -import { PendingTxStatus, TxStatus } from '../constants.js'; +import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; /** * @import {MapStore, SetStore} from '@agoric/store'; @@ -78,11 +78,27 @@ export const prepareStatusManager = ( valueShape: M.arrayOf(PendingTxShape), }); - /** @type {SetStore} */ + /** + * Transactions seen *ever* by the contract. + * + * Note that like all durable stores, this SetStore is stored in IAVL. It + * grows without bound (though the amount of growth per incoming message to + * the contract is bounded). At some point in the future we may want to prune. + * @type {SetStore} + */ const seenTxs = zone.setStore('SeenTxs', { keyShape: M.string(), }); + /** + * Transactions that have completed, but are still in vstorage. + * + * @type {SetStore} + */ + const storedCompletedTxs = zone.setStore('StoredCompletedTxs', { + keyShape: M.string(), + }); + /** * @param {CctpTxEvidence['txHash']} hash * @param {CctpTxEvidence} evidence @@ -104,6 +120,13 @@ export const prepareStatusManager = ( const txnNodeP = E(txnsNode).makeChildNode(hash); // Don't await, just writing to vstorage. void E(txnNodeP).setValue(status); + if (TerminalTxStatus[status]) { + // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 + // Queue it for deletion later because if we deleted it now the earlier + // writes in this block would be wiped. For now we keep track of what to + // delete when we know it'll be another block. + storedCompletedTxs.add(hash); + } }; /** @@ -161,6 +184,7 @@ export const prepareStatusManager = ( advanceOutcome: M.call(M.string(), M.nat(), M.boolean()).returns(), observe: M.call(CctpTxEvidenceShape).returns(M.undefined()), hasBeenObserved: M.call(CctpTxEvidenceShape).returns(M.boolean()), + deleteCompletedTxs: M.call().returns(M.undefined()), dequeueStatus: M.call(M.string(), M.bigint()).returns( M.or( { @@ -226,6 +250,19 @@ export const prepareStatusManager = ( return seenTxs.has(evidence.txHash); }, + // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 + deleteCompletedTxs() { + for (const txHash of storedCompletedTxs.values()) { + // As of now, setValue('') on a non-sequence node will delete it + const txNode = E(transactionsNode).makeChildNode(txHash, { + sequence: false, + }); + void E(txNode) + .setValue('') + .then(() => storedCompletedTxs.delete(txHash)); + } + }, + /** * Remove and return an `ADVANCED` or `OBSERVED` tx waiting to be `SETTLED`. * diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index d82479479c9..9456fb5417a 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -242,6 +242,11 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { 'ADVANCED', 'DISBURSED', ]); + + // Check deletion of DISBURSED transactions + statusManager.deleteCompletedTxs(); + await eventLoopIteration(); + t.is(storage.data.get(`fun.txns.${cctpTxEvidence.txHash}`), undefined); }); test('slow path: forward to EUD; remove pending tx', async t => { @@ -314,6 +319,11 @@ test('slow path: forward to EUD; remove pending tx', async t => { 'OBSERVED', 'FORWARDED', ]); + + // Check deletion of FORWARDED transactions + statusManager.deleteCompletedTxs(); + await eventLoopIteration(); + t.is(storage.data.get(`fun.txns.${cctpTxEvidence.txHash}`), undefined); }); test('Settlement for unknown transaction', async t => { diff --git a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md index a9fd7cab902..99f90954dbe 100644 --- a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md +++ b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.md @@ -598,6 +598,7 @@ Generated by [AVA](https://avajs.dev). PoolAccount: 'Vow', SeenTxs: [], SettleAccount: 'Vow', + StoredCompletedTxs: [], mint: { PoolShare: 'Alleged: zcfMint', }, diff --git a/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap b/packages/fast-usdc/test/snapshots/fast-usdc.contract.test.ts.snap index a0714ea13d289718d11ca5d5e50eb1173453a29f..b4eafafc0799a4cc798735079af6b348f1c0f616 100644 GIT binary patch literal 5809 zcmV;i7Eb9wRzVi7ZyyY0DF{ zSS-L7sUM3700000000B!oq2p*)pf_eBTJTK?Y3mul5J${;8oVFni+WkEf!uRTh`)D z-kxTjq_IXb@+@9}0wyd?o00?w`6Q&F2@sc0KV*Y~X_gNy32mT|HYB8h(1auuVwz_8 zB+!tp%$r4T?j6f-Jfi*7;vb}Uf4_6iz31L@&pq!x`IEy#{-9?peEL&r#24|aBSXr_ zh%%!3!U1I>JQ|FIPk+kmRU*p1$aS+QB=(=F$W*)y=mG8mo&{b9@=UPE1f3>OO)$?i zyUH|s=g?8r6ET@mKUP*&Vk*N_gsFmgro3v?EKCJerX?NGkTT>~8+xKceqVUBVY@GK zc+3~@ZczeWznX-Vwfg<)i0W-=h_wka=Jl$cV92Y63=qprrfW@*Y%W&9rvjc%fAECX z^qj7#$TO<=0$ZX(TFb&beM>M92`Qe4XveTG6pm~Sc$82;iTHwn?dmD5Ew4h8alcMR zSuo@oRl|{x2Gp8g(>3QG51t6e#=LCVELb%QMrXn2X2H2xur?pA$%l{U!?*LHx&T@V z;9vpVSRnWyFWm=4rjo}B;L8Q@W&v1d!{BTqKZUO^&cyQ zzbb@R3t?pu94&&gMex=;|92I`&BgFkF;vWfu{m(d9QgPgcw!FxaSp5~0dEQ1SORBC z;E59WNePsd!m?7>R0;=6;drTF%7|!6@dr!c?ov2c3N2-DZ5f;`gSX3|rW~5e1rgVa zA_}|8p|>19Tn?|6!}1F7R=~X#>D0ViktTMjFc}uMddGc%*5vfcc1|x4=wV-A#IHtz zfh3?d#ZE^Ga;n>WF)Mw+K(-bv>Wl_7;y~a;NST;0w7k+J)XNg2Zq%g&NMLPIJX0~b zC@Q;xBYlxzNbOc5N-R8y>o3`!t)UD1B1%Nfrk~{|(=TP0F+rsxsEC zOlU)(&B;090JSGVTDAi;H${{jSe4?n>*M7CU8ib?RL`i*+7nWTeJA^a8g7R&u4=$P z*8%4Yg_MA|Lk$GSwYD$l+q7`JH832EkJ>A`whB)$5Qxw6Nr1m<5>Vic%S`K3oj({H zi%zsBLVGE8-XsG?TyaV6kULn$jK7nl-`Gz|20 zv^OL%4NBq%LC9hmntk+0iD(b0N+fs@(L<6jRrC5kx#Uv2ex zg3&-E`EZsTrfYXjsG-<2G?>qpn@nrx>VjR58u0o8BmF1Cg5Z*v)fx4_GeX;RA`1Id zH6ZiL;xp!a5{7jW=4u;>w>>yM;a4N7R})rlGTo%Z6noNk?qR)qd_$i8 zV9+0T_}#jek_p8#rbZHtWte7*n~j#g_NtN4sn|jAVv^-W8AM3&r#?MlPD6`9q9+s_ z_l4CxO2jjo{miM`9Xzo$5K%(`#UH+inNp+a9fs%FC~YIn@bRL2D?aoHFGnf2ydch^@gi5wj%`)zwf}EodqfVfmxg5O@c6 zXEi)3!iy!TFIK}3MA#fjYEKR9u7N-e+)^XJOQdt`Cu-pS8hE+}{<8+E=YwlL49IC?xG<@%?gAa%>zjPA*mpXW%4t`z- zmG!W?9@^?*uwI~!3)J-1NXFL0bc$x0PKmbT>20RG>+0bqQTd4}m7f%QHS3Xj_`7=e zo+#+ll!C641pT2N@)yCDMS`F|k)Wp+!EKA+UJ-hO;f%eQmoiUF zP_+YTvaQ26~^)bb~L*>&DKt{&C%@G?Cxx}xmz8Zo2^c_y}8-#ZnL(TofeD3 z<#KQCa9OM!uC~@@o7>@RZgnU7`A#C0w`4MGr@B^dGP!lnlii6OXmyX%`cS7e-?v0x zkIVw?&7WJBf?i zmB8F^nZEjw#DrB(NR1>6dNea667qSI7X4HQsYpSh<7yJHyg_G*NA;`Wh))qr8Ps9s z=|&~3?|0}xHF{9Gtgq`}^S!6MCmY8VUm&1H8ZBw!SUQPYAmGv^I(5kMqtQT6kQC6h zS0>uiB|M-*R0Y&%Boqt?LcXVi%$tOy%b9n%ZU_?W4Bp>%xn5lomL}=64pNzfr1}1= z4ly@{h$x{E<(j0?Kht5#lNg=vuUMulG^N=om~&7EoSSM&H|Q=Mrdo$dH|d%4NYc;Q zyyd#iPhygWr(%Fxhua>X+bz=*W?~UTC%i-(yOwA)?2Sj6dvuLm2@5sVcDJk5>~vV# zov|M}+^sg3yS3HU?6z2}wvN`0R)@2rwbkCa+0yLjaI`xeF1OubcC@*i&26pCo9(*Z zJ+0GG=t&l4-kBSw_vpNuJT3MFPbABxSL)hlPb7*U8Nzjae@F?06|HDyw6GIDgOr<0 zQJs>ap& zAJjEeobW|Py&>g9N>_$17so09eWOY!)xpYC2e0uAcWVdoGE8}z_;2XMSB@)Vs&)!Z z9Ah=an<7GA;z&yRKYeGH>dfL5nK#U>y64FaGeb6U+19ppZN3bvp*}U>RYMnZjQ0(B zdev~$AGz4mp(J36N}!0%I3pJJOdhd~^+-r?r%1~Zx#sNX3b=L!e0l{uw*r2)0xDMu zDQ&5kq82o*1jkA^yb^9*31>t~g-DtGPb=ZMmGIU|XjlcUt6*rAK&zB!r&qyktKjS^ zcwrU%eihWM7HHKHZT)I!T@B&Y@S)Z4_-c4Tq}58aw^qaNS3}bp=w1WSHE_oofmSEc z9$o{FuYq%GplB^Lt%a_&0&THG8($0IweY}NcycYgu@;IN1zLkdTh$0nji5Bb4UKT7 z5xy$YmPxc%8{v&cSiBC_uLI9IxN)68yF#LUavhvm2j5)>Z>@tRO|ZU6pskW<2by50 z3GQx!N1EW}CU{${*5elvv3aE}?zngv>uMEkB8zHf#~3#_xifCWMpfo7Fx zcUs`17I@kMuUnwP3Tv$b%^}gctGhGi{qRf|B|Ezy(~7-@lfTHx^(_)!b6UZCxhXiL|_iuEwK9!{-?`_{t~ zBJF@gdu2VmwjSy?fO`XYHo%P=1lnOK{(o`@#UoWgY#YJ75sqwx zTSd4k!5`WP4{wAQHv*dk`0$i<9bc8{vJ5Y!w3kkaWHl4*XqD-T^U=~%*-Y#)eWgTT z$MeNZtU#5iA;l72awRj@OuV4pR)LqE*Jff*OrbTI^=9H7)Av!}oxhJEy*mU}B4f@( z3s;#|oR22t)5*fws!h-&&XsGV`kHSO1Vz}jQiboqccguG6Fe(G^KO(%cC&uG3C?YT zqALaLO>$kXKz#S8zeX{2Nvtq_St3=rDoR#O#8RKnb8K@UmdnSXd6gnyVt70a5WmTG z*_FCCdf|vN7JFA298&}Ff>gc{%QF`0M8gYH^^4r?HaetQvG4+R73*pXQ(IPHY(zVz z9#PToVvpaa1|o-jDT^x1&c=v#sENIjZEV)0`gBrDwF8|RnovTKQ-Zj>NjasHcWD}3 zVx=`4yC)Sd3MWqZcj+`#L=uOq_E9AeQ2hoiuS~bx>C^;2pS|g2I@6uj3)}vO>9^gc z3Ep^BPPR8YFKqkhRXN)(%$RuH>P+^g>t~F(95Pt`&D<>)M%@yhF;%TOjk?9asBdVU z_8Ai|JYJid?ac;O>ZhmOc8g0B{A!NlZou}+wrRKBtO?%PmeX`M5M-{&-SoMF=@v^o zx<8)1@#Xpu={8^3{2%9TepR~pR!6)zy{tVa>#Yt0>vc!_bVtefwE2tdZP!m51LJ;n z+AWW7O>gC9xq&giykoj&jLjAgl1fKTGsb2$uw37tyY(4o%rn{Bp5=^rGk42{7-^52 z?%14De770M365-@_V^wTGWX_YyOF)=>1nsUIliwJcjlH8I4*3vz4P6f?cwZA&vIM+ zMDCUgqi&4{nU`}Lb(?s^&R~1d)zd!P;|amlSLbBA)xeAiO}p)hGt=jDvptqaU&!|F z=!GJ#Y0M1)jlLkNln~* zNrM%|V6hABDb(b3yT)z0O9k3JKxvGU*Wr^-QpMN|mk)Ba=mM&zxc2ZaYo78tWwnyU z2e8w?7q6-$zbDatk5!4wO{Tqi#~xSwQPnW@Lm8+=ro3mi!M|=xzbs!S-e7)d8@wWb zsszxiH@3kqw!!l4!fS^b@l`_6-tBN`JG^f@{KIzm^>(Q4g7sanw@aYUm)=C&&;_@2 z!DAwHfu!kN7yP^n7Ii~^H{8|@pYDcdyWw27Kwl_ns@egyJ7DV$0a`CwO}FlY z_wR$p_rcF&wEfVwAAI}a*8KwAB58VPKRmo2UKOD>Nz;NsSTYD(2jTP}JTeH+55n7n zPC1bPzssP@p>{P2WBUFCB!^ zLju$-Y1(uMIu60HL-5y!;H5+G_90k$7&aXi=q-{a^)QSbhI>Wm21(Pm4#SIwq2LH? zJOUF(-~&hC(IfEu5rMu@()9KbKmn^FK(CZEsS1oK@DT;Rp+MdcEFFR^L!b@`^sD4q zJ_L6R!BZl%P15w+AuxHM(F4OC_^1cYdf@vW_?<_fw@aFqd0~|o2E77wv!v;EFWlvY zC%o|AURa~THWiMkaJwqdJ0(qjtHKvm_?ZaZB57Ja46BD>U>I&6hQA+%9}Gj`2rM5F z=vyUC+ecv62;3|}w@aGNj=)z&;M@pYJ_-Y)5E+GgM&azJK<|S!bkYyk`{6-9{Ll|I<6s|$!Erb_F3<-gP4|w&1LN?5 z2;C!TDhfb(09pcYECBZh;K=}-3qWB|pzoD5tqX!Z2&xF(FKPNn5dJaC*a8m_>~AfC~3Ol7_2=8`;Nf}kHM42;D^VcI0RRO1o|OKQ+EjZ zLU6MPJtAp(Gz4D?!B0Za5Qe@mgu?LAFgzL-=*pB=th|}OsLJ$Z+G)~m8wnpvpa0%a z-h0viaRKQ&XFW6Z8QaTY?K8I2@A;ABXKms!;DT=_+*a`buB%HO&ipE(*&hE6tT4mr zDt4yTT{KBNX%uU7HHou!PwcGSF49VpG`m?O&eaopf}x1+no#m+EglWEoBGMKQ0#la z^sn?L3`r5s_35Xr<7z1Eo4f*F=<|fF=ESEm7xsxzQ?!W{CFvG1>&m{+Ww`b@8G^FgP9_)Fj9e&Av$3;c z+Cs6~jh;?&tq40EGvah2R=S*GuMJeXtVYi#lfg?&B@C_<*Nj*x;x~*^{(oVgSS?v^ z^I29OC$ng29nT1-NQH1CPRafy<3&2fGBe(1N#6+=e0!4qQGo4#YfrJbMe{C6uLvi3 zV`ch_sX(58Uod!(pAl~u<&P$_bVt@v%bDH%p_x?=&bdCH_4^W=^&;Pw%!u1u^4~Ig zmzKxmHsHF*y5s-%^-*NXTN43GM7Y*jF8wvMz6k6SVRNOwS|)zM75}H#lE39ghy0np v^h(DSL}Oo-seWZh^`Bgn{P#8+68}zVgEAaZLk+P%%N_Y2N$dp7%ya+%A+<8f literal 5789 zcmV;O7Gmi^RzVgK)0UQ@OxmGSN*lUL^`DNH+*wsfI0 zEL~{nR8N-tbgz;~k(v2SoPT2J{(k42d(XY+o_pSX_D6?&p@@GpcHJGS7SuxOuumBt zR)*DJEUb*jMj~45x;p{^MN{@@u33~2|7R*Sm2Clffm?tlfS&^eCTKE2rwLRORGW(D znTogh4y%66WJ>*5RaJ$l98)Q#N~%o-3rw>x70oj(?wE)wzL477JK+ljVK!{hgu6F}>+q zhNe>gh!PB6G2zo&>I;l5k+2q3{F-RTP%s+PHi!L6G^}XBNO-GyLT@Xm)MeamkWn6q z`bX557S(}z^M4we3y(&Q#o}XLzGN0$JPQJ|;Ip&fg;}t?5RMkY$wK(oLZ~VNXA$fv zf~$)J9~7kfpwu+y^F{ELBKYqjSX~UeiXm1EHx`mcmdee4!Lx{_FqtGPt%39x8)5vtf8PTsIp|&W8JE!|Su*qB(GA4qQD4J~jvL zp94Rg1Fz44+PUDE3q5lMGloSo%0}iwcrH9N7v`5ke>uFb9KKr)zb=Q83PHr*h$2ds zRzOPyj8(t`74WADSXT+hD$}V2*CS2pxxz%K_Xfs-VQ+G3|Df}8~#gK;Z^k#MdSG<8mdb>fcjv8XaWp4HMylh7zjkh;;35+H%~1@W=UsRdEh z6&dc=B2l$l)s%Q>64zd`Jy%2P`!z*VbLnS=$@HkfvIU6{G7#%35OH2dg4~o-!g=NlPXrrS&2UA?29r1yQBmz)>aaSEDH_rxutJ)0%hmceFPr zG0n>44}y?IGBo$-krL4!RTV9A4$(uBaHi-Xg2g311?W`OKpw{ENs2#L0S%G>sWbH% zI+MVjer)?yO$+7jor??-G)0?;HFqoFc;w1e(1oWJBz5nC4BboT=*u={Shl5cSH-hI zz2y$$g5DYo2NLW2n})CFcLk431Oq|sM00N>5^5d|iuqZ6IwIHp&h3f#LaNvAk4%KM zsf9v(Oz69mtRTb)t=Uq|RdgNTxTRSnDh z^2CfeorDbr358?9aAM?D!?$IT$(|)f|84Wnn9u%`(W3E0r}T!$4GpD7V_GDt467MW z2dmp7v9U<3d7Dvq^JE8_uZV=QOZwAfwsb}OO6W8q&*AjZsLRuLf=ZVM| zJyJIHsbdjM%}srU$@Dv;Tm5Of@`cp~_XK_Zfk-5jaCo1gWzM+bA62!<#&S%>;zpw9 zrhTdwJrO_Pol7FzltF|PTN=}o;WV@u0D7a5v0zNyrD*<<+-FY1&d9ONVNH#Ol~C*) zW=f5&cZU`X#j+TQ7no0PBlCwYAO+7g-aJe%L3T80HO;7c$p;i)&+2z2%9ZQom&I*YoMhD zyfp%RjtFnuTLXt`;D#FbWDR_$241Owx>{(fg?+W~mRk6DEj(5WFW17NI#^!^gLUxM zI`~8#e5(%rs}8Ccf@>k{S_s!JgpV(TM;F3x77C_ROO{vFLv208>fwF$0^BFTe^U>y z)I)g#v^EIv5o!1~HNaL87Lrc6?{0vb8{o4I@OT5f&;V~VKwYCi9TTYOty;#`$>}ta zKAlVj?nc-kDmZ#Z1;<3oXN@<)(MC8a3Oas9L03tFzS;;6HbP;OAn0ldy1oh8n_!;^ zy+(3Zvk8*iN%tcSx1Znuqi-TTUF3CbL)>jzoig;iCX53deJ* z^iKk$FrEUW@(4X22*xt@qB>=so?z++%4Azd(C1&%xyj@9dOMu%PP4VsY;!mrn>?Lf zo5$v4xHo#8Hjl&Q^m>y0{A;rGwMA2*In}ia zlj&8%_sQ;5m`uwT8*(9I9~$)L!NtaUf-bGqHt5%ZBNM(>yN^n;SzRDV%9D(Rxgs6nCg$J+N43z%n&Ua3?wc3lmSwi zf=rC5Nx**?P4TNCHKqj>!IZk@DNMCtRMPt1V*u3{LFuxtH^6EGCj!S?$CO|=tZJ>6 zG;#MEa0>-oy2O_a$cn=g;fNrqgm<0w*x=HUijU?lo{h9$&HHAqUo{9ml8gN?^bGvPN!c073EH&iX`q;Hi zOvD0-D6`AZ*fnXPuG;Q#d(AF~rQH?(p~K^~xjkO5&FQgNthNqshu7ii@Otf?n=DR8 zhojx)aC__yvty&%<=p6XZn7JCcY{Gki9cCb`Rm+xz|c^UJQ4OrjwQ>UuN&Hn$0v&z z8NzkrKvW6G6usz`ZDA&H&Zsb%EEgLNDZWTF8rQG41Pv_}0d+hQ3u+0WiS|zznd-EOAI3sRmYVRlcKr|4VA}&+DIU(982lS(B-oD3BG?siKaSOmFnP? z{-JLD&|QwHKo|eF2Juy6%BZTJG$)U$I^rG?VJuN3CH_JpoDr&QQq{u^DGXeecvUI=dbT3GNxv zvdLVt*t`s!%RpHMH!g!uFN4RH2`TMdF-0wUaT)w}88j>h?{e@h7buk?rTA^j;l|}~ z&vN+Ta`@A7ShPZ*RY|mUD`4Xah^>J4uYfPFfbWU41rqJG74WAOu(}1hT0m=o_qPbN zI*E2q3w*f+UTlHVm0(^8-75uJgG39j1Z^dpS_u!Ygcnyr$tr=iNTMxY1*=!Vp;d6r zD!6kMJS@_hCED|=;KfzY)Cz5_;A@4qvaYyGEd`l4wt@foIl0r5Reyu+t1N zvp`!T(QYxrhs^Mp8Gd1gDhsq)1e#T%^;lrQ0@qvMV-|SS0zVUJ4vAK3g$gTptuSbX zcUs|;RiL>g+Sje{xE20vg+?1}w85ZFpskf?*V^C)8+_RYPubuN8#LMl+6H;y*kPj` zG&|gEhp*b<`y$ON(SC1-H|$_`K#v2CI^gdd0y>DCxZ#s-c-jrWbHic}tn~=AetF?|z~_NmJ@5q&JnMniMcPh@*38DG!Fi@786GO> z4~-_1)l9U*^GuhVj+UOvW@3*TDjRWftU#ETeh6?o}+Z6@~k z8MG#|-b}nB#y$$X)AuoIbcev2%$PILV)IPPPDc~+>15&T`StLkI9E+2N(g2A|X#c*!@X#)%DWma6jge6`oTx_?W@CBAI-O{ENveF2 zzunmmsa`8Qi(O@g(!!Z7tITdh|8nLL6%8-*hk|NY8w{o_sx-S=HT_Hzf9l%m)TJ)H zbV}-6{XC~e$CapdLJ(IlC1>u`RhU+{SZIyKuQ?@Z!jlL5Z3YdM+T_`)eMAX|)lim} zSEXC-a_NHKo4e`d2Gd>Ev)lfa>9^gc3;un6wmV&CxBa5a^0r-=F^RI3@3OpRjJO;! zSpJ^;Ef+@Jl9(}%=We=j)Gb+z`tPRQc2}bA==A0{W3pJOig((_-JQ6RoS*HMENp*l z`fWGsf@g2cYr1CmwHhsQey2X-+?pp4~R~SR2$9#74Ka#)s^U}??Iuf<%XY;e( z>d0cfmbFiJluS&UE86p#Hd%~&Y}zePY)$v%XL%N5{-gXY7iNsjmI#tf9eK?dn>CB& zdU?m2Gh=SZ-S!-3%-#80F2qQC!t~$fZn`nP+p@?B8aGXQd`|?Ky_??jz3KXCx80f8 zS0BmGcBkX)w!f6W?HOnL>drTNTiw$+-J@es)_lg>lnay`-d~*tzIan5`O1j?IbJ2MFqx{i7#w?42~DV3 zQ@b)yOHBngY=L)gNxu(YE?!{1bqm}kfaVFHS$A%M&u)R|wg`_BYQ#qgrPW)Zek*ir zg}>PfcWs4lZ-v*kLUorwua%xev~|H{T@V$a3nfjby5KWi@ck~R?1qiqpmf7KyWv!~ zK(CiHJ>Cu9?S{f00oo{Oa`nLa9tifpM|Z34YX(sXbe1h&CR5xQ8? z^u#uJavQu6m)r}7d*Q}jxT_bQ=oRQoBu%gM!XJB~b-Mt)K+<$*I}B}yo43QG+u_gK zp{Wnr``}QYK)+DZ^o~AwPaixeLYGRKUg?8B_Q56nFxU?__ru-&@PmGMwO^oLENN;Q zfC~p;$AAD`CTY5H0B#z9`v&0U0k~ubY}x^#9dP3gfxcYQbk`2};tqIGgtkbUmh6O! zcS7$@c-KyNU?)7Y6K3s#=3N4PrKIWdUC_M?t`VWFlBTdE>>l{@9$2~;yn6+@Mbb2~7s7kt zb`ffmG(EW&p56x!FTrwbi1VK5BuOR`@ptefI1~jBl{t|A3nGr zp4<<`2jJoZ&~*TU2L!rH()7LqaO(m1h6wdYn*MMA{&E0T9R&YDxb-01dk~&E2!A*z z(Ay+U&4X~sAnY9!pz9<}Hx0rE2I0X$`28TPJOo<~!I4Ao-a`U?y`<^hLvY_A__YYV zRMOO}z$FUwDex`@9#G&J1!no6*(cC1lV`aPx_xk+2;C@Y`l1i+_rcG7aDg8N{1EfQ zhy3s*zd&!7G(GEw=lxI{5TKhRO`8L-EdW;q;PU}^Apk`xtWsgKD$qM6P2(yYRpHYj z^a@GSb1M8)g{mRgJOoz{!9NVaLqqV~kU-xoX(}Fuxx;YjumIgEX^IWQiD5W33_lu% zsu5T-0y{?_HX_iwBuyV0f!jymNfFv3X(|aqc@R87hz8+Q5FQD_FN08eSfFo{G_5%d zj>9k_LbpqrZaWNj9ENWlhLTZe8-+ciaP263cvPVGNtzxRg-1u>4G}sZX|jdD6M{ep zJ{*GYgy5wR)Q*8|OrYROLu2rM5xPs#^zayba|~V`gH>S|48t{HI2DG6!UBD_ zr0Ex7cqt6c5dpea($p7$-4S?u1n!H#Zz51W4)$@_J}%JrNt%w2!!_gZIT3n5()8nT z_}MrtI09Rbz%@tU!$;teBkAI51hXpO-@ z435MEx^l)FR)NefRAqWG?OM_<8wu}2pZ?lV!CNu@ZUE_3W+OB87Td{~{uW#6^FPOu zZ?%cXfU`cG@L0tIxS=jJnE6qJ)1G(@tR%zfDt@LlTr`>drd6!X)l8nXd*f&Ac9AwG zNwb?p;(Q~qHxkth*MyQsYw>8PU(`>Yh2pORroW^&o|P2wT%Ug0I;uuv!KoYYB|(48 zYMy*k=IlNZYKk_of}GhU#sXseVMkUTnVlS3r>Nx2E=lpM;scSH;1PRvizGjfIK)zF zmL9Q*C8+b#BT@y@?8(X}>E*`UBbPYcvy5Ce>x}TqJn3>r&I`qz^Fonou30V=$BYPF zqD!pVtrO!0Z;3xS&M|n2TC!Xx7P}brW`t85*=_M@PBB|@UMRT*uN2QNT6bRhMA%Vm zW=nQXsZ4w5Y_{dPqvV!&%}ph29*_8}^1O75@Q_;U^Vv6)xEr(bNGb?9Y|fl~l5*ut zbVznPyl|~LH-A{{xdpD2KW0SEC7ey9o%if3B>vDnx0rQ~8JBdQ=)81@w2_>{(ZuR7 zXPXD7oFWcxwi}7dEgomjOSi~3h;xiv*(SlMxMj798$yj3ijRMk>}@&%T-1?71FGq=HqJ9+B=dpO+pH3tevMieDDHiOrVt2|mZFN-F5N zrOT`5rCY?TEB8WI*0sl}5R}_?GPS^FN|#IQ zbrzK_YqsZ;so*815?QVk_l#I6;ya8|{(p9#SS>kk^Ep-@r?O~i9nT1-NQLlhoRa%P z#&dLvWoA6jlHL=@^65$XO98h3tv$u!5zRX6Z bJozU^o0TC=jW)-BE4TJPJq(_Ghjah{GBF Date: Sat, 14 Dec 2024 10:01:09 -0800 Subject: [PATCH 34/65] feat: consistent publishTxnRecord (record) --- .../test/fast-usdc/fast-usdc.test.ts | 18 ++++++++-- .../fast-usdc/snapshots/fast-usdc.test.ts.md | 2 +- .../snapshots/fast-usdc.test.ts.snap | Bin 2193 -> 2220 bytes packages/fast-usdc/src/exos/status-manager.js | 25 +++++++++----- packages/fast-usdc/test/exos/advancer.test.ts | 21 ++++++------ packages/fast-usdc/test/exos/settler.test.ts | 19 +++++------ .../test/exos/status-manager.test.ts | 31 +++++++++--------- packages/internal/src/storage-test-utils.js | 2 +- 8 files changed, 68 insertions(+), 50 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index dc77ee172de..36ed449c635 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -1,4 +1,5 @@ import anyTest from '@endo/ses-ava/prepare-endo.js'; + import type { TestFn } from 'ava'; import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { AmountMath } from '@agoric/ertp'; @@ -222,6 +223,7 @@ const advanceAndSettleScenario = test.macro({ nobleAgoricChannelId, oracleWds, retryUntilCondition, + smartWalletKit, useChain, usdcOnOsmosis, vstorageClient, @@ -306,10 +308,20 @@ const advanceAndSettleScenario = test.macro({ ), ); - const queryTxStatus = async () => - vstorageClient.queryData( - `published.${contractName}.txns.${evidence.txHash}`, + const queryTxStatus = async () => { + const record = await smartWalletKit.readPublished( + `fastUsdc.txns.${evidence.txHash}`, ); + if (!record) { + throw new Error(`no record for ${evidence.txHash}`); + } + // @ts-expect-error unknown may not have 'status' + if (!record.status) { + throw new Error(`no status for ${evidence.txHash}`); + } + // @ts-expect-error still unknown? + return record.status; + }; const assertTxStatus = async (status: string) => t.notThrowsAsync(() => diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md index f83e7fc388f..a755652de7a 100644 --- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md +++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md @@ -169,6 +169,6 @@ Generated by [AVA](https://avajs.dev). [ [ 'published.fastUsdc.txns.0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', - 'ADVANCING', + '{"body":"#{\\"status\\":\\"ADVANCING\\"}","slots":[]}', ], ] diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap index 577839a970dd27509899f00d143c4d6dde03da81..ce45d025417fe72c117b612e278fa5f7ff6d438f 100644 GIT binary patch literal 2220 zcmV;d2vhe#RzVl30 z{)vZ%ejken00000000BsSZ#-P^m0WV4sl z&@_#CE4EkTvop``PHuLdb>`W7;S3n1p9IB1i&{UJG$IH^#1BG6P!I&Gf?A@M3Pq)$ zUlc(sLPh4;mz$m4+wGEo!TWH`&j0s+dHys1-|v~{M!Dp2Yb|*8CKHZu+2)}Q-w`a( z%Z%B2ox6^;r3?aBi5EUdbO&+K>O0E-BnLSsg zfw&ad)?8TmIa#<&b1O_j!aUk<0Q?@n+W_WCE7#Z)rK`*mMD1KoO-+GJB1~}~Ar}cc z=_aizbvzl|VFAd#u$Z>-fX7QND^$4eSj8&!Jm#LZ+s2gDyfd3IV{VhuZH3pUQsQLD0s0IK9a-OZn2$Lb-e*%L?YH6S+*DrHkp6Y_@Q0fiham zzNJe%yP<()f_P=960Vv>?s-u z{nCY%q8!1w)Ws^(*(R;kU8a|q%Qtk#bsK^3X*i~#M_^T1jq1ECe}zM-cj^sq`D`wg zy14hv|eY_zjAc0O$ra}kb*ATRT<0) z+8^#3CwygOPWV87PAJN{WtNvZl#sX$;0*x(1~5f{+2ORH$#HuuGH!bqov6{x%hY#h$!)s)JQ{GlWoZUX67^pMc!vP*i_dP14w6L8D!?NO za6S%A_COm7u&n^k#i4t8px;-3A1c7>acHWiL5f_@Kb6R0ZRYWs<59tVY1Gvn;~uY3 zV}8@r@qR1@Y&so_@T5AR{?F}Ff0C## ztHAeE;AiS!mQ51%uPX3&6&TlI(D82Q6v$Znf0C#l(tsHaD8}6;dNSA=a8(1Y$Dw<7 zd1~L#M(UelMqBpkXwD=P@%`0kzN*>vuzovYW)mdY-H@?qvcKTEtitT&CjH7VJ^c^= zx5VL(??xP&v@<{(b~v@+OAV4r&{2VVLjWFZ2|%55SFbVQJ614Q0uq<+ngo1pWC=Lb zM*_mqA8%GJ^L(=-0^@H2cniQD0(_7FMFNxw@a%9g7?ZEx%?Ni-GtX+&O3Y{W3F=bM zYSQ~JB9K&2r9OL-`=TmsZ%3(La6#P@-1qrLAgzZZL^>_4#g^QhVyp={8-Ywp$T`m4 zj(ICe#nOD9)#+9syL?LlzO4X19_5A-P&_>>B4 z#G$=(_JRt0y~VGC=qyRpU#r0HRN!xM=;SWUci)H<5~ZIdZGcwT+7PY#(j8=e{tkR! zyaV4Gqx&X%!(Jmt$9}wy2yNzVZP-_E1^*aEP2P&pu zfspPmC~cuvLyh~X0w695Y7eO#SAkP1P#(UGzor78SAmz}(B2QOS5)9fD)3I6swVoW zQWt+rgach@&O-a%{k!zP%W*njLb$BPJP~t$?`}=+lU^%vd#n9JJ!}|~^$v_hSTAt7 z2u5&DkM68Is2tulTy9afRjsjX%sVA(w$6Pq?^slRigVXx{;WCAeLLKT&2O(7>&y=v z?yVZjtA=9*nZ;Ri)tFf|cJM{+dCUqK>9j3jR_Dg-Vn%|iJP?Cm$I=qkVk&9fc^RdN zc^0=FuOe-Ap9{Vq?~BcgTXiPy2KL&OTEi92m0D0)HLl6!wT=(x+sBBeF=P0w#s!P@ zp~~y?U4?gbCtSe)byu#*H|tEFH!Imikz?Il+GX1_z_vGHYfAAJd1aUu57gh4qTW6} znoH@ruAk+CE$e-F?dj$q7c5JJ5B-^$zMvLOv>-BKcUe_rHD)_h>_pY6&mvM@ z+R~3VX=0xHR+Y&;fWti*c-^7;!yAsMJ`puNEE67)Q~DW;2Q?lXoeiC5TT(u|=7_ng zL36qH!d}C#(KQz6jli~aYOjYMZM_={a`3Kw(cT{Ui}tBL&rfW6!CZRN%9|xCXQs2I zT$*MUj#-OVHcc&aF>mHr$+ENAoM|uQa&|diDle2+cBx!m$S-EInZ=yBn9j6P5z@|O zZW|%x8q3Dv?NuWXR5Y4XTUfbVI9oh@_R&@2nlWR@!7`Sge&$+hQ~Hmgo6@l40cRm6 u<-=^$bm3DkpjPvdHR{~cH>!?RjU0|U;l@xnUgdwgS^Y0km~P5I8vp?6Y*9}D literal 2193 zcmV;C2yXX5RzVGE^H74iJHDdn zf9H2dKp%?;00000000BsSZ#6=_S(&d}`H+)C( zfR;J8Xwy$Lt8gdqSUso;8C<_<+f1^LYOm-RNBBpQM4JJS1+bTlO_M~y z_t_R9?Wa9^_JE{72*?B>A80%29KafYuf!a+xT6NL8+(a{eMARIOp^!ejgspGRc_Cf zSs*V4wlx=KepV%}rnwbPLc)2BUjz6ZfHwimlh#~gPn523OA@{FI5jl|GKp}C`v|!} z(3x)1sxrq@!5toe>NVqGSB1gDZ6bBMJvCQGqYx%vvSTnkYrYfJ=pw2C)>{!hfbHaubzQUel zfutADuM|}a&ZRC?Ipv$IR(ClqaaU|m$8{Tl^jX-Zp+{gigq@8@jA)n8s zQs+6R%nbxB3Fh0h#{8hlT-Wg`)Dqr0_tf&~q03TGR~LBzRJ%PEX}8^$@TAWyd5%f0 ztm_f0QFfVBqc6E(JZiTMsIxlNa!MFXz4EX{yPqW_BkZxP^K@!pNmL6Yb>4R}NY z&c&h09%w@Yu4=$Dap2O98d9GdDWkfzr2Pc5=on|q?>cuWdk8L7T)+~qZD z+;5sX-j789iIUGeJJz;|b>=p>`bBn=gqg`?G7+H z-rCoVk?N+I(UQG9nls5pe1AEbuWoj|tlx|{vk8*yF38w4*;{a3Ug7r9CjF`~J@pU& zx5VKOZ$})Ov@<{(wmG%oD-BXg&{2VVLjVr61fVX2OKV*Ejui}+fW)P{CIMd^SpxR= zk$^Du$D5g}dA`vRf$`S?ya8Yr0p3f1A_2+-czU=PjH%D>W`w(^xo0(MCGK1=qg=Fq=;rn7EP}YMHBAr&&VoPpLa^8fTi9jY5uf7fRlcPG-_n2|4Of=eHQ)^m(BsrL)&t$I0}tuIBXMY|2l|u_d{PHC z;?Q0?drk+w*5cPebe1IguXNzII`G#xbaDsgyKh7aiPF!qF+eM9V~Ey$@eXEw_6~fX zzXRVJqx&X%1NgH6ATf9sGX;|9_rJ5K1BsDUq~m*b zbl+sp_UwU9LBjq$AF@QytwV{H_Pjb&dm?HI zd`GW9s&(D3HCNlu=TIL}W$L!WEVDI!x>#r(+Et`u10o%MyOB&4YHdKMeiuOMLdBFk zkjniztu6F=sBu5h0K`Q>?;(|AI&e}4%EPzu*L2`>I`Bdq+I!%7Ne6zY18>EtYNDSi zb@9hU*wBS$FSN(*-=Y3pj?)2`(&aVo$(Z{)cPe_H>5Y=Gx7t7SgXy$ly?tX5)(c!A zgAtrFqdRK{w1ZdEuCSQf$~Jv8J@1sP*}CxMykjwS6c?_`{aJHf_;$Dto4>l6Ugv(` z2yZogbT#c*L3U}@Tuslcrnm7$;d$H&8R?X*U{+^fb}6gCRT0QRup=1-YcZ9wZhwr* z#63&cj#p8(x-XtLbZMd9CZi`SvxUnVw1eye1@% z)uAft^IeH|RVQ4)|8-TasW0nvpD!!fMUi9OT-s&ZHNdtzVrxqA7I|ry77x_ll_G6l zAI+sGrSy!D{3z|iYaeSia>24>_|iW<(-+jDi55gf46hygK^;$Wzs7Bc$?d3=`8*=! zr7e1_NfYzJx2jz20UY6}!0Qg94{tcK`b5<9u$u6Y>e5eJBB+Vr@NDQj+miCxHAl`} z37X5j7xo%{jji#3HUitC%w7)MRa z&M1YIONBGVQ)eD+?KS@~bgvnvGT@5ignCDf8kIit0%kSeM58V|x>0qkYUIw_3HN)_ T@hbn@J?MV{5xNl^7aITo-Z@PM diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 6db165b8b31..937a7285c34 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -14,6 +14,7 @@ import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; * @import {MapStore, SetStore} from '@agoric/store'; * @import {Zone} from '@agoric/zone'; * @import {CctpTxEvidence, NobleAddress, PendingTx, EvmHash, LogFn} from '../types.js'; + * @import {CopyRecord} from '@endo/pass-style'; */ /** @@ -99,17 +100,26 @@ export const prepareStatusManager = ( keyShape: M.string(), }); + /** + * @param {EvmHash} txId + * @param {CopyRecord} record + */ + const publishTxnRecord = (txId, record) => { + const txNode = E(txnsNode).makeChildNode(txId, { + sequence: true, // avoid overwriting other output in the block + }); + void E(txNode).setValue( + JSON.stringify(pureDataMarshaller.toCapData(harden(record))), + ); + }; + /** * @param {CctpTxEvidence['txHash']} hash * @param {CctpTxEvidence} evidence */ const publishEvidence = (hash, evidence) => { - const txNode = E(transactionsNode).makeChildNode(hash); // Don't await, just writing to vstorage. - void E(txNode).setValue( - // @ts-expect-error XXX CopyRecordI expects an index signature - JSON.stringify(pureDataMarshaller.toCapData(evidence)), - ); + void publishTxnRecord(hash, evidence); }; /** @@ -117,9 +127,8 @@ export const prepareStatusManager = ( * @param {TxStatus} status */ const publishStatus = (hash, status) => { - const txnNodeP = E(txnsNode).makeChildNode(hash); // Don't await, just writing to vstorage. - void E(txnNodeP).setValue(status); + void publishTxnRecord(hash, { status }); if (TerminalTxStatus[status]) { // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 // Queue it for deletion later because if we deleted it now the earlier @@ -254,7 +263,7 @@ export const prepareStatusManager = ( deleteCompletedTxs() { for (const txHash of storedCompletedTxs.values()) { // As of now, setValue('') on a non-sequence node will delete it - const txNode = E(transactionsNode).makeChildNode(txHash, { + const txNode = E(txnsNode).makeChildNode(txHash, { sequence: false, }); void E(txNode) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 815727e6bf7..eb1513e4351 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -12,7 +12,6 @@ import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { q } from '@endo/errors'; import { Far } from '@endo/pass-style'; import type { TestFn } from 'ava'; -import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; @@ -187,8 +186,8 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.getValues(`fun.txns.${mockEvidence.txHash}`), - [stringifyWithBigint(mockEvidence), PendingTxStatus.Advancing], + storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + [mockEvidence, { status: PendingTxStatus.Advancing }], 'ADVANCED status in happy path', ); @@ -261,8 +260,8 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { await eventLoopIteration(); t.deepEqual( - storage.getValues(`fun.txns.${mockEvidence.txHash}`), - [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], + storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + [mockEvidence, { status: PendingTxStatus.Observed }], 'OBSERVED status on insufficient pool funds', ); @@ -290,8 +289,8 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.getValues(`fun.txns.${mockEvidence.txHash}`), - [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], + storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + [mockEvidence, { status: PendingTxStatus.Observed }], 'OBSERVED status on makeChainAddress failure', ); @@ -323,8 +322,8 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t await eventLoopIteration(); t.deepEqual( - storage.getValues(`fun.txns.${mockEvidence.txHash}`), - [stringifyWithBigint(mockEvidence), PendingTxStatus.Advancing], + storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + [mockEvidence, { status: PendingTxStatus.Advancing }], 'tx is Advancing', ); @@ -370,8 +369,8 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.getValues(`fun.txns.${mockEvidence.txHash}`), - [stringifyWithBigint(mockEvidence), PendingTxStatus.Observed], + storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + [mockEvidence, { status: PendingTxStatus.Observed }], 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 9456fb5417a..406c55c4ae7 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -4,7 +4,6 @@ import type { TestFn } from 'ava'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import type { Zone } from '@agoric/zone'; -import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareSettler } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; @@ -236,11 +235,11 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { ); await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getValues(`fun.txns.${cctpTxEvidence.txHash}`), [ - stringifyWithBigint(cctpTxEvidence), - 'ADVANCING', - 'ADVANCED', - 'DISBURSED', + t.deepEqual(storage.getPureData(`fun.txns.${cctpTxEvidence.txHash}`), [ + cctpTxEvidence, + { status: 'ADVANCING' }, + { status: 'ADVANCED' }, + { status: 'DISBURSED' }, ]); // Check deletion of DISBURSED transactions @@ -314,10 +313,10 @@ test('slow path: forward to EUD; remove pending tx', async t => { 'SETTLED entry removed from StatusManger', ); const { storage } = t.context; - t.deepEqual(storage.getValues(`fun.txns.${cctpTxEvidence.txHash}`), [ - stringifyWithBigint(cctpTxEvidence), - 'OBSERVED', - 'FORWARDED', + t.deepEqual(storage.getPureData(`fun.txns.${cctpTxEvidence.txHash}`), [ + cctpTxEvidence, + { status: 'OBSERVED' }, + { status: 'FORWARDED' }, ]); // Check deletion of FORWARDED transactions diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 40db60149c9..06d64c6a616 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -2,7 +2,6 @@ import type { TestFn } from 'ava'; import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { StorageNode } from '@agoric/internal/src/lib-chainStorage.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; -import { stringifyWithBigint } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; import { commonSetup, provideDurableZone } from '../supports.js'; @@ -55,9 +54,9 @@ test('ADVANCED transactions are published to vstorage', async t => { await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getValues(`fun.txns.${evidence.txHash}`), [ - stringifyWithBigint(evidence), - 'ADVANCING', + t.deepEqual(storage.getPureData(`fun.txns.${evidence.txHash}`), [ + evidence, + { status: 'ADVANCING' }, ]); }); @@ -90,9 +89,9 @@ test('OBSERVED transactions are published to vstorage', async t => { await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getValues(`fun.txns.${evidence.txHash}`), [ - stringifyWithBigint(evidence), - 'OBSERVED', + t.deepEqual(storage.getPureData(`fun.txns.${evidence.txHash}`), [ + evidence, + { status: 'OBSERVED' }, ]); }); @@ -235,10 +234,10 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.deepEqual(storage.getValues(`fun.txns.${e1.txHash}`), [ - stringifyWithBigint(e1), - PendingTxStatus.Advancing, - PendingTxStatus.Advanced, + t.deepEqual(storage.getPureData(`fun.txns.${e1.txHash}`), [ + e1, + { status: 'ADVANCING' }, + { status: 'ADVANCED' }, ]); statusManager.advance(e2); @@ -249,10 +248,10 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.deepEqual(storage.getValues(`fun.txns.${e2.txHash}`), [ - stringifyWithBigint(e2), - PendingTxStatus.Advancing, - PendingTxStatus.AdvanceFailed, + t.deepEqual(storage.getPureData(`fun.txns.${e2.txHash}`), [ + e2, + { status: 'ADVANCING' }, + { status: 'ADVANCE_FAILED' }, ]); }); @@ -325,7 +324,7 @@ test('dequeueStatus returns first (earliest) matched entry', async t => { PendingTxStatus.Advanced, 'first settled entry deleted', ); - t.is( + t.deepEqual( entries0?.[1].status, PendingTxStatus.Observed, 'order of remaining entries preserved', diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index b467220ae25..0b5f594cf3b 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -195,7 +195,7 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { * Get the values at a sequence node * * @param {string} path - * @returns {unknown[]} + * @returns {string[]} */ const getValues = path => { assert(resolvedOptions.sequence); From 00e7a8d93dffc61ab74ade937a3532c29740d02d Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 19:51:47 -0800 Subject: [PATCH 35/65] chore(types): import CctpTxEvidence --- multichain-testing/test/fast-usdc/fast-usdc.test.ts | 9 ++++++--- multichain-testing/tools/noble-tools.ts | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 36ed449c635..a7fbf413e32 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -15,6 +15,10 @@ import { makeFeedPolicy, oracleMnemonics } from './config.js'; import { makeRandomDigits } from '../../tools/random.js'; import { balancesFromPurses } from '../../tools/purse.js'; import { makeTracer } from '@agoric/internal'; +import type { + CctpTxEvidence, + EvmAddress, +} from '@agoric/fast-usdc/src/types.js'; const log = makeTracer('MCFU'); @@ -258,8 +262,7 @@ const advanceAndSettleScenario = test.macro({ ); t.log('got forwardingAddress', userForwardingAddr); - // TODO export CctpTxEvidence type - const evidence = harden({ + const evidence: CctpTxEvidence = harden({ blockHash: '0x90d7343e04f8160892e94f02d6a9b9f255663ed0ac34caca98544c8143fee665', blockNumber: 21037663n, @@ -267,7 +270,7 @@ const advanceAndSettleScenario = test.macro({ tx: { amount: mintAmt, forwardingAddress: userForwardingAddr, - sender: '0x9a9eE9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9', + sender: '0x9a9eE9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9' as EvmAddress, }, aux: { forwardingChannel: nobleAgoricChannelId, diff --git a/multichain-testing/tools/noble-tools.ts b/multichain-testing/tools/noble-tools.ts index 8a08e6a85bb..cd72a332857 100644 --- a/multichain-testing/tools/noble-tools.ts +++ b/multichain-testing/tools/noble-tools.ts @@ -1,6 +1,7 @@ import type { IBCChannelID } from '@agoric/vats'; import type { ExecSync } from './agd-lib.js'; import type { ChainAddress } from '@agoric/orchestration'; +import type { NobleAddress } from '@agoric/fast-usdc/src/types.js'; const kubectlBinary = 'kubectl'; const noblePod = 'noblelocal-genesis-0'; @@ -82,7 +83,7 @@ export const makeNobleTools = ( const queryForwardingAddress = ( channelId: IBCChannelID, address: ChainAddress['value'], - ): { address: string; exists: boolean } => { + ): { address: NobleAddress; exists: boolean } => { checkEnv(); log('querying forwarding address', address, channelId); return JSON.parse( From 19d5e03b426e74b8a19d11b425634a0a83e929a1 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 14:08:38 -0800 Subject: [PATCH 36/65] feat: defaultSerializer util --- packages/internal/src/storage-test-utils.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index 0b5f594cf3b..6babcb12223 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -34,6 +34,16 @@ export const defaultMarshaller = makeMarshal(undefined, slotToRemotable, { serializeBodyFormat: 'smallcaps', }); +/** + * Serialize/deserialize functions using {@link defaultMarshaller} + */ +export const defaultSerializer = { + /** @type {(text: string) => unknown} */ + parse: txt => defaultMarshaller.fromCapData(JSON.parse(txt)), + /** @type {(obj: any) => string} */ + stringify: obj => JSON.stringify(defaultMarshaller.toCapData(obj)), +}; + /** * A deserializer which produces slot strings instead of Remotables, so if `a = * Far('iface')`, and serializing `{ a }` into `capData` assigned it slot From c20866d797f452bd04e748a0cc0f65133eacd7a9 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 14:10:46 -0800 Subject: [PATCH 37/65] test: use defaultSerializer --- packages/boot/test/fast-usdc/fast-usdc.test.ts | 9 ++++++--- packages/fast-usdc/test/exos/advancer.test.ts | 10 +++++----- packages/fast-usdc/test/exos/settler.test.ts | 4 ++-- packages/fast-usdc/test/exos/status-manager.test.ts | 8 ++++---- packages/fast-usdc/test/supports.ts | 13 +++++++------ 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index 32f3d23354b..afbd8d532f1 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -7,7 +7,10 @@ import { documentStorageSchema } from '@agoric/governance/tools/storageDoc.js'; import { Fail } from '@endo/errors'; import { unmarshalFromVstorage } from '@agoric/internal/src/marshal.js'; import { makeMarshal } from '@endo/marshal'; -import { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; +import { + defaultMarshaller, + defaultSerializer, +} from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { BridgeId } from '@agoric/internal'; import { @@ -155,7 +158,7 @@ test.serial('writes fee config to vstorage', async t => { const doc = { node: 'fastUsdc.feeConfig', owner: 'the fee configuration for Fast USDC', - showValue: v => defaultMarshaller.fromCapData(JSON.parse(v)), + showValue: defaultSerializer.parse, }; await documentStorageSchema(t, storage, doc); }); @@ -165,7 +168,7 @@ test.serial('writes pool metrics to vstorage', async t => { const doc = { node: 'fastUsdc.poolMetrics', owner: 'FastUSC LiquidityPool exo', - showValue: v => defaultMarshaller.fromCapData(JSON.parse(v)), + showValue: defaultSerializer.parse, }; await documentStorageSchema(t, storage, doc); }); diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index eb1513e4351..2b01dcb689d 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -186,7 +186,7 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), [mockEvidence, { status: PendingTxStatus.Advancing }], 'ADVANCED status in happy path', ); @@ -260,7 +260,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { await eventLoopIteration(); t.deepEqual( - storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), [mockEvidence, { status: PendingTxStatus.Observed }], 'OBSERVED status on insufficient pool funds', ); @@ -289,7 +289,7 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), [mockEvidence, { status: PendingTxStatus.Observed }], 'OBSERVED status on makeChainAddress failure', ); @@ -322,7 +322,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t await eventLoopIteration(); t.deepEqual( - storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), [mockEvidence, { status: PendingTxStatus.Advancing }], 'tx is Advancing', ); @@ -369,7 +369,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent(mockEvidence); t.deepEqual( - storage.getPureData(`fun.txns.${mockEvidence.txHash}`), + storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), [mockEvidence, { status: PendingTxStatus.Observed }], 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 406c55c4ae7..11a5ffe9fd2 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -235,7 +235,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { ); await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getPureData(`fun.txns.${cctpTxEvidence.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${cctpTxEvidence.txHash}`), [ cctpTxEvidence, { status: 'ADVANCING' }, { status: 'ADVANCED' }, @@ -313,7 +313,7 @@ test('slow path: forward to EUD; remove pending tx', async t => { 'SETTLED entry removed from StatusManger', ); const { storage } = t.context; - t.deepEqual(storage.getPureData(`fun.txns.${cctpTxEvidence.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${cctpTxEvidence.txHash}`), [ cctpTxEvidence, { status: 'OBSERVED' }, { status: 'FORWARDED' }, diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 06d64c6a616..c93441c40a6 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -54,7 +54,7 @@ test('ADVANCED transactions are published to vstorage', async t => { await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getPureData(`fun.txns.${evidence.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${evidence.txHash}`), [ evidence, { status: 'ADVANCING' }, ]); @@ -89,7 +89,7 @@ test('OBSERVED transactions are published to vstorage', async t => { await eventLoopIteration(); const { storage } = t.context; - t.deepEqual(storage.getPureData(`fun.txns.${evidence.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${evidence.txHash}`), [ evidence, { status: 'OBSERVED' }, ]); @@ -234,7 +234,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.deepEqual(storage.getPureData(`fun.txns.${e1.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${e1.txHash}`), [ e1, { status: 'ADVANCING' }, { status: 'ADVANCED' }, @@ -248,7 +248,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }, ]); await eventLoopIteration(); - t.deepEqual(storage.getPureData(`fun.txns.${e2.txHash}`), [ + t.deepEqual(storage.getDeserialized(`fun.txns.${e2.txHash}`), [ e2, { status: 'ADVANCING' }, { status: 'ADVANCE_FAILED' }, diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 1cb5284d515..8ecdc66bdb6 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -1,6 +1,10 @@ import { makeIssuerKit } from '@agoric/ertp'; import { VTRANSFER_IBC_EVENT } from '@agoric/internal/src/action-types.js'; -import { makeFakeStorageKit } from '@agoric/internal/src/storage-test-utils.js'; +import { + defaultMarshaller, + defaultSerializer, + makeFakeStorageKit, +} from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import { denomHash, @@ -48,9 +52,6 @@ export { makeFakeTransferBridge, } from '@agoric/vats/tools/fake-bridge.js'; -const unserializePureData = data => - pureDataMarshaller.fromCapData(JSON.parse(data)); - const assetOn = ( baseDenom: Denom, baseName: string, @@ -163,8 +164,8 @@ export const commonSetup = async (t: ExecutionContext) => { * Read pure data (CapData that has no slots) from the storage path * @param path */ - storage.getPureData = (path: string): PureData => - storage.getValues(path).map(unserializePureData); + storage.getDeserialized = (path: string): unknown => + storage.getValues(path).map(defaultSerializer.parse); const { portAllocator, setupIBCProtocol, ibcBridge } = setupFakeNetwork( rootZone.subZone('network'), From 7e62d8f811e212f8160c36a3b954aee8c0e1fb90 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 14:16:17 -0800 Subject: [PATCH 38/65] feat: publish OBSERVED with first evidence --- .../boot/test/fast-usdc/fast-usdc.test.ts | 10 +++ packages/fast-usdc/src/exos/status-manager.js | 14 ++-- packages/fast-usdc/test/exos/advancer.test.ts | 66 ++++++++++--------- packages/fast-usdc/test/exos/settler.test.ts | 5 +- .../test/exos/status-manager.test.ts | 9 ++- 5 files changed, 61 insertions(+), 43 deletions(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index afbd8d532f1..14f04876108 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -258,6 +258,16 @@ test.serial('makes usdc advance', async t => { ); harness?.resetRunPolicy(); + t.deepEqual( + storage + .getValues(`published.fastUsdc.txns.${evidence.txHash}`) + .map(defaultSerializer.parse), + [ + { evidence, status: 'OBSERVED' }, // observation includes evidence observed + { status: 'ADVANCING' }, + ], + ); + const doc = { node: `fastUsdc.txns`, owner: `the Ethereum transactions upon which Fast USDC is acting`, diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 937a7285c34..0fb63eed628 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -109,7 +109,7 @@ export const prepareStatusManager = ( sequence: true, // avoid overwriting other output in the block }); void E(txNode).setValue( - JSON.stringify(pureDataMarshaller.toCapData(harden(record))), + JSON.stringify(pureDataMarshaller.toCapData(record)), ); }; @@ -119,7 +119,10 @@ export const prepareStatusManager = ( */ const publishEvidence = (hash, evidence) => { // Don't await, just writing to vstorage. - void publishTxnRecord(hash, evidence); + void publishTxnRecord( + hash, + harden({ evidence, status: TxStatus.Observed }), + ); }; /** @@ -128,7 +131,7 @@ export const prepareStatusManager = ( */ const publishStatus = (hash, status) => { // Don't await, just writing to vstorage. - void publishTxnRecord(hash, { status }); + void publishTxnRecord(hash, harden({ status })); if (TerminalTxStatus[status]) { // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 // Queue it for deletion later because if we deleted it now the earlier @@ -160,7 +163,10 @@ export const prepareStatusManager = ( harden({ ...evidence, status }), ); publishEvidence(txHash, evidence); - publishStatus(txHash, status); + if (status !== PendingTxStatus.Observed) { + // publishEvidence publishes Observed + publishStatus(txHash, status); + } }; /** diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 2b01dcb689d..7f118598f88 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -175,8 +175,8 @@ test('updates status to ADVANCING in happy path', async t => { bootstrap: { storage }, } = t.context; - const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); - void advancer.handleTransactionEvent(mockEvidence); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + void advancer.handleTransactionEvent(evidence); // pretend borrow succeeded and funds were depositing to the LCA resolveLocalTransferV(); @@ -186,8 +186,11 @@ test('updates status to ADVANCING in happy path', async t => { await eventLoopIteration(); t.deepEqual( - storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), - [mockEvidence, { status: PendingTxStatus.Advancing }], + storage.getDeserialized(`fun.txns.${evidence.txHash}`), + [ + { evidence, status: PendingTxStatus.Observed }, + { status: PendingTxStatus.Advancing }, + ], 'ADVANCED status in happy path', ); @@ -215,11 +218,11 @@ test('updates status to ADVANCING in happy path', async t => { t.like(inspectNotifyCalls(), [ [ { - txHash: mockEvidence.txHash, - forwardingAddress: mockEvidence.tx.forwardingAddress, - fullAmount: usdc.make(mockEvidence.tx.amount), + txHash: evidence.txHash, + forwardingAddress: evidence.tx.forwardingAddress, + fullAmount: usdc.make(evidence.tx.amount), destination: { - value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD, + value: decodeAddressHook(evidence.aux.recipientAddress).query.EUD, }, }, true, // indicates transfer succeeded @@ -255,13 +258,13 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { intermediateRecipient, }); - const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); - void advancer.handleTransactionEvent(mockEvidence); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); + void advancer.handleTransactionEvent(evidence); await eventLoopIteration(); t.deepEqual( - storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), - [mockEvidence, { status: PendingTxStatus.Observed }], + storage.getDeserialized(`fun.txns.${evidence.txHash}`), + [{ evidence, status: PendingTxStatus.Observed }], 'OBSERVED status on insufficient pool funds', ); @@ -285,12 +288,12 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { }, } = t.context; - const mockEvidence = MockCctpTxEvidences.AGORIC_UNKNOWN_EUD(); - await advancer.handleTransactionEvent(mockEvidence); + const evidence = MockCctpTxEvidences.AGORIC_UNKNOWN_EUD(); + await advancer.handleTransactionEvent(evidence); t.deepEqual( - storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), - [mockEvidence, { status: PendingTxStatus.Observed }], + storage.getDeserialized(`fun.txns.${evidence.txHash}`), + [{ evidence, status: PendingTxStatus.Observed }], 'OBSERVED status on makeChainAddress failure', ); @@ -314,16 +317,19 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t brands: { usdc }, } = t.context; - const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); - void advancer.handleTransactionEvent(mockEvidence); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); + void advancer.handleTransactionEvent(evidence); // pretend borrow and deposit to LCA succeed resolveLocalTransferV(); await eventLoopIteration(); t.deepEqual( - storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), - [mockEvidence, { status: PendingTxStatus.Advancing }], + storage.getDeserialized(`fun.txns.${evidence.txHash}`), + [ + { evidence, status: PendingTxStatus.Observed }, + { status: PendingTxStatus.Advancing }, + ], 'tx is Advancing', ); @@ -340,14 +346,12 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t t.like(inspectNotifyCalls(), [ [ { - txHash: mockEvidence.txHash, - forwardingAddress: mockEvidence.tx.forwardingAddress, - fullAmount: usdc.make(mockEvidence.tx.amount), - advanceAmount: feeTools.calculateAdvance( - usdc.make(mockEvidence.tx.amount), - ), + txHash: evidence.txHash, + forwardingAddress: evidence.tx.forwardingAddress, + fullAmount: usdc.make(evidence.tx.amount), + advanceAmount: feeTools.calculateAdvance(usdc.make(evidence.tx.amount)), destination: { - value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD, + value: decodeAddressHook(evidence.aux.recipientAddress).query.EUD, }, }, false, // this indicates transfer failed @@ -364,13 +368,13 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { }, } = t.context; - const mockEvidence = MockCctpTxEvidences.AGORIC_NO_PARAMS(); + const evidence = MockCctpTxEvidences.AGORIC_NO_PARAMS(); - await advancer.handleTransactionEvent(mockEvidence); + await advancer.handleTransactionEvent(evidence); t.deepEqual( - storage.getDeserialized(`fun.txns.${mockEvidence.txHash}`), - [mockEvidence, { status: PendingTxStatus.Observed }], + storage.getDeserialized(`fun.txns.${evidence.txHash}`), + [{ evidence, status: PendingTxStatus.Observed }], 'tx is recorded as OBSERVED', ); diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index 11a5ffe9fd2..f23f90702d4 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -236,7 +236,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { await eventLoopIteration(); const { storage } = t.context; t.deepEqual(storage.getDeserialized(`fun.txns.${cctpTxEvidence.txHash}`), [ - cctpTxEvidence, + { evidence: cctpTxEvidence, status: 'OBSERVED' }, { status: 'ADVANCING' }, { status: 'ADVANCED' }, { status: 'DISBURSED' }, @@ -314,8 +314,7 @@ test('slow path: forward to EUD; remove pending tx', async t => { ); const { storage } = t.context; t.deepEqual(storage.getDeserialized(`fun.txns.${cctpTxEvidence.txHash}`), [ - cctpTxEvidence, - { status: 'OBSERVED' }, + { evidence: cctpTxEvidence, status: 'OBSERVED' }, { status: 'FORWARDED' }, ]); diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index c93441c40a6..14c45185fa8 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -55,7 +55,7 @@ test('ADVANCED transactions are published to vstorage', async t => { const { storage } = t.context; t.deepEqual(storage.getDeserialized(`fun.txns.${evidence.txHash}`), [ - evidence, + { evidence, status: 'OBSERVED' }, { status: 'ADVANCING' }, ]); }); @@ -90,8 +90,7 @@ test('OBSERVED transactions are published to vstorage', async t => { const { storage } = t.context; t.deepEqual(storage.getDeserialized(`fun.txns.${evidence.txHash}`), [ - evidence, - { status: 'OBSERVED' }, + { evidence, status: 'OBSERVED' }, ]); }); @@ -235,7 +234,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { ]); await eventLoopIteration(); t.deepEqual(storage.getDeserialized(`fun.txns.${e1.txHash}`), [ - e1, + { evidence: e1, status: 'OBSERVED' }, { status: 'ADVANCING' }, { status: 'ADVANCED' }, ]); @@ -249,7 +248,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { ]); await eventLoopIteration(); t.deepEqual(storage.getDeserialized(`fun.txns.${e2.txHash}`), [ - e2, + { evidence: e2, status: 'OBSERVED' }, { status: 'ADVANCING' }, { status: 'ADVANCE_FAILED' }, ]); From ccb9e28a92c17ce3362ac5898acb80128614edab Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Mon, 16 Dec 2024 14:25:17 -0800 Subject: [PATCH 39/65] feat(types): TransactionRecord --- .../boot/test/fast-usdc/fast-usdc.test.ts | 1 + .../fast-usdc/snapshots/fast-usdc.test.ts.md | 4 +++- .../snapshots/fast-usdc.test.ts.snap | Bin 2220 -> 2209 bytes packages/fast-usdc/src/exos/status-manager.js | 5 ++--- packages/fast-usdc/src/types.ts | 11 ++++++++++- 5 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index 14f04876108..3c17e8b6f55 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -271,6 +271,7 @@ test.serial('makes usdc advance', async t => { const doc = { node: `fastUsdc.txns`, owner: `the Ethereum transactions upon which Fast USDC is acting`, + showValue: defaultSerializer.parse, }; await documentStorageSchema(t, storage, doc); }); diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md index a755652de7a..eae055ef42a 100644 --- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md +++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md @@ -169,6 +169,8 @@ Generated by [AVA](https://avajs.dev). [ [ 'published.fastUsdc.txns.0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', - '{"body":"#{\\"status\\":\\"ADVANCING\\"}","slots":[]}', + { + status: 'ADVANCING', + }, ], ] diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap index ce45d025417fe72c117b612e278fa5f7ff6d438f..c837074b0fac8a8353a3bc2e4a0b8b6253eecf4f 100644 GIT binary patch literal 2209 zcmV;S2wwL=RzV2`E6f!>t&1v`;>In zK(`2KKkePS7i0p2fJ_qdfwq&*0IUJ{O3YD6}n&5^l`6?2z{q58Ae@U*v1de}W0Y{0a+tV_VCMi)qJ7uPhhs{8HA+Sb0XvS?gpzpU2hDR>aQ`6mYBEspG&^O0yEY5%u=(a ztTHpz=W9!uK6jYu3e#a8tAw=*J12x!n9l<0nbdbomCu~0Guth@cC*FYu;F;1u&1by z=A{cOMb(1y6Bnz@WSg{B_n28?9^Wus&ua)7(6CKI4`EkXjheiyeuYhGcJd8}0yaM} zae*@|rF`iw0b8S(*WpME@57-Xg%e;=LQAgCxaJ_ICP??K$=?5KefnW9p>|z>r=@CWi<6|<1W8Z zV?oo@@qRo4NR$HVJF&J+tW&SS)GxA|B&>8gosRf_cr^dcDq(;HUavmQ518XGC zza;8KJ+sDS;M!ua1SBrsGYR}V)y&0u`$tCqp@F3tDLRk+*h;&9-i!Hf1#aI(^HUgPakaL`S z9rIR{ik101tJ5u^s(f1mzNG;_8m=s_Yrq>CpvS3gtOt5P2OideN8`|m9_Z6L@ChB* zh(mkn>^U9yT8m!?(OHt{ztVx<>cHRP(5W4mZ_kJn5~ZJIV}MpT#t^Oh!d=Y#rMvKb z{w{oPj_#Z6k;5GcH%atw8o-MN@Z%xcm?Zk24B#&YfW+Wk%rr=%-~Y~{4kkuck&f@V z(S4IW+p`Bd1qu82LdX)LTZa-Y?Rj;m_C)w@2lWXx=F)|tdB*)@!*yJ_6;5ihO@4o9 z&ciLup|;H%zBFm`NXUi=&sa4gJc&Gj4+8iQfC~UVK1_rRB@S*gz$78hwq#hZ^@24M1EJ^d3?+K(lu%7U^ z6eBpNM|ai^YKN|+JZ@93m2K)+YQZhpb9Elb1=ptPD9$~P1#{K{51eoxws37Vwax}XoST1=&^+aIGc zG2iBn>sOSm9&pJQ)wtZexK(FrR5)u_Y7I}iS8AfNn!2u**SbDjXkQ~*so7M(YFx5d z9jd&((3N;sb;1SwUsvV2`m)aS`LdE-6gk$-rCqjN18ln^wx$$sk(Y*P@j(4uDVpu; zqxlKbG|jVIvSVf+Ui)aXkqfph!XIJ%G!76?omH<|7-ftUehvJ)$N&th)45HWxK6j?9J5b1f;KTXW_7 zRnc7T{jk>vYIKbWvmqSYq|SPHXzSfrklZ~x(cT&PMEi7~_a`@fF`wSF^H#~uS?O#k zm!_G;qxO=WO;g)i%3C>BvYl);XE}?xoKw!1%8MnIT`rdw^Gn%mW+`Var86qWKXgvR zT9N>JhM#;%jHbtgq_WYuvENl#xm-9~Jbm`D){gZbLwBsl30 z{)vZ%ejken00000000BsSZ#-P^m0WV4sl z&@_#CE4EkTvop``PHuLdb>`W7;S3n1p9IB1i&{UJG$IH^#1BG6P!I&Gf?A@M3Pq)$ zUlc(sLPh4;mz$m4+wGEo!TWH`&j0s+dHys1-|v~{M!Dp2Yb|*8CKHZu+2)}Q-w`a( z%Z%B2ox6^;r3?aBi5EUdbO&+K>O0E-BnLSsg zfw&ad)?8TmIa#<&b1O_j!aUk<0Q?@n+W_WCE7#Z)rK`*mMD1KoO-+GJB1~}~Ar}cc z=_aizbvzl|VFAd#u$Z>-fX7QND^$4eSj8&!Jm#LZ+s2gDyfd3IV{VhuZH3pUQsQLD0s0IK9a-OZn2$Lb-e*%L?YH6S+*DrHkp6Y_@Q0fiham zzNJe%yP<()f_P=960Vv>?s-u z{nCY%q8!1w)Ws^(*(R;kU8a|q%Qtk#bsK^3X*i~#M_^T1jq1ECe}zM-cj^sq`D`wg zy14hv|eY_zjAc0O$ra}kb*ATRT<0) z+8^#3CwygOPWV87PAJN{WtNvZl#sX$;0*x(1~5f{+2ORH$#HuuGH!bqov6{x%hY#h$!)s)JQ{GlWoZUX67^pMc!vP*i_dP14w6L8D!?NO za6S%A_COm7u&n^k#i4t8px;-3A1c7>acHWiL5f_@Kb6R0ZRYWs<59tVY1Gvn;~uY3 zV}8@r@qR1@Y&so_@T5AR{?F}Ff0C## ztHAeE;AiS!mQ51%uPX3&6&TlI(D82Q6v$Znf0C#l(tsHaD8}6;dNSA=a8(1Y$Dw<7 zd1~L#M(UelMqBpkXwD=P@%`0kzN*>vuzovYW)mdY-H@?qvcKTEtitT&CjH7VJ^c^= zx5VL(??xP&v@<{(b~v@+OAV4r&{2VVLjWFZ2|%55SFbVQJ614Q0uq<+ngo1pWC=Lb zM*_mqA8%GJ^L(=-0^@H2cniQD0(_7FMFNxw@a%9g7?ZEx%?Ni-GtX+&O3Y{W3F=bM zYSQ~JB9K&2r9OL-`=TmsZ%3(La6#P@-1qrLAgzZZL^>_4#g^QhVyp={8-Ywp$T`m4 zj(ICe#nOD9)#+9syL?LlzO4X19_5A-P&_>>B4 z#G$=(_JRt0y~VGC=qyRpU#r0HRN!xM=;SWUci)H<5~ZIdZGcwT+7PY#(j8=e{tkR! zyaV4Gqx&X%!(Jmt$9}wy2yNzVZP-_E1^*aEP2P&pu zfspPmC~cuvLyh~X0w695Y7eO#SAkP1P#(UGzor78SAmz}(B2QOS5)9fD)3I6swVoW zQWt+rgach@&O-a%{k!zP%W*njLb$BPJP~t$?`}=+lU^%vd#n9JJ!}|~^$v_hSTAt7 z2u5&DkM68Is2tulTy9afRjsjX%sVA(w$6Pq?^slRigVXx{;WCAeLLKT&2O(7>&y=v z?yVZjtA=9*nZ;Ri)tFf|cJM{+dCUqK>9j3jR_Dg-Vn%|iJP?Cm$I=qkVk&9fc^RdN zc^0=FuOe-Ap9{Vq?~BcgTXiPy2KL&OTEi92m0D0)HLl6!wT=(x+sBBeF=P0w#s!P@ zp~~y?U4?gbCtSe)byu#*H|tEFH!Imikz?Il+GX1_z_vGHYfAAJd1aUu57gh4qTW6} znoH@ruAk+CE$e-F?dj$q7c5JJ5B-^$zMvLOv>-BKcUe_rHD)_h>_pY6&mvM@ z+R~3VX=0xHR+Y&;fWti*c-^7;!yAsMJ`puNEE67)Q~DW;2Q?lXoeiC5TT(u|=7_ng zL36qH!d}C#(KQz6jli~aYOjYMZM_={a`3Kw(cT{Ui}tBL&rfW6!CZRN%9|xCXQs2I zT$*MUj#-OVHcc&aF>mHr$+ENAoM|uQa&|diDle2+cBx!m$S-EInZ=yBn9j6P5z@|O zZW|%x8q3Dv?NuWXR5Y4XTUfbVI9oh@_R&@2nlWR@!7`Sge&$+hQ~Hmgo6@l40cRm6 u<-=^$bm3DkpjPvdHR{~cH>!?RjU0|U;l@xnUgdwgS^Y0km~P5I8vp?6Y*9}D diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 0fb63eed628..588126a3b73 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -13,8 +13,7 @@ import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; /** * @import {MapStore, SetStore} from '@agoric/store'; * @import {Zone} from '@agoric/zone'; - * @import {CctpTxEvidence, NobleAddress, PendingTx, EvmHash, LogFn} from '../types.js'; - * @import {CopyRecord} from '@endo/pass-style'; + * @import {CctpTxEvidence, NobleAddress, PendingTx, EvmHash, LogFn, TransactionRecord} from '../types.js'; */ /** @@ -102,7 +101,7 @@ export const prepareStatusManager = ( /** * @param {EvmHash} txId - * @param {CopyRecord} record + * @param {TransactionRecord} record */ const publishTxnRecord = (txId, record) => { const txNode = E(txnsNode).makeChildNode(txId, { diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index 35bbf84da1f..0d3701e9d82 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -7,7 +7,7 @@ import type { import type { IBCChannelID } from '@agoric/vats'; import type { Amount } from '@agoric/ertp'; import type { CopyRecord, Passable } from '@endo/pass-style'; -import type { PendingTxStatus } from './constants.js'; +import type { PendingTxStatus, TxStatus } from './constants.js'; import type { FastUsdcTerms } from './fast-usdc.contract.js'; export type EvmHash = `0x${string}`; @@ -34,6 +34,15 @@ export interface CctpTxEvidence { txHash: EvmHash; } +/** + * 'evidence' only available when it's first observed and not in subsequent + * updates. + */ +export interface TransactionRecord extends CopyRecord { + evidence?: CctpTxEvidence; + status: TxStatus; +} + export type LogFn = (...args: unknown[]) => void; export interface PendingTx extends CctpTxEvidence { From bfca51a6114a29205a8ec05f793edee1249f8953 Mon Sep 17 00:00:00 2001 From: Ikenna Omekam Date: Tue, 17 Dec 2024 09:50:48 -0600 Subject: [PATCH 40/65] Add AssetReserve to Upgrade 19 with A3P test coverage (#10541) closes: https://github.com/Agoric/agoric-sdk/issues/10399 ## Description Adds the upgrade of the reserve to upgrade 19. To ensure that this upgrade will succeed, we've also added test coverage in A3P. One caveat we discovered while testing was that the `adminFacet` that's produced with the `reserveKit` was referencing the `adminFacet` of the governor. Luckily, we were able to get the `adminFacet` of the reserve contract by calling `getAdminFacet` on the governor's `creatorFacet`. ### Upgrade Considerations This PR adds the reserve to the list of vat upgrades for upgrade-19. These upgrades are currently commented out as we are still in the process of getting upgrade-18 out the door. We've added A3P tests to ensure that the upgrade is successful and that assets are still in the reserve after the upgrade. --- .../proposals/p:upgrade-19/.gitignore | 1 + .../addCollateral/add-collateral-permit.json | 8 ++ .../addCollateral/add-collateral.js | 59 ++++++++++++ .../p:upgrade-19/assetReserve.test.js | 92 ++++++++++++++++++ .../proposals/p:upgrade-19/package.json | 1 + .../proposals/p:upgrade-19/test.sh | 3 + golang/cosmos/app/upgrade.go | 3 + .../scripts/vats/upgrade-asset-reserve.js | 21 +++++ .../src/proposals/econ-behaviors.js | 5 +- .../src/reserve/assetReserve.js | 21 ++--- .../reserve/bootstrap-assetReserve-upgrade.js | 5 + .../upgrade-asset-reserve-proposal.js | 93 +++++++++++++++++++ 12 files changed, 295 insertions(+), 17 deletions(-) create mode 100644 a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral-permit.json create mode 100644 a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral.js create mode 100644 a3p-integration/proposals/p:upgrade-19/assetReserve.test.js create mode 100644 packages/builders/scripts/vats/upgrade-asset-reserve.js create mode 100644 packages/vats/src/proposals/upgrade-asset-reserve-proposal.js diff --git a/a3p-integration/proposals/p:upgrade-19/.gitignore b/a3p-integration/proposals/p:upgrade-19/.gitignore index 57c4873daf7..b1f2bfa095d 100644 --- a/a3p-integration/proposals/p:upgrade-19/.gitignore +++ b/a3p-integration/proposals/p:upgrade-19/.gitignore @@ -6,3 +6,4 @@ upgradeProvisionPool/ upgradeAgoricNames/ publishTestInfo/ upgrade-mintHolder/ +upgradeAssetReserve/ diff --git a/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral-permit.json b/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral-permit.json new file mode 100644 index 00000000000..211b499fe4c --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral-permit.json @@ -0,0 +1,8 @@ +{ + "consume": { + "contractKits": true, + "zoe": true, + "agoricNames": true, + "reserveKit": true + } +} diff --git a/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral.js b/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral.js new file mode 100644 index 00000000000..c14306cf0eb --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/addCollateral/add-collateral.js @@ -0,0 +1,59 @@ +// @ts-nocheck +/* eslint-disable no-undef */ + +const addCollateral = async powers => { + const { + consume: { + contractKits: contractKitsP, + reserveKit: reserveKitP, + zoe, + agoricNames, + }, + } = powers; + + const [contractKits, reserveKit, usdLemonsIssuer, usdLemonsBrand] = + await Promise.all([ + contractKitsP, + reserveKitP, + E(agoricNames).lookup('issuer', 'USD_LEMONS'), + E(agoricNames).lookup('brand', 'USD_LEMONS'), + ]); + + console.log('[CONTRACT_KITS]', contractKits); + console.log('[ISSUER]', usdLemonsIssuer); + + const { governorCreatorFacet } = reserveKit; + + const arPublicFacet = await E(governorCreatorFacet).getPublicFacet(); + const arLimitedFacet = await E(governorCreatorFacet).getCreatorFacet(); + + let usdLemonsMint; + for (const { publicFacet, creatorFacet: mint } of contractKits.values()) { + if (publicFacet === usdLemonsIssuer) { + usdLemonsMint = mint; + console.log('USD_LEMONS found', mint); + break; + } + } + + await E(arLimitedFacet).addIssuer(usdLemonsIssuer, 'USD_LEMONS'); + + console.log('Minting USD_LEMONS'); + const amt = harden({ brand: usdLemonsBrand, value: 500000n }); + const helloPayment = await E(usdLemonsMint).mintPayment(amt); + + console.log('Adding to the reserve...'); + + const seat = E(zoe).offer( + E(arPublicFacet).makeAddCollateralInvitation(), + harden({ + give: { Collateral: amt }, + }), + harden({ Collateral: helloPayment }), + ); + + console.log(await E(seat).getOfferResult()); + console.log('Done.'); +}; + +addCollateral; diff --git a/a3p-integration/proposals/p:upgrade-19/assetReserve.test.js b/a3p-integration/proposals/p:upgrade-19/assetReserve.test.js new file mode 100644 index 00000000000..a3bda12bde3 --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/assetReserve.test.js @@ -0,0 +1,92 @@ +/* eslint-env node */ +/** + * @file The goal of this file is to make sure v36-reserve upgraded. + * + * The test scenario is as follows; + * 1. Add asset USD_LEMONS + * 2. Add collateral to the reserve + * 3. Upgrade reserve + * 4. Ensure that the collateral is still in the reserve + */ + +import '@endo/init'; +import test from 'ava'; +import { + evalBundles, + agd as agdAmbient, + agoric, + getDetailsMatchingVats, +} from '@agoric/synthetic-chain'; +import { + makeVstorageKit, + waitUntilContractDeployed, +} from '@agoric/client-utils'; + +const ADD_PSM_DIR = 'addUsdLemons'; +const UPGRADE_AR_DIR = 'upgradeAssetReserve'; +const ADD_COLLATERAL = 'addCollateral'; + +const ambientAuthority = { + query: agdAmbient.query, + follow: agoric.follow, + setTimeout, + log: console.log, +}; + +/** + * @typedef {import('@agoric/ertp').NatAmount} NatAmount + * @typedef {{ + * allocations: { Fee: NatAmount, USD_LEMONS: NatAmount }, + * }} ReserveAllocations + */ + +test.before(async t => { + const vstorageKit = await makeVstorageKit( + { fetch }, + { rpcAddrs: ['http://localhost:26657'], chainName: 'agoriclocal' }, + ); + + t.context = { + vstorageKit, + }; +}); + +test.serial('add collatoral to reserve', async t => { + // @ts-expect-error casting + const { vstorageKit } = t.context; + + // Introduce USD_LEMONS + await evalBundles(ADD_PSM_DIR); + await waitUntilContractDeployed('psm-IST-USD_LEMONS', ambientAuthority, { + errorMessage: 'psm-IST-USD_LEMONS instance not observed.', + }); + + await evalBundles(ADD_COLLATERAL); + + const metrics = /** @type {ReserveAllocations} */ ( + await vstorageKit.readLatestHead('published.reserve.metrics') + ); + + t.truthy(Object.keys(metrics.allocations).includes('USD_LEMONS')); + t.is(metrics.allocations.USD_LEMONS.value, 500000n); +}); + +test.serial('upgrade', async t => { + // @ts-expect-error casting + const { vstorageKit } = t.context; + + await evalBundles(UPGRADE_AR_DIR); + + const vatDetailsAfter = await getDetailsMatchingVats('reserve'); + const { incarnation } = vatDetailsAfter.find(vat => vat.vatID === 'v36'); // assetReserve is v36 + + t.log(vatDetailsAfter); + t.is(incarnation, 1, 'incorrect incarnation'); + + const metrics = /** @type {ReserveAllocations} */ ( + await vstorageKit.readLatestHead('published.reserve.metrics') + ); + + t.truthy(Object.keys(metrics.allocations).includes('USD_LEMONS')); + t.is(metrics.allocations.USD_LEMONS.value, 500000n); +}); diff --git a/a3p-integration/proposals/p:upgrade-19/package.json b/a3p-integration/proposals/p:upgrade-19/package.json index bdd9490ec35..666230406a8 100644 --- a/a3p-integration/proposals/p:upgrade-19/package.json +++ b/a3p-integration/proposals/p:upgrade-19/package.json @@ -5,6 +5,7 @@ "testing/replace-feeDistributor-short.js replaceFeeDistributor", "testing/add-USD-LEMONS.js addUsdLemons", "vats/upgrade-provisionPool.js upgradeProvisionPool", + "vats/upgrade-asset-reserve.js upgradeAssetReserve", "vats/upgrade-paRegistry.js", "vats/upgrade-board.js", "testing/test-upgraded-board.js testUpgradedBoard", diff --git a/a3p-integration/proposals/p:upgrade-19/test.sh b/a3p-integration/proposals/p:upgrade-19/test.sh index f42147483ef..193e27da231 100644 --- a/a3p-integration/proposals/p:upgrade-19/test.sh +++ b/a3p-integration/proposals/p:upgrade-19/test.sh @@ -4,4 +4,7 @@ yarn ava replaceFeeDistributor.test.js yarn ava upgradedBoard.test.js yarn ava mintHolder.test.js yarn ava provisionPool.test.js + yarn ava agoricNames.test.js + +yarn ava assetReserve.test.js diff --git a/golang/cosmos/app/upgrade.go b/golang/cosmos/app/upgrade.go index 8e6a2c68bcd..89857e26166 100644 --- a/golang/cosmos/app/upgrade.go +++ b/golang/cosmos/app/upgrade.go @@ -259,6 +259,9 @@ func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Conte // vm.CoreProposalStepForModules( // "@agoric/builders/scripts/vats/upgrade-agoricNames.js", // ), + // vm.CoreProposalStepForModules( + // "@agoric/builders/scripts/vats/upgrade-asset-reserve.js", + // ), // ) } diff --git a/packages/builders/scripts/vats/upgrade-asset-reserve.js b/packages/builders/scripts/vats/upgrade-asset-reserve.js new file mode 100644 index 00000000000..b7d70d8e205 --- /dev/null +++ b/packages/builders/scripts/vats/upgrade-asset-reserve.js @@ -0,0 +1,21 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }) => + harden({ + sourceSpec: '@agoric/vats/src/proposals/upgrade-asset-reserve-proposal.js', + getManifestCall: [ + 'getManifestForUpgradingAssetReserve', + { + assetReserveRef: publishRef( + install('@agoric/inter-protocol/src/reserve/assetReserve.js'), + ), + }, + ], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + const { writeCoreProposal } = await makeHelpers(homeP, endowments); + await writeCoreProposal('upgrade-asset-reserve', defaultProposalBuilder); +}; diff --git a/packages/inter-protocol/src/proposals/econ-behaviors.js b/packages/inter-protocol/src/proposals/econ-behaviors.js index 9b58897e6c9..a90744fca9a 100644 --- a/packages/inter-protocol/src/proposals/econ-behaviors.js +++ b/packages/inter-protocol/src/proposals/econ-behaviors.js @@ -157,9 +157,10 @@ export const setupReserve = async ({ 'reserve.governor', ); - const [creatorFacet, publicFacet, instance] = await Promise.all([ + const [creatorFacet, publicFacet, adminFacet, instance] = await Promise.all([ E(g.creatorFacet).getCreatorFacet(), E(g.creatorFacet).getPublicFacet(), + E(g.creatorFacet).getAdminFacet(), E(g.publicFacet).getGovernedContract(), ]); @@ -169,7 +170,7 @@ export const setupReserve = async ({ instance, publicFacet, creatorFacet, - adminFacet: g.adminFacet, + adminFacet, governor: g.instance, governorCreatorFacet: g.creatorFacet, diff --git a/packages/inter-protocol/src/reserve/assetReserve.js b/packages/inter-protocol/src/reserve/assetReserve.js index 322172e0e0f..f8ed8204564 100644 --- a/packages/inter-protocol/src/reserve/assetReserve.js +++ b/packages/inter-protocol/src/reserve/assetReserve.js @@ -57,22 +57,13 @@ export const start = async (zcf, privateArgs, baggage) => { privateArgs.marshaller, ); - /** @type {() => Promise>} */ - const takeFeeMint = async () => { - if (baggage.has('feeMint')) { - return baggage.get('feeMint'); - } - - const feeMintTemp = await zcf.registerFeeMint( - 'Fee', - privateArgs.feeMintAccess, - ); - baggage.init('feeMint', feeMintTemp); - return feeMintTemp; - }; - trace('awaiting takeFeeMint'); - const feeMint = await takeFeeMint(); const storageNode = await privateArgs.storageNode; + + trace('awaiting feeMint'); + const { feeMint } = await provideAll(baggage, { + feeMint: () => zcf.registerFeeMint('Fee', privateArgs.feeMintAccess), + }); + const makeAssetReserveKit = await prepareAssetReserveKit(baggage, { feeMint, makeRecorderKit, diff --git a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js index d6bb13d4d50..91318683cb5 100644 --- a/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js +++ b/packages/inter-protocol/test/swingsetTests/reserve/bootstrap-assetReserve-upgrade.js @@ -271,6 +271,11 @@ export const buildRootObject = async () => { metricsRecord = await E(metrics).getUpdateSince(); + // verify allocations + const allocations = await E(arLimitedFacet).getAllocations(); + assert.equal(allocations.Moola.value, 100_000n); + assert.equal(allocations.Moola.brand, moola.brand); + // same as last assert.equal(metricsRecord.updateCount, 2n); diff --git a/packages/vats/src/proposals/upgrade-asset-reserve-proposal.js b/packages/vats/src/proposals/upgrade-asset-reserve-proposal.js new file mode 100644 index 00000000000..89fbf0042c3 --- /dev/null +++ b/packages/vats/src/proposals/upgrade-asset-reserve-proposal.js @@ -0,0 +1,93 @@ +import { E } from '@endo/far'; +import { deeplyFulfilled } from '@endo/marshal'; +import { makeTracer } from '@agoric/internal'; + +const tracer = makeTracer('UpgradeAssetReserve'); + +/** + * @param {BootstrapPowers & { + * consume: { + * economicCommitteeCreatorFacet: any; + * reserveKit: any; + * }; + * produce: { + * reserveKit: any; + * }; + * }} powers + * @param {object} options + * @param {{ assetReserveRef: VatSourceRef }} options.options + */ +export const upgradeAssetReserve = async ( + { + consume: { + economicCommitteeCreatorFacet: electorateCreatorFacet, + reserveKit: reserveKitP, + instancePrivateArgs: instancePrivateArgsP, + }, + produce: { reserveKit: reserveKitWriter }, + }, + options, +) => { + const { assetReserveRef } = options.options; + + assert(assetReserveRef.bundleID); + tracer(`ASSET RESERVE BUNDLE ID: `, assetReserveRef); + + const [reserveKit, instancePrivateArgs] = await Promise.all([ + reserveKitP, + instancePrivateArgsP, + ]); + const { governorCreatorFacet, instance } = reserveKit; + + const [originalPrivateArgs, poserInvitation] = await Promise.all([ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore Local tsc sees this as an error but typedoc does not + deeplyFulfilled(instancePrivateArgs.get(instance)), + E(electorateCreatorFacet).getPoserInvitation(), + ]); + + const newPrivateArgs = harden({ + ...originalPrivateArgs, + initialPoserInvitation: poserInvitation, + }); + + const adminFacet = await E(governorCreatorFacet).getAdminFacet(); + + // We need to reset the kit and produce a new adminFacet because the + // original contract is producing an admin facet that is for the + // governor, not the reserve. + reserveKitWriter.reset(); + reserveKitWriter.resolve( + harden({ + ...reserveKit, + adminFacet, + }), + ); + + const upgradeResult = await E(adminFacet).upgradeContract( + assetReserveRef.bundleID, + newPrivateArgs, + ); + + tracer('AssetReserve upgraded: ', upgradeResult); + tracer('Done.'); +}; + +export const getManifestForUpgradingAssetReserve = ( + _powers, + { assetReserveRef }, +) => ({ + manifest: { + [upgradeAssetReserve.name]: { + consume: { + economicCommitteeCreatorFacet: true, + instancePrivateArgs: true, + reserveKit: true, + }, + produce: { + reserveKit: true, + }, + }, + }, + options: { assetReserveRef }, +}); From 32f13984751a5404aad3e9f3dc72b056292a78a3 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Mon, 16 Dec 2024 14:50:55 -0800 Subject: [PATCH 41/65] feat: add an accessor for the vaultDirector's parameters --- .../src/vaultFactory/vaultDirector.js | 6 +++- .../test/vaultFactory/vaultFactory.test.js | 35 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/inter-protocol/src/vaultFactory/vaultDirector.js b/packages/inter-protocol/src/vaultFactory/vaultDirector.js index fdfa8d2f9d9..56e0706f3f1 100644 --- a/packages/inter-protocol/src/vaultFactory/vaultDirector.js +++ b/packages/inter-protocol/src/vaultFactory/vaultDirector.js @@ -325,6 +325,7 @@ const prepareVaultDirector = ( getGovernedParams: M.callWhen({ collateralBrand: BrandShape }).returns( M.record(), ), + getDirectorGovernedParams: M.call().returns(M.promise()), getInvitationAmount: M.call(M.string()).returns(AmountShape), getPublicTopics: M.call().returns(TopicsRecordShape), }), @@ -492,7 +493,7 @@ const prepareVaultDirector = ( }, /** * Note this works only for a collateral manager. For the director use, - * `getElectorateSubscription` + * `getDirectorGovernedParams` * * @param {{ collateralBrand: Brand }} selector */ @@ -500,6 +501,9 @@ const prepareVaultDirector = ( // TODO use named getters of TypedParamManager return vaultParamManagers.get(collateralBrand).getParams(); }, + getDirectorGovernedParams() { + return directorParamManager.getParams(); + }, /** @param {string} name */ getInvitationAmount(name) { return directorParamManager.getInvitationAmount(name); diff --git a/packages/inter-protocol/test/vaultFactory/vaultFactory.test.js b/packages/inter-protocol/test/vaultFactory/vaultFactory.test.js index f285b00bd00..f7d8b8bc296 100644 --- a/packages/inter-protocol/test/vaultFactory/vaultFactory.test.js +++ b/packages/inter-protocol/test/vaultFactory/vaultFactory.test.js @@ -2049,4 +2049,39 @@ test('governance publisher', async t => { LiquidationPenalty: { type: 'ratio' }, MintFee: { type: 'ratio' }, }); + + const params = await E(vfPublic).getDirectorGovernedParams(); + t.like(params, { + ChargingPeriod: { type: 'nat', value: 2n }, + Electorate: { type: 'invitation' }, + MinInitialDebt: { type: 'amount' }, + RecordingPeriod: { type: 'nat' }, + ReferencedUI: { value: 'abracadabra' }, + ShortfallInvitation: { type: 'invitation' }, + }); +}); + +test('access to director params', async t => { + const { aeth } = t.context; + + t.context.referencedUi = 'hocus pocus'; + const services = await setupServices( + t, + [500n, 15n], + aeth.make(900n), + undefined, + undefined, + 500n, + ); + const { vfPublic } = services.vaultFactory; + + const params = await E(vfPublic).getDirectorGovernedParams(); + t.like(params, { + ChargingPeriod: { type: 'nat', value: 2n }, + Electorate: { type: 'invitation' }, + MinInitialDebt: { type: 'amount' }, + RecordingPeriod: { type: 'nat' }, + ReferencedUI: { value: 'hocus pocus' }, + ShortfallInvitation: { type: 'invitation' }, + }); }); From 02c111b7e6a54528186e37f5408d1a41462e5526 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:38:23 -0800 Subject: [PATCH 42/65] feat: storage-test-utils report missing data --- packages/internal/src/storage-test-utils.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/internal/src/storage-test-utils.js b/packages/internal/src/storage-test-utils.js index 6babcb12223..15774a7ec01 100644 --- a/packages/internal/src/storage-test-utils.js +++ b/packages/internal/src/storage-test-utils.js @@ -209,7 +209,9 @@ export const makeFakeStorageKit = (rootPath, rootOptions) => { */ const getValues = path => { assert(resolvedOptions.sequence); - const wrapper = JSON.parse(data.get(path)); + const nodeData = data.get(path); + assert(nodeData, `no data at path ${path}`); + const wrapper = JSON.parse(nodeData); return wrapper.values; }; From 12627eeecb98e1509620da211b5148f63979eb41 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:30:49 -0800 Subject: [PATCH 43/65] test: DRY setup of status-manager test --- .../test/exos/status-manager.test.ts | 97 ++++++------------- 1 file changed, 29 insertions(+), 68 deletions(-) diff --git a/packages/fast-usdc/test/exos/status-manager.test.ts b/packages/fast-usdc/test/exos/status-manager.test.ts index 14c45185fa8..7322fe0aeea 100644 --- a/packages/fast-usdc/test/exos/status-manager.test.ts +++ b/packages/fast-usdc/test/exos/status-manager.test.ts @@ -1,16 +1,21 @@ import type { TestFn } from 'ava'; + import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { StorageNode } from '@agoric/internal/src/lib-chainStorage.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; +import { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; import { PendingTxStatus } from '../../src/constants.js'; -import { prepareStatusManager } from '../../src/exos/status-manager.js'; +import { + prepareStatusManager, + type StatusManager, +} from '../../src/exos/status-manager.js'; import { commonSetup, provideDurableZone } from '../supports.js'; import { MockCctpTxEvidences } from '../fixtures.js'; import type { CctpTxEvidence } from '../../src/types.js'; type Common = Awaited>; type TestContext = { - txnsNode: ERef; + statusManager: StatusManager; storage: Common['bootstrap']['storage']; }; @@ -18,18 +23,21 @@ const test = anyTest as TestFn; test.beforeEach(async t => { const common = await commonSetup(t); + const zone = provideDurableZone('status-test'); + const txnsNode = common.commonPrivateArgs.storageNode.makeChildNode('txns'); + const statusManager = prepareStatusManager( + zone.subZone('status-manager'), + txnsNode, + { marshaller: defaultMarshaller }, + ); t.context = { - txnsNode: common.commonPrivateArgs.storageNode.makeChildNode('txns'), + statusManager, storage: common.bootstrap.storage, }; }); test('advance creates new entry with ADVANCED status', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -43,11 +51,7 @@ test('advance creates new entry with ADVANCED status', t => { }); test('ADVANCED transactions are published to vstorage', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -61,11 +65,7 @@ test('ADVANCED transactions are published to vstorage', async t => { }); test('observe creates new entry with OBSERVED status', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -78,11 +78,7 @@ test('observe creates new entry with OBSERVED status', t => { }); test('OBSERVED transactions are published to vstorage', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.observe(evidence); @@ -95,11 +91,8 @@ test('OBSERVED transactions are published to vstorage', async t => { }); test('cannot process same tx twice', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); statusManager.advance(evidence); @@ -118,11 +111,7 @@ test('cannot process same tx twice', t => { }); test('isSeen checks if a tx has been processed', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); t.false(statusManager.hasBeenObserved(e1)); @@ -136,11 +125,7 @@ test('isSeen checks if a tx has been processed', t => { }); test('dequeueStatus removes entries from PendingTxs', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -188,11 +173,7 @@ test('dequeueStatus removes entries from PendingTxs', t => { }); test('cannot advanceOutcome without ADVANCING entry', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const advanceOutcomeFn = () => statusManager.advanceOutcome(e1.tx.forwardingAddress, e1.tx.amount, true); @@ -217,11 +198,7 @@ test('cannot advanceOutcome without ADVANCING entry', t => { test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { const { storage } = t.context; - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -255,11 +232,7 @@ test('advanceOutcome transitions to ADVANCED and ADVANCE_FAILED', async t => { }); test('dequeueStatus returns undefined when nothing is settleable', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); t.is( @@ -269,11 +242,7 @@ test('dequeueStatus returns undefined when nothing is settleable', t => { }); test('dequeueStatus returns first (earliest) matched entry', async t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); // advance two txs @@ -366,20 +335,12 @@ test('dequeueStatus returns first (earliest) matched entry', async t => { }); test('lookupPending returns empty array when presented a key it has not seen', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; t.deepEqual(statusManager.lookupPending('noble123', 1n), []); }); test('StatusManagerKey logic handles addresses with hyphens', t => { - const zone = provideDurableZone('status-test'); - const statusManager = prepareStatusManager( - zone.subZone('status-manager'), - t.context.txnsNode, - ); + const { statusManager } = t.context; const evidence: CctpTxEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); evidence.tx.forwardingAddress = 'noble1-foo'; From 8c5bf8501ab3f810493b4487a5b5401c04a58ab2 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:45:02 -0800 Subject: [PATCH 44/65] test: quieter advancer test --- packages/fast-usdc/test/exos/advancer.test.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 7f118598f88..384d3547c6e 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -12,6 +12,7 @@ import { type ZoeTools } from '@agoric/orchestration/src/utils/zoe-tools.js'; import { q } from '@endo/errors'; import { Far } from '@endo/pass-style'; import type { TestFn } from 'ava'; +import { makeTracer } from '@agoric/internal'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; @@ -26,6 +27,8 @@ import { } from '../mocks.js'; import { commonSetup } from '../supports.js'; +const trace = makeTracer('AdvancerTest', false); + const LOCAL_DENOM = `ibc/${denomHash({ denom: 'uusdc', channelId: @@ -74,7 +77,7 @@ const createTestExtensions = (t, common: CommonSetup) => { }; const mockZoeTools = Far('MockZoeTools', { localTransfer(...args: Parameters) { - console.log('ZoeTools.localTransfer called with', args); + trace('ZoeTools.localTransfer called with', args); return localTransferVK.vow; }, }); @@ -99,7 +102,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const notifyAdvancingResultCalls: NotifyArgs[] = []; const mockNotifyF = Far('Settler Notify Facet', { notifyAdvancingResult: (...args: NotifyArgs) => { - console.log('Settler.notifyAdvancingResult called with', args); + trace('Settler.notifyAdvancingResult called with', args); notifyAdvancingResultCalls.push(args); }, }); From 28cc2f69a7ec6ad9357bbc325f036c7fd4c5249f Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:08:25 -0800 Subject: [PATCH 45/65] refactor: inline publishStatus --- packages/fast-usdc/src/exos/status-manager.js | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 588126a3b73..af15d95b4cc 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -102,12 +102,23 @@ export const prepareStatusManager = ( /** * @param {EvmHash} txId * @param {TransactionRecord} record + * @returns {Promise} */ - const publishTxnRecord = (txId, record) => { + const publishTxnRecord = async (txId, record) => { const txNode = E(txnsNode).makeChildNode(txId, { sequence: true, // avoid overwriting other output in the block }); - void E(txNode).setValue( + + // XXX awkward for publish* to update a store, but it's temporary + if (record.status && TerminalTxStatus[record.status]) { + // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 + // Queue it for deletion later because if we deleted it now the earlier + // writes in this block would be wiped. For now we keep track of what to + // delete when we know it'll be another block. + storedCompletedTxs.add(txId); + } + + await E(txNode).setValue( JSON.stringify(pureDataMarshaller.toCapData(record)), ); }; @@ -124,22 +135,6 @@ export const prepareStatusManager = ( ); }; - /** - * @param {CctpTxEvidence['txHash']} hash - * @param {TxStatus} status - */ - const publishStatus = (hash, status) => { - // Don't await, just writing to vstorage. - void publishTxnRecord(hash, harden({ status })); - if (TerminalTxStatus[status]) { - // UNTIL https://github.com/Agoric/agoric-sdk/issues/7405 - // Queue it for deletion later because if we deleted it now the earlier - // writes in this block would be wiped. For now we keep track of what to - // delete when we know it'll be another block. - storedCompletedTxs.add(hash); - } - }; - /** * Ensures that `txHash+chainId` has not been processed * and adds entry to `seenTxs` set. @@ -164,7 +159,7 @@ export const prepareStatusManager = ( publishEvidence(txHash, evidence); if (status !== PendingTxStatus.Observed) { // publishEvidence publishes Observed - publishStatus(txHash, status); + void publishTxnRecord(txHash, harden({ status })); } }; @@ -187,7 +182,7 @@ export const prepareStatusManager = ( ]; const txpost = { ...tx, status }; pendingTxs.set(key, harden([...prefix, txpost, ...suffix])); - publishStatus(tx.txHash, status); + void publishTxnRecord(tx.txHash, harden({ status })); } return zone.exo( @@ -315,7 +310,7 @@ export const prepareStatusManager = ( * @param {EvmHash} txHash */ disbursed(txHash) { - publishStatus(txHash, TxStatus.Disbursed); + void publishTxnRecord(txHash, harden({ status: TxStatus.Disbursed })); }, /** @@ -327,7 +322,7 @@ export const prepareStatusManager = ( */ forwarded(txHash, nfa, amount) { if (txHash) { - publishStatus(txHash, TxStatus.Forwarded); + void publishTxnRecord(txHash, harden({ status: TxStatus.Forwarded })); } else { // TODO store (early) `Minted` transactions to check against incoming evidence log( From e3f49bef04ae889ad5716e3c370080fdddb0bf36 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:40:20 -0800 Subject: [PATCH 46/65] refactor: full marshaller --- packages/fast-usdc/src/exos/status-manager.js | 16 +++++++++------- packages/fast-usdc/src/fast-usdc.contract.js | 1 + packages/fast-usdc/test/exos/advancer.test.ts | 13 ++++++++----- packages/fast-usdc/test/exos/settler.test.ts | 5 +++-- packages/fast-usdc/test/supports.ts | 9 ++------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index af15d95b4cc..0e597348f83 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -1,14 +1,14 @@ -import { M } from '@endo/patterns'; -import { Fail, makeError, q } from '@endo/errors'; +import { makeTracer } from '@agoric/internal'; import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js'; +import { Fail, makeError, q } from '@endo/errors'; import { E } from '@endo/eventual-send'; -import { makeTracer, pureDataMarshaller } from '@agoric/internal'; +import { M } from '@endo/patterns'; +import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; import { CctpTxEvidenceShape, EvmHashShape, PendingTxShape, } from '../type-guards.js'; -import { PendingTxStatus, TerminalTxStatus, TxStatus } from '../constants.js'; /** * @import {MapStore, SetStore} from '@agoric/store'; @@ -48,6 +48,7 @@ const pendingTxKeyOf = evidence => { /** * @typedef {{ * log?: LogFn; + * marshaller: ERef; * }} StatusManagerPowers */ @@ -66,6 +67,7 @@ export const prepareStatusManager = ( zone, txnsNode, { + marshaller, log = makeTracer('Advancer', true), } = /** @type {StatusManagerPowers} */ ({}), ) => { @@ -118,9 +120,9 @@ export const prepareStatusManager = ( storedCompletedTxs.add(txId); } - await E(txNode).setValue( - JSON.stringify(pureDataMarshaller.toCapData(record)), - ); + const capData = await E(marshaller).toCapData(record); + + await E(txNode).setValue(JSON.stringify(capData)); }; /** diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index 80f8c4a6df1..b9629bb05c3 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -112,6 +112,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { const statusManager = prepareStatusManager( zone, E(storageNode).makeChildNode(TXNS_NODE), + { marshaller }, ); const { USDC } = terms.brands; diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 384d3547c6e..4bb122220df 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -53,6 +53,7 @@ const createTestExtensions = (t, common: CommonSetup) => { const statusManager = prepareStatusManager( rootZone.subZone('status-manager'), storageNode.makeChildNode('txns'), + { marshaller: common.commonPrivateArgs.marshaller }, ); const mockAccounts = prepareMockOrchAccounts(rootZone.subZone('accounts'), { @@ -170,7 +171,7 @@ test.beforeEach(async t => { test('updates status to ADVANCING in happy path', async t => { const { extensions: { - services: { advancer, feeTools, statusManager }, + services: { advancer, feeTools }, helpers: { inspectLogs, inspectNotifyCalls }, mocks: { mockPoolAccount, resolveLocalTransferV }, }, @@ -238,7 +239,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { brands: { usdc }, bootstrap: { storage }, extensions: { - services: { makeAdvancer, statusManager }, + services: { makeAdvancer }, helpers: { inspectLogs }, mocks: { mockPoolAccount, mockNotifyF }, }, @@ -286,13 +287,14 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { const { bootstrap: { storage }, extensions: { - services: { advancer, statusManager }, + services: { advancer }, helpers: { inspectLogs }, }, } = t.context; const evidence = MockCctpTxEvidences.AGORIC_UNKNOWN_EUD(); await advancer.handleTransactionEvent(evidence); + await eventLoopIteration(); t.deepEqual( storage.getDeserialized(`fun.txns.${evidence.txHash}`), @@ -313,7 +315,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t const { bootstrap: { storage }, extensions: { - services: { advancer, feeTools, statusManager }, + services: { advancer, feeTools }, helpers: { inspectLogs, inspectNotifyCalls }, mocks: { mockPoolAccount, resolveLocalTransferV }, }, @@ -366,7 +368,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { const { bootstrap: { storage }, extensions: { - services: { advancer, statusManager }, + services: { advancer }, helpers: { inspectLogs }, }, } = t.context; @@ -374,6 +376,7 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { const evidence = MockCctpTxEvidences.AGORIC_NO_PARAMS(); await advancer.handleTransactionEvent(evidence); + await eventLoopIteration(); t.deepEqual( storage.getDeserialized(`fun.txns.${evidence.txHash}`), diff --git a/packages/fast-usdc/test/exos/settler.test.ts b/packages/fast-usdc/test/exos/settler.test.ts index f23f90702d4..bedcf3f6065 100644 --- a/packages/fast-usdc/test/exos/settler.test.ts +++ b/packages/fast-usdc/test/exos/settler.test.ts @@ -4,6 +4,7 @@ import type { TestFn } from 'ava'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import type { Zone } from '@agoric/zone'; +import { defaultMarshaller } from '@agoric/internal/src/storage-test-utils.js'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareSettler } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; @@ -48,7 +49,7 @@ const makeTestContext = async t => { const statusManager = prepareStatusManager( zone.subZone('status-manager'), common.commonPrivateArgs.storageNode.makeChildNode('txns'), - { log }, + { marshaller: defaultMarshaller, log }, ); const { zcf, callLog } = mockZcf(zone.subZone('Mock ZCF')); @@ -239,7 +240,7 @@ test('happy path: disburse to LPs; StatusManager removes tx', async t => { { evidence: cctpTxEvidence, status: 'OBSERVED' }, { status: 'ADVANCING' }, { status: 'ADVANCED' }, - { status: 'DISBURSED' }, + { split: expectedSplit, status: 'DISBURSED' }, ]); // Check deletion of DISBURSED transactions diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 8ecdc66bdb6..984352b3c07 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -1,7 +1,6 @@ import { makeIssuerKit } from '@agoric/ertp'; import { VTRANSFER_IBC_EVENT } from '@agoric/internal/src/action-types.js'; import { - defaultMarshaller, defaultSerializer, makeFakeStorageKit, } from '@agoric/internal/src/storage-test-utils.js'; @@ -28,10 +27,7 @@ import { makeWellKnownSpaces } from '@agoric/vats/src/core/utils.js'; import { prepareLocalChainTools } from '@agoric/vats/src/localchain.js'; import { prepareTransferTools } from '@agoric/vats/src/transfer.js'; import { makeFakeBankManagerKit } from '@agoric/vats/tools/bank-utils.js'; -import { - makeFakeBoard, - pureDataMarshaller, -} from '@agoric/vats/tools/board-utils.js'; +import { makeFakeBoard } from '@agoric/vats/tools/board-utils.js'; import { makeFakeLocalchainBridge, makeFakeTransferBridge, @@ -44,7 +40,6 @@ import { makeHeapZone, type Zone } from '@agoric/zone'; import { makeDurableZone } from '@agoric/zone/durable.js'; import { E } from '@endo/far'; import type { ExecutionContext } from 'ava'; -import type { PureData } from '@endo/pass-style'; import { makeTestFeeConfig } from './mocks.js'; export { @@ -156,7 +151,7 @@ export const commonSetup = async (t: ExecutionContext) => { transfer: transferMiddleware, }); const timer = buildZoeManualTimer(t.log); - const marshaller = makeFakeBoard().getReadonlyMarshaller(); + const marshaller = makeFakeBoard().getPublishingMarshaller(); const storage = makeFakeStorageKit( 'fun', // Fast USDC Node ); From 884697238ad5f8a112ed24616b10c3b3a94af737 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 07:14:41 -0800 Subject: [PATCH 47/65] feat: record fee split in transaction --- packages/fast-usdc/src/exos/settler.js | 2 +- packages/fast-usdc/src/exos/status-manager.js | 13 ++++++++++--- packages/fast-usdc/src/types.ts | 2 ++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 727e02bfbb0..fc6708eedee 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -260,7 +260,7 @@ export const prepareSettler = ( repayer.repay(settlingSeat, split); // update status manager, marking tx `SETTLED` - statusManager.disbursed(txHash); + statusManager.disbursed(txHash, split); }, /** * @param {EvmHash} txHash diff --git a/packages/fast-usdc/src/exos/status-manager.js b/packages/fast-usdc/src/exos/status-manager.js index 0e597348f83..6f264fd8997 100644 --- a/packages/fast-usdc/src/exos/status-manager.js +++ b/packages/fast-usdc/src/exos/status-manager.js @@ -1,5 +1,6 @@ import { makeTracer } from '@agoric/internal'; import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js'; +import { AmountKeywordRecordShape } from '@agoric/zoe/src/typeGuards.js'; import { Fail, makeError, q } from '@endo/errors'; import { E } from '@endo/eventual-send'; import { M } from '@endo/patterns'; @@ -209,7 +210,9 @@ export const prepareStatusManager = ( M.undefined(), ), ), - disbursed: M.call(EvmHashShape).returns(M.undefined()), + disbursed: M.call(EvmHashShape, AmountKeywordRecordShape).returns( + M.undefined(), + ), forwarded: M.call(M.opt(EvmHashShape), M.string(), M.nat()).returns( M.undefined(), ), @@ -310,9 +313,13 @@ export const prepareStatusManager = ( * Mark a transaction as `DISBURSED` * * @param {EvmHash} txHash + * @param {import('./liquidity-pool.js').RepayAmountKWR} split */ - disbursed(txHash) { - void publishTxnRecord(txHash, harden({ status: TxStatus.Disbursed })); + disbursed(txHash, split) { + void publishTxnRecord( + txHash, + harden({ split, status: TxStatus.Disbursed }), + ); }, /** diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index 0d3701e9d82..44f9669613d 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -9,6 +9,7 @@ import type { Amount } from '@agoric/ertp'; import type { CopyRecord, Passable } from '@endo/pass-style'; import type { PendingTxStatus, TxStatus } from './constants.js'; import type { FastUsdcTerms } from './fast-usdc.contract.js'; +import type { RepayAmountKWR } from './exos/liquidity-pool.js'; export type EvmHash = `0x${string}`; export type EvmAddress = `0x${string & { length: 40 }}`; @@ -40,6 +41,7 @@ export interface CctpTxEvidence { */ export interface TransactionRecord extends CopyRecord { evidence?: CctpTxEvidence; + split?: RepayAmountKWR; status: TxStatus; } From caf6d7ac9334672ec9d9d5246bd231ee2a900e0f Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 10:59:30 -0800 Subject: [PATCH 48/65] chore: constrain fast-usdc config for Mainnet --- packages/fast-usdc/src/utils/deploy-config.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/fast-usdc/src/utils/deploy-config.js b/packages/fast-usdc/src/utils/deploy-config.js index 7b160a7996c..22b2cd5a593 100644 --- a/packages/fast-usdc/src/utils/deploy-config.js +++ b/packages/fast-usdc/src/utils/deploy-config.js @@ -156,3 +156,11 @@ export const configurations = { }, }; harden(configurations); + +// Constraints on the configurations +const MAINNET_EXPECTED_ORACLES = 3; +assert( + new Set(Object.values(configurations.MAINNET.oracles)).size === + MAINNET_EXPECTED_ORACLES, + `Mainnet must have exactly ${MAINNET_EXPECTED_ORACLES} oracles`, +); From 621e22fdfe01706e22a3ebb81164b372ef9c80e0 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 11:10:42 -0800 Subject: [PATCH 49/65] test: disabled operators --- .../fast-usdc/test/exos/transaction-feed.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index 5f11c504dc2..ff3f2705aa6 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -79,6 +79,21 @@ test('happy aggregation', async t => { }); }); +test('disabled operator', async t => { + const feedKit = makeFeedKit(); + const { op1 } = await makeOperators(feedKit); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + + // works before disabling + await op1.operator.submitEvidence(evidence); + + op1.admin.disable(); + + await t.throwsAsync(() => op1.operator.submitEvidence(evidence), { + message: 'submitEvidence for disabled operator', + }); +}); + // TODO: find a way to get this working test.skip('forged source', async t => { const feedKit = makeFeedKit(); From 0b57a6559fe627c70767b0a6d4e687cf9f1deaca Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 11:18:27 -0800 Subject: [PATCH 50/65] refactor: TransactionFeed attest --- packages/fast-usdc/src/exos/operator-kit.js | 4 ++-- packages/fast-usdc/src/exos/transaction-feed.js | 6 ++++-- packages/fast-usdc/test/exos/transaction-feed.test.ts | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/fast-usdc/src/exos/operator-kit.js b/packages/fast-usdc/src/exos/operator-kit.js index 08b3ac9c368..b5e847f30d5 100644 --- a/packages/fast-usdc/src/exos/operator-kit.js +++ b/packages/fast-usdc/src/exos/operator-kit.js @@ -12,7 +12,7 @@ const trace = makeTracer('TxOperator'); /** * @typedef {object} OperatorPowers - * @property {(evidence: CctpTxEvidence, operatorKit: OperatorKit) => void} submitEvidence + * @property {(evidence: CctpTxEvidence, operatorKit: OperatorKit) => void} attest */ /** @@ -102,7 +102,7 @@ export const prepareOperatorKit = (zone, staticPowers) => async submitEvidence(evidence) { const { state } = this; !state.disabled || Fail`submitEvidence for disabled operator`; - const result = state.powers.submitEvidence(evidence, this.facets); + const result = state.powers.attest(evidence, this.facets); return result; }, /** @returns {OperatorStatus} */ diff --git a/packages/fast-usdc/src/exos/transaction-feed.js b/packages/fast-usdc/src/exos/transaction-feed.js index 782236d615f..40d456ef9ea 100644 --- a/packages/fast-usdc/src/exos/transaction-feed.js +++ b/packages/fast-usdc/src/exos/transaction-feed.js @@ -18,7 +18,7 @@ export const INVITATION_MAKERS_DESC = 'oracle operator invitation'; const TransactionFeedKitI = harden({ operatorPowers: M.interface('Transaction Feed Admin', { - submitEvidence: M.call(CctpTxEvidenceShape, M.any()).returns(), + attest: M.call(CctpTxEvidenceShape, M.any()).returns(), }), creator: M.interface('Transaction Feed Creator', { // TODO narrow the return shape to OperatorKit @@ -118,10 +118,12 @@ export const prepareTransactionFeedKit = (zone, zcf) => { /** * Add evidence from an operator. * + * NB: the operatorKit is responsible for + * * @param {CctpTxEvidence} evidence * @param {OperatorKit} operatorKit */ - submitEvidence(evidence, operatorKit) { + attest(evidence, operatorKit) { const { pending } = this.state; trace( 'submitEvidence', diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index ff3f2705aa6..64c6f8c34a1 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -102,7 +102,7 @@ test.skip('forged source', async t => { // op1 is different than the facets object the evidence must come from t.throws(() => - feedKit.operatorPowers.submitEvidence( + feedKit.operatorPowers.attest( evidence, // @ts-expect-error XXX Types of property '[GET_INTERFACE_GUARD]' are incompatible. op1, From 1e52a415b7d9fc6a446263b4a8c22d5eac1fd28e Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 11:41:05 -0800 Subject: [PATCH 51/65] refactor: sync submitEvidence --- packages/fast-usdc/src/exos/operator-kit.js | 10 +++---- .../test/exos/transaction-feed.test.ts | 28 ++++++++----------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/packages/fast-usdc/src/exos/operator-kit.js b/packages/fast-usdc/src/exos/operator-kit.js index b5e847f30d5..310b10ad0a9 100644 --- a/packages/fast-usdc/src/exos/operator-kit.js +++ b/packages/fast-usdc/src/exos/operator-kit.js @@ -35,7 +35,7 @@ const OperatorKitI = { }), operator: M.interface('Operator', { - submitEvidence: M.call(CctpTxEvidenceShape).returns(M.promise()), + submitEvidence: M.call(CctpTxEvidenceShape).returns(), getStatus: M.call().returns(M.record()), }), }; @@ -87,7 +87,7 @@ export const prepareOperatorKit = (zone, staticPowers) => const { operator } = this.facets; // TODO(bootstrap integration): cause this call to throw and confirm that it // shows up in the the smart-wallet UpdateRecord `error` property - await operator.submitEvidence(evidence); + operator.submitEvidence(evidence); return staticPowers.makeInertInvitation( 'evidence was pushed in the invitation maker call', ); @@ -98,12 +98,12 @@ export const prepareOperatorKit = (zone, staticPowers) => * submit evidence from this operator * * @param {CctpTxEvidence} evidence + * @returns {void} */ - async submitEvidence(evidence) { + submitEvidence(evidence) { const { state } = this; !state.disabled || Fail`submitEvidence for disabled operator`; - const result = state.powers.attest(evidence, this.facets); - return result; + state.powers.attest(evidence, this.facets); }, /** @returns {OperatorStatus} */ getStatus() { diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index 64c6f8c34a1..9f1c902aaae 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -48,12 +48,9 @@ test('happy aggregation', async t => { const { op1, op2, op3 } = await makeOperators(feedKit); const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); - const results = await Promise.all([ - op1.operator.submitEvidence(evidence), - op2.operator.submitEvidence(evidence), - op3.operator.submitEvidence(evidence), - ]); - t.deepEqual(results, [undefined, undefined, undefined]); + op1.operator.submitEvidence(evidence); + op2.operator.submitEvidence(evidence); + op3.operator.submitEvidence(evidence); const accepted = await evidenceSubscriber.getUpdateSince(0); t.deepEqual(accepted, { @@ -62,18 +59,17 @@ test('happy aggregation', async t => { }); // verify that it doesn't publish until three match - await Promise.all([ - // once it publishes, it doesn't remember that it already saw these - op1.operator.submitEvidence(evidence), - op2.operator.submitEvidence(evidence), - // but this time the third is different - op3.operator.submitEvidence(MockCctpTxEvidences.AGORIC_PLUS_DYDX()), - ]); + // once it publishes, it doesn't remember that it already saw these + op1.operator.submitEvidence(evidence); + op2.operator.submitEvidence(evidence); + // but this time the third is different + op3.operator.submitEvidence(MockCctpTxEvidences.AGORIC_PLUS_DYDX()); + t.like(await evidenceSubscriber.getUpdateSince(0), { // Update count is still 1 updateCount: 1n, }); - await op3.operator.submitEvidence(evidence); + op3.operator.submitEvidence(evidence); t.like(await evidenceSubscriber.getUpdateSince(0), { updateCount: 2n, }); @@ -85,11 +81,11 @@ test('disabled operator', async t => { const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); // works before disabling - await op1.operator.submitEvidence(evidence); + op1.operator.submitEvidence(evidence); op1.admin.disable(); - await t.throwsAsync(() => op1.operator.submitEvidence(evidence), { + t.throws(() => op1.operator.submitEvidence(evidence), { message: 'submitEvidence for disabled operator', }); }); From fb4ff309bdc2ebb15a1c6632db231d7f378f11f6 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 11:51:16 -0800 Subject: [PATCH 52/65] refactor: attest by operatorId --- packages/fast-usdc/src/exos/operator-kit.js | 4 ++-- .../fast-usdc/src/exos/transaction-feed.js | 18 ++++-------------- .../test/exos/transaction-feed.test.ts | 16 ---------------- 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/packages/fast-usdc/src/exos/operator-kit.js b/packages/fast-usdc/src/exos/operator-kit.js index 310b10ad0a9..7a98af3da5a 100644 --- a/packages/fast-usdc/src/exos/operator-kit.js +++ b/packages/fast-usdc/src/exos/operator-kit.js @@ -12,7 +12,7 @@ const trace = makeTracer('TxOperator'); /** * @typedef {object} OperatorPowers - * @property {(evidence: CctpTxEvidence, operatorKit: OperatorKit) => void} attest + * @property {(evidence: CctpTxEvidence, operatorId: string) => void} attest */ /** @@ -103,7 +103,7 @@ export const prepareOperatorKit = (zone, staticPowers) => submitEvidence(evidence) { const { state } = this; !state.disabled || Fail`submitEvidence for disabled operator`; - state.powers.attest(evidence, this.facets); + state.powers.attest(evidence, state.operatorId); }, /** @returns {OperatorStatus} */ getStatus() { diff --git a/packages/fast-usdc/src/exos/transaction-feed.js b/packages/fast-usdc/src/exos/transaction-feed.js index 40d456ef9ea..b991c570022 100644 --- a/packages/fast-usdc/src/exos/transaction-feed.js +++ b/packages/fast-usdc/src/exos/transaction-feed.js @@ -18,7 +18,7 @@ export const INVITATION_MAKERS_DESC = 'oracle operator invitation'; const TransactionFeedKitI = harden({ operatorPowers: M.interface('Transaction Feed Admin', { - attest: M.call(CctpTxEvidenceShape, M.any()).returns(), + attest: M.call(CctpTxEvidenceShape, M.string()).returns(), }), creator: M.interface('Transaction Feed Creator', { // TODO narrow the return shape to OperatorKit @@ -121,21 +121,11 @@ export const prepareTransactionFeedKit = (zone, zcf) => { * NB: the operatorKit is responsible for * * @param {CctpTxEvidence} evidence - * @param {OperatorKit} operatorKit + * @param {string} operatorId */ - attest(evidence, operatorKit) { + attest(evidence, operatorId) { const { pending } = this.state; - trace( - 'submitEvidence', - operatorKit.operator.getStatus().operatorId, - evidence, - ); - const { operatorId } = operatorKit.operator.getStatus(); - - // TODO should this verify that the operator is one made by this exo? - // This doesn't work... - // operatorKit === operators.get(operatorId) || - // Fail`operatorKit mismatch`; + trace('submitEvidence', operatorId, evidence); // TODO validate that it's a valid for Fast USDC before accepting // E.g. that the `recipientAddress` is the FU settlement account and that diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index 9f1c902aaae..8e3b04f9271 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -89,19 +89,3 @@ test('disabled operator', async t => { message: 'submitEvidence for disabled operator', }); }); - -// TODO: find a way to get this working -test.skip('forged source', async t => { - const feedKit = makeFeedKit(); - const { op1 } = await makeOperators(feedKit); - const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); - - // op1 is different than the facets object the evidence must come from - t.throws(() => - feedKit.operatorPowers.attest( - evidence, - // @ts-expect-error XXX Types of property '[GET_INTERFACE_GUARD]' are incompatible. - op1, - ), - ); -}); From bc28201f60978263d4c88375130da15128f8fd5c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 12:46:18 -0800 Subject: [PATCH 53/65] feat: operator majority logic --- .../fast-usdc/src/exos/transaction-feed.js | 23 +++++++---- .../test/exos/transaction-feed.test.ts | 29 +++++++------ .../fast-usdc/test/fast-usdc.contract.test.ts | 41 +++++++++++-------- 3 files changed, 55 insertions(+), 38 deletions(-) diff --git a/packages/fast-usdc/src/exos/transaction-feed.js b/packages/fast-usdc/src/exos/transaction-feed.js index b991c570022..3d150f5db42 100644 --- a/packages/fast-usdc/src/exos/transaction-feed.js +++ b/packages/fast-usdc/src/exos/transaction-feed.js @@ -124,7 +124,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => { * @param {string} operatorId */ attest(evidence, operatorId) { - const { pending } = this.state; + const { operators, pending } = this.state; trace('submitEvidence', operatorId, evidence); // TODO validate that it's a valid for Fast USDC before accepting @@ -146,18 +146,27 @@ export const prepareTransactionFeedKit = (zone, zcf) => { const found = [...pending.values()].filter(store => store.has(txHash), ); - // TODO determine the real policy for checking agreement - if (found.length < pending.getSize()) { - // not all have seen it + const minAttestations = Math.ceil(operators.getSize() / 2); + trace( + 'transaction', + txHash, + 'has', + found.length, + 'of', + minAttestations, + 'necessary attestations', + ); + if (found.length < minAttestations) { return; } // TODO verify that all found deep equal - // all agree, so remove from pending and publish - for (const pendingStore of pending.values()) { - pendingStore.delete(txHash); + // sufficient agreement, so remove from pending and publish + for (const store of found) { + store.delete(txHash); } + trace('publishing evidence', evidence); publisher.publish(evidence); }, }, diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index 8e3b04f9271..5c5b74e094b 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -47,31 +47,30 @@ test('happy aggregation', async t => { const evidenceSubscriber = feedKit.public.getEvidenceSubscriber(); const { op1, op2, op3 } = await makeOperators(feedKit); - const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); - op1.operator.submitEvidence(evidence); - op2.operator.submitEvidence(evidence); - op3.operator.submitEvidence(evidence); + const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + op1.operator.submitEvidence(e1); + op2.operator.submitEvidence(e1); + // Publishes with 2 of 3 const accepted = await evidenceSubscriber.getUpdateSince(0); t.deepEqual(accepted, { - value: evidence, + value: e1, updateCount: 1n, }); - // verify that it doesn't publish until three match - // once it publishes, it doesn't remember that it already saw these - op1.operator.submitEvidence(evidence); - op2.operator.submitEvidence(evidence); - // but this time the third is different - op3.operator.submitEvidence(MockCctpTxEvidences.AGORIC_PLUS_DYDX()); - + // Now third operator catches up with same evidence already published + op3.operator.submitEvidence(e1); t.like(await evidenceSubscriber.getUpdateSince(0), { - // Update count is still 1 + // The confirming evidence doesn't change anything updateCount: 1n, }); - op3.operator.submitEvidence(evidence); + + const e2 = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); + assert(e1.txHash !== e2.txHash); + op1.operator.submitEvidence(e2); t.like(await evidenceSubscriber.getUpdateSince(0), { - updateCount: 2n, + // op1 attestation insufficient + updateCount: 1n, }); }); diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index f7869f3def1..bc73389a5b9 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -1,8 +1,11 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { ExecutionContext, TestFn } from 'ava'; +import { + decodeAddressHook, + encodeAddressHook, +} from '@agoric/cosmic-proto/address-hooks.js'; import { AmountMath } from '@agoric/ertp/src/amountMath.js'; -import { deeplyFulfilledObject } from '@agoric/internal'; import { eventLoopIteration, inspectMapStore, @@ -24,13 +27,9 @@ import { import type { Instance } from '@agoric/zoe/src/zoeService/utils.js'; import { setUpZoeForTest } from '@agoric/zoe/tools/setup-zoe.js'; import { E } from '@endo/far'; -import { matches, objectMap } from '@endo/patterns'; +import { matches } from '@endo/patterns'; import { makePromiseKit } from '@endo/promise-kit'; import path from 'path'; -import { - decodeAddressHook, - encodeAddressHook, -} from '@agoric/cosmic-proto/address-hooks.js'; import type { OperatorKit } from '../src/exos/operator-kit.js'; import type { FastUsdcSF } from '../src/fast-usdc.contract.js'; import { PoolMetricsShape } from '../src/type-guards.js'; @@ -56,10 +55,12 @@ const getInvitationProperties = async ( return amount.value[0]; }; +// Spec for Mainnet. Other values are covered in unit tests of TransactionFeed. +const operatorQty = 3; + type CommonSetup = Awaited>; const startContract = async ( common: Pick, - operatorQty = 1, ) => { const { brands: { usdc }, @@ -104,7 +105,7 @@ const makeTestContext = async (t: ExecutionContext) => { const common = await commonSetup(t); await E(common.mocks.ibcBridge).setAddressPrefix('noble'); - const startKit = await startContract(common, 2); + const startKit = await startContract(common); const { transferBridge } = common.mocks; const evm = makeEVM(); @@ -227,12 +228,17 @@ const makeOracleOperator = async ( ]); const { invitationMakers } = operatorKit; + let active = true; + return harden({ watch: () => { void observeIteration(subscribeEach(txSubscriber), { - updateState: tx => + updateState: tx => { + if (!active) { + return; + } // KLUDGE: tx wouldn't include aux. OCW looks it up - E.when( + return E.when( E(invitationMakers).SubmitEvidence(tx), inv => E.when(E(E(zoe).offer(inv)).getOfferResult(), res => { @@ -242,13 +248,17 @@ const makeOracleOperator = async ( reason => { failures.push(reason.message); }, - ), + ); + }, }); }, getDone: () => done, getFailures: () => harden([...failures]), // operator only gets .invitationMakers getKit: () => operatorKit, + setActive: flag => { + active = flag; + }, }); }; @@ -760,10 +770,12 @@ test.serial('Settlement for unknown transaction (operator down)', async t => { } = t.context; const operators = await sync.ocw.promise; + // Simulate 2 of 3 operators being unavailable + operators[0].setActive(false); + operators[1].setActive(false); + const opDown = makeCustomer('Otto', cctp, txPub.publisher, feeConfig); - // what removeOperator will do - await E(E.get(E(operators[1]).getKit()).admin).disable(); const bridgePos = snapshot(); const sent = await opDown.sendFast(t, 20_000_000n, 'osmo12345'); await mint(sent); @@ -788,9 +800,6 @@ test.serial('Settlement for unknown transaction (operator down)', async t => { t.deepEqual(bridgeTraffic.local, [], 'no IBC transfers'); await transmitTransferAck(); - t.deepEqual(await E(operators[1]).getFailures(), [ - 'submitEvidence for disabled operator', - ]); }); test.todo( From cd2a40c0e4e5923510e7c77edc710b6c7ba8bc8c Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 17 Dec 2024 13:07:19 -0800 Subject: [PATCH 54/65] feat: error on conflicting evidence --- .../fast-usdc/src/exos/transaction-feed.js | 25 ++++++++++- .../test/exos/transaction-feed.test.ts | 43 +++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/packages/fast-usdc/src/exos/transaction-feed.js b/packages/fast-usdc/src/exos/transaction-feed.js index 3d150f5db42..231ef4f828d 100644 --- a/packages/fast-usdc/src/exos/transaction-feed.js +++ b/packages/fast-usdc/src/exos/transaction-feed.js @@ -1,6 +1,7 @@ import { makeTracer } from '@agoric/internal'; import { prepareDurablePublishKit } from '@agoric/notifier'; -import { M } from '@endo/patterns'; +import { keyEQ, M } from '@endo/patterns'; +import { Fail } from '@endo/errors'; import { CctpTxEvidenceShape } from '../type-guards.js'; import { defineInertInvitation } from '../utils/zoe.js'; import { prepareOperatorKit } from './operator-kit.js'; @@ -127,6 +128,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => { const { operators, pending } = this.state; trace('submitEvidence', operatorId, evidence); + // TODO https://github.com/Agoric/agoric-sdk/pull/10720 // TODO validate that it's a valid for Fast USDC before accepting // E.g. that the `recipientAddress` is the FU settlement account and that // the EUD is a chain supported by FU. @@ -160,7 +162,26 @@ export const prepareTransactionFeedKit = (zone, zcf) => { return; } - // TODO verify that all found deep equal + let lastEvidence; + for (const store of found) { + const next = store.get(txHash); + if (lastEvidence) { + if (keyEQ(lastEvidence, next)) { + lastEvidence = next; + } else { + trace( + '🚨 conflicting evidence for', + txHash, + ':', + lastEvidence, + '!=', + next, + ); + Fail`conflicting evidence for ${txHash}`; + } + } + lastEvidence = next; + } // sufficient agreement, so remove from pending and publish for (const store of found) { diff --git a/packages/fast-usdc/test/exos/transaction-feed.test.ts b/packages/fast-usdc/test/exos/transaction-feed.test.ts index 5c5b74e094b..8f5084af0ea 100644 --- a/packages/fast-usdc/test/exos/transaction-feed.test.ts +++ b/packages/fast-usdc/test/exos/transaction-feed.test.ts @@ -47,6 +47,7 @@ test('happy aggregation', async t => { const evidenceSubscriber = feedKit.public.getEvidenceSubscriber(); const { op1, op2, op3 } = await makeOperators(feedKit); + const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); op1.operator.submitEvidence(e1); op2.operator.submitEvidence(e1); @@ -74,6 +75,48 @@ test('happy aggregation', async t => { }); }); +test('disagreement', async t => { + const feedKit = makeFeedKit(); + const { op1, op2 } = await makeOperators(feedKit); + const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + const e1bad = { ...e1, tx: { ...e1.tx, amount: 999_999_999n } }; + assert(e1.txHash === e1bad.txHash); + op1.operator.submitEvidence(e1); + + t.throws(() => op2.operator.submitEvidence(e1bad), { + message: + 'conflicting evidence for "0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702"', + }); +}); + +test('disagreement after publishing', async t => { + const feedKit = makeFeedKit(); + const evidenceSubscriber = feedKit.public.getEvidenceSubscriber(); + const { op1, op2, op3 } = await makeOperators(feedKit); + const e1 = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + const e1bad = { ...e1, tx: { ...e1.tx, amount: 999_999_999n } }; + assert(e1.txHash === e1bad.txHash); + op1.operator.submitEvidence(e1); + op2.operator.submitEvidence(e1); + + t.like(await evidenceSubscriber.getUpdateSince(0), { + updateCount: 1n, + }); + + // it's simply ignored + t.notThrows(() => op3.operator.submitEvidence(e1bad)); + t.like(await evidenceSubscriber.getUpdateSince(0), { + updateCount: 1n, + }); + + // now another op repeats the bad evidence, so it's published to the stream. + // It's the responsibility of the Advancer to fail because it has already processed that tx hash. + op1.operator.submitEvidence(e1bad); + t.like(await evidenceSubscriber.getUpdateSince(0), { + updateCount: 2n, + }); +}); + test('disabled operator', async t => { const feedKit = makeFeedKit(); const { op1 } = await makeOperators(feedKit); From 28284443141f700d2214c42d8d7b983b40f569fc Mon Sep 17 00:00:00 2001 From: samsiegart Date: Tue, 17 Dec 2024 10:57:43 -0800 Subject: [PATCH 55/65] feat(fast-usdc): detect transfer completion in cli --- packages/fast-usdc/demo/testnet/config.json | 9 ++- packages/fast-usdc/src/cli/cli.js | 5 ++ packages/fast-usdc/src/cli/config.js | 9 +++ packages/fast-usdc/src/cli/transfer.js | 42 ++++++++++++ packages/fast-usdc/src/util/bank.js | 12 ++++ packages/fast-usdc/src/util/cctp.js | 2 +- packages/fast-usdc/test/cli/transfer.test.ts | 68 ++++++++++++++++---- packages/fast-usdc/testing/mocks.ts | 4 +- 8 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 packages/fast-usdc/src/util/bank.js diff --git a/packages/fast-usdc/demo/testnet/config.json b/packages/fast-usdc/demo/testnet/config.json index 13b4420b23f..67a26f2a6d7 100644 --- a/packages/fast-usdc/demo/testnet/config.json +++ b/packages/fast-usdc/demo/testnet/config.json @@ -7,5 +7,12 @@ "nobleApi": "https://noble-api.polkachu.com", "ethRpc": "https://sepolia.drpc.org", "tokenMessengerAddress": "0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5", - "tokenAddress": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" + "tokenAddress": "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238", + "destinationChains": [ + { + "bech32prefix": "osmo", + "api": "https://lcd.osmosis.zone", + "USDCDenom": "ibc/498A0751C798A0D9A389AA3691123DADA57DAA4FE165D5C75894505B876BA6E4" + } + ] } diff --git a/packages/fast-usdc/src/cli/cli.js b/packages/fast-usdc/src/cli/cli.js index 8676ef955e2..18acb636fe9 100644 --- a/packages/fast-usdc/src/cli/cli.js +++ b/packages/fast-usdc/src/cli/cli.js @@ -91,7 +91,12 @@ export const initProgram = ( /** @type {string} */ amount, /** @type {string} */ destination, ) => { + const start = now(); await transferHelpers.transfer(makeConfigFile(), amount, destination); + const duration = now() - start; + stdout.write( + `Transfer finished in ${(duration / 1000).toFixed(1)} seconds`, + ); }, ); diff --git a/packages/fast-usdc/src/cli/config.js b/packages/fast-usdc/src/cli/config.js index 2b67a4868a3..c59e6c8fc13 100644 --- a/packages/fast-usdc/src/cli/config.js +++ b/packages/fast-usdc/src/cli/config.js @@ -1,6 +1,14 @@ import * as readline from 'node:readline/promises'; import { stdin as input, stdout as output } from 'node:process'; +/** + @typedef {{ + bech32Prefix: string, + api: string, + USDCDenom: string + }} DestinationChain + */ + /** @typedef {{ nobleSeed: string, @@ -11,6 +19,7 @@ import { stdin as input, stdout as output } from 'node:process'; ethRpc: string, tokenMessengerAddress: string, tokenAddress: string + destinationChains?: DestinationChain[] }} ConfigOpts */ diff --git a/packages/fast-usdc/src/cli/transfer.js b/packages/fast-usdc/src/cli/transfer.js index 41719ac1c37..31b8e212f65 100644 --- a/packages/fast-usdc/src/cli/transfer.js +++ b/packages/fast-usdc/src/cli/transfer.js @@ -14,6 +14,7 @@ import { queryForwardingAccount, registerFwdAccount, } from '../util/noble.js'; +import { queryUSDCBalance } from '../util/bank.js'; /** @import { File } from '../util/file' */ /** @import { VStorage } from '@agoric/client-utils' */ @@ -30,6 +31,7 @@ const transfer = async ( /** @type {{signer: SigningStargateClient, address: string} | undefined} */ nobleSigner, /** @type {ethProvider | undefined} */ ethProvider, env = process.env, + setTimeout = globalThis.setTimeout, ) => { const execute = async ( /** @type {import('./config').ConfigOpts} */ config, @@ -71,6 +73,18 @@ const transfer = async ( } } + const destChain = config.destinationChains?.find(chain => + EUD.startsWith(chain.bech32Prefix), + ); + if (!destChain) { + out.error( + `No destination chain found in config with matching bech32 prefix for ${EUD}, cannot query destination address`, + ); + throw new Error(); + } + const { api, USDCDenom } = destChain; + const startingBalance = await queryUSDCBalance(EUD, api, USDCDenom, fetch); + ethProvider ||= makeProvider(config.ethRpc); await depositForBurn( ethProvider, @@ -81,6 +95,34 @@ const transfer = async ( amount, out, ); + + const refreshDelayMS = 1200; + const completeP = /** @type {Promise} */ ( + new Promise((res, rej) => { + const refreshUSDCBalance = async () => { + out.log('polling usdc balance'); + const currentBalance = await queryUSDCBalance( + EUD, + api, + USDCDenom, + fetch, + ); + if (currentBalance !== startingBalance) { + res(); + } else { + setTimeout(() => refreshUSDCBalance().catch(rej), refreshDelayMS); + } + }; + refreshUSDCBalance().catch(rej); + }) + ).catch(e => { + out.error( + 'Error checking destination address balance, could not detect completion of transfer.', + ); + out.error(e.message); + }); + + await completeP; }; let config; diff --git a/packages/fast-usdc/src/util/bank.js b/packages/fast-usdc/src/util/bank.js new file mode 100644 index 00000000000..24f1ced5265 --- /dev/null +++ b/packages/fast-usdc/src/util/bank.js @@ -0,0 +1,12 @@ +export const queryUSDCBalance = async ( + /** @type {string} */ address, + /** @type {string} */ api, + /** @type {string} */ denom, + /** @type {typeof globalThis.fetch} */ fetch, +) => { + const query = `${api}/cosmos/bank/v1beta1/balances/${address}`; + const json = await fetch(query).then(res => res.json()); + const amount = json.balances?.find(b => b.denom === denom)?.amount ?? '0'; + + return BigInt(amount); +}; diff --git a/packages/fast-usdc/src/util/cctp.js b/packages/fast-usdc/src/util/cctp.js index 08d8d475564..761e5221f69 100644 --- a/packages/fast-usdc/src/util/cctp.js +++ b/packages/fast-usdc/src/util/cctp.js @@ -67,5 +67,5 @@ export const depositForBurn = async ( out.log('Transaction confirmed in block', receipt.blockNumber); out.log('Transaction hash:', receipt.hash); - out.log('USDC transfer initiated successfully, our work here is done.'); + out.log('USDC transfer initiated successfully'); }; diff --git a/packages/fast-usdc/test/cli/transfer.test.ts b/packages/fast-usdc/test/cli/transfer.test.ts index 28cd3d41569..1f75734d5ae 100644 --- a/packages/fast-usdc/test/cli/transfer.test.ts +++ b/packages/fast-usdc/test/cli/transfer.test.ts @@ -52,6 +52,8 @@ test('Transfer registers the noble forwarding account if it does not exist', asy const path = 'config/dir/.fast-usdc/config.json'; const nobleApi = 'http://api.noble.test'; const nobleToAgoricChannel = 'channel-test-7'; + const destinationChainApi = 'http://api.dydx.fake-test'; + const destinationUSDCDenom = 'ibc/USDCDENOM'; const config = { agoricRpc: 'http://rpc.agoric.test', nobleApi, @@ -61,6 +63,13 @@ test('Transfer registers the noble forwarding account if it does not exist', asy ethSeed: 'a4b7f431465df5dc1458cd8a9be10c42da8e3729e3ce53f18814f48ae2a98a08', tokenMessengerAddress: '0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5', tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + destinationChains: [ + { + bech32Prefix: 'dydx', + api: destinationChainApi, + USDCDenom: destinationUSDCDenom, + }, + ], }; const out = mockOut(); const file = mockFile(path, JSON.stringify(config)); @@ -76,11 +85,25 @@ test('Transfer registers the noble forwarding account if it does not exist', asy agoricSettlementAccount, { EUD }, )}/`; - const fetchMock = makeFetchMock({ - [nobleFwdAccountQuery]: { - address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', - exists: false, - }, + const destinationBankQuery = `${destinationChainApi}/cosmos/bank/v1beta1/balances/${EUD}`; + let balanceQueryCount = 0; + const fetchMock = makeFetchMock((query: string) => { + if (query === nobleFwdAccountQuery) { + return { + address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', + exists: false, + }; + } + if (query === destinationBankQuery) { + if (balanceQueryCount > 1) { + return { + balances: [{ denom: destinationUSDCDenom, amount }], + }; + } else { + balanceQueryCount += 1; + return {}; + } + } }); const nobleSignerAddress = 'noble09876'; const signerMock = makeMockSigner(); @@ -97,7 +120,6 @@ test('Transfer registers the noble forwarding account if it does not exist', asy { signer: signerMock.signer, address: nobleSignerAddress }, mockEthProvider.provider, ); - t.is(vstorageMock.getQueryCounts()[settlementAccountVstoragePath], 1); t.is(fetchMock.getQueryCounts()[nobleFwdAccountQuery], 1); t.snapshot(signerMock.getSigned()); @@ -107,6 +129,8 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy const path = 'config/dir/.fast-usdc/config.json'; const nobleApi = 'http://api.noble.test'; const nobleToAgoricChannel = 'channel-test-7'; + const destinationChainApi = 'http://api.dydx.fake-test'; + const destinationUSDCDenom = 'ibc/USDCDENOM'; const config = { agoricRpc: 'http://rpc.agoric.test', nobleApi, @@ -116,6 +140,13 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy ethSeed: 'a4b7f431465df5dc1458cd8a9be10c42da8e3729e3ce53f18814f48ae2a98a08', tokenMessengerAddress: '0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5', tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238', + destinationChains: [ + { + bech32Prefix: 'dydx', + api: destinationChainApi, + USDCDenom: destinationUSDCDenom, + }, + ], }; const out = mockOut(); const file = mockFile(path, JSON.stringify(config)); @@ -131,11 +162,25 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy agoricSettlementAccount, { EUD }, )}/`; - const fetchMock = makeFetchMock({ - [nobleFwdAccountQuery]: { - address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', - exists: true, - }, + const destinationBankQuery = `${destinationChainApi}/cosmos/bank/v1beta1/balances/${EUD}`; + let balanceQueryCount = 0; + const fetchMock = makeFetchMock((query: string) => { + if (query === nobleFwdAccountQuery) { + return { + address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', + exists: true, + }; + } + if (query === destinationBankQuery) { + if (balanceQueryCount > 1) { + return { + balances: [{ denom: destinationUSDCDenom, amount }], + }; + } else { + balanceQueryCount += 1; + return {}; + } + } }); const nobleSignerAddress = 'noble09876'; const signerMock = makeMockSigner(); @@ -162,4 +207,5 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy t.deepEqual(mockEthProvider.getTxnArgs()[1], [ '0xf8e4800180949f3b8679c73c2fef8b59b4f3444d4e156fb70aa580b8846fd3504e0000000000000000000000000000000000000000000000000000000008f0d1800000000000000000000000000000000000000000000000000000000000000004000000000000000000000000afdd918f09158436695a754a1b0913ed5ab474f80000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c723882011aa09fc97790b2ba23fbb974554dbcee00df1a1f50e9fec4fdf370454773604aa477a038a1d86afc2a7afdc78088878a912f1a7c678b10c3120d308f8260a277b135a3', ]); + t.is(fetchMock.getQueryCounts()[destinationBankQuery], 3); }); diff --git a/packages/fast-usdc/testing/mocks.ts b/packages/fast-usdc/testing/mocks.ts index 92f6c885d45..55b0a495ee6 100644 --- a/packages/fast-usdc/testing/mocks.ts +++ b/packages/fast-usdc/testing/mocks.ts @@ -43,11 +43,11 @@ export const makeVstorageMock = (records: { [key: string]: any }) => { return { vstorage, getQueryCounts: () => queryCounts }; }; -export const makeFetchMock = (records: { [key: string]: any }) => { +export const makeFetchMock = get => { const queryCounts = {}; const fetch = async (path: string) => { queryCounts[path] = (queryCounts[path] ?? 0) + 1; - return { json: async () => records[path] }; + return { json: async () => get(path) }; }; return { fetch, getQueryCounts: () => queryCounts }; From 702e494da46a66a4ae47f6f36ea7f7c89ef6aa44 Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 18 Dec 2024 09:51:31 -0800 Subject: [PATCH 56/65] test: turn on test of priceAuthority registry --- a3p-integration/proposals/p:upgrade-19/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/a3p-integration/proposals/p:upgrade-19/test.sh b/a3p-integration/proposals/p:upgrade-19/test.sh index 193e27da231..25cd9bde21f 100644 --- a/a3p-integration/proposals/p:upgrade-19/test.sh +++ b/a3p-integration/proposals/p:upgrade-19/test.sh @@ -8,3 +8,5 @@ yarn ava provisionPool.test.js yarn ava agoricNames.test.js yarn ava assetReserve.test.js + +yarn ava registry.test.js From ae1963e9f73f159be2fab93920fcceeb9ebc555d Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Mon, 16 Dec 2024 19:00:26 -0600 Subject: [PATCH 57/65] feat(fast-usdc): add FastLP/ufastlp to vbank --- packages/fast-usdc/src/fast-usdc.start.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/fast-usdc/src/fast-usdc.start.js b/packages/fast-usdc/src/fast-usdc.start.js index 2815569d2ed..44a2838a130 100644 --- a/packages/fast-usdc/src/fast-usdc.start.js +++ b/packages/fast-usdc/src/fast-usdc.start.js @@ -27,6 +27,13 @@ import { fromExternalConfig } from './utils/config-marshal.js'; * @import {FeedPolicy, FastUSDCConfig} from './types.js' */ +const ShareAssetInfo = /** @type {const} */ harden({ + issuerName: 'FastLP', + denom: 'ufastlp', + assetKind: 'nat', + decimalPlaces: 6, +}); + const trace = makeTracer('FUSD-Start', true); const contractName = 'fastUsdc'; @@ -116,6 +123,7 @@ export const startFastUSDC = async ( consume: { agoricNames, namesByAddress, + bankManager, board, chainStorage, chainTimerService: timerService, @@ -206,13 +214,23 @@ export const startFastUSDC = async ( await publishFeedPolicy(storageNode, feedPolicy); const { - issuers: { PoolShares: shareIssuer }, + issuers: fastUsdcIssuers, brands: { PoolShares: shareBrand }, } = await E(zoe).getTerms(instance); + /** @type {{ PoolShares: Issuer<'nat'> }} */ + // @ts-expect-error see zcf.makeZCFMint(...) in fast-usdc.contract.js + const { PoolShares: shareIssuer } = fastUsdcIssuers; produceShareIssuer.resolve(shareIssuer); produceShareBrand.resolve(shareBrand); await publishDisplayInfo(shareBrand, { board, chainStorage }); + const { denom, issuerName } = ShareAssetInfo; + trace('addAsset', denom, shareBrand); + await E(bankManager).addAsset(denom, issuerName, issuerName, { + issuer: shareIssuer, + brand: shareBrand, + }); + await Promise.all( Object.entries(oracleDepositFacets).map(async ([name, depositFacet]) => { const address = oracles[name]; @@ -258,6 +276,8 @@ export const getManifestForFastUSDC = ( fastUsdcKit: true, }, consume: { + bankManager: true, // to add FastLP as vbank asset + chainStorage: true, chainTimerService: true, localchain: true, From b7aa5f091a418fe652d87ab5cbed7c0aacdb643b Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Mon, 16 Dec 2024 19:21:36 -0600 Subject: [PATCH 58/65] test(boot): FastLP/ufastlp is in published.agoricNames.vbankAsset --- packages/boot/test/fast-usdc/fast-usdc.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index 3c17e8b6f55..d8a27106189 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -92,6 +92,14 @@ test.serial( refreshAgoricNamesRemotes(); t.truthy(agoricNamesRemotes.instance.fastUsdc); t.truthy(agoricNamesRemotes.brand.FastLP); + const lpAsset = agoricNamesRemotes.vbankAsset.FastLP; + t.like(lpAsset, { + issuerName: 'FastLP', + denom: 'ufastlp', + displayInfo: { assetKind: 'nat', decimalPlaces: 6 }, + }); + const lpId = lpAsset.brand.getBoardId(); + t.is(agoricNamesRemotes.brand.FastLP.getBoardId(), lpId); const { EV } = t.context.runUtils; const agoricNames = await EV.vat('bootstrap').consumeItem('agoricNames'); @@ -99,6 +107,7 @@ test.serial( const getBoardAux = async name => { const brand = await EV(agoricNames).lookup('brand', name); const id = await EV(board).getId(brand); + t.is(id || null, lpId); t.truthy(storage.data.get(`published.boardAux.${id}`)); return unmarshalFromVstorage( storage.data, From 2ba4a950b2d44bed56fcf69ecf7b16cf40e41608 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Mon, 16 Dec 2024 19:32:48 -0600 Subject: [PATCH 59/65] test(boot): FastLP balance not in wallet record --- .../boot/test/fast-usdc/fast-usdc.test.ts | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index d8a27106189..f581f665a7f 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -98,7 +98,7 @@ test.serial( denom: 'ufastlp', displayInfo: { assetKind: 'nat', decimalPlaces: 6 }, }); - const lpId = lpAsset.brand.getBoardId(); + const lpId = lpAsset.brand.getBoardId() || assert.fail('impossible'); t.is(agoricNamesRemotes.brand.FastLP.getBoardId(), lpId); const { EV } = t.context.runUtils; @@ -107,7 +107,7 @@ test.serial( const getBoardAux = async name => { const brand = await EV(agoricNames).lookup('brand', name); const id = await EV(board).getId(brand); - t.is(id || null, lpId); + t.is(id, lpId); t.truthy(storage.data.get(`published.boardAux.${id}`)); return unmarshalFromVstorage( storage.data, @@ -130,7 +130,7 @@ test.serial( const current = watcherWallet.getCurrentWalletRecord(); - // XXX We should be able to compare objects by identity like this: + // XXX #10491 We should be able to compare objects by identity like this: // // const invitationPurse = current.purses.find( // p => p.brand === agoricNamesRemotes.brand.Invitation, @@ -225,9 +225,11 @@ test.serial('makes usdc advance', async t => { ), ); + const lp = oracles[0]; // somewhat arbitrary + // @ts-expect-error it doesnt recognize usdc as a Brand type const usdc = agoricNamesRemotes.vbankAsset.USDC.brand as Brand<'nat'>; - await oracles[0].sendOffer({ + await lp.sendOffer({ id: 'deposit-lp-0', invitationSpec: { source: 'agoricContract', @@ -242,6 +244,23 @@ test.serial('makes usdc advance', async t => { }); await eventLoopIteration(); + const { getOutboundMessages } = t.context.bridgeUtils; + const lpBankDeposit = getOutboundMessages(BridgeId.BANK).find( + obj => + obj.type === 'VBANK_GIVE' && + obj.denom === 'ufastlp' && + obj.recipient === lp.getAddress(), + ); + t.log('LP vbank deposit', lpBankDeposit); + t.true(BigInt(lpBankDeposit.amount) > 1_000_000n, 'vbank GIVEs shares to LP'); + + const { purses } = lp.getCurrentWalletRecord(); + // XXX #10491 should not need to resort to string match on brand + t.falsy( + purses.find(p => `${p.brand}`.match(/FastLP/)), + 'FastLP balance not in wallet record', + ); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); harness?.useRunPolicy(true); From 26d3b0f143f89d03bb496403657abd9f24681f70 Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Tue, 17 Dec 2024 15:16:05 -0600 Subject: [PATCH 60/65] test: get FastLP/ufastlp balance from x/bank query - prune balancesFromPurses, which was not type-safe - factor out vstorage queries for type safety - add static check on deposit / withdraw proposals - refactor usdcToGive as give.USDC etc. balancesFromPurses() seemed to return a Record but Brands can't be record keys. It "worked" by stringifying the brands. ``` > b = {[Symbol.toStringTag]:'B123'} { [Symbol(Symbol.toStringTag)]: 'B123' } > b.toString() '[object B123]' > fromEntries([[b, 1]]) { '[object B123]': 1 } ``` --- .../test/fast-usdc/fast-usdc.test.ts | 148 +++++++++++------- multichain-testing/tools/purse.ts | 10 -- 2 files changed, 94 insertions(+), 64 deletions(-) delete mode 100644 multichain-testing/tools/purse.ts diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index a7fbf413e32..1b0958a3441 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -13,17 +13,20 @@ import { makeQueryClient } from '../../tools/query.js'; import { commonSetup, type SetupContextWithWallets } from '../support.js'; import { makeFeedPolicy, oracleMnemonics } from './config.js'; import { makeRandomDigits } from '../../tools/random.js'; -import { balancesFromPurses } from '../../tools/purse.js'; import { makeTracer } from '@agoric/internal'; import type { CctpTxEvidence, EvmAddress, + PoolMetrics, } from '@agoric/fast-usdc/src/types.js'; +import type { CurrentWalletRecord } from '@agoric/smart-wallet/src/smartWallet.js'; +import type { QueryBalanceResponseSDKType } from '@agoric/cosmic-proto/cosmos/bank/v1beta1/query.js'; +import type { USDCProposalShapes } from '@agoric/fast-usdc/src/pool-share-math.js'; const log = makeTracer('MCFU'); const { keys, values, fromEntries } = Object; -const { isGTE, isEmpty, make } = AmountMath; +const { isGTE, isEmpty, make, subtract } = AmountMath; const makeRandomNumber = () => Math.random(); @@ -107,23 +110,62 @@ test.after(async t => { deleteTestKeys(accounts); }); +type VStorageClient = Awaited>['vstorageClient']; +const agoricNamesQ = (vsc: VStorageClient) => + harden({ + brands: (_assetKind: K) => + vsc + .queryData('published.agoricNames.brand') + .then(pairs => fromEntries(pairs) as Record>), + }); +const walletQ = (vsc: VStorageClient) => { + const self = harden({ + current: (addr: string) => + vsc.queryData( + `published.wallet.${addr}.current`, + ) as Promise, + findInvitationDetail: async (addr: string, description: string) => { + const { Invitation } = await agoricNamesQ(vsc).brands('set'); + const current = await self.current(addr); + const { purses } = current; + const { value: details } = purses.find(p => p.brand === Invitation)! + .balance as Amount<'set', InvitationDetails>; + const detail = details.find(x => x.description === description); + return { current, detail }; + }, + }); + return self; +}; + +const fastLPQ = (vsc: VStorageClient) => + harden({ + metrics: () => + vsc.queryData(`published.fastUsdc.poolMetrics`) as Promise, + info: () => + vsc.queryData(`published.${contractName}`) as Promise<{ + poolAccount: string; + settlementAccount: string; + }>, + }); + const toOracleOfferId = (idx: number) => `oracle${idx + 1}-accept`; test.serial('oracles accept', async t => { const { oracleWds, retryUntilCondition, vstorageClient, wallets } = t.context; - const brands = await vstorageClient.queryData('published.agoricNames.brand'); - const { Invitation } = Object.fromEntries(brands); const description = 'oracle operator invitation'; // ensure we have an unused (or used) oracle invitation in each purse let hasAccepted = false; for (const name of keys(oracleMnemonics)) { - const { offerToUsedInvitation, purses } = await vstorageClient.queryData( - `published.wallet.${wallets[name]}.current`, + const { + current: { offerToUsedInvitation }, + detail, + } = await walletQ(vstorageClient).findInvitationDetail( + wallets[name], + description, ); - const { value: invitations } = balancesFromPurses(purses)[Invitation]; - const hasInvitation = invitations.some(x => x.description === description); + const hasInvitation = !!detail; const usedInvitation = offerToUsedInvitation?.[0]?.[0] === `${name}-accept`; t.log({ name, hasInvitation, usedInvitation }); t.true(hasInvitation || usedInvitation, 'has or accepted invitation'); @@ -167,20 +209,24 @@ test.serial('oracles accept', async t => { } }); +const toAmt = ( + brand: Brand<'nat'>, + balance: QueryBalanceResponseSDKType['balance'], +) => make(brand, BigInt(balance?.amount || 0)); + test.serial('lp deposits', async t => { const { lpUser, retryUntilCondition, vstorageClient, wallets } = t.context; const lpDoOffer = makeDoOffer(lpUser); - const brands = await vstorageClient.queryData('published.agoricNames.brand'); - const { USDC, FastLP } = Object.fromEntries(brands); - const usdcToGive = make(USDC, LP_DEPOSIT_AMOUNT); + const { USDC, FastLP } = await agoricNamesQ(vstorageClient).brands('nat'); - const { shareWorth: currShareWorth } = await vstorageClient.queryData( - `published.${contractName}.poolMetrics`, - ); - const poolSharesWanted = divideBy(usdcToGive, currShareWorth); + const give = { USDC: make(USDC, LP_DEPOSIT_AMOUNT) }; + + const metricsPre = await fastLPQ(vstorageClient).metrics(); + const want = { PoolShare: divideBy(give.USDC, metricsPre.shareWorth) }; + const proposal: USDCProposalShapes['deposit'] = harden({ give, want }); await lpDoOffer({ id: `lp-deposit-${Date.now()}`, invitationSpec: { @@ -188,30 +234,28 @@ test.serial('lp deposits', async t => { instancePath: [contractName], callPipe: [['makeDepositInvitation']], }, - proposal: { - give: { USDC: usdcToGive }, - want: { PoolShare: poolSharesWanted }, - }, + proposal, }); await t.notThrowsAsync(() => retryUntilCondition( - () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + () => fastLPQ(vstorageClient).metrics(), ({ shareWorth }) => - !isGTE(currShareWorth.numerator, shareWorth.numerator), + !isGTE(metricsPre.shareWorth.numerator, shareWorth.numerator), 'share worth numerator increases from deposit', { log }, ), ); + const { useChain } = t.context; + const queryClient = makeQueryClient( + await useChain('agoric').getRestEndpoint(), + ); + await t.notThrowsAsync(() => retryUntilCondition( - () => - vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`), - ({ purses }) => { - const currentPoolShares = balancesFromPurses(purses)[FastLP]; - return currentPoolShares && isGTE(currentPoolShares, poolSharesWanted); - }, + () => queryClient.queryBalance(wallets['lp'], 'ufastlp'), + ({ balance }) => isGTE(toAmt(FastLP, balance), want.PoolShare), 'lp has pool shares', { log }, ), @@ -344,7 +388,7 @@ const advanceAndSettleScenario = test.macro({ nobleTools.mockCctpMint(mintAmt, userForwardingAddr); await t.notThrowsAsync(() => retryUntilCondition( - () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + () => fastLPQ(vstorageClient).metrics(), ({ encumberedBalance }) => encumberedBalance && isEmpty(encumberedBalance), 'encumberedBalance returns to 0', @@ -372,27 +416,28 @@ test.serial('lp withdraws', async t => { await useChain('agoric').getRestEndpoint(), ); const lpDoOffer = makeDoOffer(lpUser); - const brands = await vstorageClient.queryData('published.agoricNames.brand'); - const { FastLP } = Object.fromEntries(brands); + const { FastLP } = await agoricNamesQ(vstorageClient).brands('nat'); t.log('FastLP brand', FastLP); - const { shareWorth: currShareWorth } = await vstorageClient.queryData( - `published.${contractName}.poolMetrics`, - ); - const { purses } = await vstorageClient.queryData( - `published.wallet.${wallets['lp']}.current`, + const metricsPre = await fastLPQ(vstorageClient).metrics(); + + const { balance: lpCoins } = await queryClient.queryBalance( + wallets['lp'], + 'ufastlp', ); - const currentPoolShares = balancesFromPurses(purses)[FastLP]; - t.log('currentPoolShares', currentPoolShares); - const usdcWanted = multiplyBy(currentPoolShares, currShareWorth); - t.log('usdcWanted', usdcWanted); + const give = { PoolShare: toAmt(FastLP, lpCoins) }; + t.log('give', give, lpCoins); - const { balance: currentUSDCBalance } = await queryClient.queryBalance( + const { balance: usdcCoinsPre } = await queryClient.queryBalance( wallets['lp'], usdcDenom, ); - t.log(`current ${usdcDenom} balance`, currentUSDCBalance); + t.log('usdc coins pre', usdcCoinsPre); + + const want = { USDC: multiplyBy(give.PoolShare, metricsPre.shareWorth) }; + t.log('want', want); + const proposal: USDCProposalShapes['withdraw'] = harden({ give, want }); await lpDoOffer({ id: `lp-withdraw-${Date.now()}`, invitationSpec: { @@ -400,32 +445,27 @@ test.serial('lp withdraws', async t => { instancePath: [contractName], callPipe: [['makeWithdrawInvitation']], }, - proposal: { - give: { PoolShare: currentPoolShares }, - want: { USDC: usdcWanted }, - }, + proposal, }); await t.notThrowsAsync(() => retryUntilCondition( - () => - vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`), - ({ purses }) => { - const currentPoolShares = balancesFromPurses(purses)[FastLP]; - return !currentPoolShares || isEmpty(currentPoolShares); - }, + () => queryClient.queryBalance(wallets['lp'], 'ufastlp'), + ({ balance }) => isEmpty(toAmt(FastLP, balance)), 'lp no longer has pool shares', { log }, ), ); + const USDC = want.USDC.brand; await t.notThrowsAsync(() => retryUntilCondition( () => queryClient.queryBalance(wallets['lp'], usdcDenom), ({ balance }) => - !!balance?.amount && - BigInt(balance.amount) - BigInt(currentUSDCBalance!.amount!) > - LP_DEPOSIT_AMOUNT, + !isGTE( + make(USDC, LP_DEPOSIT_AMOUNT), + subtract(toAmt(USDC, balance), toAmt(USDC, usdcCoinsPre)), + ), "lp's USDC balance increases", { log }, ), diff --git a/multichain-testing/tools/purse.ts b/multichain-testing/tools/purse.ts deleted file mode 100644 index 82a76d2a3f4..00000000000 --- a/multichain-testing/tools/purse.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Amount, Brand } from '@agoric/ertp'; -const { fromEntries } = Object; - -// @ts-expect-error Type 'Brand' does not satisfy the constraint 'string | number | symbol' -type BrandToBalance = Record; - -export const balancesFromPurses = ( - purses: { balance: Amount; brand: Brand }[], -): BrandToBalance => - fromEntries(purses.map(({ balance, brand }) => [brand, balance])); From 3815e4c856120cbf525968179017e28812964cfb Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Wed, 18 Dec 2024 10:09:49 -0600 Subject: [PATCH 61/65] chore: walletDriver supports getAddress() --- packages/boot/tools/drivers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/boot/tools/drivers.ts b/packages/boot/tools/drivers.ts index d3029886674..850cf668d04 100644 --- a/packages/boot/tools/drivers.ts +++ b/packages/boot/tools/drivers.ts @@ -55,6 +55,7 @@ export const makeWalletFactoryDriver = async ( isNew: boolean, ) => ({ isNew, + getAddress: () => walletAddress, executeOffer(offer: OfferSpec): Promise { const offerCapData = marshaller.toCapData( From 6f4936902fed970858e4666e6794b299d8fd6ad9 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 17 Dec 2024 20:14:58 -0500 Subject: [PATCH 62/65] tools: makeTestAddress helper - returns valid bech32 address for tests --- packages/orchestration/package.json | 1 + .../test/tools/make-test-address.test.ts | 22 +++++++++++++++++++ .../orchestration/tools/make-test-address.js | 21 ++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 packages/orchestration/test/tools/make-test-address.test.ts create mode 100644 packages/orchestration/tools/make-test-address.js diff --git a/packages/orchestration/package.json b/packages/orchestration/package.json index f104ad60ad6..e23054785e7 100644 --- a/packages/orchestration/package.json +++ b/packages/orchestration/package.json @@ -62,6 +62,7 @@ "@endo/import-bundle": "^1.3.2", "@endo/ses-ava": "^1.2.8", "ava": "^5.3.1", + "bech32": "^2.0.0", "c8": "^10.1.2", "prettier": "^3.4.2", "ts-blank-space": "^0.4.4" diff --git a/packages/orchestration/test/tools/make-test-address.test.ts b/packages/orchestration/test/tools/make-test-address.test.ts new file mode 100644 index 00000000000..54b859ad736 --- /dev/null +++ b/packages/orchestration/test/tools/make-test-address.test.ts @@ -0,0 +1,22 @@ +import test from '@endo/ses-ava/prepare-endo.js'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; +import { makeTestAddress } from '../../tools/make-test-address.js'; + +test('makeTestAddress returns valid bech32', t => { + t.is(makeTestAddress(), 'agoric1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp7zqht'); + t.is(makeTestAddress(1), 'agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g'); + t.is( + makeTestAddress(0, 'agoric', 32), + 'agoric1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkppep3', + ); + t.is( + makeTestAddress(0, 'cosmos'), + 'cosmos1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqnrql8a', + ); +}); + +test('makeTestAddress creates address accepted by encodeAddressHook', t => { + const params = { EUD: makeTestAddress(0, 'osmosis') }; + t.throws(() => encodeAddressHook('agoric1FakeLCAAddress', params)); + t.notThrows(() => encodeAddressHook(makeTestAddress(), params)); +}); diff --git a/packages/orchestration/tools/make-test-address.js b/packages/orchestration/tools/make-test-address.js new file mode 100644 index 00000000000..0a80a82562d --- /dev/null +++ b/packages/orchestration/tools/make-test-address.js @@ -0,0 +1,21 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { bech32 } from 'bech32'; + +/** + * @param {number} index + * @param {string} prefix + * @param {number} byteLength + * @returns {string} a mock bech32 address for tests + */ +export const makeTestAddress = ( + index = 0, + prefix = 'agoric', + byteLength = 20, +) => { + // create a simple 20-byte array (common address length) + const bytes = new Uint8Array(byteLength).fill(0); + // if index provided, put it in the first byte + if (index !== 0) bytes[0] = Number(index); + const words = bech32.toWords(bytes); + return bech32.encode(prefix, words); +}; From 45eeee0ec349b10623871b800479babdf100c21b Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 17 Dec 2024 17:43:04 -0500 Subject: [PATCH 63/65] chore: mock `VLOCALCHAIN_ALLOCATE_ADDRESS` handler returns valid bech32 - instead of `agoric1fakeLCAAddress`, `agoric1fakeLCAAddress1` - to support `encodeAddressHook` which relies on valid bech32 --- .../test/bootstrapTests/orchestration.test.ts | 14 +++++++++++--- .../fast-usdc/snapshots/fast-usdc.test.ts.md | 8 ++++---- .../snapshots/fast-usdc.test.ts.snap | Bin 2209 -> 2218 bytes .../orchestration/contract-upgrade.test.ts | 3 +++ .../orchestration/restart-contracts.test.ts | 3 +++ packages/boot/tools/supports.ts | 3 ++- 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/boot/test/bootstrapTests/orchestration.test.ts b/packages/boot/test/bootstrapTests/orchestration.test.ts index 0de187aa734..e2e49122890 100644 --- a/packages/boot/test/bootstrapTests/orchestration.test.ts +++ b/packages/boot/test/bootstrapTests/orchestration.test.ts @@ -16,6 +16,7 @@ import { SIMULATED_ERRORS } from '@agoric/vats/tools/fake-bridge.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; import { BridgeId } from '@agoric/internal'; +import { makeTestAddress } from '@agoric/orchestration/tools/make-test-address.js'; import { makeWalletFactoryContext, type WalletFactoryTestContext, @@ -410,8 +411,9 @@ test.serial('basic-flows', async t => { const publicSubscriberPaths = Object.fromEntries( wd.getCurrentWalletRecord().offerToPublicSubscriberPaths, ); + const expectedAddress = makeTestAddress(); t.deepEqual(publicSubscriberPaths['request-loa'], { - account: 'published.basicFlows.agoric1fakeLCAAddress', + account: `published.basicFlows.${expectedAddress}`, }); t.like(wd.getLatestUpdateRecord(), { status: { id: 'request-loa', numWantsSatisfied: 1 }, @@ -487,6 +489,8 @@ test.serial('basic-flows', async t => { await runInbound( BridgeId.VTRANSFER, buildVTransferEvent({ + sender: expectedAddress, + target: expectedAddress, sourceChannel: 'channel-62', sequence: '1', }), @@ -598,7 +602,8 @@ test.serial('basic-flows - portfolio holder', async t => { [ 'request-portfolio-acct', { - agoric: 'published.basicFlows.agoric1fakeLCAAddress1', + agoric: + 'published.basicFlows.agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g', cosmoshub: 'published.basicFlows.cosmos1test2', osmosis: 'published.basicFlows.cosmos1test3', }, @@ -615,7 +620,10 @@ test.serial('basic-flows - portfolio holder', async t => { remoteAddress: '/ibc-hop/connection-1/ibc-port/icahost/ordered/{"version":"ics27-1","controllerConnectionId":"connection-1","hostConnectionId":"connection-1649","address":"cosmos1test3","encoding":"proto3","txType":"sdk_multi_msg"}/ibc-channel/channel-4', }); - t.is(readPublished('basicFlows.agoric1fakeLCAAddress1'), ''); + t.is( + readPublished('basicFlows.agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g'), + '', + ); const { BLD } = agoricNamesRemotes.brand; BLD || Fail`BLD missing from agoricNames`; diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md index eae055ef42a..ace588bbdf2 100644 --- a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md +++ b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.md @@ -132,19 +132,19 @@ Generated by [AVA](https://avajs.dev). [ 'published.fastUsdc', { - poolAccount: 'agoric1fakeLCAAddress', - settlementAccount: 'agoric1fakeLCAAddress1', + poolAccount: 'agoric1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp7zqht', + settlementAccount: 'agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g', }, ], [ - 'published.fastUsdc.agoric1fakeLCAAddress', + 'published.fastUsdc.agoric1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqp7zqht', { body: '#""', slots: [], }, ], [ - 'published.fastUsdc.agoric1fakeLCAAddress1', + 'published.fastUsdc.agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g', { body: '#""', slots: [], diff --git a/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap b/packages/boot/test/fast-usdc/snapshots/fast-usdc.test.ts.snap index c837074b0fac8a8353a3bc2e4a0b8b6253eecf4f..0098b4788bfb2c84ca53df4b055872bf5e179aab 100644 GIT binary patch literal 2218 zcmV;b2vzq%RzV*U(0|lC_oI+c4zVrHGpD#tIjxPyO zX&Q1#D%yiE-W}VUTkkl#dPMTn$9h)NYgJRpI1Kq@@&PXej}1*8^G zC3vAi0;)K&lb$r ztBhHClRLJ#tqZPi_=0=1#%$lEO~1~CfAzX$Q9(bhysTmZ!H1-XG6x_B-~dU^l0?b# z=r$ppr~Ui)gG_=DkSRhw)NxW7fOP<0h&d{8M+Iar4iE)*5EUdbOYUm6Dvs^fnKfUf zzBun&=6q238CkeYb0bJXf;`$U0Q?%jTL2bFJ6H1I$|YtBqIMr=W@bR95v15h$T@;; zx@ogcZC3`jnGdo*D5hh)!{rr+m1^9x&2pW(E^|&<9pj`Kwq$Zf%xzk_t?&l5-8Nn$ znjFk41h^WnQ|qgf$U2{k)R`)I6ZLzpD!I*q>Pqx zg(6!#vJ{Jcr)i4jIlj)^hnVj(x5m8w*v9hWV%9RUE6ZiGxRf_?Mv>8K-Z)+?7V|6F ze6esOcRX7x#bQs$DeDZZ`i&cikH5*?s_iwXu(|8E$6sL%tuSZnU*}zmd3w70nx*G- zQD=I3z}uGAU2ZYm_H~OntQL$_uyO);jk(ODj!s=mm-S@)CNu4-ZH7zC4i+5uB=!XL zg?@f@r7V}={N%Yh)7chnG##c_n8P=9+i_aH@My410}tP-Sz1T&K+@qu#~)<~yWt*A6M@a=2>4 zIYIl~E#rh|#^!|g4d#ThtXpPzzDo&-R{;DLz}o<32#^^~3z}SR4@Q>TUX#1Rqoz1Z z1(Vi|h*hgPRLItAk=CgO-MT>D6O_UCU(q_Y-tdBb+8;GQ(<>W*=b z+iEZ`G0@v7diuy?0lz)`T-4?(|~f^ZK^MWr2&^T;A$MY zcb8fFvNqPZDMob2el(sl$whpBHlD9)^i0+-$INViqgnObcZEr=XUvNR4W8CxjrZ26BBSbnYt>w1doM0@3oQ^=ICFBg} zPS?C0rDAD5%bIlCm!o_`0bWpm?~PWL*A(Cl1yJMEmh6KbRDruy;QlytvJd*G3Vcch zHsjEKI{Ul|e6h{1!{{tU)Ss)suTQG{A73un( z8Q(Y6w>`VFJ0QXOT@6^m@71A1TYFv|sXYjXA$s)<0@rZrPSCwu7WP+v2x} z=G@)Z9BP`p%uCr62pCdI)H156R}bXz8-2>DL% zsL01Z29K(I`=+Hx00lBkrBXyK5#S^No{0gqIPiG_e2oBa$AA-YU_t?=6ku8D1x}6> z$anP%r0my<683hG&jSNQmCD-=%SB(olaY3%<1Y0IO{VZ9M)j2*e&ckoTCBNY87s6cYdgc(`m`6 zUNXX|zQct-hVxV7J1d8j!&lM{H>uOUe@Y)sFW40`)8w95uuUot`rL7tmoXN&X9c^w zg)3|64d(each}NK*V4A>=aw?YT6%6Ry@M}v*JWnFcc&}~GrJ9$rJMxUxi5ynj$|dQ z&4bdq^X^I$b4_m9ZcW;n9v6I3wu`NE+f620eQW(4&QON?Gq*PR&p1x~`w*f*sWd(BNa?`YxHK2qyg#a|1zbR%t_I#NbkM5Y%=B^BT;u zso06CQ;$V93YBgBfsj2GxM$Xx++o<Gs^7C|i~7S+(>*fby>gX)+T?zN`}bu6 z=S+K}kXg6I{3So^?(MLX@fviU`FhK@Or2UA!I7|k+d>Mr?7aNS*yrU(2h5+?a{c-2 zmRU3^X2HnjD}^l0EgmtK%zT!b#!}HJu!?Er^993NEEKG2u~J>Eu>5khx>#Jw=W|O1 zV=0@HHNM_GYbz-N>>GWqCNY{$`htp9_y2%BrIib%)8$jAPqz2Ne;v6W4*E0X8s@m1 s=~hD*9(8?chV$8Ka#!E1+h#p-FK-8XQenHb|Ls2c--S_@2D=*o00@auLjV8( literal 2209 zcmV;S2wwL=RzV2`E6f!>t&1v`;>In zK(`2KKkePS7i0p2fJ_qdfwq&*0IUJ{O3YD6}n&5^l`6?2z{q58Ae@U*v1de}W0Y{0a+tV_VCMi)qJ7uPhhs{8HA+Sb0XvS?gpzpU2hDR>aQ`6mYBEspG&^O0yEY5%u=(a ztTHpz=W9!uK6jYu3e#a8tAw=*J12x!n9l<0nbdbomCu~0Guth@cC*FYu;F;1u&1by z=A{cOMb(1y6Bnz@WSg{B_n28?9^Wus&ua)7(6CKI4`EkXjheiyeuYhGcJd8}0yaM} zae*@|rF`iw0b8S(*WpME@57-Xg%e;=LQAgCxaJ_ICP??K$=?5KefnW9p>|z>r=@CWi<6|<1W8Z zV?oo@@qRo4NR$HVJF&J+tW&SS)GxA|B&>8gosRf_cr^dcDq(;HUavmQ518XGC zza;8KJ+sDS;M!ua1SBrsGYR}V)y&0u`$tCqp@F3tDLRk+*h;&9-i!Hf1#aI(^HUgPakaL`S z9rIR{ik101tJ5u^s(f1mzNG;_8m=s_Yrq>CpvS3gtOt5P2OideN8`|m9_Z6L@ChB* zh(mkn>^U9yT8m!?(OHt{ztVx<>cHRP(5W4mZ_kJn5~ZJIV}MpT#t^Oh!d=Y#rMvKb z{w{oPj_#Z6k;5GcH%atw8o-MN@Z%xcm?Zk24B#&YfW+Wk%rr=%-~Y~{4kkuck&f@V z(S4IW+p`Bd1qu82LdX)LTZa-Y?Rj;m_C)w@2lWXx=F)|tdB*)@!*yJ_6;5ihO@4o9 z&ciLup|;H%zBFm`NXUi=&sa4gJc&Gj4+8iQfC~UVK1_rRB@S*gz$78hwq#hZ^@24M1EJ^d3?+K(lu%7U^ z6eBpNM|ai^YKN|+JZ@93m2K)+YQZhpb9Elb1=ptPD9$~P1#{K{51eoxws37Vwax}XoST1=&^+aIGc zG2iBn>sOSm9&pJQ)wtZexK(FrR5)u_Y7I}iS8AfNn!2u**SbDjXkQ~*so7M(YFx5d z9jd&((3N;sb;1SwUsvV2`m)aS`LdE-6gk$-rCqjN18ln^wx$$sk(Y*P@j(4uDVpu; zqxlKbG|jVIvSVf+Ui)aXkqfph!XIJ%G!76?omH<|7-ftUehvJ)$N&th)45HWxK6j?9J5b1f;KTXW_7 zRnc7T{jk>vYIKbWvmqSYq|SPHXzSfrklZ~x(cT&PMEi7~_a`@fF`wSF^H#~uS?O#k zm!_G;qxO=WO;g)i%3C>BvYl);XE}?xoKw!1%8MnIT`rdw^Gn%mW+`Var86qWKXgvR zT9N>JhM#;%jHbtgq_WYuvENl#xm-9~Jbm`D){gZbLwBs { await runInbound( BridgeId.VTRANSFER, buildVTransferEvent({ + sender: makeTestAddress(), + target: makeTestAddress(), sourceChannel: 'channel-5', sequence: '1', }), diff --git a/packages/boot/test/orchestration/restart-contracts.test.ts b/packages/boot/test/orchestration/restart-contracts.test.ts index b727b8a74be..bf5d22efd07 100644 --- a/packages/boot/test/orchestration/restart-contracts.test.ts +++ b/packages/boot/test/orchestration/restart-contracts.test.ts @@ -10,6 +10,7 @@ import { import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; import type { UpdateRecord } from '@agoric/smart-wallet/src/smartWallet.js'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; +import { makeTestAddress } from '@agoric/orchestration/tools/make-test-address.js'; import { makeWalletFactoryContext, type WalletFactoryTestContext, @@ -101,6 +102,8 @@ test.serial('send-anywhere', async t => { await runInbound( BridgeId.VTRANSFER, buildVTransferEvent({ + sender: makeTestAddress(), + target: makeTestAddress(), sourceChannel: 'channel-5', sequence: '1', }), diff --git a/packages/boot/tools/supports.ts b/packages/boot/tools/supports.ts index 77e1cdc61ca..8f17cb2be16 100644 --- a/packages/boot/tools/supports.ts +++ b/packages/boot/tools/supports.ts @@ -7,6 +7,7 @@ import { resolve as importMetaResolve } from 'import-meta-resolve'; import { basename, join } from 'path'; import { inspect } from 'util'; +import { makeTestAddress } from '@agoric/orchestration/tools/make-test-address.js'; import { buildSwingset } from '@agoric/cosmic-swingset/src/launch-chain.js'; import type { TypedPublished } from '@agoric/client-utils'; import { @@ -538,7 +539,7 @@ export const makeSwingsetTestKit = async ( return undefined; } case `${BridgeId.VLOCALCHAIN}:VLOCALCHAIN_ALLOCATE_ADDRESS`: { - const address = `${LOCALCHAIN_DEFAULT_ADDRESS}${lcaAccountsCreated || ''}`; + const address = makeTestAddress(lcaAccountsCreated); lcaAccountsCreated += 1; return address; } From 5ad59bdd690a4180481c7597aec9cf95e1db661f Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 17 Dec 2024 18:26:57 -0500 Subject: [PATCH 64/65] chore: `makeFakeLocalchainBridge` accepts `makeAddressFn` --- packages/vats/tools/fake-bridge.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/vats/tools/fake-bridge.js b/packages/vats/tools/fake-bridge.js index d8e1585d6a7..067d5dc724f 100644 --- a/packages/vats/tools/fake-bridge.js +++ b/packages/vats/tools/fake-bridge.js @@ -291,9 +291,14 @@ export const fakeLocalChainBridgeQueryHandler = message => { /** * @param {import('@agoric/zone').Zone} zone * @param {(obj) => void} [onToBridge] + * @param {(number) => string} makeAddressFn * @returns {ScopedBridgeManager<'vlocalchain'>} */ -export const makeFakeLocalchainBridge = (zone, onToBridge = () => {}) => { +export const makeFakeLocalchainBridge = ( + zone, + onToBridge = () => {}, + makeAddressFn = index => `${LOCALCHAIN_DEFAULT_ADDRESS}${index || ''}`, +) => { /** @type {Remote} */ let hndlr; let lcaExecuteTxSequence = 0; @@ -306,7 +311,7 @@ export const makeFakeLocalchainBridge = (zone, onToBridge = () => {}) => { trace('toBridge', type, method, params); switch (type) { case 'VLOCALCHAIN_ALLOCATE_ADDRESS': { - const address = `${LOCALCHAIN_DEFAULT_ADDRESS}${accountsCreated || ''}`; + const address = makeAddressFn(accountsCreated); accountsCreated += 1; return address; } From e06f12a37d7070c25f866a4ca59089f180e08c04 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 17 Dec 2024 18:29:49 -0500 Subject: [PATCH 65/65] chore: `advancer` validates `settlementAddress` --- .../boot/test/fast-usdc/fast-usdc.test.ts | 11 ++++- packages/fast-usdc/src/exos/advancer.js | 11 ++++- packages/fast-usdc/src/fast-usdc.contract.js | 15 +++--- packages/fast-usdc/test/cli/transfer.test.ts | 7 ++- packages/fast-usdc/test/exos/advancer.test.ts | 47 +++++++++++++++++-- .../fast-usdc/test/fast-usdc.contract.test.ts | 40 ++++++++++------ packages/fast-usdc/test/fixtures.ts | 32 +++++++------ packages/fast-usdc/test/supports.ts | 7 ++- 8 files changed, 117 insertions(+), 53 deletions(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index f581f665a7f..38b2268e2c4 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -1,6 +1,7 @@ import { test as anyTest } from '@agoric/zoe/tools/prepare-test-env-ava.js'; import type { TestFn } from 'ava'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { configurations } from '@agoric/fast-usdc/src/utils/deploy-config.js'; import { MockCctpTxEvidences } from '@agoric/fast-usdc/test/fixtures.js'; import { documentStorageSchema } from '@agoric/governance/tools/storageDoc.js'; @@ -12,7 +13,7 @@ import { defaultSerializer, } from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration } from '@agoric/internal/src/testing-utils.js'; -import { BridgeId } from '@agoric/internal'; +import { BridgeId, NonNullish } from '@agoric/internal'; import { makeWalletFactoryContext, type WalletFactoryTestContext, @@ -261,7 +262,13 @@ test.serial('makes usdc advance', async t => { 'FastLP balance not in wallet record', ); - const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + const EUD = 'dydx1anything'; + const lastNodeValue = storage.getValues('published.fastUsdc').at(-1); + const { settlementAccount } = JSON.parse(NonNullish(lastNodeValue)); + const evidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO( + // mock with the read settlementAccount address + encodeAddressHook(settlementAccount, { EUD }), + ); harness?.useRunPolicy(true); await Promise.all( diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index f63c2b7474c..a96c781f140 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -6,6 +6,7 @@ import { pickFacet } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; import { E } from '@endo/far'; import { M, mustMatch } from '@endo/patterns'; +import { Fail, q } from '@endo/errors'; import { CctpTxEvidenceShape, AddressHookShape, @@ -116,6 +117,7 @@ export const prepareAdvancerKit = ( * notifyFacet: import('./settler.js').SettlerKit['notify']; * borrowerFacet: LiquidityPoolKit['borrower']; * poolAccount: HostInterface>; + * settlementAddress: ChainAddress; * intermediateRecipient?: ChainAddress; * }} config */ @@ -145,10 +147,14 @@ export const prepareAdvancerKit = ( return; } - const { borrowerFacet, poolAccount } = this.state; + const { borrowerFacet, poolAccount, settlementAddress } = + this.state; const { recipientAddress } = evidence.aux; const decoded = decodeAddressHook(recipientAddress); mustMatch(decoded, AddressHookShape); + if (decoded.baseAddress !== settlementAddress.value) { + throw Fail`⚠️ baseAddress of address hook ${q(decoded.baseAddress)} does not match the expected address ${q(settlementAddress.value)}`; + } const { EUD } = /** @type {AddressHook['query']} */ (decoded.query); log(`decoded EUD: ${EUD}`); // throws if the bech32 prefix is not found @@ -172,10 +178,10 @@ export const prepareAdvancerKit = ( harden({ USDC: advanceAmount }), ); void watch(depositV, this.facets.depositHandler, { - fullAmount, advanceAmount, destination, forwardingAddress: evidence.tx.forwardingAddress, + fullAmount, tmpSeat, txHash: evidence.txHash, }); @@ -271,6 +277,7 @@ export const prepareAdvancerKit = ( borrowerFacet: M.remotable(), poolAccount: M.remotable(), intermediateRecipient: M.opt(ChainAddressShape), + settlementAddress: M.opt(ChainAddressShape), }), }, ); diff --git a/packages/fast-usdc/src/fast-usdc.contract.js b/packages/fast-usdc/src/fast-usdc.contract.js index b9629bb05c3..cb3ed9bd8e7 100644 --- a/packages/fast-usdc/src/fast-usdc.contract.js +++ b/packages/fast-usdc/src/fast-usdc.contract.js @@ -179,16 +179,12 @@ export const contract = async (zcf, privateArgs, zone, tools) => { }, async publishAddresses() { !baggage.has(ADDRESSES_BAGGAGE_KEY) || Fail`Addresses already published`; - const [poolAccountAddress, settlementAccountAddress] = - await vowTools.when( - vowTools.all([ - E(poolAccount).getAddress(), - E(settlementAccount).getAddress(), - ]), - ); + const [poolAccountAddress] = await vowTools.when( + vowTools.all([E(poolAccount).getAddress()]), + ); const addresses = harden({ poolAccount: poolAccountAddress.value, - settlementAccount: settlementAccountAddress.value, + settlementAccount: settlementAddress.value, }); baggage.init(ADDRESSES_BAGGAGE_KEY, addresses); await publishAddresses(storageNode, addresses); @@ -284,6 +280,8 @@ export const contract = async (zcf, privateArgs, zone, tools) => { ); trace('settlementAccount', settlementAccount); trace('poolAccount', poolAccount); + const settlementAddress = await E(settlementAccount).getAddress(); + trace('settlementAddress', settlementAddress); const [_agoric, _noble, agToNoble] = await vowTools.when( chainHub.getChainsAndConnection('agoric', 'noble'), @@ -300,6 +298,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => { borrowerFacet: poolKit.borrower, notifyFacet: settlerKit.notify, poolAccount, + settlementAddress, }), ); // Connect evidence stream to advancer diff --git a/packages/fast-usdc/test/cli/transfer.test.ts b/packages/fast-usdc/test/cli/transfer.test.ts index 1f75734d5ae..bdac4d4117a 100644 --- a/packages/fast-usdc/test/cli/transfer.test.ts +++ b/packages/fast-usdc/test/cli/transfer.test.ts @@ -8,6 +8,7 @@ import { makeFetchMock, makeMockSigner, } from '../../testing/mocks.js'; +import { settlementAddress } from '../fixtures.js'; test('Errors if config missing', async t => { const path = 'config/dir/.fast-usdc/config.json'; @@ -73,8 +74,7 @@ test('Transfer registers the noble forwarding account if it does not exist', asy }; const out = mockOut(); const file = mockFile(path, JSON.stringify(config)); - const agoricSettlementAccount = - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek'; + const agoricSettlementAccount = settlementAddress.value; const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount'; const vstorageMock = makeVstorageMock({ [settlementAccountVstoragePath]: agoricSettlementAccount, @@ -150,8 +150,7 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy }; const out = mockOut(); const file = mockFile(path, JSON.stringify(config)); - const agoricSettlementAccount = - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek'; + const agoricSettlementAccount = settlementAddress.value; const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount'; const vstorageMock = makeVstorageMock({ [settlementAccountVstoragePath]: agoricSettlementAccount, diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 4bb122220df..1fba00c8fe3 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -19,7 +19,11 @@ import type { SettlerKit } from '../../src/exos/settler.js'; import { prepareStatusManager } from '../../src/exos/status-manager.js'; import type { LiquidityPoolKit } from '../../src/types.js'; import { makeFeeTools } from '../../src/utils/fees.js'; -import { MockCctpTxEvidences, intermediateRecipient } from '../fixtures.js'; +import { + MockCctpTxEvidences, + settlementAddress, + intermediateRecipient, +} from '../fixtures.js'; import { makeTestFeeConfig, makeTestLogger, @@ -127,6 +131,7 @@ const createTestExtensions = (t, common: CommonSetup) => { notifyFacet: mockNotifyF, poolAccount: mockAccounts.mockPoolAccount.account, intermediateRecipient, + settlementAddress, }); return { @@ -141,6 +146,7 @@ const createTestExtensions = (t, common: CommonSetup) => { }, mocks: { ...mockAccounts, + mockBorrowerF, mockNotifyF, resolveLocalTransferV, rejectLocalTransfeferV, @@ -260,6 +266,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { notifyFacet: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, + settlementAddress, }); const evidence = MockCctpTxEvidences.AGORIC_PLUS_DYDX(); @@ -393,10 +400,10 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { await advancer.handleTransactionEvent({ ...MockCctpTxEvidences.AGORIC_NO_PARAMS( - encodeAddressHook( - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', - { EUD: 'osmo1234', extra: 'value' }, - ), + encodeAddressHook(settlementAddress.value, { + EUD: 'osmo1234', + extra: 'value', + }), ), txHash: '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799', @@ -550,6 +557,7 @@ test('alerts if `returnToPool` fallback fails', async t => { notifyFacet: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, + settlementAddress, }); const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -588,3 +596,32 @@ test('alerts if `returnToPool` fallback fails', async t => { 'Advancing tx is recorded as AdvanceFailed', ); }); + +test('rejects advances to unknown settlementAccount', async t => { + const { + extensions: { + services: { advancer }, + helpers: { inspectLogs }, + }, + } = t.context; + + const invalidSettlementAcct = + 'agoric1ax7hmw49tmqrdld7emc5xw3wf43a49rtkacr9d5nfpqa0y7k6n0sl8v94h'; + t.not(settlementAddress.value, invalidSettlementAcct); + const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO( + encodeAddressHook(invalidSettlementAcct, { + EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + }), + ); + + void advancer.handleTransactionEvent(mockEvidence); + await eventLoopIteration(); + t.deepEqual(inspectLogs(), [ + [ + 'Advancer error:', + Error( + '⚠️ baseAddress of address hook "agoric1ax7hmw49tmqrdld7emc5xw3wf43a49rtkacr9d5nfpqa0y7k6n0sl8v94h" does not match the expected address "agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek"', + ), + ], + ]); +}); diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index bc73389a5b9..6187f5ddc69 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -6,6 +6,7 @@ import { encodeAddressHook, } from '@agoric/cosmic-proto/address-hooks.js'; import { AmountMath } from '@agoric/ertp/src/amountMath.js'; +import type { makeFakeStorageKit } from '@agoric/internal/src/storage-test-utils.js'; import { eventLoopIteration, inspectMapStore, @@ -18,6 +19,7 @@ import { } from '@agoric/notifier'; import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; +import { makeTestAddress } from '@agoric/orchestration/tools/make-test-address.js'; import { heapVowE as VE } from '@agoric/vow/vat.js'; import { divideBy, @@ -136,12 +138,15 @@ const makeTestContext = async (t: ExecutionContext) => { }; const mint = async (e: CctpTxEvidence) => { - const settlerAddr = 'agoric1fakeLCAAddress1'; // TODO: get from contract - const rxd = await receiveUSDCAt(settlerAddr, e.tx.amount); + const accountsData = common.bootstrap.storage.data.get('fun'); + const { settlementAccount } = JSON.parse( + JSON.parse(accountsData!).values[0], + ); + const rxd = await receiveUSDCAt(settlementAccount, e.tx.amount); await VE(transferBridge).fromBridge( buildVTransferEvent({ receiver: e.aux.recipientAddress, - target: settlerAddr, + target: settlementAccount, sourceChannel: agToNoble.transferChannel.counterPartyChannelId, denom: 'uusdc', amount: e.tx.amount, @@ -155,7 +160,8 @@ const makeTestContext = async (t: ExecutionContext) => { return { bridges: { snapshot, since }, common, evm, mint, startKit, sync }; }; -const test = anyTest as TestFn>>; +type FucContext = Awaited>; +const test = anyTest as TestFn; test.before(async t => (t.context = await makeTestContext(t))); test('baggage', async t => { @@ -190,8 +196,8 @@ test('getStaticInfo', async t => { t.deepEqual(await E(publicFacet).getStaticInfo(), { addresses: { - poolAccount: 'agoric1fakeLCAAddress', - settlementAccount: 'agoric1fakeLCAAddress1', + poolAccount: makeTestAddress(), + settlementAccount: makeTestAddress(1), }, }); }); @@ -346,7 +352,6 @@ const makeLP = async ( }; const makeEVM = (template = MockCctpTxEvidences.AGORIC_PLUS_OSMO()) => { - const [settleAddr] = template.aux.recipientAddress.split('?'); let nonce = 0; const makeTx = (amount: bigint, recipientAddress: string): CctpTxEvidence => { @@ -378,10 +383,6 @@ const makeCustomer = ( const feeTools = makeFeeTools(feeConfig); const sent = [] as CctpTxEvidence[]; - // TODO: get settlerAddr from vstorage - const [settleAddr] = - MockCctpTxEvidences.AGORIC_PLUS_OSMO().aux.recipientAddress.split('?'); - const me = harden({ checkPoolAvailable: async ( t: ExecutionContext, @@ -394,8 +395,17 @@ const makeCustomer = ( t.log(who, 'sees', poolBalance.value, enough ? '>' : 'NOT >', want); return enough; }, - sendFast: async (t: ExecutionContext, amount: bigint, EUD: string) => { - const recipientAddress = encodeAddressHook(settleAddr, { EUD }); + sendFast: async ( + t: ExecutionContext, + amount: bigint, + EUD: string, + ) => { + const { storage } = t.context.common.bootstrap; + const accountsData = storage.data.get('fun'); + const { settlementAccount } = JSON.parse( + JSON.parse(accountsData!).values[0], + ); + const recipientAddress = encodeAddressHook(settlementAccount, { EUD }); // KLUDGE: UI would ask noble for a forwardingAddress // "cctp" here has some noble stuff mixed in. const tx = cctp.makeTx(amount, recipientAddress); @@ -559,7 +569,7 @@ test.serial('STORY01: advancing happy path for 100 USDC', async t => { t.deepEqual(inspectBankBridge().at(-1), { amount: String(expectedAdvance.value), denom: uusdcOnAgoric, - recipient: 'agoric1fakeLCAAddress', + recipient: makeTestAddress(), type: 'VBANK_GIVE', }); @@ -791,7 +801,7 @@ test.serial('Settlement for unknown transaction (operator down)', async t => { }, { amount: '20000000', - recipient: 'agoric1fakeLCAAddress1', + recipient: 'agoric1qyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqc09z0g', type: 'VBANK_GIVE', }, ], diff --git a/packages/fast-usdc/test/fixtures.ts b/packages/fast-usdc/test/fixtures.ts index 35ec0c231e2..8496051125d 100644 --- a/packages/fast-usdc/test/fixtures.ts +++ b/packages/fast-usdc/test/fixtures.ts @@ -37,10 +37,9 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - encodeAddressHook( - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', - { EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' }, - ), + encodeAddressHook(settlementAddress.value, { + EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + }), }, chainId: 1, }), @@ -59,10 +58,9 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - encodeAddressHook( - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', - { EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' }, - ), + encodeAddressHook(settlementAddress.value, { + EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + }), }, chainId: 1, }), @@ -79,9 +77,7 @@ export const MockCctpTxEvidences: Record< }, aux: { forwardingChannel: 'channel-21', - recipientAddress: - receiverAddress || - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + recipientAddress: receiverAddress || settlementAddress.value, }, chainId: 1, }), @@ -100,10 +96,9 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - encodeAddressHook( - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', - { EUD: 'random1addr' }, - ), + encodeAddressHook(settlementAddress.value, { + EUD: 'random1addr', + }), }, chainId: 1, }), @@ -166,3 +161,10 @@ export const intermediateRecipient: ChainAddress = harden({ value: 'noble1test', encoding: 'bech32', }); + +export const settlementAddress: ChainAddress = harden({ + chainId: 'agoric-3', + encoding: 'bech32' as const, + // Random value, copied from tests of address hooks + value: 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', +}); diff --git a/packages/fast-usdc/test/supports.ts b/packages/fast-usdc/test/supports.ts index 984352b3c07..6a4608a0cf5 100644 --- a/packages/fast-usdc/test/supports.ts +++ b/packages/fast-usdc/test/supports.ts @@ -20,6 +20,7 @@ import { prepareCosmosInterchainService } from '@agoric/orchestration/src/exos/c import fetchedChainInfo from '@agoric/orchestration/src/fetched-chain-info.js'; import { setupFakeNetwork } from '@agoric/orchestration/test/network-fakes.js'; import { buildVTransferEvent } from '@agoric/orchestration/tools/ibc-mocks.js'; +import { makeTestAddress } from '@agoric/orchestration/tools/make-test-address.js'; import { reincarnate } from '@agoric/swingset-liveslots/tools/setup-vat-data.js'; import { makeNameHubKit } from '@agoric/vats'; import { prepareBridgeTargetModule } from '@agoric/vats/src/bridge-target.js'; @@ -139,8 +140,10 @@ export const commonSetup = async (t: ExecutionContext) => { await E(transferBridge).initHandler(bridgeTargetKit.bridgeHandler); const localBridgeMessages = [] as any[]; - const localchainBridge = makeFakeLocalchainBridge(rootZone, obj => - localBridgeMessages.push(obj), + const localchainBridge = makeFakeLocalchainBridge( + rootZone, + obj => localBridgeMessages.push(obj), + makeTestAddress, ); const localchain = prepareLocalChainTools( rootZone.subZone('localchain'),