From a3872d0f2f49b7bc6dd297e612355a581e94febe Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 Dec 2024 17:29:53 -0800 Subject: [PATCH 01/42] chore(types): stdout optional --- packages/agoric-cli/src/lib/wallet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agoric-cli/src/lib/wallet.js b/packages/agoric-cli/src/lib/wallet.js index e9eff2f2ca1..c4e66cf2437 100644 --- a/packages/agoric-cli/src/lib/wallet.js +++ b/packages/agoric-cli/src/lib/wallet.js @@ -149,7 +149,7 @@ export const coalesceWalletState = async (follower, invitationBrand) => { * fees?: string, * verbose?: boolean, * keyring?: {home?: string, backend: string}, - * stdout: Pick, + * stdout?: Pick, * execFileSync: typeof import('child_process').execFileSync, * delay: (ms: number) => Promise, * dryRun?: boolean, From e11547451b19c5c3a4550980ee789ba6f3e0a1d5 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 11 Dec 2024 09:41:28 -0800 Subject: [PATCH 02/42] chore(types): add typescript --- .../proposals/s:stake-bld/package.json | 3 ++- .../proposals/s:stake-bld/yarn.lock | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/a3p-integration/proposals/s:stake-bld/package.json b/a3p-integration/proposals/s:stake-bld/package.json index 2c0a5093c38..2432417370d 100644 --- a/a3p-integration/proposals/s:stake-bld/package.json +++ b/a3p-integration/proposals/s:stake-bld/package.json @@ -26,7 +26,8 @@ }, "packageManager": "yarn@4.5.3", "devDependencies": { - "@types/node": "^22.0.0" + "@types/node": "^22.0.0", + "typescript": "^5.7.2" }, "resolutions": { "@agoric/cosmos": "portal:../../agoric-sdk/golang/cosmos", diff --git a/a3p-integration/proposals/s:stake-bld/yarn.lock b/a3p-integration/proposals/s:stake-bld/yarn.lock index a406cffd13a..cad8d9ce435 100644 --- a/a3p-integration/proposals/s:stake-bld/yarn.lock +++ b/a3p-integration/proposals/s:stake-bld/yarn.lock @@ -4617,6 +4617,7 @@ __metadata: agoric: "npm:dev" ava: "npm:^5.3.1" execa: "npm:^8.0.1" + typescript: "npm:^5.7.2" languageName: unknown linkType: soft @@ -5189,6 +5190,16 @@ __metadata: languageName: node linkType: hard +"typescript@npm:^5.7.2": + version: 5.7.2 + resolution: "typescript@npm:5.7.2" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/a873118b5201b2ef332127ef5c63fb9d9c155e6fdbe211cbd9d8e65877283797cca76546bad742eea36ed7efbe3424a30376818f79c7318512064e8625d61622 + languageName: node + linkType: hard + "typescript@patch:typescript@npm%3A5.1.6 - 5.6.x#optional!builtin": version: 5.6.3 resolution: "typescript@patch:typescript@npm%3A5.6.3#optional!builtin::version=5.6.3&hash=8c6c40" @@ -5199,6 +5210,16 @@ __metadata: languageName: node linkType: hard +"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: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/f3b8082c9d1d1629a215245c9087df56cb784f9fb6f27b5d55577a20e68afe2a889c040aacff6d27e35be165ecf9dca66e694c42eb9a50b3b2c451b36b5675cb + languageName: node + linkType: hard + "undici-types@npm:~5.26.4": version: 5.26.5 resolution: "undici-types@npm:5.26.5" From 10302ad01dfbb7b65f9791549028ce82f9eb0e6d Mon Sep 17 00:00:00 2001 From: "Turadg Aleahmad (aider)" Date: Tue, 10 Dec 2024 16:39:42 -0800 Subject: [PATCH 03/42] test: vstorageKit.agoricNames --- .../test/snapshots/vstorage-kit.test.js.md | 352 ++++++++++++++++++ .../test/snapshots/vstorage-kit.test.js.snap | Bin 0 -> 3914 bytes .../client-utils/test/vstorage-kit.test.js | 84 +++++ 3 files changed, 436 insertions(+) create mode 100644 packages/client-utils/test/snapshots/vstorage-kit.test.js.md create mode 100644 packages/client-utils/test/snapshots/vstorage-kit.test.js.snap create mode 100644 packages/client-utils/test/vstorage-kit.test.js diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.md b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md new file mode 100644 index 00000000000..1a06e804b30 --- /dev/null +++ b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md @@ -0,0 +1,352 @@ +# Snapshot report for `test/vstorage-kit.test.js` + +The actual snapshot is saved in `vstorage-kit.test.js.snap`. + +Generated by [AVA](https://avajs.dev). + +## agoricNames contains expected structure + +> agoricnNames from A3P + + { + brand: { + ATOM: Object @Alleged: BoardRemoteATOM brand { + getBoardId: Function getBoardId {}, + }, + BLD: Object @Alleged: BoardRemoteBLD brand { + getBoardId: Function getBoardId {}, + }, + DAI_axl: Object @Alleged: BoardRemoteDAI_axl brand { + getBoardId: Function getBoardId {}, + }, + DAI_grv: Object @Alleged: BoardRemoteDAI_grv brand { + getBoardId: Function getBoardId {}, + }, + IST: Object @Alleged: BoardRemoteIST brand { + getBoardId: Function getBoardId {}, + }, + Invitation: Object @Alleged: BoardRemoteZoe Invitation brand { + getBoardId: Function getBoardId {}, + }, + KREAdCHARACTER: Object @Alleged: BoardRemoteKREAdCHARACTER brand { + getBoardId: Function getBoardId {}, + }, + KREAdITEM: Object @Alleged: BoardRemoteKREAdITEM brand { + getBoardId: Function getBoardId {}, + }, + USDC_axl: Object @Alleged: BoardRemoteUSDC_axl brand { + getBoardId: Function getBoardId {}, + }, + USDC_grv: Object @Alleged: BoardRemoteUSDC_grv brand { + getBoardId: Function getBoardId {}, + }, + USDT_axl: Object @Alleged: BoardRemoteUSDT_axl brand { + getBoardId: Function getBoardId {}, + }, + USDT_grv: Object @Alleged: BoardRemoteUSDT_grv brand { + getBoardId: Function getBoardId {}, + }, + stATOM: Object @Alleged: BoardRemotestATOM brand { + getBoardId: Function getBoardId {}, + }, + timer: Object @Alleged: BoardRemotetimerBrand { + getBoardId: Function getBoardId {}, + }, + }, + instance: { + 'ATOM-USD price feed': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + Crabble: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + CrabbleCommittee: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + CrabbleGovernor: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + VaultFactory: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + VaultFactoryGovernor: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + auctioneer: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + econCommitteeCharter: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + economicCommittee: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + feeDistributor: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + kread: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + kreadCommittee: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + kreadCommitteeCharter: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + provisionPool: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-DAI_axl': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-DAI_grv': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-USDC_axl': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-USDC_grv': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-USDT_axl': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'psm-IST-USDT_grv': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + reserve: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + reserveGovernor: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'scaledPriceAuthority-stATOM': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + 'stATOM-USD price feed': Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + walletFactory: Object @Alleged: BoardRemoteInstanceHandle { + getBoardId: Function getBoardId {}, + }, + }, + reverse: { + board00282: 'KREAdITEM', + board00360: 'VaultFactory', + board0074: 'Invitation', + board00990: 'stATOM', + board01272: 'psm-IST-USDT_grv', + board01664: 'provisionPool', + board01744: 'USDT_axl', + board01867: 'psm-IST-DAI_axl', + board01985: 'kreadCommittee', + board02271: 'psm-IST-USDT_axl', + board02393: 'CrabbleCommittee', + board02568: 'psm-IST-DAI_grv', + board0257: 'IST', + board02963: 'ATOM-USD price feed', + board03040: 'USDC_axl', + board03138: 'DAI_grv', + board03281: 'KREAdCHARACTER', + board03365: 'reserveGovernor', + board03446: 'USDT_grv', + board03773: 'VaultFactoryGovernor', + board04091: 'stATOM-USD price feed', + board04149: 'economicCommittee', + board0425: 'timer', + board04395: 'Crabble', + board04542: 'USDC_grv', + board04661: 'econCommitteeCharter', + board04783: 'kread', + board05262: 'feeDistributor', + board05396: 'CrabbleGovernor', + board05557: 'ATOM', + board0566: 'BLD', + board05669: 'psm-IST-USDC_axl', + board05736: 'DAI_axl', + board05892: 'scaledPriceAuthority-stATOM', + board05970: 'psm-IST-USDC_grv', + board06284: 'kreadCommitteeCharter', + board06299: 'auctioneer', + board06366: 'walletFactory', + board06458: 'reserve', + }, + vbankAsset: { + 'ibc/295548A78785A1007F232DE286149A6FF512F180AF5657780FC89C009E2C348F': { + brand: Object @Alleged: BoardRemoteUSDC_axl brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/295548A78785A1007F232DE286149A6FF512F180AF5657780FC89C009E2C348F', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteUSDC_axl issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'USDC_axl', + proposedName: 'USD Coin', + }, + 'ibc/386D09AE31DA7C0C93091BB45D08CB7A0730B1F697CD813F06A5446DCF02EEB2': { + brand: Object @Alleged: BoardRemoteUSDT_grv brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/386D09AE31DA7C0C93091BB45D08CB7A0730B1F697CD813F06A5446DCF02EEB2', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteUSDT_grv issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'USDT_grv', + proposedName: 'Tether USD', + }, + 'ibc/3914BDEF46F429A26917E4D8D434620EC4817DC6B6E68FB327E190902F1E9242': { + brand: Object @Alleged: BoardRemoteDAI_axl brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/3914BDEF46F429A26917E4D8D434620EC4817DC6B6E68FB327E190902F1E9242', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 18, + }, + issuer: Object @Alleged: BoardRemoteDAI_axl issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'DAI_axl', + proposedName: 'DAI', + }, + 'ibc/3D5291C23D776C3AA7A7ABB34C7B023193ECD2BC42EA19D3165B2CF9652117E7': { + brand: Object @Alleged: BoardRemoteDAI_grv brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/3D5291C23D776C3AA7A7ABB34C7B023193ECD2BC42EA19D3165B2CF9652117E7', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 18, + }, + issuer: Object @Alleged: BoardRemoteDAI_grv issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'DAI_grv', + proposedName: 'DAI', + }, + 'ibc/42225F147137DDEB5FEF0F1D0A92F2AD57557AFA2C4D6F30B21E0D983001C002': { + brand: Object @Alleged: BoardRemotestATOM brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/42225F147137DDEB5FEF0F1D0A92F2AD57557AFA2C4D6F30B21E0D983001C002', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemotestATOM issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'stATOM', + proposedName: 'stATOM', + }, + 'ibc/6831292903487E58BF9A195FDDC8A2E626B3DF39B88F4E7F41C935CADBAF54AC': { + brand: Object @Alleged: BoardRemoteUSDC_grv brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/6831292903487E58BF9A195FDDC8A2E626B3DF39B88F4E7F41C935CADBAF54AC', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteUSDC_grv issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'USDC_grv', + proposedName: 'USC Coin', + }, + 'ibc/BA313C4A19DFBF943586C0387E6B11286F9E416B4DD27574E6909CABE0E342FA': { + brand: Object @Alleged: BoardRemoteATOM brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/BA313C4A19DFBF943586C0387E6B11286F9E416B4DD27574E6909CABE0E342FA', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteATOM issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'ATOM', + proposedName: 'ATOM', + }, + 'ibc/F2331645B9683116188EF36FC04A809C28BD36B54555E8705A37146D0182F045': { + brand: Object @Alleged: BoardRemoteUSDT_axl brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ibc/F2331645B9683116188EF36FC04A809C28BD36B54555E8705A37146D0182F045', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteUSDT_axl issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'USDT_axl', + proposedName: 'Tether USD', + }, + ubld: { + brand: Object @Alleged: BoardRemoteBLD brand { + getBoardId: Function getBoardId {}, + }, + denom: 'ubld', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteBLD issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'BLD', + proposedName: 'Agoric staking token', + }, + uist: { + brand: Object @Alleged: BoardRemoteIST brand { + getBoardId: Function getBoardId {}, + }, + denom: 'uist', + displayInfo: { + assetKind: 'nat', + decimalPlaces: 6, + }, + issuer: Object @Alleged: BoardRemoteIST issuer { + getBoardId: Function getBoardId {}, + }, + issuerName: 'IST', + proposedName: 'Agoric stable token', + }, + }, + } + +> priceFeed from A3P + + { + amountIn: { + brand: Object @Alleged: BoardRemoteBrand { + getBoardId: Function getBoardId {}, + }, + value: 1000000n, + }, + amountOut: { + brand: Object @Alleged: BoardRemoteBrand { + getBoardId: Function getBoardId {}, + }, + value: 12010000n, + }, + timer: Object @Alleged: BoardRemotetimerService { + getBoardId: Function getBoardId {}, + }, + timestamp: { + absValue: 1729176290n, + timerBrand: Object @Alleged: BoardRemotetimerBrand { + getBoardId: Function getBoardId {}, + }, + }, + } diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap b/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..029f118c99889b62b8f1dace482bd1b92837ad60 GIT binary patch literal 3914 zcmV-Q54G??RzV4q0s$HTX~}Y8yUnC-#)&%~H%Du?iKa=MtEt_NW4Bd38Ml+Vo-|dQ#+}ruCsmvA zv}x?7wbPk2O^XEyE*=(GJyw2&^~^L8OsNZV&d z5+}2{)Y5wr%XU7xl+6?psZ2gr3;?eMfVTrca}XE~0#*=61c7rw;5UN6SA)Py|9k8QL82Rh%5FrM zz5f{m{yPW^GypRVz?}`i0}a5F4Zw>H!0Qb_C4tG`126(!w?W| z1jZVH!;QdlBk*V=@Khu4QX}wABhVctn$b%(V{|4A#KJ%(3_KYIUJ3(02?IkBU?BoL z7y+J%0GA@bt|nl%2{_jTe7XtvZWF*X0~5`_?ajc)nt|t=fw!80(H7wL7T{M}fUmRw zf7=3dv;s;iaHC3y zJgz5=L;7*un2#TK;=|iF<4sO{c0OKe^4+dbWMR%U%FX*qRb-=mZxNCCvPalKMm9Wa zu1I6PP%hcmT*pI&)Uus(s=UVuzT*mRFIx65%$d=ZTx!XVp0MrGwXE%QmC?v078lc{ zEB1a@pmRN7WS5syg@RpDyx>xFtSfHJuGzUvHs=TeyEX-_Hziin1uL;s$mY&E(YPzR z!yT<)JnT|6Csvn=XU(=tv6tNhdnubKx6e40$Q9OA?YlQsT}4%PIki;TllQtL?I zOyvu?)Z%Jky%CSQ;-S+yJ5j3Lt8SZfxDvbfU7PWpm2r0i?{LZ5R&v?3R6do>9Lr`) zqvF%9aK}o1dH?L({C@Y9aH*DHWAqH~ah=KyLB(iI)l_USzFb4GIeOo$sn}rfdn;y# zyq#Ms6>8NL=vWU_jDqJ}f_?d=MA}XsD~@A*wQwq%OBK%UcU=@ebBTABj(d&#>-V|J zes3b3wl{}o8<-I=9oWtU%7bq)o5&?umREVNn}MfRkl7mJze3)$E>}d)Ta+hS)5_@b z4Z%yu@d{t(taw^vS*$f4J@txM*1K+Ko>Em-YL8`4ho(w3uQ4wJ&nsM=f$C`yG@;I| z&eI~vYVB*z>+JGUx#y)>$rG!|<(7Egvb|gaE3)nrVASrazzOAchrQdoq2$$a9jj(V zPlF(r&s6nA?CB6i*<-%*lqyQOFf}F%FPq3})BwjAJq-uWjGzePx%vL`dcsiub z>!ZQrcD7z*NiK6skBFWuSuUSFkNM8iq6lShxb6)}Qnhj|>Q6 zz1Dh)@b+otDpWiZV}{7bbxtz{PL^W4VQI3&bDR=a9O^Pj6?vYQ zEKXE7K{3sEOtRt@YjGy4YrMtlrld%cqFXv|h^A}_Y>emPtf{F2%W?+GmfHFhNtIQB z<27Dm1yNPvk{Yu#ozo=CG!0ef<1#PD1k)0 z7dXKXi@mdAmL>|4DjTezDsef+al9&9T3qDhm}r{3A}L~A)>zHZV{tYvh`gmc)ShmF zYVm@=$)Xg~imm2kPF3TUAX^42>ME-lyc#nFIVOpcB*j&Qm2^SjMA>9HmA6CzM8;}u6!d1tvI@U3p(Z@P(Jy1_1{M^C5ilXh|{8Y^BR$L-~8!7knjqRz_6 z`j6?rzjXsYCGDXurrXONJ7QM4xAy>hdI)#8i|O-nuiwWi2~rO*O%j^w5KiXSDhW6D z0C$jtmKr^notv+8pX~u2Al+?U%&3?9)~p@fd=#z({ZS6RGpcDUSNzw?5>TNuWm)W z7dT8J_S8dEwc=ziuuLNMbum#dL}{|D1pHbr@F)rBu5pDqk6JOe{Y$;T)1*CGqYJa^ z%a?}|nPl4DKzy?oc!fmtQz72$1>PnRgH(vFD6l(9AcmL`+d3ezgzyD2bS%LVTeQ_$rCGo(l1DA8?UG9Hc`0Yaj6MBqBzI z=;#M__7ez`3c>XQ3W>0&5Oe*&EhOR)6=Jm?I7cFWi3;(Fe&9(GafAx-d_V94iFgkc z;_v!_ACQP+G>Gue`+?v9uy+8se*pN@0Pyqx@Y(=@ohM(qgqsF|jzM5}5O{bH`0OBX zVGwv@kg&e5%DQ_9=pF*ZA>iXfz#j|&FAo844-wYetE}C_z`!stH4Hp43_L#!TpR{| zHcVLGUu7K_0mepvgCoHC5#WUp;MEZTql7hCWt|uWxKZHHDDcHm;2WdB>!U#P7-2nC zWmU$217pDa81U>E@X8qQFJr*Aal)FevQCc!`Z(~uao~@}fmg?YH^+g!6NGi8$~rp% z9Gw78OaKp00H2)zE=&NINNb_Wdd(!zKM81)z-^PjnMvT+CxK@t3G11vmuHOgtK`R% zt~Vkl?SeB1XOk{PbibeCxUb?vzKUmk6>s<|_Fn6!IO41Lps(WheHH)UtJra!pThE0 zobgqB(O2=BucDpxQylbF#O*#uOhq;)WlFi#mQXDn1sf?=@ zj6`3HE3(8Img>}km$q07uh&JMwP>EV3#aT{bYaePRby={)wmK%!}r&##^<+EjT&z( zJc|)D^;uUH{&_1^xDrd*Z`G^9K6$HExXd9zRN+pUz6w`l={+gesluaMse<=z0M8(wEkZ24|^nZqHnFlUf=OG}}z#T9wQaYU(8i+i_H3$GWdo^@y- z#>3aPP=hP-Lgqrf8oaU9@!+)wgkr{+RH>@5`67u|>-6Rhbql@mc=_$wksZ3Tg*cio zBu=L?C!>YzY1=)>pP=oM^A@a~Vb0g<(l@u%rRrTVo?Y6$*`>v_z0spRMPJ23pz~uo zVy$MJH{VQy>mSY!YF|eqwIf39Xr^|wQajqI9i7yUZPbn()Q(-$j(1Tz_EI~pp?368 zJNl>{1JsToYR3q*V~pA{LG9R2?YNHG!BIN|YKKJaP^cXmwPTvvae&%!1GPh^b{N!- zIJM(OYR4?K<1n@3-PDew)Qu$kRt?yu0g6Vfb}x_%<$>EZV3CyFRAXC4 zc}qpEp30OOd58QzNG>0Xu!THf_6t$ z(t}fgMau51@uF#CQ%_~iCMW0O6mV(^_$UcWRONhT3V4o`E!N3d-Oqha&hJbC-VLyl-*r#5LNdx=p=n^ z8u-&`;1Wq&u1Xr20orE>S*DBWt+_+2GU09~;rI-|&HxJ}>7J^D_sswglCoUAQCmHN zLQc{rW`OfEz&A+RYE{x7%>X|kWotEd=@d7zRpx7P^0glTb{qh-0|e-7RlYk907+7I zUyXdlZD+20ZD0cAhT=r=1H{9rOtSm~B$Fr*qPC>Hlv+-tkEIh!cHTMKQ2gaoUVwh^ zKwU zrhcxvjoNV+wPT6eagy3`n%a@2cI2rY_fk8~RXXf+V$n{omcH80ls?-(k;^Veb>Z0h zhxrZHdwrOHD}Yr1k6iAD`JZ=vm>)?jXIC?Y+0w_%-*!csN|B?hr6s$cyT9gN|3azw z9i;1<{ifpKd?B&C;>^w|2FNnNhZ(;w?So%pfTtPYFGy*qY9jwJ1N;Xmi`3X3?6h;v z&aI`EHg;77I|IP30H6m5NOM)W0;MI^fZrQ YEhguDzi8QZvV4E}AEVDPWIaRx0Ln~;C;$Ke literal 0 HcmV?d00001 diff --git a/packages/client-utils/test/vstorage-kit.test.js b/packages/client-utils/test/vstorage-kit.test.js new file mode 100644 index 00000000000..bf2ffb07ea5 --- /dev/null +++ b/packages/client-utils/test/vstorage-kit.test.js @@ -0,0 +1,84 @@ +/* eslint-env node */ +import test from 'ava'; +import { makeVstorageKit } from '../src/vstorage-kit.js'; + +const makeMockFetch = (responses = {}) => { + return async url => { + const response = responses[url] || { + result: { + response: { + code: 0, + value: Buffer.from( + JSON.stringify({ value: '{"blockHeight":1,"values":[]}' }), + ).toString('base64'), + }, + }, + }; + return { json: () => Promise.resolve(response) }; + }; +}; + +const makeTestConfig = () => ({ + chainName: 'test-chain', + rpcAddrs: ['http://localhost:26657'], +}); + +test('agoricNames contains expected structure', async t => { + /** @type {typeof window.fetch} */ + // @ts-expect-error mock + const fetch = makeMockFetch({ + 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.brand%22&height=0': + { + result: { + response: { + code: 0, + value: + // observed in a3p + 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNzY5XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIjW1tcXFxcXFxcIkFUT01cXFxcXFxcIixcXFxcXFxcIiQwLkFsbGVnZWQ6IEFUT00gYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiQkxEXFxcXFxcXCIsXFxcXFxcXCIkMS5BbGxlZ2VkOiBCTEQgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiREFJX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogREFJX2F4bCBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJEQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBEQUlfZ3J2IGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIklTVFxcXFxcXFwiLFxcXFxcXFwiJDQuQWxsZWdlZDogSVNUIGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIkludml0YXRpb25cXFxcXFxcIixcXFxcXFxcIiQ1LkFsbGVnZWQ6IFpvZSBJbnZpdGF0aW9uIGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIktSRUFkQ0hBUkFDVEVSXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBLUkVBZENIQVJBQ1RFUiBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJLUkVBZElURU1cXFxcXFxcIixcXFxcXFxcIiQ3LkFsbGVnZWQ6IEtSRUFkSVRFTSBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJVU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDguQWxsZWdlZDogVVNEQ19heGwgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcIiQ5LkFsbGVnZWQ6IFVTRENfZ3J2IGJyYW5kXFxcXFxcXCJdLFtcXFxcXFxcIlVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTAuQWxsZWdlZDogVVNEVF9heGwgYnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwiVVNEVF9ncnZcXFxcXFxcIixcXFxcXFxcIiQxMS5BbGxlZ2VkOiBVU0RUX2dydiBicmFuZFxcXFxcXFwiXSxbXFxcXFxcXCJ0aW1lclxcXFxcXFwiLFxcXFxcXFwiJDEyLkFsbGVnZWQ6IHRpbWVyQnJhbmRcXFxcXFxcIl0sW1xcXFxcXFwic3RBVE9NXFxcXFxcXCIsXFxcXFxcXCIkMTMuQWxsZWdlZDogc3RBVE9NIGJyYW5kXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDU1NTdcXFwiLFxcXCJib2FyZDA1NjZcXFwiLFxcXCJib2FyZDA1NzM2XFxcIixcXFwiYm9hcmQwMzEzOFxcXCIsXFxcImJvYXJkMDI1N1xcXCIsXFxcImJvYXJkMDA3NFxcXCIsXFxcImJvYXJkMDMyODFcXFwiLFxcXCJib2FyZDAwMjgyXFxcIixcXFwiYm9hcmQwMzA0MFxcXCIsXFxcImJvYXJkMDQ1NDJcXFwiLFxcXCJib2FyZDAxNzQ0XFxcIixcXFwiYm9hcmQwMzQ0NlxcXCIsXFxcImJvYXJkMDQyNVxcXCIsXFxcImJvYXJkMDA5OTBcXFwiXX1cIl19Igp9', + }, + }, + }, + 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.instance%22&height=0': + { + result: { + response: { + code: 0, + value: + // observed in a3p + 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiMTE0MVwiLFwidmFsdWVzXCI6W1wie1xcXCJib2R5XFxcIjpcXFwiI1tbXFxcXFxcXCJBVE9NLVVTRCBwcmljZSBmZWVkXFxcXFxcXCIsXFxcXFxcXCIkMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlXFxcXFxcXCIsXFxcXFxcXCIkMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlQ29tbWl0dGVlXFxcXFxcXCIsXFxcXFxcXCIkMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJDcmFiYmxlR292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQzLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeVxcXFxcXFwiLFxcXFxcXFwiJDQuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiVmF1bHRGYWN0b3J5R292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQ1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImVjb25Db21taXR0ZWVDaGFydGVyXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29ub21pY0NvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZmVlRGlzdHJpYnV0b3JcXFxcXFxcIixcXFxcXFxcIiQ4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkXFxcXFxcXCIsXFxcXFxcXCIkOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZENvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDEwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDExLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInByb3Zpc2lvblBvb2xcXFxcXFxcIixcXFxcXFxcIiQxMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULURBSV9heGxcXFxcXFxcIixcXFxcXFxcIiQxMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULURBSV9ncnZcXFxcXFxcIixcXFxcXFxcIiQxNC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRENfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTUuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RDX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE2LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEVF9heGxcXFxcXFxcIixcXFxcXFxcIiQxNy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRFRfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTguQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicmVzZXJ2ZVxcXFxcXFwiLFxcXFxcXFwiJDE5LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInJlc2VydmVHb3Zlcm5vclxcXFxcXFwiLFxcXFxcXFwiJDIwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInNjYWxlZFByaWNlQXV0aG9yaXR5LXN0QVRPTVxcXFxcXFwiLFxcXFxcXFwiJDIxLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInN0QVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDIyLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIndhbGxldEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQyMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXV1cXFwiLFxcXCJzbG90c1xcXCI6W1xcXCJib2FyZDAyOTYzXFxcIixcXFwiYm9hcmQwNDM5NVxcXCIsXFxcImJvYXJkMDIzOTNcXFwiLFxcXCJib2FyZDA1Mzk2XFxcIixcXFwiYm9hcmQwMDM2MFxcXCIsXFxcImJvYXJkMDM3NzNcXFwiLFxcXCJib2FyZDA0NjYxXFxcIixcXFwiYm9hcmQwNDE0OVxcXCIsXFxcImJvYXJkMDUyNjJcXFwiLFxcXCJib2FyZDA0NzgzXFxcIixcXFwiYm9hcmQwMTk4NVxcXCIsXFxcImJvYXJkMDYyODRcXFwiLFxcXCJib2FyZDAxNjY0XFxcIixcXFwiYm9hcmQwMTg2N1xcXCIsXFxcImJvYXJkMDI1NjhcXFwiLFxcXCJib2FyZDA1NjY5XFxcIixcXFwiYm9hcmQwNTk3MFxcXCIsXFxcImJvYXJkMDIyNzFcXFwiLFxcXCJib2FyZDAxMjcyXFxcIixcXFwiYm9hcmQwNjQ1OFxcXCIsXFxcImJvYXJkMDMzNjVcXFwiLFxcXCJib2FyZDA1ODkyXFxcIixcXFwiYm9hcmQwNDA5MVxcXCIsXFxcImJvYXJkMDYzNjZcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiNbW1xcXFxcXFwiQVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZVxcXFxcXFwiLFxcXFxcXFwiJDEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUNvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJWYXVsdEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQ0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkNS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29uQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDYuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZWNvbm9taWNDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQ3LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImZlZURpc3RyaWJ1dG9yXFxcXFxcXCIsXFxcXFxcXCIkOC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZFxcXFxcXFwiLFxcXFxcXFwiJDkuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwia3JlYWRDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQxMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZENvbW1pdHRlZUNoYXJ0ZXJcXFxcXFxcIixcXFxcXFxcIiQxMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwcm92aXNpb25Qb29sXFxcXFxcXCIsXFxcXFxcXCIkMTIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1EQUlfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1EQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTQuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcIiQxNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCIkMTcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RUX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInJlc2VydmVcXFxcXFxcIixcXFxcXFxcIiQxOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJyZXNlcnZlR292ZXJub3JcXFxcXFxcIixcXFxcXFxcIiQyMC5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJzY2FsZWRQcmljZUF1dGhvcml0eS1zdEFUT01cXFxcXFxcIixcXFxcXFxcIiQyMS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJzdEFUT00tVVNEIHByaWNlIGZlZWRcXFxcXFxcIixcXFxcXFxcIiQyMi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJ3YWxsZXRGYWN0b3J5XFxcXFxcXCIsXFxcXFxcXCIkMjMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiYXVjdGlvbmVlclxcXFxcXFwiLFxcXFxcXFwiJDI0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDI5NjNcXFwiLFxcXCJib2FyZDA0Mzk1XFxcIixcXFwiYm9hcmQwMjM5M1xcXCIsXFxcImJvYXJkMDUzOTZcXFwiLFxcXCJib2FyZDAwMzYwXFxcIixcXFwiYm9hcmQwMzc3M1xcXCIsXFxcImJvYXJkMDQ2NjFcXFwiLFxcXCJib2FyZDA0MTQ5XFxcIixcXFwiYm9hcmQwNTI2MlxcXCIsXFxcImJvYXJkMDQ3ODNcXFwiLFxcXCJib2FyZDAxOTg1XFxcIixcXFwiYm9hcmQwNjI4NFxcXCIsXFxcImJvYXJkMDE2NjRcXFwiLFxcXCJib2FyZDAxODY3XFxcIixcXFwiYm9hcmQwMjU2OFxcXCIsXFxcImJvYXJkMDU2NjlcXFwiLFxcXCJib2FyZDA1OTcwXFxcIixcXFwiYm9hcmQwMjI3MVxcXCIsXFxcImJvYXJkMDEyNzJcXFwiLFxcXCJib2FyZDA2NDU4XFxcIixcXFwiYm9hcmQwMzM2NVxcXCIsXFxcImJvYXJkMDU4OTJcXFwiLFxcXCJib2FyZDA0MDkxXFxcIixcXFwiYm9hcmQwNjM2NlxcXCIsXFxcImJvYXJkMDYyOTlcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiNbW1xcXFxcXFwiQVRPTS1VU0QgcHJpY2UgZmVlZFxcXFxcXFwiLFxcXFxcXFwiJDAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZVxcXFxcXFwiLFxcXFxcXFwiJDEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUNvbW1pdHRlZVxcXFxcXFwiLFxcXFxcXFwiJDIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiQ3JhYmJsZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMy5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJWYXVsdEZhY3RvcnlcXFxcXFxcIixcXFxcXFxcIiQ0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcIlZhdWx0RmFjdG9yeUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkNS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJhdWN0aW9uZWVyXFxcXFxcXCIsXFxcXFxcXCIkNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJlY29uQ29tbWl0dGVlQ2hhcnRlclxcXFxcXFwiLFxcXFxcXFwiJDcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwiZWNvbm9taWNDb21taXR0ZWVcXFxcXFxcIixcXFxcXFxcIiQ4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImZlZURpc3RyaWJ1dG9yXFxcXFxcXCIsXFxcXFxcXCIkOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJrcmVhZFxcXFxcXFwiLFxcXFxcXFwiJDEwLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcImtyZWFkQ29tbWl0dGVlXFxcXFxcXCIsXFxcXFxcXCIkMTEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwia3JlYWRDb21taXR0ZWVDaGFydGVyXFxcXFxcXCIsXFxcXFxcXCIkMTIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHJvdmlzaW9uUG9vbFxcXFxcXFwiLFxcXFxcXFwiJDEzLkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtREFJX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtREFJX2dydlxcXFxcXFwiLFxcXFxcXFwiJDE1LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEQ19heGxcXFxcXFxcIixcXFxcXFxcIiQxNi5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJwc20tSVNULVVTRENfZ3J2XFxcXFxcXCIsXFxcXFxcXCIkMTcuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicHNtLUlTVC1VU0RUX2F4bFxcXFxcXFwiLFxcXFxcXFwiJDE4LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdLFtcXFxcXFxcInBzbS1JU1QtVVNEVF9ncnZcXFxcXFxcIixcXFxcXFxcIiQxOS5BbGxlZ2VkOiBJbnN0YW5jZUhhbmRsZVxcXFxcXFwiXSxbXFxcXFxcXCJyZXNlcnZlXFxcXFxcXCIsXFxcXFxcXCIkMjAuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwicmVzZXJ2ZUdvdmVybm9yXFxcXFxcXCIsXFxcXFxcXCIkMjEuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwic2NhbGVkUHJpY2VBdXRob3JpdHktc3RBVE9NXFxcXFxcXCIsXFxcXFxcXCIkMjIuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwic3RBVE9NLVVTRCBwcmljZSBmZWVkXFxcXFxcXCIsXFxcXFxcXCIkMjMuQWxsZWdlZDogSW5zdGFuY2VIYW5kbGVcXFxcXFxcIl0sW1xcXFxcXFwid2FsbGV0RmFjdG9yeVxcXFxcXFwiLFxcXFxcXFwiJDI0LkFsbGVnZWQ6IEluc3RhbmNlSGFuZGxlXFxcXFxcXCJdXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDI5NjNcXFwiLFxcXCJib2FyZDA0Mzk1XFxcIixcXFwiYm9hcmQwMjM5M1xcXCIsXFxcImJvYXJkMDUzOTZcXFwiLFxcXCJib2FyZDAwMzYwXFxcIixcXFwiYm9hcmQwMzc3M1xcXCIsXFxcImJvYXJkMDYyOTlcXFwiLFxcXCJib2FyZDA0NjYxXFxcIixcXFwiYm9hcmQwNDE0OVxcXCIsXFxcImJvYXJkMDUyNjJcXFwiLFxcXCJib2FyZDA0NzgzXFxcIixcXFwiYm9hcmQwMTk4NVxcXCIsXFxcImJvYXJkMDYyODRcXFwiLFxcXCJib2FyZDAxNjY0XFxcIixcXFwiYm9hcmQwMTg2N1xcXCIsXFxcImJvYXJkMDI1NjhcXFwiLFxcXCJib2FyZDA1NjY5XFxcIixcXFwiYm9hcmQwNTk3MFxcXCIsXFxcImJvYXJkMDIyNzFcXFwiLFxcXCJib2FyZDAxMjcyXFxcIixcXFwiYm9hcmQwNjQ1OFxcXCIsXFxcImJvYXJkMDMzNjVcXFwiLFxcXCJib2FyZDA1ODkyXFxcIixcXFwiYm9hcmQwNDA5MVxcXCIsXFxcImJvYXJkMDYzNjZcXFwiXX1cIl19Igp9', + }, + }, + }, + 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.agoricNames.vbankAsset%22&height=0': + { + result: { + response: { + code: 0, + value: + // observed in a3p + 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNzY5XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIjW1tcXFxcXFxcImliYy8yOTU1NDhBNzg3ODVBMTAwN0YyMzJERTI4NjE0OUE2RkY1MTJGMTgwQUY1NjU3NzgwRkM4OUMwMDlFMkMzNDhGXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQwLkFsbGVnZWQ6IFVTRENfYXhsIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzI5NTU0OEE3ODc4NUExMDA3RjIzMkRFMjg2MTQ5QTZGRjUxMkYxODBBRjU2NTc3ODBGQzg5QzAwOUUyQzM0OEZcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDEuQWxsZWdlZDogVVNEQ19heGwgaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJVU0RDX2F4bFxcXFxcXFwiLFxcXFxcXFwicHJvcG9zZWROYW1lXFxcXFxcXCI6XFxcXFxcXCJVU0QgQ29pblxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzM4NkQwOUFFMzFEQTdDMEM5MzA5MUJCNDVEMDhDQjdBMDczMEIxRjY5N0NEODEzRjA2QTU0NDZEQ0YwMkVFQjJcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDIuQWxsZWdlZDogVVNEVF9ncnYgYnJhbmRcXFxcXFxcIixcXFxcXFxcImRlbm9tXFxcXFxcXCI6XFxcXFxcXCJpYmMvMzg2RDA5QUUzMURBN0MwQzkzMDkxQkI0NUQwOENCN0EwNzMwQjFGNjk3Q0Q4MTNGMDZBNTQ0NkRDRjAyRUVCMlxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjZ9LFxcXFxcXFwiaXNzdWVyXFxcXFxcXCI6XFxcXFxcXCIkMy5BbGxlZ2VkOiBVU0RUX2dydiBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIlVTRFRfZ3J2XFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIlRldGhlciBVU0RcXFxcXFxcIn1dLFtcXFxcXFxcImliYy8zOTE0QkRFRjQ2RjQyOUEyNjkxN0U0RDhENDM0NjIwRUM0ODE3REM2QjZFNjhGQjMyN0UxOTA5MDJGMUU5MjQyXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQ0LkFsbGVnZWQ6IERBSV9heGwgYnJhbmRcXFxcXFxcIixcXFxcXFxcImRlbm9tXFxcXFxcXCI6XFxcXFxcXCJpYmMvMzkxNEJERUY0NkY0MjlBMjY5MTdFNEQ4RDQzNDYyMEVDNDgxN0RDNkI2RTY4RkIzMjdFMTkwOTAyRjFFOTI0MlxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjE4fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDUuQWxsZWdlZDogREFJX2F4bCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIkRBSV9heGxcXFxcXFxcIixcXFxcXFxcInByb3Bvc2VkTmFtZVxcXFxcXFwiOlxcXFxcXFwiREFJXFxcXFxcXCJ9XSxbXFxcXFxcXCJpYmMvM0Q1MjkxQzIzRDc3NkMzQUE3QTdBQkIzNEM3QjAyMzE5M0VDRDJCQzQyRUExOUQzMTY1QjJDRjk2NTIxMTdFN1xcXFxcXFwiLHtcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkNi5BbGxlZ2VkOiBEQUlfZ3J2IGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzNENTI5MUMyM0Q3NzZDM0FBN0E3QUJCMzRDN0IwMjMxOTNFQ0QyQkM0MkVBMTlEMzE2NUIyQ0Y5NjUyMTE3RTdcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjoxOH0sXFxcXFxcXCJpc3N1ZXJcXFxcXFxcIjpcXFxcXFxcIiQ3LkFsbGVnZWQ6IERBSV9ncnYgaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJEQUlfZ3J2XFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkRBSVxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzQyMjI1RjE0NzEzN0RERUI1RkVGMEYxRDBBOTJGMkFENTc1NTdBRkEyQzRENkYzMEIyMUUwRDk4MzAwMUMwMDJcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDguQWxsZWdlZDogc3RBVE9NIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzQyMjI1RjE0NzEzN0RERUI1RkVGMEYxRDBBOTJGMkFENTc1NTdBRkEyQzRENkYzMEIyMUUwRDk4MzAwMUMwMDJcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDkuQWxsZWdlZDogc3RBVE9NIGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwic3RBVE9NXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcInN0QVRPTVxcXFxcXFwifV0sW1xcXFxcXFwiaWJjLzY4MzEyOTI5MDM0ODdFNThCRjlBMTk1RkREQzhBMkU2MjZCM0RGMzlCODhGNEU3RjQxQzkzNUNBREJBRjU0QUNcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDEwLkFsbGVnZWQ6IFVTRENfZ3J2IGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjLzY4MzEyOTI5MDM0ODdFNThCRjlBMTk1RkREQzhBMkU2MjZCM0RGMzlCODhGNEU3RjQxQzkzNUNBREJBRjU0QUNcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDExLkFsbGVnZWQ6IFVTRENfZ3J2IGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwiVVNEQ19ncnZcXFxcXFxcIixcXFxcXFxcInByb3Bvc2VkTmFtZVxcXFxcXFwiOlxcXFxcXFwiVVNDIENvaW5cXFxcXFxcIn1dLFtcXFxcXFxcImliYy9CQTMxM0M0QTE5REZCRjk0MzU4NkMwMzg3RTZCMTEyODZGOUU0MTZCNEREMjc1NzRFNjkwOUNBQkUwRTM0MkZBXFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxMi5BbGxlZ2VkOiBBVE9NIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwiaWJjL0JBMzEzQzRBMTlERkJGOTQzNTg2QzAzODdFNkIxMTI4NkY5RTQxNkI0REQyNzU3NEU2OTA5Q0FCRTBFMzQyRkFcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDEzLkFsbGVnZWQ6IEFUT00gaXNzdWVyXFxcXFxcXCIsXFxcXFxcXCJpc3N1ZXJOYW1lXFxcXFxcXCI6XFxcXFxcXCJBVE9NXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkFUT01cXFxcXFxcIn1dLFtcXFxcXFxcImliYy9GMjMzMTY0NUI5NjgzMTE2MTg4RUYzNkZDMDRBODA5QzI4QkQzNkI1NDU1NUU4NzA1QTM3MTQ2RDAxODJGMDQ1XFxcXFxcXCIse1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxNC5BbGxlZ2VkOiBVU0RUX2F4bCBicmFuZFxcXFxcXFwiLFxcXFxcXFwiZGVub21cXFxcXFxcIjpcXFxcXFxcImliYy9GMjMzMTY0NUI5NjgzMTE2MTg4RUYzNkZDMDRBODA5QzI4QkQzNkI1NDU1NUU4NzA1QTM3MTQ2RDAxODJGMDQ1XFxcXFxcXCIsXFxcXFxcXCJkaXNwbGF5SW5mb1xcXFxcXFwiOntcXFxcXFxcImFzc2V0S2luZFxcXFxcXFwiOlxcXFxcXFwibmF0XFxcXFxcXCIsXFxcXFxcXCJkZWNpbWFsUGxhY2VzXFxcXFxcXCI6Nn0sXFxcXFxcXCJpc3N1ZXJcXFxcXFxcIjpcXFxcXFxcIiQxNS5BbGxlZ2VkOiBVU0RUX2F4bCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIlVTRFRfYXhsXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIlRldGhlciBVU0RcXFxcXFxcIn1dLFtcXFxcXFxcInVibGRcXFxcXFxcIix7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDE2LkFsbGVnZWQ6IEJMRCBicmFuZFxcXFxcXFwiLFxcXFxcXFwiZGVub21cXFxcXFxcIjpcXFxcXFxcInVibGRcXFxcXFxcIixcXFxcXFxcImRpc3BsYXlJbmZvXFxcXFxcXCI6e1xcXFxcXFwiYXNzZXRLaW5kXFxcXFxcXCI6XFxcXFxcXCJuYXRcXFxcXFxcIixcXFxcXFxcImRlY2ltYWxQbGFjZXNcXFxcXFxcIjo2fSxcXFxcXFxcImlzc3VlclxcXFxcXFwiOlxcXFxcXFwiJDE3LkFsbGVnZWQ6IEJMRCBpc3N1ZXJcXFxcXFxcIixcXFxcXFxcImlzc3Vlck5hbWVcXFxcXFxcIjpcXFxcXFxcIkJMRFxcXFxcXFwiLFxcXFxcXFwicHJvcG9zZWROYW1lXFxcXFxcXCI6XFxcXFxcXCJBZ29yaWMgc3Rha2luZyB0b2tlblxcXFxcXFwifV0sW1xcXFxcXFwidWlzdFxcXFxcXFwiLHtcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMTguQWxsZWdlZDogSVNUIGJyYW5kXFxcXFxcXCIsXFxcXFxcXCJkZW5vbVxcXFxcXFwiOlxcXFxcXFwidWlzdFxcXFxcXFwiLFxcXFxcXFwiZGlzcGxheUluZm9cXFxcXFxcIjp7XFxcXFxcXCJhc3NldEtpbmRcXFxcXFxcIjpcXFxcXFxcIm5hdFxcXFxcXFwiLFxcXFxcXFwiZGVjaW1hbFBsYWNlc1xcXFxcXFwiOjZ9LFxcXFxcXFwiaXNzdWVyXFxcXFxcXCI6XFxcXFxcXCIkMTkuQWxsZWdlZDogSVNUIGlzc3VlclxcXFxcXFwiLFxcXFxcXFwiaXNzdWVyTmFtZVxcXFxcXFwiOlxcXFxcXFwiSVNUXFxcXFxcXCIsXFxcXFxcXCJwcm9wb3NlZE5hbWVcXFxcXFxcIjpcXFxcXFxcIkFnb3JpYyBzdGFibGUgdG9rZW5cXFxcXFxcIn1dXVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDMwNDBcXFwiLFxcXCJib2FyZDA1MTQxXFxcIixcXFwiYm9hcmQwMzQ0NlxcXCIsXFxcImJvYXJkMDE1NDdcXFwiLFxcXCJib2FyZDA1NzM2XFxcIixcXFwiYm9hcmQwMjQzN1xcXCIsXFxcImJvYXJkMDMxMzhcXFwiLFxcXCJib2FyZDA1MDM5XFxcIixcXFwiYm9hcmQwMDk5MFxcXCIsXFxcImJvYXJkMDA2ODlcXFwiLFxcXCJib2FyZDA0NTQyXFxcIixcXFwiYm9hcmQwMDQ0M1xcXCIsXFxcImJvYXJkMDU1NTdcXFwiLFxcXCJib2FyZDAyNjU2XFxcIixcXFwiYm9hcmQwMTc0NFxcXCIsXFxcImJvYXJkMDY0NDVcXFwiLFxcXCJib2FyZDA1NjZcXFwiLFxcXCJib2FyZDA1OTJcXFwiLFxcXCJib2FyZDAyNTdcXFwiLFxcXCJib2FyZDAyMjNcXFwiXX1cIl19Igp9', + }, + }, + }, + 'http://localhost:26657/abci_query?path=%22/custom/vstorage/data/published.priceFeed.ATOM-USD_price_feed%22&height=0': + { + result: { + response: { + code: 0, + value: + // observed in a3p + 'ewogICJ2YWx1ZSI6ICJ7XCJibG9ja0hlaWdodFwiOlwiNTA4XCIsXCJ2YWx1ZXNcIjpbXCJ7XFxcImJvZHlcXFwiOlxcXCIje1xcXFxcXFwiYW1vdW50SW5cXFxcXFxcIjp7XFxcXFxcXCJicmFuZFxcXFxcXFwiOlxcXFxcXFwiJDAuQWxsZWdlZDogQnJhbmRcXFxcXFxcIixcXFxcXFxcInZhbHVlXFxcXFxcXCI6XFxcXFxcXCIrMTAwMDAwMFxcXFxcXFwifSxcXFxcXFxcImFtb3VudE91dFxcXFxcXFwiOntcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMS5BbGxlZ2VkOiBCcmFuZFxcXFxcXFwiLFxcXFxcXFwidmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxMjAxMDAwMFxcXFxcXFwifSxcXFxcXFxcInRpbWVyXFxcXFxcXCI6XFxcXFxcXCIkMi5BbGxlZ2VkOiB0aW1lclNlcnZpY2VcXFxcXFxcIixcXFxcXFxcInRpbWVzdGFtcFxcXFxcXFwiOntcXFxcXFxcImFic1ZhbHVlXFxcXFxcXCI6XFxcXFxcXCIrMTcyOTE3NjI5MFxcXFxcXFwiLFxcXFxcXFwidGltZXJCcmFuZFxcXFxcXFwiOlxcXFxcXFwiJDMuQWxsZWdlZDogdGltZXJCcmFuZFxcXFxcXFwifX1cXFwiLFxcXCJzbG90c1xcXCI6W1xcXCJib2FyZDAzOTM1XFxcIixcXFwiYm9hcmQwMTAzNFxcXCIsXFxcImJvYXJkMDU2NzRcXFwiLFxcXCJib2FyZDA0MjVcXFwiXX1cIixcIntcXFwiYm9keVxcXCI6XFxcIiN7XFxcXFxcXCJhbW91bnRJblxcXFxcXFwiOntcXFxcXFxcImJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMC5BbGxlZ2VkOiBCcmFuZFxcXFxcXFwiLFxcXFxcXFwidmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxMDAwMDAwXFxcXFxcXCJ9LFxcXFxcXFwiYW1vdW50T3V0XFxcXFxcXCI6e1xcXFxcXFwiYnJhbmRcXFxcXFxcIjpcXFxcXFxcIiQxLkFsbGVnZWQ6IEJyYW5kXFxcXFxcXCIsXFxcXFxcXCJ2YWx1ZVxcXFxcXFwiOlxcXFxcXFwiKzEyMDEwMDAwXFxcXFxcXCJ9LFxcXFxcXFwidGltZXJcXFxcXFxcIjpcXFxcXFxcIiQyLkFsbGVnZWQ6IHRpbWVyU2VydmljZVxcXFxcXFwiLFxcXFxcXFwidGltZXN0YW1wXFxcXFxcXCI6e1xcXFxcXFwiYWJzVmFsdWVcXFxcXFxcIjpcXFxcXFxcIisxNzI5MTc2MjkwXFxcXFxcXCIsXFxcXFxcXCJ0aW1lckJyYW5kXFxcXFxcXCI6XFxcXFxcXCIkMy5BbGxlZ2VkOiB0aW1lckJyYW5kXFxcXFxcXCJ9fVxcXCIsXFxcInNsb3RzXFxcIjpbXFxcImJvYXJkMDM5MzVcXFwiLFxcXCJib2FyZDAxMDM0XFxcIixcXFwiYm9hcmQwNTY3NFxcXCIsXFxcImJvYXJkMDQyNVxcXCJdfVwiXX0iCn0', + }, + }, + }, + }); + + const vstorageKit = await makeVstorageKit({ fetch }, makeTestConfig()); + + t.snapshot(vstorageKit.agoricNames, 'agoricnNames from A3P'); + + const priceFeed = await vstorageKit.readPublished( + 'priceFeed.ATOM-USD_price_feed', + ); + t.snapshot(priceFeed, 'priceFeed from A3P'); +}); From 1c69d39c6b5571e8501cd4be8d32e3d1bd9d3844 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 Dec 2024 17:16:28 -0800 Subject: [PATCH 04/42] chore!: remove agoricNames from VstorageKit --- .../proposals/z:acceptance/test-lib/utils.js | 2 +- .../proposals/z:acceptance/test-lib/vaults.js | 28 +++++++-------- packages/agoric-cli/src/commands/auction.js | 9 +++-- packages/agoric-cli/src/commands/gov.js | 36 ++++++++++++------- packages/agoric-cli/src/commands/oracle.js | 10 +++--- packages/agoric-cli/src/commands/psm.js | 17 ++++----- packages/agoric-cli/src/commands/reserve.js | 12 +++++-- packages/agoric-cli/src/commands/vaults.js | 15 +++++--- packages/agoric-cli/src/commands/wallet.js | 18 +++++----- packages/client-utils/src/vstorage-kit.js | 9 +++-- packages/client-utils/src/wallet-utils.js | 13 +++---- .../client-utils/test/vstorage-kit.test.js | 10 ++++-- packages/fast-usdc/src/cli/lp-commands.js | 19 ++++++---- .../fast-usdc/src/cli/operator-commands.js | 11 ++++-- .../fast-usdc/test/cli/lp-commands.test.ts | 4 +-- 15 files changed, 131 insertions(+), 82 deletions(-) diff --git a/a3p-integration/proposals/z:acceptance/test-lib/utils.js b/a3p-integration/proposals/z:acceptance/test-lib/utils.js index 330fb799c6d..c4cc3316128 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/utils.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/utils.js @@ -4,7 +4,7 @@ import { readFile, writeFile } from 'node:fs/promises'; import { networkConfig } from './rpc.js'; export const stargateClientP = makeStargateClient(networkConfig, { fetch }); -export const vstorageKitP = makeVstorageKit({ fetch }, networkConfig); +export const vstorageKit = makeVstorageKit({ fetch }, networkConfig); /** * @import {WalletUtils} from '@agoric/client-utils'; diff --git a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js index 88a07564ca9..a7604622a3f 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js @@ -1,10 +1,6 @@ /* eslint-env node */ -import { - boardSlottingMarshaller, - makeFromBoard, - retryUntilCondition, -} from '@agoric/client-utils'; +import { makeAgoricNames, retryUntilCondition } from '@agoric/client-utils'; import { AmountMath } from '@agoric/ertp'; import { agops, @@ -18,12 +14,8 @@ import { ceilMultiplyBy, makeRatio, } from '@agoric/zoe/src/contractSupport/ratio.js'; -import { E } from '@endo/far'; import { walletUtils } from './index.js'; -import { listVaults, vstorageKitP } from './utils.js'; - -const fromBoard = makeFromBoard(); -const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); +import { listVaults, vstorageKit } from './utils.js'; /** * @param {string} address @@ -97,7 +89,10 @@ export const getMinInitialDebt = async () => { * @returns {Promise<{ mintFee: import('@agoric/ertp/src/types.js').NatAmount, adjustedToMintAmount: import('@agoric/ertp/src/types.js').NatAmount }>} */ export const calculateMintFee = async (toMintValue, vaultManager) => { - const { brand } = await E.get(vstorageKitP).agoricNames; + const { brand } = await makeAgoricNames( + vstorageKit.fromBoard, + vstorageKit.vstorage, + ); /** @type {import('@agoric/ertp').Brand} */ // @ts-expect-error let this BoardRemote masquerade as a Brand const ISTBrand = brand.IST; @@ -157,11 +152,16 @@ const paramChangeOfferGeneration = async ( ) => { const ISTunit = 1_000_000n; // aka displayInfo: { decimalPlaces: 6 } - const { brand } = await E.get(vstorageKitP).agoricNames; + const agoricNames = await makeAgoricNames( + vstorageKit.fromBoard, + vstorageKit.vstorage, + ); + + const { brand } = agoricNames; assert(brand.IST); assert(brand.ATOM); - const { instance } = await E.get(vstorageKitP).agoricNames; + const { instance } = agoricNames; assert(instance.VaultFactory); const voteDurSec = BigInt(voteDur); @@ -203,7 +203,7 @@ const paramChangeOfferGeneration = async ( }; // @ts-expect-error tolerate BoardRemote instances with getBoardId methods - return JSON.stringify(marshaller.toCapData(harden(body))); + return JSON.stringify(vstorageKit.marshaller.toCapData(harden(body))); }; /** diff --git a/packages/agoric-cli/src/commands/auction.js b/packages/agoric-cli/src/commands/auction.js index ac9306ffb45..684cd4356a4 100644 --- a/packages/agoric-cli/src/commands/auction.js +++ b/packages/agoric-cli/src/commands/auction.js @@ -1,6 +1,10 @@ // @ts-check /* eslint-env node */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { Fail } from '@endo/errors'; import { InvalidArgumentError } from 'commander'; import { outputActionAndHint } from '../lib/wallet.js'; @@ -88,10 +92,11 @@ export const makeAuctionCommand = ( * }} opts */ async opts => { - const { agoricNames, readPublished } = await makeVstorageKit( + const { readPublished, ...vsk } = makeVstorageKit( { fetch }, networkConfig, ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const { current } = await readPublished(`auction.governance`); diff --git a/packages/agoric-cli/src/commands/gov.js b/packages/agoric-cli/src/commands/gov.js index be116b87514..007b6b1a2ea 100644 --- a/packages/agoric-cli/src/commands/gov.js +++ b/packages/agoric-cli/src/commands/gov.js @@ -1,7 +1,11 @@ // @ts-check /* eslint-disable func-names */ /* eslint-env node */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { execFileSync as execFileSyncAmbient } from 'child_process'; import { Command, CommanderError } from 'commander'; import { normalizeAddressWithOptions, pollBlocks } from '../lib/chain.js'; @@ -14,8 +18,10 @@ import { } from '../lib/wallet.js'; /** - * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js' - * @import {QuestionDetails} from '@agoric/governance/src/types.js' + * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js'; + * @import {AgoricNamesRemotes} from '@agoric/vats/tools/board-utils.js'; + * @import {CurrentWalletRecord} from '@agoric/smart-wallet/src/smartWallet.js'; + * @import {VstorageKit} from '@agoric/client-utils'; */ const collectValues = (val, memo) => { @@ -85,19 +91,21 @@ export const makeGovCommand = (_logger, io = {}) => { * given a sendFrom address; else print it. * * @param {{ - * toOffer: (agoricNames: *, current: import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord | undefined) => OfferSpec, + * toOffer: (agoricNames: AgoricNamesRemotes, current: CurrentWalletRecord | undefined) => OfferSpec, * sendFrom?: string | undefined, * keyringBackend: string, * instanceName?: string, * }} detail - * @param {Awaited>} [optUtils] + * @param {VstorageKit} [vsk] */ const processOffer = async function ( { toOffer, sendFrom, keyringBackend }, - optUtils, + vsk, ) { - const utils = await (optUtils || makeVstorageKit({ fetch }, networkConfig)); - const { agoricNames, readPublished } = utils; + await null; + vsk ||= makeVstorageKit({ fetch }, networkConfig); + const { readPublished } = vsk; + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); assert(keyringBackend, 'missing keyring-backend option'); @@ -264,10 +272,11 @@ export const makeGovCommand = (_logger, io = {}) => { ) .requiredOption('--for ', 'description of the invitation') .action(async opts => { - const { agoricNames, readPublished } = await makeVstorageKit( + const { readPublished, ...vsk } = makeVstorageKit( { fetch }, networkConfig, ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const current = await getCurrent(opts.from, { readPublished }); const known = findContinuingIds(current, agoricNames); @@ -293,10 +302,11 @@ export const makeGovCommand = (_logger, io = {}) => { normalizeAddress, ) .action(async opts => { - const { agoricNames, readPublished } = await makeVstorageKit( + const { readPublished, ...vsk } = makeVstorageKit( { fetch }, networkConfig, ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const current = await getCurrent(opts.from, { readPublished }); const found = findContinuingIds(current, agoricNames); @@ -332,8 +342,8 @@ export const makeGovCommand = (_logger, io = {}) => { normalizeAddress, ) .action(async function (opts, options) { - const utils = await makeVstorageKit({ fetch }, networkConfig); - const { readPublished } = utils; + const vsk = makeVstorageKit({ fetch }, networkConfig); + const { readPublished } = vsk; const questionDesc = await readPublished( `committees.${opts.pathname}.latestQuestion`, @@ -383,7 +393,7 @@ export const makeGovCommand = (_logger, io = {}) => { sendFrom: opts.sendFrom, keyringBackend: options.optsWithGlobals().keyringBackend, }, - utils, + vsk, ); }); diff --git a/packages/agoric-cli/src/commands/oracle.js b/packages/agoric-cli/src/commands/oracle.js index 2882cef094a..e91d9967be7 100644 --- a/packages/agoric-cli/src/commands/oracle.js +++ b/packages/agoric-cli/src/commands/oracle.js @@ -3,6 +3,7 @@ /* eslint-env node */ import { fetchEnvNetworkConfig, + makeAgoricNames, makeVstorageKit, makeWalletUtils, storageHelper, @@ -90,19 +91,20 @@ export const makeOracleCommand = (logger, io = {}) => { env: process.env, fetch, }); - const utils = await makeVstorageKit({ fetch }, networkConfig); + const vsk = makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const lookupPriceAggregatorInstance = ([brandIn, brandOut]) => { const name = oracleBrandFeedName(brandIn, brandOut); - const instance = utils.agoricNames.instance[name]; + const instance = agoricNames.instance[name]; if (!instance) { - logger.debug('known instances:', utils.agoricNames.instance); + logger.debug('known instances:', agoricNames.instance); throw Error(`Unknown instance ${name}`); } return instance; }; - return { ...utils, networkConfig, lookupPriceAggregatorInstance }; + return { ...vsk, networkConfig, lookupPriceAggregatorInstance }; }; oracle diff --git a/packages/agoric-cli/src/commands/psm.js b/packages/agoric-cli/src/commands/psm.js index a59a8b81639..e800b5f1c16 100644 --- a/packages/agoric-cli/src/commands/psm.js +++ b/packages/agoric-cli/src/commands/psm.js @@ -3,6 +3,7 @@ /* eslint-env node */ import { fetchEnvNetworkConfig, + makeAgoricNames, makeVstorageKit, storageHelper, } from '@agoric/client-utils'; @@ -66,13 +67,14 @@ export const makePsmCommand = logger => { ); const rpcTools = async () => { - const utils = await makeVstorageKit({ fetch }, networkConfig); + const vsk = await makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const lookupPsmInstance = ([minted, anchor]) => { const name = `psm-${minted}-${anchor}`; - const instance = utils.agoricNames.instance[name]; + const instance = agoricNames.instance[name]; if (!instance) { - logger.debug('known instances:', utils.agoricNames.instance); + logger.debug('known instances:', agoricNames.instance); throw Error(`Unknown instance ${name}`); } return instance; @@ -83,20 +85,19 @@ export const makePsmCommand = logger => { * @param {[Minted: string, Anchor: string]} pair */ const getGovernanceState = async ([Minted, Anchor]) => { - const govContent = await utils.vstorage.readLatest( + const govContent = await vsk.vstorage.readLatest( `published.psm.${Minted}.${Anchor}.governance`, ); assert(govContent, 'no gov content'); const { current: governance } = last( - storageHelper.unserializeTxt(govContent, utils.fromBoard), + storageHelper.unserializeTxt(govContent, vsk.fromBoard), ); - const { [`psm.${Minted}.${Anchor}`]: instance } = - utils.agoricNames.instance; + const { [`psm.${Minted}.${Anchor}`]: instance } = agoricNames.instance; return { instance, governance }; }; - return { ...utils, lookupPsmInstance, getGovernanceState }; + return { ...vsk, agoricNames, lookupPsmInstance, getGovernanceState }; }; psm diff --git a/packages/agoric-cli/src/commands/reserve.js b/packages/agoric-cli/src/commands/reserve.js index eebb6c7d73d..9716590402e 100644 --- a/packages/agoric-cli/src/commands/reserve.js +++ b/packages/agoric-cli/src/commands/reserve.js @@ -1,7 +1,11 @@ // @ts-check /* eslint-disable func-names */ /* eslint-env node */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { Offers } from '@agoric/inter-protocol/src/clientSupport.js'; import { Command } from 'commander'; import { outputActionAndHint } from '../lib/wallet.js'; @@ -31,7 +35,8 @@ export const makeReserveCommand = (_logger, io = {}) => { * }} opts */ async ({ collateralBrand, ...opts }) => { - const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig); + const vsk = makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const offer = Offers.reserve.AddCollateral(agoricNames, { collateralBrandKey: collateralBrand, @@ -65,7 +70,8 @@ export const makeReserveCommand = (_logger, io = {}) => { 1, ) .action(async function (opts) { - const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig); + const vsk = makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const reserveInstance = agoricNames.instance.reserve; assert(reserveInstance, 'missing reserve in names'); diff --git a/packages/agoric-cli/src/commands/vaults.js b/packages/agoric-cli/src/commands/vaults.js index 51032d89482..006831862e7 100644 --- a/packages/agoric-cli/src/commands/vaults.js +++ b/packages/agoric-cli/src/commands/vaults.js @@ -1,7 +1,11 @@ // @ts-check /* eslint-disable func-names */ /* eslint-env node */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { lookupOfferIdForVault, Offers, @@ -63,7 +67,8 @@ export const makeVaultsCommand = logger => { .option('--collateralBrand ', 'Collateral brand key', 'ATOM') .action(async function (opts) { logger.warn('running with options', opts); - const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig); + const vsk = makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const offer = Offers.vaults.OpenVault(agoricNames, { giveCollateral: opts.giveCollateral, @@ -98,10 +103,11 @@ export const makeVaultsCommand = logger => { .requiredOption('--vaultId ', 'Key of vault (e.g. vault1)') .action(async function (opts) { logger.warn('running with options', opts); - const { agoricNames, readPublished } = await makeVstorageKit( + const { readPublished, ...vsk } = makeVstorageKit( { fetch }, networkConfig, ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const previousOfferId = await lookupOfferIdForVault( opts.vaultId, @@ -142,10 +148,11 @@ export const makeVaultsCommand = logger => { ) .action(async function (opts) { logger.warn('running with options', opts); - const { agoricNames, readPublished } = await makeVstorageKit( + const { readPublished, ...vsk } = makeVstorageKit( { fetch }, networkConfig, ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const previousOfferId = await lookupOfferIdForVault( opts.vaultId, diff --git a/packages/agoric-cli/src/commands/wallet.js b/packages/agoric-cli/src/commands/wallet.js index e41258716d4..18d3d597c2b 100644 --- a/packages/agoric-cli/src/commands/wallet.js +++ b/packages/agoric-cli/src/commands/wallet.js @@ -8,7 +8,11 @@ import { makeLeader, makeLeaderFromRpcAddresses, } from '@agoric/casting'; -import { makeVstorageKit, fetchEnvNetworkConfig } from '@agoric/client-utils'; +import { + makeVstorageKit, + fetchEnvNetworkConfig, + makeAgoricNames, +} from '@agoric/client-utils'; import { execFileSync } from 'child_process'; import fs from 'fs'; import util from 'util'; @@ -214,13 +218,11 @@ export const makeWalletCommand = async command => { normalizeAddress, ) .action(async function (opts) { - const { agoricNames, unserializer, readPublished } = - await makeVstorageKit( - { - fetch, - }, - networkConfig, - ); + const { readPublished, unserializer, ...vsk } = makeVstorageKit( + { fetch }, + networkConfig, + ); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); const leader = makeLeader(networkConfig.rpcAddrs[0]); const follower = await makeFollower( diff --git a/packages/client-utils/src/vstorage-kit.js b/packages/client-utils/src/vstorage-kit.js index bca8d7b074e..6643d81fe63 100644 --- a/packages/client-utils/src/vstorage-kit.js +++ b/packages/client-utils/src/vstorage-kit.js @@ -2,6 +2,7 @@ import { boardSlottingMarshaller, makeBoardRemote, } from '@agoric/vats/tools/board-utils.js'; +import { assertAllDefined } from '@agoric/internal'; import { makeVStorage } from './vstorage.js'; export { boardSlottingMarshaller }; @@ -73,6 +74,7 @@ harden(storageHelper); * @returns {Promise} */ export const makeAgoricNames = async (ctx, vstorage) => { + assertAllDefined({ ctx, vstorage }); const reverse = {}; const entries = await Promise.all( ['brand', 'instance', 'vbankAsset'].map(async kind => { @@ -96,12 +98,10 @@ export const makeAgoricNames = async (ctx, vstorage) => { * @param {{ fetch: typeof window.fetch }} io * @param {MinimalNetworkConfig} config */ -export const makeVstorageKit = async ({ fetch }, config) => { - await null; +export const makeVstorageKit = ({ fetch }, config) => { try { const vstorage = makeVStorage({ fetch }, config); const fromBoard = makeFromBoard(); - const agoricNames = await makeAgoricNames(fromBoard, vstorage); const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); @@ -131,7 +131,6 @@ export const makeVstorageKit = async ({ fetch }, config) => { readLatestHead(`published.${subpath}`); return { - agoricNames, fromBoard, marshaller, readLatestHead, @@ -143,4 +142,4 @@ export const makeVstorageKit = async ({ fetch }, config) => { throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`); } }; -/** @typedef {Awaited>} VstorageKit */ +/** @typedef {ReturnType} VstorageKit */ diff --git a/packages/client-utils/src/wallet-utils.js b/packages/client-utils/src/wallet-utils.js index 2cd63a1498d..b7d44a4c9d6 100644 --- a/packages/client-utils/src/wallet-utils.js +++ b/packages/client-utils/src/wallet-utils.js @@ -1,7 +1,7 @@ import { makeWalletStateCoalescer } from '@agoric/smart-wallet/src/utils.js'; import { pollBlocks } from './chain.js'; import { makeStargateClient } from './rpc.js'; -import { boardSlottingMarshaller, makeVstorageKit } from './vstorage-kit.js'; +import { makeAgoricNames, makeVstorageKit } from './vstorage-kit.js'; /** * @import {Amount, Brand} from '@agoric/ertp/src/types.js' @@ -20,12 +20,12 @@ import { boardSlottingMarshaller, makeVstorageKit } from './vstorage-kit.js'; * @param {MinimalNetworkConfig} networkConfig */ export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => { - const vsk = await makeVstorageKit({ fetch }, networkConfig); - - const m = boardSlottingMarshaller(vsk.fromBoard.convertSlotToVal); + const vsk = makeVstorageKit({ fetch }, networkConfig); const client = await makeStargateClient(networkConfig, { fetch }); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); + /** * @param {string} from * @param {number|string} [minHeight] @@ -38,12 +38,12 @@ export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => { /** @type {{ Invitation: Brand<'set'> }} */ // @ts-expect-error XXX how to narrow AssetKind to set? - const { Invitation } = vsk.agoricNames.brand; + const { Invitation } = agoricNames.brand; const coalescer = makeWalletStateCoalescer(Invitation); // update with oldest first for (const txt of history.reverse()) { const { body, slots } = JSON.parse(txt); - const record = m.fromCapData({ body, slots }); + const record = vsk.marshaller.fromCapData({ body, slots }); coalescer.update(record); } const coalesced = coalescer.state; @@ -103,6 +103,7 @@ export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => { return { // pass along all of VstorageKit ...vsk, + agoricNames, networkConfig, getLastUpdate, getCurrentWalletRecord, diff --git a/packages/client-utils/test/vstorage-kit.test.js b/packages/client-utils/test/vstorage-kit.test.js index bf2ffb07ea5..a6d11c6972f 100644 --- a/packages/client-utils/test/vstorage-kit.test.js +++ b/packages/client-utils/test/vstorage-kit.test.js @@ -1,6 +1,6 @@ /* eslint-env node */ import test from 'ava'; -import { makeVstorageKit } from '../src/vstorage-kit.js'; +import { makeAgoricNames, makeVstorageKit } from '../src/vstorage-kit.js'; const makeMockFetch = (responses = {}) => { return async url => { @@ -73,9 +73,13 @@ test('agoricNames contains expected structure', async t => { }, }); - const vstorageKit = await makeVstorageKit({ fetch }, makeTestConfig()); + const vstorageKit = makeVstorageKit({ fetch }, makeTestConfig()); + const agoricNames = await makeAgoricNames( + vstorageKit.fromBoard, + vstorageKit.vstorage, + ); - t.snapshot(vstorageKit.agoricNames, 'agoricnNames from A3P'); + t.snapshot(agoricNames, 'agoricNames from A3P'); const priceFeed = await vstorageKit.readPublished( 'priceFeed.ATOM-USD_price_feed', diff --git a/packages/fast-usdc/src/cli/lp-commands.js b/packages/fast-usdc/src/cli/lp-commands.js index 4b829cfbfba..ab354313f84 100644 --- a/packages/fast-usdc/src/cli/lp-commands.js +++ b/packages/fast-usdc/src/cli/lp-commands.js @@ -5,7 +5,11 @@ * @import {USDCProposalShapes} from '../pool-share-math.js'; */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { InvalidArgumentError } from 'commander'; import { assertParsableNumber, @@ -41,7 +45,8 @@ const parseUSDCAmount = (amountString, usdc) => { * @param {Command} program * @param {{ * fetch?: Window['fetch']; - * vstorageKit?: Awaited>; + * agoricNames?: import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes; + * vstorageKit?: import('@agoric/client-utils').VstorageKit; * stdout: typeof process.stdout; * stderr: typeof process.stderr; * env: typeof process.env; @@ -50,7 +55,7 @@ const parseUSDCAmount = (amountString, usdc) => { */ export const addLPCommands = ( program, - { fetch, vstorageKit, stderr, stdout, env, now }, + { fetch, agoricNames, vstorageKit, stderr, stdout, env, now }, ) => { const loadVsk = async () => { if (vstorageKit) { @@ -75,9 +80,10 @@ export const addLPCommands = ( .action(async opts => { vskP ||= loadVsk(); const vsk = await vskP; + agoricNames ||= await makeAgoricNames(vsk.fromBoard, vsk.vstorage); /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize usdc as a Brand type - const usdc = vsk.agoricNames.brand.USDC; + const usdc = agoricNames.brand.USDC; assert(usdc, 'USDC brand not in agoricNames'); const usdcAmount = parseUSDCAmount(opts.amount, usdc); @@ -121,15 +127,16 @@ export const addLPCommands = ( .action(async opts => { vskP ||= loadVsk(); const vsk = await vskP; + agoricNames ||= await makeAgoricNames(vsk.fromBoard, vsk.vstorage); /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize FastLP as a Brand type - const poolShare = vsk.agoricNames.brand.FastLP; + const poolShare = agoricNames.brand.FastLP; assert(poolShare, 'FastLP brand not in agoricNames'); /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize usdc as a Brand type - const usdc = vsk.agoricNames.brand.USDC; + const usdc = agoricNames.brand.USDC; assert(usdc, 'USDC brand not in agoricNames'); const usdcAmount = parseUSDCAmount(opts.amount, usdc); diff --git a/packages/fast-usdc/src/cli/operator-commands.js b/packages/fast-usdc/src/cli/operator-commands.js index 196a48af8a4..b635efd41ed 100644 --- a/packages/fast-usdc/src/cli/operator-commands.js +++ b/packages/fast-usdc/src/cli/operator-commands.js @@ -5,7 +5,11 @@ * @import {OperatorKit} from '../exos/operator-kit.js'; */ -import { fetchEnvNetworkConfig, makeVstorageKit } from '@agoric/client-utils'; +import { + fetchEnvNetworkConfig, + makeAgoricNames, + makeVstorageKit, +} from '@agoric/client-utils'; import { mustMatch } from '@agoric/internal'; import { Nat } from '@endo/nat'; import { InvalidArgumentError } from 'commander'; @@ -53,8 +57,9 @@ export const addOperatorCommands = ( .option('--offerId ', 'Offer id', String, `operatorAccept-${now()}`) .action(async opts => { const networkConfig = await fetchEnvNetworkConfig({ env, fetch }); - const vsk = await makeVstorageKit({ fetch }, networkConfig); - const instance = vsk.agoricNames.instance.fastUsdc; + const vsk = makeVstorageKit({ fetch }, networkConfig); + const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); + const instance = agoricNames.instance.fastUsdc; assert(instance, 'fastUsdc instance not in agoricNames'); /** @type {OfferSpec} */ diff --git a/packages/fast-usdc/test/cli/lp-commands.test.ts b/packages/fast-usdc/test/cli/lp-commands.test.ts index 367dc9a78f6..f3bb7ef1a73 100644 --- a/packages/fast-usdc/test/cli/lp-commands.test.ts +++ b/packages/fast-usdc/test/cli/lp-commands.test.ts @@ -32,9 +32,9 @@ const makeTestContext = () => { const now = () => 1234; addLPCommands(program, { + // @ts-expect-error fake brands + agoricNames: { brand: { FastLP, USDC } }, vstorageKit: { - // @ts-expect-error fake brands - agoricNames: { brand: { FastLP, USDC } }, marshaller, // @ts-expect-error ignore fancy return type readPublished: async (path: string) => { From 15976b5f6a25df25242c6304c0f226fa950cd68b Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 11 Dec 2024 12:28:30 -0800 Subject: [PATCH 05/42] refactor: s/makeWalletUtils/makeSmartWalletKit --- packages/client-utils/src/main.js | 2 +- .../{wallet-utils.js => smart-wallet-kit.js} | 5 ++--- .../test/snapshots/exports.test.js.md | 2 +- .../test/snapshots/exports.test.js.snap | Bin 584 -> 584 bytes .../test/snapshots/vstorage-kit.test.js.md | 2 +- .../test/snapshots/vstorage-kit.test.js.snap | Bin 3914 -> 3910 bytes 6 files changed, 5 insertions(+), 6 deletions(-) rename packages/client-utils/src/{wallet-utils.js => smart-wallet-kit.js} (94%) diff --git a/packages/client-utils/src/main.js b/packages/client-utils/src/main.js index fad3e63225e..6a07e21524d 100644 --- a/packages/client-utils/src/main.js +++ b/packages/client-utils/src/main.js @@ -4,7 +4,7 @@ export * from './rpc.js'; export * from './sync-tools.js'; export * from './vstorage.js'; export * from './vstorage-kit.js'; -export * from './wallet-utils.js'; +export * from './smart-wallet-kit.js'; // eslint-disable-next-line import/export -- just types export * from './types.js'; diff --git a/packages/client-utils/src/wallet-utils.js b/packages/client-utils/src/smart-wallet-kit.js similarity index 94% rename from packages/client-utils/src/wallet-utils.js rename to packages/client-utils/src/smart-wallet-kit.js index b7d44a4c9d6..a570fe9855a 100644 --- a/packages/client-utils/src/wallet-utils.js +++ b/packages/client-utils/src/smart-wallet-kit.js @@ -9,7 +9,6 @@ import { makeAgoricNames, makeVstorageKit } from './vstorage-kit.js'; * @import {MinimalNetworkConfig} from './network-config.js'; */ -// XXX this is really a SmartWalletKit /** * Augment VstorageKit with addtional convenience methods for working with * Agoric smart wallets. @@ -19,7 +18,7 @@ import { makeAgoricNames, makeVstorageKit } from './vstorage-kit.js'; * @param {(ms: number) => Promise} root0.delay * @param {MinimalNetworkConfig} networkConfig */ -export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => { +export const makeSmartWalletKit = async ({ fetch, delay }, networkConfig) => { const vsk = makeVstorageKit({ fetch }, networkConfig); const client = await makeStargateClient(networkConfig, { fetch }); @@ -111,4 +110,4 @@ export const makeWalletUtils = async ({ fetch, delay }, networkConfig) => { pollOffer, }; }; -/** @typedef {Awaited>} WalletUtils */ +/** @typedef {Awaited>} SmartWalletKit */ diff --git a/packages/client-utils/test/snapshots/exports.test.js.md b/packages/client-utils/test/snapshots/exports.test.js.md index 22f45e43b82..b07f3339908 100644 --- a/packages/client-utils/test/snapshots/exports.test.js.md +++ b/packages/client-utils/test/snapshots/exports.test.js.md @@ -16,11 +16,11 @@ Generated by [AVA](https://avajs.dev). 'fetchNetworkConfig', 'makeAgoricNames', 'makeFromBoard', + 'makeSmartWalletKit', 'makeStargateClient', 'makeTendermint34Client', 'makeVStorage', 'makeVstorageKit', - 'makeWalletUtils', 'pickEndpoint', 'retryUntilCondition', 'sleep', diff --git a/packages/client-utils/test/snapshots/exports.test.js.snap b/packages/client-utils/test/snapshots/exports.test.js.snap index c6c052973b55a0c534312dd6feb121c4e29772d8..f255f686a3eba350ed02283cba31f10e7276eb2a 100644 GIT binary patch literal 584 zcmV-O0=NA^RzVBQ{Sa zH8k_OL?4R?00000000AZ(lKunF%$>zzwbyJO3F1&+EO9D0}@Q#LP(%$Nu-7rb*h{@ zC$Zw#C*MojjM)$a;wu!10kQKP82Sy^nOT_8HMNsSaFcca-}ya1-*vC6OgzkHp9M)$ zLP(v6E17AYW&=an>^ey}@$>L!h;`%-E3*Cf06qfv2H*z39{^7nP-8%s0W$`CVZaXt z{ANHD08ay;6#!WPdgd=G&NTPw3d&00QX%&np*0^0z4 z1Xe56OH&#)cVHCxWz{zb70MZ%^WnX z8NJAxbMd;bk;k18xAZRWm5wAiQ(QH~ZJ(2FzZjE4=Kq(&|_-*jok3bNBvO;Xj3P9#aA9eU_cAyY!6 z?seqnbXWDYQ0d~zw)_mptX#yYRnC;1DUvx!zzwbyJN=lk0ZK)6+fe9q$a3oNrBvM0)Iu+;6 zNv$~c$@h{rV9Q2imN7?+dAW2FH zsS|M_GtJZN%uqJJOcGA~B>Wj-9r?qGZ2tp*PXN9FxB~D8z#|6K8PI3IoB>}LaK(V% z3@8P_;{a#{KpFt=1K?`_{0M+w0ZrVu+^SqIgKdC4 z04t%&0@PRtR;aMjVJE5|o<^N^^Wf!8$e2sFZl|ZM#)%Vw6MKEbZPHbSNb2EhZnHD4 zl&}tl4(<#D#b*sYZ3{X#b`%*skVD7rIJSMw{%H!%l*fD|>O*5?+~#AEIk4uyW)7Ox zjGyPtxp>{z$m1??JLDuHC50wuiq7oj=8e#auw$v|$Gjwj7JTfq(&~QZ@RQ<1=(3olT?w>i6m*XL-!pjWJ-wC zy)OG9-L&;esC0Q>TYgAnR&JqZl`|D*ie!$`_*Sy*$9K*pUH4UwV>8jzoajXOtEf7+ z?_FdxSsv31kt#D=(whI%JZ&fu=O;Z9*+luF>^S()!vj5)#1}Lca=P4g*WsGSoxwoZ W#)YJ%+WU`M6#fgE`*l_W1ONbY!4nSv diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.md b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md index 1a06e804b30..fb788564f20 100644 --- a/packages/client-utils/test/snapshots/vstorage-kit.test.js.md +++ b/packages/client-utils/test/snapshots/vstorage-kit.test.js.md @@ -6,7 +6,7 @@ Generated by [AVA](https://avajs.dev). ## agoricNames contains expected structure -> agoricnNames from A3P +> agoricNames from A3P { brand: { diff --git a/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap b/packages/client-utils/test/snapshots/vstorage-kit.test.js.snap index 029f118c99889b62b8f1dace482bd1b92837ad60..b36c073f9252acaf1424d7a3cfd0947dd4a3c347 100644 GIT binary patch delta 356 zcmV-q0h|8H9>yLrK~_N^Q*L2!b7*gLAa*kf0|2np>D~1zIoB-5>L>f1p(S4AS+)HIM(80se!OMQUshcG@{-=hjk78=Ioj)$ZC+G+fj%T?tqI93Q7`Xg9QzWsNzsU`3<`iDz6q(mp z2Nn#vV4FLjo%+Utz#;O#MhJE>dpw`Z+#9EpLEvuE+34%^y-b?O3oF6|J{$xdA#=4{ z-X8CAO`i(Zu4yPq@jYKfYr|IW-}EcW;s5JuZ|M$`b3R|RY&%)Lzx)qYz{#sTL;wK8 CeY1H0 delta 360 zcmV-u0hj*99?BjvK~_N^Q*L2!b7*gLAa*kf0|0Vej%zau_{^I5Hv40jvo&8g%l}O> z8rA|*P~XK>p<=Nz?hSvhmcH80ls?-(k;^Veb>Z0hhxrZHdwrOHD}Yr1k6iAD`JZ=v zm>)?jXIC?Y+0w_%-*!csN|B?hr6s$cyT9gN|3azw9i;1<{ifpKd?B&C;>^w|2FNnN zhZ(;w?So%pfTtPYFGy*qY9jwJ1N;Xmi`3X3?6h;v&aI`EHg-4t^lA12uO2P zxdNpn)_~tC=UO7YT3TUbTA47%I)7Y*PtXw}9M5uPMCnFxF>v{}rbuEjf0G;7%qhIa zDKf9I4lEdS!8W%*JN1nPfkWi~jS%c&_IN&+xpz({gTURSv(eY-d!00qS5|}xd^iX^ zLgs3@yiMNanm#NQtX Date: Wed, 11 Dec 2024 12:41:28 -0800 Subject: [PATCH 06/42] refactor: fu cmds with SmartWalletKit --- packages/fast-usdc/src/cli/lp-commands.js | 50 +++++++++---------- .../fast-usdc/src/cli/operator-commands.js | 12 +++-- .../fast-usdc/test/cli/lp-commands.test.ts | 6 +-- 3 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/fast-usdc/src/cli/lp-commands.js b/packages/fast-usdc/src/cli/lp-commands.js index ab354313f84..afcbd063650 100644 --- a/packages/fast-usdc/src/cli/lp-commands.js +++ b/packages/fast-usdc/src/cli/lp-commands.js @@ -1,3 +1,4 @@ +/* eslint-env node */ /** * @import {Command} from 'commander'; * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js'; @@ -7,19 +8,20 @@ import { fetchEnvNetworkConfig, - makeAgoricNames, - makeVstorageKit, + makeSmartWalletKit, } from '@agoric/client-utils'; -import { InvalidArgumentError } from 'commander'; +import { AmountMath } from '@agoric/ertp'; import { assertParsableNumber, ceilDivideBy, multiplyBy, parseRatio, } from '@agoric/zoe/src/contractSupport/ratio.js'; -import { AmountMath } from '@agoric/ertp'; +import { InvalidArgumentError } from 'commander'; import { outputActionAndHint } from './bridge-action.js'; +export const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + /** @param {string} arg */ const parseDecimal = arg => { try { @@ -45,8 +47,7 @@ const parseUSDCAmount = (amountString, usdc) => { * @param {Command} program * @param {{ * fetch?: Window['fetch']; - * agoricNames?: import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes; - * vstorageKit?: import('@agoric/client-utils').VstorageKit; + * smartWalletKit?: import('@agoric/client-utils').SmartWalletKit; * stdout: typeof process.stdout; * stderr: typeof process.stderr; * env: typeof process.env; @@ -55,18 +56,18 @@ const parseUSDCAmount = (amountString, usdc) => { */ export const addLPCommands = ( program, - { fetch, agoricNames, vstorageKit, stderr, stdout, env, now }, + { fetch, smartWalletKit, stderr, stdout, env, now }, ) => { - const loadVsk = async () => { - if (vstorageKit) { - return vstorageKit; + const loadSwk = async () => { + if (smartWalletKit) { + return smartWalletKit; } assert(fetch); const networkConfig = await fetchEnvNetworkConfig({ env, fetch }); - return makeVstorageKit({ fetch }, networkConfig); + return makeSmartWalletKit({ delay, fetch }, networkConfig); }; - /** @type {undefined | ReturnType} */ - let vskP; + /** @type {undefined | ReturnType} */ + let swkP; program .command('deposit') @@ -78,12 +79,11 @@ export const addLPCommands = ( .requiredOption('--amount ', 'USDC amount', parseDecimal) .option('--offerId ', 'Offer id', String, `lpDeposit-${now()}`) .action(async opts => { - vskP ||= loadVsk(); - const vsk = await vskP; - agoricNames ||= await makeAgoricNames(vsk.fromBoard, vsk.vstorage); + swkP ||= loadSwk(); + const swk = await swkP; /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize usdc as a Brand type - const usdc = agoricNames.brand.USDC; + const usdc = swk.agoricNames.brand.USDC; assert(usdc, 'USDC brand not in agoricNames'); const usdcAmount = parseUSDCAmount(opts.amount, usdc); @@ -112,7 +112,7 @@ export const addLPCommands = ( offer, }; - outputActionAndHint(bridgeAction, { stderr, stdout }, vsk.marshaller); + outputActionAndHint(bridgeAction, { stderr, stdout }, swk.marshaller); }); program @@ -125,25 +125,25 @@ export const addLPCommands = ( .requiredOption('--amount ', 'USDC amount', parseDecimal) .option('--offerId ', 'Offer id', String, `lpWithdraw-${now()}`) .action(async opts => { - vskP ||= loadVsk(); - const vsk = await vskP; - agoricNames ||= await makeAgoricNames(vsk.fromBoard, vsk.vstorage); + swkP ||= loadSwk(); + swkP ||= loadSwk(); + const swk = await swkP; /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize FastLP as a Brand type - const poolShare = agoricNames.brand.FastLP; + const poolShare = swk.agoricNames.brand.FastLP; assert(poolShare, 'FastLP brand not in agoricNames'); /** @type {Brand<'nat'>} */ // @ts-expect-error it doesnt recognize usdc as a Brand type - const usdc = agoricNames.brand.USDC; + const usdc = swk.agoricNames.brand.USDC; assert(usdc, 'USDC brand not in agoricNames'); const usdcAmount = parseUSDCAmount(opts.amount, usdc); /** @type {import('../types.js').PoolMetrics} */ // @ts-expect-error it treats this as "unknown" - const metrics = await vsk.readPublished('fastUsdc.poolMetrics'); + const metrics = await swk.readPublished('fastUsdc.poolMetrics'); const fastLPAmount = ceilDivideBy(usdcAmount, metrics.shareWorth); /** @type {USDCProposalShapes['withdraw']} */ @@ -170,7 +170,7 @@ export const addLPCommands = ( outputActionAndHint( { method: 'executeOffer', offer }, { stderr, stdout }, - vsk.marshaller, + swk.marshaller, ); }); diff --git a/packages/fast-usdc/src/cli/operator-commands.js b/packages/fast-usdc/src/cli/operator-commands.js index b635efd41ed..8f849f760db 100644 --- a/packages/fast-usdc/src/cli/operator-commands.js +++ b/packages/fast-usdc/src/cli/operator-commands.js @@ -1,3 +1,4 @@ +/* eslint-env node */ /** * @import {Command} from 'commander'; * @import {OfferSpec} from '@agoric/smart-wallet/src/offers.js'; @@ -7,8 +8,7 @@ import { fetchEnvNetworkConfig, - makeAgoricNames, - makeVstorageKit, + makeSmartWalletKit, } from '@agoric/client-utils'; import { mustMatch } from '@agoric/internal'; import { Nat } from '@endo/nat'; @@ -17,6 +17,8 @@ import { INVITATION_MAKERS_DESC } from '../exos/transaction-feed.js'; import { CctpTxEvidenceShape } from '../type-guards.js'; import { outputActionAndHint } from './bridge-action.js'; +export const delay = ms => new Promise(resolve => setTimeout(resolve, ms)); + /** @param {string} arg */ const parseNat = arg => { const n = Nat(BigInt(arg)); @@ -57,9 +59,9 @@ export const addOperatorCommands = ( .option('--offerId ', 'Offer id', String, `operatorAccept-${now()}`) .action(async opts => { const networkConfig = await fetchEnvNetworkConfig({ env, fetch }); - const vsk = makeVstorageKit({ fetch }, networkConfig); - const agoricNames = await makeAgoricNames(vsk.fromBoard, vsk.vstorage); - const instance = agoricNames.instance.fastUsdc; + + const swk = await makeSmartWalletKit({ delay, fetch }, networkConfig); + const instance = swk.agoricNames.instance.fastUsdc; assert(instance, 'fastUsdc instance not in agoricNames'); /** @type {OfferSpec} */ diff --git a/packages/fast-usdc/test/cli/lp-commands.test.ts b/packages/fast-usdc/test/cli/lp-commands.test.ts index f3bb7ef1a73..0ca642aa704 100644 --- a/packages/fast-usdc/test/cli/lp-commands.test.ts +++ b/packages/fast-usdc/test/cli/lp-commands.test.ts @@ -32,9 +32,9 @@ const makeTestContext = () => { const now = () => 1234; addLPCommands(program, { - // @ts-expect-error fake brands - agoricNames: { brand: { FastLP, USDC } }, - vstorageKit: { + smartWalletKit: { + // @ts-expect-error fake brands + agoricNames: { brand: { FastLP, USDC } }, marshaller, // @ts-expect-error ignore fancy return type readPublished: async (path: string) => { From fdcf70c8e3b660c1be86be85415c57616c0b69b6 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Wed, 11 Dec 2024 12:31:05 -0800 Subject: [PATCH 07/42] refactor: backwards-compat for wallet-utils --- packages/client-utils/src/main.js | 3 ++- packages/client-utils/src/wallet-utils.js | 8 ++++++++ .../test/snapshots/exports.test.js.md | 1 + .../test/snapshots/exports.test.js.snap | Bin 584 -> 595 bytes 4 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 packages/client-utils/src/wallet-utils.js diff --git a/packages/client-utils/src/main.js b/packages/client-utils/src/main.js index 6a07e21524d..decf0366b5b 100644 --- a/packages/client-utils/src/main.js +++ b/packages/client-utils/src/main.js @@ -1,10 +1,11 @@ export * from './cli.js'; export * from './network-config.js'; export * from './rpc.js'; +export * from './smart-wallet-kit.js'; export * from './sync-tools.js'; export * from './vstorage.js'; export * from './vstorage-kit.js'; -export * from './smart-wallet-kit.js'; +export * from './wallet-utils.js'; // eslint-disable-next-line import/export -- just types export * from './types.js'; diff --git a/packages/client-utils/src/wallet-utils.js b/packages/client-utils/src/wallet-utils.js new file mode 100644 index 00000000000..79f0d9edc96 --- /dev/null +++ b/packages/client-utils/src/wallet-utils.js @@ -0,0 +1,8 @@ +/** @file backwards compat */ + +import { makeSmartWalletKit } from './smart-wallet-kit.js'; + +/** @typedef {import('./smart-wallet-kit.js').SmartWalletKit} WalletUtils */ + +/** @deprecated use `makeSmartWalletKit` */ +export const makeWalletUtils = makeSmartWalletKit; diff --git a/packages/client-utils/test/snapshots/exports.test.js.md b/packages/client-utils/test/snapshots/exports.test.js.md index b07f3339908..1dc0f08ff90 100644 --- a/packages/client-utils/test/snapshots/exports.test.js.md +++ b/packages/client-utils/test/snapshots/exports.test.js.md @@ -21,6 +21,7 @@ Generated by [AVA](https://avajs.dev). 'makeTendermint34Client', 'makeVStorage', 'makeVstorageKit', + 'makeWalletUtils', 'pickEndpoint', 'retryUntilCondition', 'sleep', diff --git a/packages/client-utils/test/snapshots/exports.test.js.snap b/packages/client-utils/test/snapshots/exports.test.js.snap index f255f686a3eba350ed02283cba31f10e7276eb2a..f44f9a7329c1cab116a8704c6c1e1fc26c82114b 100644 GIT binary patch literal 595 zcmV-Z0<8T(RzVdt zA$2USWU6_R4h^N(H*w5~pRchH8^|7(XHPx=_z2(@zz+a_06b$rg8_X8yko!@27F_{ zZw8bDpc(+(07wJiQvlos!1n<76##`0sD?l<1m1_h*AVy_0%f*dV!4{Ne8!l2D;A4j zn_vfE1(aEU3Jbwke#X zplQwcFe}c*8~%6*;LmmXLg*)lQ~VIrKIe~cgZE))m4ik zGttzX=ver5Rh&EUu5L709?=VtC^K8oUH> hx;S;;;flxYeqY$em86Aw{2w*H_%HUD%Uml2003jT9IpTX literal 584 zcmV-O0=NA^RzVBQ{Sa zH8k_OL?4R?00000000AZ(lKunF%$>zzwbyJO3F1&+EO9D0}@Q#LP(%$Nu-7rb*h{@ zC$Zw#C*MojjM)$a;wu!10kQKP82Sy^nOT_8HMNsSaFcca-}ya1-*vC6OgzkHp9M)$ zLP(v6E17AYW&=an>^ey}@$>L!h;`%-E3*Cf06qfv2H*z39{^7nP-8%s0W$`CVZaXt z{ANHD08ay;6#!WPdgd=G&NTPw3d&00QX%&np*0^0z4 z1Xe56OH&#)cVHCxWz{zb70MZ%^WnX z8NJAxbMd;bk;k18xAZRWm5wAiQ(QH~ZJ(2FzZjE4=Kq(&|_-*jok3bNBvO;Xj3P9#aA9eU_cAyY!6 z?seqnbXWDYQ0d~zw)_mptX#yYRnC;1DUvx! Date: Tue, 10 Dec 2024 17:20:00 -0800 Subject: [PATCH 08/42] test: replace rpc.js with client-utils --- .../proposals/z:acceptance/test-lib/rpc.js | 272 ------------------ .../proposals/z:acceptance/test-lib/utils.js | 11 +- .../proposals/z:acceptance/test-lib/wallet.js | 4 +- 3 files changed, 8 insertions(+), 279 deletions(-) delete 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 deleted file mode 100644 index 2a25b534911..00000000000 --- a/a3p-integration/proposals/z:acceptance/test-lib/rpc.js +++ /dev/null @@ -1,272 +0,0 @@ -/** @file copied from packages/agoric-cli */ -// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109 -// @ts-check -/* global Buffer */ - -import { - boardSlottingMarshaller, - makeBoardRemote, -} from '@agoric/internal/src/marshal.js'; -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 }} MinimalNetworkConfig - */ - -/** @type {MinimalNetworkConfig} */ -const networkConfig = { - rpcAddrs: ['http://0.0.0.0:26657'], - chainName: 'agoriclocal', -}; -export { networkConfig }; -// console.warn('networkConfig', networkConfig); - -/** - * @param {object} powers - * @param {typeof window.fetch} powers.fetch - * @param {MinimalNetworkConfig} config - */ -export const makeVStorage = ({ fetch }, config = networkConfig) => { - /** @param {string} path */ - const getJSON = path => { - const url = config.rpcAddrs[0] + path; - // console.warn('fetching', url); - return fetch(url, { keepalive: true }).then(res => res.json()); - }; - // height=0 is the same as omitting height and implies the highest block - const url = (path = 'published', { kind = 'children', height = 0 } = {}) => - `/abci_query?path=%22/custom/vstorage/${kind}/${path}%22&height=${height}`; - - const readStorage = (path = 'published', { kind = 'children', height = 0 }) => - getJSON(url(path, { kind, height })) - .catch(err => { - throw Error(`cannot read ${kind} of ${path}: ${err.message}`); - }) - .then(data => { - const { - result: { response }, - } = data; - if (response?.code !== 0) { - /** @type {any} */ - const err = Error( - `error code ${response?.code} reading ${kind} of ${path}: ${response.log}`, - ); - err.code = response?.code; - err.codespace = response?.codespace; - throw err; - } - return data; - }); - - return { - url, - /** @param {{ result: { response: { code: number, value: string } } }} rawResponse */ - decode({ result: { response } }) { - const { code } = response; - if (code !== 0) { - throw response; - } - const { value } = response; - return Buffer.from(value, 'base64').toString(); - }, - /** - * - * @param {string} path - * @returns {Promise} latest vstorage value at path - */ - async readLatest(path = 'published') { - const raw = await readStorage(path, { kind: 'data' }); - return this.decode(raw); - }, - async keys(path = 'published') { - const raw = await readStorage(path, { kind: 'children' }); - return JSON.parse(this.decode(raw)).children; - }, - /** - * @param {string} path - * @param {number} [height] default is highest - * @returns {Promise<{blockHeight: number, values: string[]}>} - */ - async readAt(path, height = undefined) { - const raw = await readStorage(path, { kind: 'data', height }); - const txt = this.decode(raw); - /** @type {{ value: string }} */ - const { value } = JSON.parse(txt); - return JSON.parse(value); - }, - /** - * Read values going back as far as available - * - * @param {string} path - * @param {number | string} [minHeight] - * @returns {Promise} - */ - async readFully(path, minHeight = undefined) { - const parts = []; - // undefined the first iteration, to query at the highest - let blockHeight; - await null; - do { - // console.debug('READING', { blockHeight }); - let values; - try { - ({ blockHeight, values } = await this.readAt( - path, - blockHeight && Number(blockHeight) - 1, - )); - // console.debug('readAt returned', { blockHeight }); - } catch (err) { - if ( - // CosmosSDK ErrNotFound; there is no data at the path - (err.codespace === 'sdk' && err.code === 38) || - // CosmosSDK ErrUnknownRequest; misrepresentation of the same until - // https://github.com/Agoric/agoric-sdk/commit/dafc7c1708977aaa55e245dc09a73859cf1df192 - // TODO remove after upgrade-12 - err.message.match(/unknown request/) - ) { - // console.error(err); - break; - } - throw err; - } - parts.push(values); - // console.debug('PUSHED', values); - // console.debug('NEW', { blockHeight, minHeight }); - if (minHeight && Number(blockHeight) <= Number(minHeight)) break; - } while (blockHeight > 0); - return parts.flat(); - }, - }; -}; -/** @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 = { - /** @param { string } txt */ - parseCapData: txt => { - assert(typeof txt === 'string', typeof txt); - /** @type {{ value: string }} */ - const { value } = JSON.parse(txt); - 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 vstorage = makeVStorage({ fetch }, config); - 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 */ diff --git a/a3p-integration/proposals/z:acceptance/test-lib/utils.js b/a3p-integration/proposals/z:acceptance/test-lib/utils.js index c4cc3316128..0826daa3660 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/utils.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/utils.js @@ -1,10 +1,13 @@ /* eslint-env node */ -import { makeStargateClient, makeVstorageKit } from '@agoric/client-utils'; +import { + LOCAL_CONFIG, + makeStargateClient, + makeVstorageKit, +} from '@agoric/client-utils'; import { readFile, writeFile } from 'node:fs/promises'; -import { networkConfig } from './rpc.js'; -export const stargateClientP = makeStargateClient(networkConfig, { fetch }); -export const vstorageKit = makeVstorageKit({ fetch }, networkConfig); +export const stargateClientP = makeStargateClient(LOCAL_CONFIG, { fetch }); +export const vstorageKit = makeVstorageKit({ fetch }, LOCAL_CONFIG); /** * @import {WalletUtils} from '@agoric/client-utils'; diff --git a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js index 11813654bbc..d19d09d0012 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js @@ -11,7 +11,7 @@ import { makeTimerUtils } from './utils.js'; * * @throws { Error & { code: number } } if transaction fails * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction - * @param {import('./rpc.js').MinimalNetworkConfig & { + * @param {import('@agoric/client-utils').MinimalNetworkConfig & { * from: string, * marshaller: Pick, 'toCapData'>, * fees?: string, @@ -25,7 +25,6 @@ import { makeTimerUtils } from './utils.js'; */ export const sendAction = async (bridgeAction, opts) => { const { marshaller } = opts; - // @ts-expect-error BridgeAction has methods disallowed by Passable const offerBody = JSON.stringify(marshaller.toCapData(harden(bridgeAction))); // tryExit should not require --allow-spend @@ -81,7 +80,6 @@ export const makeAgdWalletUtils = async ( delay, execFileSync, from, - // @ts-expect-error version skew in @endo/marshal and/or @endo/pass-style marshaller, keyring: { backend: 'test' }, }); From 36a986b81cdf6226f55766131f0211b44818c930 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 Dec 2024 18:00:35 -0800 Subject: [PATCH 09/42] test: DRYer z:acceptance test-lib --- .../proposals/z:acceptance/psm.test.js | 2 +- .../proposals/z:acceptance/test-lib/chain.js | 140 ------------------ .../proposals/z:acceptance/test-lib/errors.js | 20 --- .../proposals/z:acceptance/test-lib/index.js | 7 +- .../proposals/z:acceptance/test-lib/kread.js | 1 + .../z:acceptance/test-lib/psm-lib.js | 2 +- 6 files changed, 5 insertions(+), 167 deletions(-) delete mode 100644 a3p-integration/proposals/z:acceptance/test-lib/chain.js delete mode 100644 a3p-integration/proposals/z:acceptance/test-lib/errors.js diff --git a/a3p-integration/proposals/z:acceptance/psm.test.js b/a3p-integration/proposals/z:acceptance/psm.test.js index 8496cc1d3b3..ae176ec51c8 100644 --- a/a3p-integration/proposals/z:acceptance/psm.test.js +++ b/a3p-integration/proposals/z:acceptance/psm.test.js @@ -21,7 +21,7 @@ import { } from '@agoric/synthetic-chain'; import { waitUntilAccountFunded } from '@agoric/client-utils'; import test from 'ava'; -import { NonNullish } from './test-lib/errors.js'; +import { NonNullish } from '@agoric/internal/src/errors.js'; import { adjustBalancesIfNotProvisioned, bankSend, diff --git a/a3p-integration/proposals/z:acceptance/test-lib/chain.js b/a3p-integration/proposals/z:acceptance/test-lib/chain.js deleted file mode 100644 index 74cc0d3c14f..00000000000 --- a/a3p-integration/proposals/z:acceptance/test-lib/chain.js +++ /dev/null @@ -1,140 +0,0 @@ -/** @file copied from packages/agoric-cli */ -// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109 -// @ts-check -/* global process */ - -const agdBinary = 'agd'; - -/** - * @param {ReadonlyArray} swingsetArgs - * @param {import('./rpc.js').MinimalNetworkConfig & { - * from: string, - * fees?: string, - * dryRun?: boolean, - * verbose?: boolean, - * keyring?: {home?: string, backend: string} - * stdout?: Pick - * execFileSync: typeof import('child_process').execFileSync - * }} opts - */ -export const execSwingsetTransaction = (swingsetArgs, opts) => { - const { - from, - fees, - dryRun = false, - verbose = true, - keyring = undefined, - chainName, - rpcAddrs, - stdout = process.stdout, - execFileSync, - } = opts; - const homeOpt = keyring?.home ? [`--home=${keyring.home}`] : []; - const backendOpt = keyring?.backend - ? [`--keyring-backend=${keyring.backend}`] - : []; - const feeOpt = fees ? ['--fees', fees] : []; - const cmd = [`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`].concat( - homeOpt, - backendOpt, - feeOpt, - [`--from=${from}`, 'tx', 'swingset'], - swingsetArgs, - ); - - if (dryRun) { - stdout.write(`Run this interactive command in shell:\n\n`); - stdout.write(`${agdBinary} `); - stdout.write(cmd.join(' ')); - stdout.write('\n'); - } else { - const yesCmd = cmd.concat(['--yes']); - if (verbose) console.log('Executing ', agdBinary, yesCmd); - const out = execFileSync(agdBinary, yesCmd, { encoding: 'utf-8' }); - - // agd puts this diagnostic on stdout rather than stderr :-/ - // "Default sign-mode 'direct' not supported by Ledger, using sign-mode 'amino-json'. - if (out.startsWith('Default sign-mode')) { - const stripDiagnostic = out.replace(/^Default[^\n]+\n/, ''); - return stripDiagnostic; - } - return out; - } -}; -harden(execSwingsetTransaction); - -/** - * @param {import('./rpc.js').MinimalNetworkConfig & { - * execFileSync: typeof import('child_process').execFileSync, - * delay: (ms: number) => Promise, - * period?: number, - * retryMessage?: string, - * }} opts - * @returns {(l: (b: { time: string, height: string }) => Promise) => Promise} - */ -export const pollBlocks = opts => async lookup => { - const { execFileSync, delay, rpcAddrs, period = 3 * 1000 } = opts; - assert(execFileSync, 'missing execFileSync'); - const { retryMessage } = opts; - - const nodeArgs = [`--node=${rpcAddrs[0]}`]; - - await null; // separate sync prologue - - for (;;) { - const sTxt = execFileSync(agdBinary, ['status', ...nodeArgs]); - const status = JSON.parse(sTxt.toString()); - const { - SyncInfo: { latest_block_time: time, latest_block_height: height }, - } = status; - try { - // see await null above - const result = await lookup({ time, height }); - return result; - } catch (_err) { - console.error( - time, - retryMessage || 'not in block', - height, - 'retrying...', - ); - await delay(period); - } - } -}; - -/** - * @param {string} txhash - * @param {import('./rpc.js').MinimalNetworkConfig & { - * execFileSync: typeof import('child_process').execFileSync, - * delay: (ms: number) => Promise, - * period?: number, - * }} opts - */ -export const pollTx = async (txhash, opts) => { - const { execFileSync, rpcAddrs, chainName } = opts; - assert(execFileSync, 'missing execFileSync in pollTx'); - - const nodeArgs = [`--node=${rpcAddrs[0]}`]; - const outJson = ['--output', 'json']; - - const lookup = async () => { - const out = execFileSync( - agdBinary, - [ - 'query', - 'tx', - txhash, - `--chain-id=${chainName}`, - ...nodeArgs, - ...outJson, - ], - { stdio: ['ignore', 'pipe', 'ignore'] }, - ); - // XXX this type is defined in a .proto file somewhere - /** @type {{ height: string, txhash: string, code: number, timestamp: string }} */ - const info = JSON.parse(out.toString()); - return info; - }; - return pollBlocks({ ...opts, retryMessage: 'tx not in block' })(lookup); -}; diff --git a/a3p-integration/proposals/z:acceptance/test-lib/errors.js b/a3p-integration/proposals/z:acceptance/test-lib/errors.js deleted file mode 100644 index 57dc771e6a5..00000000000 --- a/a3p-integration/proposals/z:acceptance/test-lib/errors.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @file Copied from "@agoric/internal" - */ - -import { q } from '@endo/errors'; - -/** - * @template T - * @param {T | null | undefined} val - * @param {string} [optDetails] - * @returns {T} - */ -export const NonNullish = (val, optDetails = `unexpected ${q(val)}`) => { - if (val != null) { - // This `!= null` idiom checks that `val` is neither `null` nor `undefined`. - return val; - } - assert.fail(optDetails); -}; -harden(NonNullish); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/index.js b/a3p-integration/proposals/z:acceptance/test-lib/index.js index 479d81503fc..82e2f302020 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/index.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/index.js @@ -1,12 +1,9 @@ /* eslint-env node */ -import { makeWalletUtils } from '@agoric/client-utils'; +import { makeWalletUtils, LOCAL_CONFIG } from '@agoric/client-utils'; import { execFileSync } from 'child_process'; import { makeAgdWalletUtils } from './wallet.js'; -export const networkConfig = { - rpcAddrs: ['http://0.0.0.0:26657'], - chainName: 'agoriclocal', -}; +export const networkConfig = LOCAL_CONFIG; /** * Resolve after a delay in milliseconds. diff --git a/a3p-integration/proposals/z:acceptance/test-lib/kread.js b/a3p-integration/proposals/z:acceptance/test-lib/kread.js index 01cd0d29b5f..1bb58b3eef1 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/kread.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/kread.js @@ -1,4 +1,5 @@ // @ts-nocheck FIXME +// XXX uses agoric.follow to read data through spawned processes; replace with VstorageKit import assert from 'node:assert'; import { 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 7b5beceb1d1..74763e6f401 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/psm-lib.js @@ -26,7 +26,7 @@ import { VALIDATORADDR, } from '@agoric/synthetic-chain'; import fsp from 'node:fs/promises'; -import { NonNullish } from './errors.js'; +import { NonNullish } from '@agoric/internal/src/errors.js'; import { getBalances } from './utils.js'; /** @import {Result as ExecaResult, ExecaError} from 'execa'; */ From 501be3a9d0d91cbb74d5d24f3436197350b7180e Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Tue, 10 Dec 2024 17:27:42 -0800 Subject: [PATCH 10/42] test: base makeAgdWalletUtils on SmartWalletKit --- .../proposals/s:stake-bld/stakeBld.test.js | 11 ++-- .../proposals/s:stake-bld/test-lib/index.js | 15 +++-- .../proposals/s:stake-bld/test-lib/wallet.js | 24 +++---- .../proposals/z:acceptance/test-lib/index.js | 10 +-- .../proposals/z:acceptance/test-lib/vaults.js | 4 +- .../proposals/z:acceptance/test-lib/wallet.js | 64 ++----------------- .../proposals/z:acceptance/valueVow.test.js | 8 ++- .../proposals/z:acceptance/vaults.test.js | 20 +++--- 8 files changed, 56 insertions(+), 100 deletions(-) diff --git a/a3p-integration/proposals/s:stake-bld/stakeBld.test.js b/a3p-integration/proposals/s:stake-bld/stakeBld.test.js index 549e4562545..13836f6cf3d 100644 --- a/a3p-integration/proposals/s:stake-bld/stakeBld.test.js +++ b/a3p-integration/proposals/s:stake-bld/stakeBld.test.js @@ -8,7 +8,7 @@ import { GOV1ADDR } from '@agoric/synthetic-chain'; import { Tendermint34Client } from '@cosmjs/tendermint-rpc'; import assert from 'node:assert'; import process from 'node:process'; -import { networkConfig, walletUtils } from './test-lib/index.js'; +import { networkConfig, agdWalletUtils } from './test-lib/index.js'; // XXX not the same as VALIDATOR_ADDRESS, which is actually the delegator const VALIDATOR_ADDRESS = process.env.VALIDATOR_ADDRESS; @@ -26,14 +26,15 @@ const currentDelegation = async () => { test('basic', async t => { assert(GOV1ADDR); - const { brand } = walletUtils.agoricNames; + const { brand } = agdWalletUtils.agoricNames; t.is((await currentDelegation()).length, 1, 'just the initial delegation'); /** @type {import('@agoric/ertp').Brand} */ + // @ts-expect-error actually a BoardRemote const BLDBrand = brand.BLD; - await walletUtils.broadcastBridgeAction(GOV1ADDR, { + await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, { method: 'executeOffer', offer: { id: 'request-stake', @@ -50,7 +51,7 @@ test('basic', async t => { }, }); - await walletUtils.broadcastBridgeAction(GOV1ADDR, { + await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, { method: 'executeOffer', offer: { id: 'request-delegate-6', @@ -75,7 +76,7 @@ test('basic', async t => { // omit 'delegation' because it has 'delegatorAddress' which is different every test run }); - await walletUtils.broadcastBridgeAction(GOV1ADDR, { + await agdWalletUtils.broadcastBridgeAction(GOV1ADDR, { method: 'executeOffer', offer: { id: 'request-undelegate', diff --git a/a3p-integration/proposals/s:stake-bld/test-lib/index.js b/a3p-integration/proposals/s:stake-bld/test-lib/index.js index 9c22b218e19..b56da4836cc 100644 --- a/a3p-integration/proposals/s:stake-bld/test-lib/index.js +++ b/a3p-integration/proposals/s:stake-bld/test-lib/index.js @@ -1,9 +1,9 @@ /* eslint-env node */ +import { makeSmartWalletKit, LOCAL_CONFIG } from '@agoric/client-utils'; import { execFileSync } from 'child_process'; -import { LOCAL_CONFIG as networkConfig } from '@agoric/client-utils'; -import { makeWalletUtils } from './wallet.js'; +import { makeAgdWalletKit } from './wallet.js'; -export { networkConfig }; +export const networkConfig = LOCAL_CONFIG; /** * Resolve after a delay in milliseconds. @@ -13,7 +13,12 @@ export { networkConfig }; */ const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms)); -export const walletUtils = await makeWalletUtils( - { execFileSync, delay, fetch }, +export const smartWalletKit = await makeSmartWalletKit( + { delay, fetch }, + networkConfig, +); + +export const agdWalletUtils = await makeAgdWalletKit( + { execFileSync, smartWalletKit, delay }, networkConfig, ); diff --git a/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js b/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js index e3ef23af929..fa8e8ca5112 100644 --- a/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js +++ b/a3p-integration/proposals/s:stake-bld/test-lib/wallet.js @@ -1,16 +1,21 @@ // @ts-check -import { makeVstorageKit } from '@agoric/client-utils'; import { sendAction } from 'agoric/src/lib/index.js'; import { inspect } from 'util'; -export const makeWalletUtils = async ( - { delay, execFileSync, fetch }, +/** + * Stop-gap using execFileSync until we have a pure JS signing client. + * + * @param {object} root0 + * @param {import('child_process')['execFileSync']} root0.execFileSync + * @param {import('@agoric/client-utils').SmartWalletKit} root0.smartWalletKit + * @param {any} root0.delay + * @param {import('@agoric/client-utils').MinimalNetworkConfig} networkConfig + */ +export const makeAgdWalletKit = async ( + { execFileSync, smartWalletKit, delay }, networkConfig, ) => { - const { agoricNames, fromBoard, marshaller, readLatestHead, vstorage } = - await makeVstorageKit({ fetch }, networkConfig); - /** * * @param {string} from @@ -23,17 +28,12 @@ export const makeWalletUtils = async ( delay, execFileSync, from, - marshaller, keyring: { backend: 'test' }, }); }; return { - agoricNames, + ...smartWalletKit, broadcastBridgeAction, - fromBoard, - networkConfig, - readLatestHead, - vstorage, }; }; diff --git a/a3p-integration/proposals/z:acceptance/test-lib/index.js b/a3p-integration/proposals/z:acceptance/test-lib/index.js index 82e2f302020..b56da4836cc 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/index.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/index.js @@ -1,7 +1,7 @@ /* eslint-env node */ -import { makeWalletUtils, LOCAL_CONFIG } from '@agoric/client-utils'; +import { makeSmartWalletKit, LOCAL_CONFIG } from '@agoric/client-utils'; import { execFileSync } from 'child_process'; -import { makeAgdWalletUtils } from './wallet.js'; +import { makeAgdWalletKit } from './wallet.js'; export const networkConfig = LOCAL_CONFIG; @@ -13,12 +13,12 @@ export const networkConfig = LOCAL_CONFIG; */ const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms)); -export const walletUtils = await makeWalletUtils( +export const smartWalletKit = await makeSmartWalletKit( { delay, fetch }, networkConfig, ); -export const agdWalletUtils = await makeAgdWalletUtils( - { execFileSync, setTimeout, walletUtils }, +export const agdWalletUtils = await makeAgdWalletKit( + { execFileSync, smartWalletKit, delay }, networkConfig, ); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js index a7604622a3f..1dabb741e95 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/vaults.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/vaults.js @@ -14,7 +14,7 @@ import { ceilMultiplyBy, makeRatio, } from '@agoric/zoe/src/contractSupport/ratio.js'; -import { walletUtils } from './index.js'; +import { smartWalletKit } from './index.js'; import { listVaults, vstorageKit } from './utils.js'; /** @@ -22,7 +22,7 @@ import { listVaults, vstorageKit } from './utils.js'; * @returns {Promise<{ vaultID: string, debt: bigint, collateral: bigint, state: string }>} */ export const getLastVaultFromAddress = async address => { - const activeVaults = await listVaults(address, walletUtils); + const activeVaults = await listVaults(address, smartWalletKit); const vaultPath = activeVaults[activeVaults.length - 1]; const vaultID = vaultPath.split('.').pop(); diff --git a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js index d19d09d0012..fa8e8ca5112 100644 --- a/a3p-integration/proposals/z:acceptance/test-lib/wallet.js +++ b/a3p-integration/proposals/z:acceptance/test-lib/wallet.js @@ -1,73 +1,21 @@ -// TODO DRY in https://github.com/Agoric/agoric-sdk/issues/9109 // @ts-check -/* global */ +import { sendAction } from 'agoric/src/lib/index.js'; import { inspect } from 'util'; -import { execSwingsetTransaction, pollTx } from './chain.js'; -import { makeTimerUtils } from './utils.js'; - -/** - * Sign and broadcast a wallet-action. - * - * @throws { Error & { code: number } } if transaction fails - * @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction - * @param {import('@agoric/client-utils').MinimalNetworkConfig & { - * from: string, - * marshaller: Pick, 'toCapData'>, - * fees?: string, - * verbose?: boolean, - * keyring?: {home?: string, backend: string}, - * stdout?: Pick, - * execFileSync: typeof import('child_process').execFileSync, - * delay: (ms: number) => Promise, - * dryRun?: boolean, - * }} opts - */ -export const sendAction = async (bridgeAction, opts) => { - const { marshaller } = opts; - const offerBody = JSON.stringify(marshaller.toCapData(harden(bridgeAction))); - - // tryExit should not require --allow-spend - // https://github.com/Agoric/agoric-sdk/issues/7291 - const spendMethods = ['executeOffer', 'tryExitOffer']; - const spendArg = spendMethods.includes(bridgeAction.method) - ? ['--allow-spend'] - : []; - - const act = ['wallet-action', ...spendArg, offerBody]; - const out = execSwingsetTransaction([...act, '--output', 'json'], opts); - if (opts.dryRun) { - return; - } - - assert(out); // not dry run - const tx = JSON.parse(out); - if (tx.code !== 0) { - const err = Error(`failed to send tx: ${tx.raw_log} code: ${tx.code}`); - // @ts-expect-error XXX how to add properties to an error? - err.code = tx.code; - throw err; - } - - return pollTx(tx.txhash, opts); -}; /** * Stop-gap using execFileSync until we have a pure JS signing client. * * @param {object} root0 - * @param {import('@agoric/client-utils').WalletUtils} root0.walletUtils * @param {import('child_process')['execFileSync']} root0.execFileSync - * @param {typeof setTimeout} root0.setTimeout + * @param {import('@agoric/client-utils').SmartWalletKit} root0.smartWalletKit + * @param {any} root0.delay * @param {import('@agoric/client-utils').MinimalNetworkConfig} networkConfig */ -export const makeAgdWalletUtils = async ( - { execFileSync, walletUtils, setTimeout }, +export const makeAgdWalletKit = async ( + { execFileSync, smartWalletKit, delay }, networkConfig, ) => { - const { marshaller } = walletUtils; - - const { delay } = await makeTimerUtils({ setTimeout }); /** * * @param {string} from @@ -80,12 +28,12 @@ export const makeAgdWalletUtils = async ( delay, execFileSync, from, - marshaller, keyring: { backend: 'test' }, }); }; return { + ...smartWalletKit, broadcastBridgeAction, }; }; diff --git a/a3p-integration/proposals/z:acceptance/valueVow.test.js b/a3p-integration/proposals/z:acceptance/valueVow.test.js index 7e62e16420d..8490351eb58 100644 --- a/a3p-integration/proposals/z:acceptance/valueVow.test.js +++ b/a3p-integration/proposals/z:acceptance/valueVow.test.js @@ -10,7 +10,7 @@ import { GOV1ADDR as GETTER, // not particular to governance, just a handy wallet GOV2ADDR as SETTER, } from '@agoric/synthetic-chain'; -import { agdWalletUtils, walletUtils } from './test-lib/index.js'; +import { agdWalletUtils } from './test-lib/index.js'; const START_VALUEVOW_DIR = 'start-valueVow'; const RESTART_VALUEVOW_DIR = 'restart-valueVow'; @@ -37,7 +37,7 @@ test('vow survives restart', async t => { t.log('confirm the value is not in offer results'); let getterStatus = await retryUntilCondition( /** @type {() => Promise} */ - async () => walletUtils.readLatestHead(`published.wallet.${GETTER}`), + async () => agdWalletUtils.readLatestHead(`published.wallet.${GETTER}`), value => value.status.id === 'get-value' && value.updated === 'offerStatus', 'Offer get-value not succeeded', { @@ -79,7 +79,9 @@ test('vow survives restart', async t => { }); t.log('confirm the value is now in offer results'); - getterStatus = await walletUtils.readLatestHead(`published.wallet.${GETTER}`); + getterStatus = await agdWalletUtils.readLatestHead( + `published.wallet.${GETTER}`, + ); t.like(getterStatus, { status: { result: offerArgs.value } }); }); diff --git a/a3p-integration/proposals/z:acceptance/vaults.test.js b/a3p-integration/proposals/z:acceptance/vaults.test.js index 62086e7ad68..d99c8fe45e1 100644 --- a/a3p-integration/proposals/z:acceptance/vaults.test.js +++ b/a3p-integration/proposals/z:acceptance/vaults.test.js @@ -17,7 +17,7 @@ import { openVault, USER1ADDR, } from '@agoric/synthetic-chain'; -import { agdWalletUtils, walletUtils } from './test-lib/index.js'; +import { agdWalletUtils } from './test-lib/index.js'; import { getPriceFeedRoundId, verifyPushedPrice, @@ -55,7 +55,7 @@ const exec = { offerId = `openVault-${Date.now()}`, collateralBrandKey = 'ATOM', ) => { - const offer = Offers.vaults.OpenVault(walletUtils.agoricNames, { + const offer = Offers.vaults.OpenVault(agdWalletUtils.agoricNames, { giveCollateral, wantMinted, offerId, @@ -73,14 +73,14 @@ test.serial('open new vault', async t => { await bankSend(USER1ADDR, `20000000${ATOM_DENOM}`); const istBalanceBefore = await getISTBalance(USER1ADDR); - const activeVaultsBefore = await listVaults(USER1ADDR, walletUtils); + const activeVaultsBefore = await listVaults(USER1ADDR, agdWalletUtils); const mint = 5.0; const collateral = 10.0; await exec.vaults.OpenVault(USER1ADDR, mint, collateral); const istBalanceAfter = await getISTBalance(USER1ADDR); - const activeVaultsAfter = await listVaults(USER1ADDR, walletUtils); + const activeVaultsAfter = await listVaults(USER1ADDR, agdWalletUtils); await tryISTBalances( t, @@ -178,7 +178,7 @@ test.serial( 'user cannot open a vault under the minimum initial debt', async t => { await bankSend(GOV1ADDR, `200000000000000000${ATOM_DENOM}`); - const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils); const minInitialDebt = await getMinInitialDebt(); @@ -192,7 +192,7 @@ test.serial( }, ); - const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils); t.is( activeVaultsAfter.length, @@ -203,7 +203,7 @@ test.serial( ); test.serial('user cannot open a vault above debt limit', async t => { - const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils); const { availableDebtForMint } = await getAvailableDebtForMint(VAULT_MANAGER); @@ -217,7 +217,7 @@ test.serial('user cannot open a vault above debt limit', async t => { }, ); - const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils); t.is( activeVaultsAfter.length, @@ -228,7 +228,7 @@ test.serial('user cannot open a vault above debt limit', async t => { test.serial('user can open a vault under debt limit', async t => { const istBalanceBefore = await getISTBalance(GOV1ADDR); - const activeVaultsBefore = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsBefore = await listVaults(GOV1ADDR, agdWalletUtils); const { availableDebtForMint } = await getAvailableDebtForMint(VAULT_MANAGER); @@ -238,7 +238,7 @@ test.serial('user can open a vault under debt limit', async t => { await openVault(GOV1ADDR, mint.toString(), collateral.toString()); const istBalanceAfter = await getISTBalance(GOV1ADDR); - const activeVaultsAfter = await listVaults(GOV1ADDR, walletUtils); + const activeVaultsAfter = await listVaults(GOV1ADDR, agdWalletUtils); await tryISTBalances( t, From 8955990242b0df621ab6fc6056dfb5b1cd3c5e25 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 11 Dec 2024 19:48:59 -0500 Subject: [PATCH 11/42] chore: `ChainPolicy` schema - rename `nobleContractAddress` to `attenuatedCttpBridgeAddress` - include jsdoc comments for `ChainPolicy` type - removed `chainType` from `ChainPolicy`. unused and should have been an enum. not needed for OCW currently --- .../fast-usdc/snapshots/fast-usdc.test.ts.md | 2 +- .../snapshots/fast-usdc.test.ts.snap | Bin 2150 -> 2198 bytes packages/fast-usdc/src/type-guards.js | 19 ++++++++---------- packages/fast-usdc/src/types.ts | 9 ++++++--- packages/fast-usdc/src/utils/deploy-config.js | 10 +++++---- 5 files changed, 21 insertions(+), 19 deletions(-) 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 4b19508a1d9..f27a41da2c4 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 @@ -17,10 +17,10 @@ Generated by [AVA](https://avajs.dev). { chainPolicies: { Arbitrum: { + attenuatedCttpBridgeAddress: '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347', cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', chainId: 42161, confirmations: 2, - nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', }, }, nobleAgoricChannelId: 'channel-21', 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 0245ac610536e1cb1eb05b4dcbb3488a31497b0d..4647d12715fa8bbddbe4a9e3641aa8f369ea9e3a 100644 GIT binary patch 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$ zTcgM2TxIu zR}M@FWgm+O00000000BsSZ$0OM;U%*cYWvha?Kq{k&0+Katck*eR%KUJ10dbuCFOk z(=^Rj`8WvU-SK&I>m9Q*zT7E9BB1`_2ci;Hq5L3e5E4>%V%zI|8L+yn3MH@Ia9yU@$BkD_j3fGyG%;oXECAR`#->TC z7=~<%koMD_J$pbhAOvKBkPo+=Ob%cjz}FIvM$*v$*^Rx#z&>Jvq^8OJ^+wtEWR<&f z6(-er={j>!=BIVyx|^F(CnV~}`Za*x0eA<%JZbec_GI}IcN8%@k5f}qAd`r?xQCE) z1fA|CohtJJ9o*v*WKWb#+qf?fWuF(pXaZOUZ*Z9u{3UiK>{s*pwNGxCs5mDd;*75x^i zM%u|YY6|&WCUcf^%6utkS+LNhH5SS$^L;N^qmBqRc%Z9F4_;J)vU;7f@ZzDlHXGc( z%?4C|g|)$CVEz7%k-_sLlfnD@lR-)6t$TT~!v(3=0K5s{UjU{EFgu(NEWOSikFB%a zPHVoMVTx<(M$Bqee5Q2k^;qjfjcs0Fp~uR8)8*&!fEz7KGhmvS|0KXI0=zG|XcIh; zCT89M9yWk8NocwU+Ax4C2JmbWx~m8JeFONR0lblfW_k)_=<)o+hz-`|fv9-_QzFzx zYHk~M1&taHo2HKU<1s+09J0VoEcDa{^BY{hk=-O^=W@AR%>Sv;{KxaTTq45L=79Xa zutWZ7V!mVo-!p-qnS<#yP0YWTz~4+@+)6;lyP;DcW9|PmF+XSlGZs)vx=r--;99^X z3%Hhq?%v_6ebXALZiXE%*(;+tlZBY?FGuq=?XHjY+Yx)VLDJm?8Ji}1i@wj-xO=oo zzdB4${iFYuIQ-$=h(nWh257@Jr#3<@ZCVLBDsXoQzymD-s0-oK8dss`$iWhjx^TxN z;Oiqx!2UiG5T*V^GjrX~w>ly){uY3@0qi2c2MACiK!pI$3>SkjJ^gOPxOCy}ufRWMq|v{Am%YsDz9Z;o@`gq(^& zCN<==5PrwJ6{litKEvy5OX@1$G=T3Iz>kM3%UcHUwgH$)Y8&f;?l*x4P2k}qG}8n9 zgb94c1TH6`y>#}R34Ei)uY>3;P0U}J!0RUP*Ccdu2j;tHL<))1&k<{YR=Cy>t^4wA z^!(M^@O|Mne6Nr0o9>ar9SJv0%x_!3OBV2xA=;QG<{vHK&lZ5x;9blVNUGm|XHXBM zMpluI@9EKf(>>d>`#J@Q*6-PfC1ke_rCQqa#!&5v@!byU6KTx(vn6`c`)tE=J+&2e zO8KU^J2dCPmgX?W5sg4m);!GdA;L3OjR{Yx0N^74J__J0fKLw-Axn#c*9}c_(W9Xs{}er%diG6fkpPy+AeBlJvq*r)2=Ms?&`JWoM1Zdl;FSb$JPCY_0B;f? zV{`*ELk03Zy#lGnb+6GJZ9kubeMFV%YYw}@*7?a&v31vuerfl~zEE-m=iKPd#skKID_LJS%x`6zJ(`{O%Fb+EglgV%m_CXN-{;}1JugBx+K0_w zSlbScUwId6a&0wxRS&OqZ#dt+KeV$m z*^t+S;)yy`MSZ?2@viDb1NgtL%2hqHPWG8u=`M;K>*mrf+pYn&-7#BJinqwi!?bvy z{;rg0`}$}uLn)=FgyKhOA71-pb0HU<=EdfxX8M9!G|__Sh|#rUKd2Wd9@e<)F|{3) zvXIB5yu3w^HECjAgie*~J%A?y9eBfI^r6e1sy-PvJ)}E4s8{Ld93g8$9-57uXIoM} zyY8vEOR_oKyJ4>p*4R3iv>{!GGIt|7wDoK(KKA!JcA$NI1Qw=$n+jI(c z*;%r4`SMbZEi4{(mYsZ#IrehFUgBlP&F7bFcX4UStrW_Y#WK$ysZ ca;nO`kg82uWwOfU|8_(AAEU=jv>h7&0JuFVy#N3J diff --git a/packages/fast-usdc/src/type-guards.js b/packages/fast-usdc/src/type-guards.js index a645f90bae4..ebc50505267 100644 --- a/packages/fast-usdc/src/type-guards.js +++ b/packages/fast-usdc/src/type-guards.js @@ -94,16 +94,13 @@ export const PoolMetricsShape = { harden(PoolMetricsShape); /** @type {TypedPattern} */ -export const ChainPoliciesShape = M.splitRecord( - { - nobleContractAddress: EvmHashShape, - cctpTokenMessengerAddress: EvmHashShape, - confirmations: M.number(), - chainId: M.number(), - }, - { chainType: M.number() }, -); -harden(ChainPoliciesShape); +export const ChainPolicyShape = { + attenuatedCttpBridgeAddress: EvmHashShape, + cctpTokenMessengerAddress: EvmHashShape, + confirmations: M.number(), + chainId: M.number(), +}; +harden(ChainPolicyShape); /** * @type {TypedPattern} @@ -115,7 +112,7 @@ export const FeedPolicyShape = M.splitRecord( { nobleDomainId: M.number(), nobleAgoricChannelId: M.string(), - chainPolicies: M.recordOf(M.string(), ChainPoliciesShape), + chainPolicies: M.recordOf(M.string(), ChainPolicyShape), }, { eventFilter: M.string() }, ); diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index ee9a90efffd..eac08e8a5b5 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -58,11 +58,14 @@ export interface PoolMetrics extends PoolStats { } export interface ChainPolicy { - nobleContractAddress: EvmHash; + /** `msg.sender` of DepositAndBurn to TokenMessenger must be an attenuated wrapper contract that does not contain `replaceDepositForBurn` */ + attenuatedCttpBridgeAddress: EvmHash; + /** @see {@link https://developers.circle.com/stablecoins/evm-smart-contracts} */ cctpTokenMessengerAddress: EvmHash; - confirmations: number; + /** e.g., `1` for ETH mainnet 42161 for Arbitrum One. @see {@link https://chainlist.org/} */ chainId: EvmChainID; - chainType?: number; + /** the number of block confirmations to observe before reporting */ + confirmations: number; } export interface FeedPolicy { diff --git a/packages/fast-usdc/src/utils/deploy-config.js b/packages/fast-usdc/src/utils/deploy-config.js index 653d95ff293..7b160a7996c 100644 --- a/packages/fast-usdc/src/utils/deploy-config.js +++ b/packages/fast-usdc/src/utils/deploy-config.js @@ -64,11 +64,12 @@ export const configurations = { nobleDomainId: 4, chainPolicies: { Arbitrum: { + attenuatedCttpBridgeAddress: + '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347', cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', chainId: 42161, confirmations: 2, - nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', }, }, }, @@ -92,11 +93,12 @@ export const configurations = { nobleDomainId: 4, chainPolicies: { Arbitrum: { + attenuatedCttpBridgeAddress: + '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347', cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', chainId: 42161, confirmations: 2, - nobleContractAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', }, }, }, @@ -118,10 +120,10 @@ export const configurations = { nobleDomainId: 4, chainPolicies: { Arbitrum: { + attenuatedCttpBridgeAddress: '0xTODO', cctpTokenMessengerAddress: '0xTODO', chainId: 421614, confirmations: 2, - nobleContractAddress: '0xTODO', }, }, }, @@ -140,10 +142,10 @@ export const configurations = { nobleDomainId: 4, chainPolicies: { Arbitrum: { + attenuatedCttpBridgeAddress: '0xTODO', cctpTokenMessengerAddress: '0xTODO', chainId: 421614, confirmations: 2, - nobleContractAddress: '0xTODO', }, }, }, From 01a15d0bef4264dd898609ef96d3497a7a2a29e0 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 10 Dec 2024 22:28:26 +0000 Subject: [PATCH 12/42] test(a3p): add mintHolder upgrade test and helpers --- .../mint-payment/send-script-permit.json | 1 + .../p:upgrade-19/mint-payment/send-script.tjs | 56 +++++ .../proposals/p:upgrade-19/mintHolder.test.js | 32 +++ .../test-lib/mintHolder-helpers.js | 156 ++++++++++++++ .../p:upgrade-19/test-lib/psm-helpers.js | 192 ++++++++++++++++++ .../proposals/p:upgrade-19/test.sh | 2 +- 6 files changed, 438 insertions(+), 1 deletion(-) create mode 100644 a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json create mode 100644 a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs create mode 100644 a3p-integration/proposals/p:upgrade-19/mintHolder.test.js create mode 100644 a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js create mode 100644 a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js diff --git a/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json new file mode 100644 index 00000000000..27ba77ddaf6 --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script-permit.json @@ -0,0 +1 @@ +true diff --git a/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs new file mode 100644 index 00000000000..eb1a4815470 --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/mint-payment/send-script.tjs @@ -0,0 +1,56 @@ +/* global E */ + +/// +/// + +/** + * The primary purpose of this script is to mint a payment of a certain + * bankAsset and deposit in an user wallet. + * + * The receiverAddress and label placeholders should be replaced with + * the desired address and asset name during the execution of each test case. + * + * See z:acceptance/mintHolder.test.js + * + * @param {BootstrapPowers} powers + */ +const sendBankAsset = async powers => { + const { + consume: { namesByAddress, contractKits: contractKitsP }, + } = powers; + + const receiverAddress = '{{ADDRESS}}'; + const label = '{{LABEL}}'; + const valueStr = '{{VALUE}}'; + const value = BigInt(valueStr) + + console.log(`Start sendBankAsset for ${label}`); + + const contractKits = await contractKitsP; + const mintHolderKit = Array.from(contractKits.values()).filter( + kit => kit.label && kit.label === label, + ); + + const { creatorFacet: mint, publicFacet: issuer } = mintHolderKit[0]; + + /* + * Ensure that publicFacet holds an issuer by verifying that has + * the makeEmptyPurse method. + */ + await E(issuer).makeEmptyPurse() + + const brand = await E(issuer).getBrand(); + const amount = harden({ value, brand }); + const payment = await E(mint).mintPayment(amount); + + const receiverDepositFacet = E(namesByAddress).lookup( + receiverAddress, + 'depositFacet', + ); + + await E(receiverDepositFacet).receive(payment); + + console.log(`Finished sendBankAsset for ${label}`); +}; + +sendBankAsset; diff --git a/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js new file mode 100644 index 00000000000..b47a499411e --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js @@ -0,0 +1,32 @@ +/* eslint-env node */ + +import '@endo/init'; +import test from 'ava'; +import { addUser, provisionSmartWallet } from '@agoric/synthetic-chain'; +import { + mintPayment, + getAssetList, + swap, + getPSMChildren, + upgradeMintHolder, +} from './test-lib/mintHolder-helpers.js'; + +const networkConfig = { + rpcAddrs: ['http://0.0.0.0:26657'], + chainName: 'agoriclocal', +}; + +test('mintHolder contract is upgraded', async t => { + const receiver = await addUser('receiver'); + await provisionSmartWallet(receiver, `20000000ubld`); + + let assetList = await getAssetList(); + t.log('List of mintHolder vats being upgraded: ', assetList); + await upgradeMintHolder(`upgrade-mintHolder`, assetList); + await mintPayment(t, receiver, assetList, 10); + + const psmLabelList = await getPSMChildren(fetch, networkConfig); + assetList = await getAssetList(psmLabelList); + t.log('List of assets being swapped with IST via PSM: ', assetList); + await swap(t, receiver, assetList, 5); +}); diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js new file mode 100644 index 00000000000..131de77d30e --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js @@ -0,0 +1,156 @@ +/* eslint-env node */ + +import { + agoric, + evalBundles, + getDetailsMatchingVats, + getISTBalance, +} from '@agoric/synthetic-chain'; +import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils'; +import { readFile, writeFile } from 'node:fs/promises'; +import { sendOfferAgd, psmSwap, snapshotAgoricNames } from './psm-helpers.js'; + +/** + * @param {string} fileName base file name without .tjs extension + * @param {Record} replacements + */ +export const replaceTemplateValuesInFile = async (fileName, replacements) => { + let script = await readFile(`${fileName}.tjs`, 'utf-8'); + for (const [template, value] of Object.entries(replacements)) { + script = script.replaceAll(`{{${template}}}`, value); + } + await writeFile(`${fileName}.js`, script); +}; + +export const getPSMChildren = async (fetch, networkConfig) => { + const { + vstorage: { keys }, + } = await makeVstorageKit({ fetch }, networkConfig); + + const children = await keys('published.psm.IST'); + + return children; +}; + +export const getAssetList = async labelList => { + const assetList = []; + const { vbankAssets } = await snapshotAgoricNames(); + + // Determine the assets to consider based on labelList + const assetsToConsider = + labelList || Object.values(vbankAssets).map(asset => asset.issuerName); + + for (const label of assetsToConsider) { + if (label === 'IST') { + break; + } + + const vbankAsset = Object.values(vbankAssets).find( + asset => asset.issuerName === label, + ); + assert(vbankAsset, `vbankAsset not found for ${label}`); + + const { denom } = vbankAsset; + const mintHolderVat = `zcf-mintHolder-${label}`; + + assetList.push({ label, denom, mintHolderVat }); + } + + return assetList; +}; + +export const mintPayment = async (t, address, assetList, value) => { + const SUBMISSION_DIR = 'mint-payment'; + + for (const asset of assetList) { + const { label, denom } = asset; + const scaled = BigInt(parseInt(value, 10) * 1_000_000).toString(); + + await replaceTemplateValuesInFile(`${SUBMISSION_DIR}/send-script`, { + ADDRESS: address, + LABEL: label, + VALUE: scaled, + }); + + await evalBundles(SUBMISSION_DIR); + + const balance = await getISTBalance(address, denom); + + // Add to value the BLD provisioned to smart wallet + if (label === 'BLD') { + value += 10; + } + + t.is( + balance, + value, + `receiver ${denom} balance ${balance} is not ${value}`, + ); + } +}; + +export const swap = async (t, address, assetList, want) => { + for (const asset of assetList) { + const { label, denom } = asset; + + // TODO: remove condition after fixing issue #10655 + if (/^DAI/.test(label)) { + break; + } + + const pair = `IST.${label}`; + + const istBalanceBefore = await getISTBalance(address, 'uist'); + const anchorBalanceBefore = await getISTBalance(address, denom); + + await psmSwap(address, ['swap', '--pair', pair, '--wantMinted', want], { + now: Date.now, + follow: agoric.follow, + setTimeout, + sendOffer: sendOfferAgd, + }); + + const istBalanceAfter = await getISTBalance(address, 'uist'); + const anchorBalanceAfter = await getISTBalance(address, denom); + + t.is(istBalanceAfter, istBalanceBefore + want); + t.is(anchorBalanceAfter, anchorBalanceBefore - want); + } +}; + +const getIncarnationForAllVats = async assetList => { + const vatsIncarnation = {}; + + for (const asset of assetList) { + const { label, mintHolderVat } = asset; + const matchingVats = await getDetailsMatchingVats(label); + const expectedVat = matchingVats.find(vat => vat.vatName === mintHolderVat); + vatsIncarnation[label] = expectedVat.incarnation; + } + assert(Object.keys(vatsIncarnation).length === assetList.length); + + return vatsIncarnation; +}; + +const checkVatsUpgraded = (before, current) => { + for (const vatLabel in before) { + if (current[vatLabel] !== before[vatLabel] + 1) { + console.log(`${vatLabel} upgrade failed. `); + return false; + } + } + return true; +}; + +export const upgradeMintHolder = async (submissionPath, assetList) => { + const before = await getIncarnationForAllVats(assetList); + + await evalBundles(submissionPath); + + return retryUntilCondition( + async () => getIncarnationForAllVats(assetList), + current => checkVatsUpgraded(before, current), + `mintHolder upgrade not processed yet`, + { setTimeout, retryIntervalMs: 5000, maxRetries: 15 }, + ); +}; diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js new file mode 100644 index 00000000000..954e954941c --- /dev/null +++ b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js @@ -0,0 +1,192 @@ +/* eslint-env node */ + +import { execa } from 'execa'; +import { + boardSlottingMarshaller, + makeFromBoard, + waitUntilOfferResult, + fetchEnvNetworkConfig, +} from '@agoric/client-utils'; +import { + agopsLocation, + agoric, + executeCommand, + mkTemp, +} from '@agoric/synthetic-chain'; +import fsp from 'node:fs/promises'; + +/** @import {Result as ExecaResult, ExecaError} from 'execa'; */ +/** + * @typedef {ExecaResult & { all: string } & ( + * | { failed: false } + * | Pick< + * ExecaError & { failed: true }, + * | 'failed' + * | 'shortMessage' + * | 'cause' + * | 'exitCode' + * | 'signal' + * | 'signalDescription' + * > + * )} SendOfferResult + */ + +/** + * @typedef {object} PsmMetrics + * @property {import('@agoric/ertp').Amount<'nat'>} anchorPoolBalance + * @property {import('@agoric/ertp').Amount<'nat'>} feePoolBalance + * @property {import('@agoric/ertp').Amount<'nat'>} mintedPoolBalance + * @property {import('@agoric/ertp').Amount<'nat'>} totalAnchorProvided + * @property {import('@agoric/ertp').Amount<'nat'>} totalMintedProvided + */ + +const fromBoard = makeFromBoard(); +const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); + +/** + * @param {string} path + */ +const objectFromVstorageEntries = async path => { + const rawEntries = await agoric.follow('-lF', `:${path}`, '-o', 'text'); + return Object.fromEntries(marshaller.fromCapData(JSON.parse(rawEntries))); +}; + +export const snapshotAgoricNames = async () => { + const [brands, instances, vbankAssets] = await Promise.all([ + objectFromVstorageEntries('published.agoricNames.brand'), + objectFromVstorageEntries('published.agoricNames.instance'), + objectFromVstorageEntries('published.agoricNames.vbankAsset'), + ]); + return { brands, instances, vbankAssets }; +}; + +/** + * Similar to + * https://github.com/Agoric/agoric-3-proposals/blob/422b163fecfcf025d53431caebf6d476778b5db3/packages/synthetic-chain/src/lib/commonUpgradeHelpers.ts#L123-L139 + * However, for an address that is not provisioned, `agoric wallet send` is + * needed because `agops perf satisfaction` hangs when trying to follow + * nonexistent vstorage path ":published.wallet.${address}". + * + * @param {string} address + * @param {Promise} offerPromise + * @returns {Promise} + */ +export const sendOfferAgoric = async (address, offerPromise) => { + const offerPath = await mkTemp('agops.XXX'); + const offer = await offerPromise; + await fsp.writeFile(offerPath, offer); + + const [settlement] = await Promise.allSettled([ + execa({ + all: true, + })`agoric wallet --keyring-backend=test send --offer ${offerPath} --from ${address} --verbose`, + ]); + return settlement.status === 'fulfilled' + ? settlement.value + : settlement.reason; +}; + +/** + * A variant of {@link sendOfferAgoric} that uses `agd` directly to e.g. + * control gas calculation. + * + * @param {string} address + * @param {Promise} offerPromise + * @returns {Promise} + */ +export const sendOfferAgd = async (address, offerPromise) => { + const offer = await offerPromise; + const networkConfig = await fetchEnvNetworkConfig({ + env: process.env, + fetch, + }); + const { chainName, rpcAddrs } = networkConfig; + const args = /** @type {string[]} */ ( + // @ts-expect-error heterogeneous concat + [].concat( + [`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`], + [`--keyring-backend=test`, `--from=${address}`], + ['tx', 'swingset', 'wallet-action', '--allow-spend', offer], + '--yes', + '-bblock', + '-ojson', + ) + ); + + const [settlement] = await Promise.allSettled([ + execa('agd', args, { all: true }), + ]); + + // Upon successful exit, verify that the *output* also indicates success. + // cf. https://github.com/Agoric/agoric-sdk/blob/master/packages/agoric-cli/src/lib/wallet.js + if (settlement.status === 'fulfilled') { + const result = settlement.value; + try { + const tx = JSON.parse(result.stdout); + if (tx.code !== 0) { + return { ...result, failed: true, shortMessage: `code ${tx.code}` }; + } + } catch (err) { + return { + ...result, + failed: true, + shortMessage: 'unexpected output', + cause: err, + }; + } + } + + return settlement.status === 'fulfilled' + ? settlement.value + : settlement.reason; +}; + +/** + * @param {string} address + * @param {Array} params + * @param {{ + * follow: (...params: string[]) => Promise; + * sendOffer?: (address: string, offerPromise: Promise) => Promise; + * setTimeout: typeof global.setTimeout; + * now: () => number + * }} io + */ +export const psmSwap = async (address, params, io) => { + const { now, sendOffer = sendOfferAgoric, ...waitIO } = io; + const offerId = `${address}-psm-swap-${now()}`; + const newParams = ['psm', ...params, '--offerId', offerId]; + const offerPromise = executeCommand(agopsLocation, newParams); + const sendResult = await sendOffer(address, offerPromise); + if (sendResult.failed) { + const { + command, + durationMs, + shortMessage, + cause, + exitCode, + signal, + signalDescription, + all: output, + } = sendResult; + const summary = { + command, + durationMs, + shortMessage, + cause, + exitCode, + signal, + signalDescription, + output, + }; + console.error('psmSwap tx send failed', summary); + throw Error( + `psmSwap tx send failed: ${JSON.stringify({ exitCode, signal, signalDescription })}`, + { cause }, + ); + } + console.log('psmSwap tx send results', sendResult.all); + + await waitUntilOfferResult(address, offerId, true, waitIO, { + errorMessage: `${offerId} not succeeded`, + }); +}; diff --git a/a3p-integration/proposals/p:upgrade-19/test.sh b/a3p-integration/proposals/p:upgrade-19/test.sh index aa766db3a28..f42147483ef 100644 --- a/a3p-integration/proposals/p:upgrade-19/test.sh +++ b/a3p-integration/proposals/p:upgrade-19/test.sh @@ -2,6 +2,6 @@ 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 From 02fde3c475a92f64e4c5e434c2891caa0e7fc74d Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 10 Dec 2024 23:15:36 +0000 Subject: [PATCH 13/42] chore(a3p): add submission and update client-utils version --- .../proposals/p:upgrade-19/.gitignore | 1 + .../proposals/p:upgrade-19/package.json | 5 +- .../proposals/p:upgrade-19/yarn.lock | 776 +++++++++--------- 3 files changed, 392 insertions(+), 390 deletions(-) diff --git a/a3p-integration/proposals/p:upgrade-19/.gitignore b/a3p-integration/proposals/p:upgrade-19/.gitignore index 70e47ab7438..57c4873daf7 100644 --- a/a3p-integration/proposals/p:upgrade-19/.gitignore +++ b/a3p-integration/proposals/p:upgrade-19/.gitignore @@ -5,3 +5,4 @@ addUsdOlives/ upgradeProvisionPool/ upgradeAgoricNames/ publishTestInfo/ +upgrade-mintHolder/ diff --git a/a3p-integration/proposals/p:upgrade-19/package.json b/a3p-integration/proposals/p:upgrade-19/package.json index d5503b4d1c6..a8bb3cc998f 100644 --- a/a3p-integration/proposals/p:upgrade-19/package.json +++ b/a3p-integration/proposals/p:upgrade-19/package.json @@ -10,13 +10,14 @@ "testing/test-upgraded-board.js testUpgradedBoard", "vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames", "testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives", - "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo" + "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo", + "vats/upgrade-mintHolder.js upgrade-mintHolder USDC_axl USDT_grv DAI_axl DAI_grv stATOM USDC_grv ATOM USDT_axl USDC BLD IST" ] }, "type": "module", "license": "Apache-2.0", "dependencies": { - "@agoric/client-utils": "0.1.1-dev-02c06c4.0", + "@agoric/client-utils": "dev", "@agoric/ertp": "dev", "@agoric/internal": "dev", "@agoric/synthetic-chain": "^0.4.3", diff --git a/a3p-integration/proposals/p:upgrade-19/yarn.lock b/a3p-integration/proposals/p:upgrade-19/yarn.lock index a9c86ac69e3..29afd5a4438 100644 --- a/a3p-integration/proposals/p:upgrade-19/yarn.lock +++ b/a3p-integration/proposals/p:upgrade-19/yarn.lock @@ -27,21 +27,6 @@ __metadata: languageName: node linkType: hard -"@agoric/base-zone@npm:0.1.1-dev-02c06c4.0+02c06c4": - version: 0.1.1-dev-02c06c4.0 - resolution: "@agoric/base-zone@npm:0.1.1-dev-02c06c4.0" - dependencies: - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@endo/common": "npm:^1.2.7" - "@endo/errors": "npm:^1.2.7" - "@endo/exo": "npm:^1.5.6" - "@endo/far": "npm:^1.1.8" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - checksum: 10c0/54c4fc0855010809b09aa0558454639ecd87152af8c52024e07b1a46f38aeeef8d4642318eaf933b5219fc16e849a832d7a2c6d0e1827634dc6a64dd7530353b - languageName: node - linkType: hard - "@agoric/base-zone@npm:0.1.1-dev-1dd4589.0+1dd4589": version: 0.1.1-dev-1dd4589.0 resolution: "@agoric/base-zone@npm:0.1.1-dev-1dd4589.0" @@ -72,6 +57,21 @@ __metadata: languageName: node linkType: hard +"@agoric/base-zone@npm:0.1.1-dev-c1ae023.0+c1ae023": + version: 0.1.1-dev-c1ae023.0 + resolution: "@agoric/base-zone@npm:0.1.1-dev-c1ae023.0" + dependencies: + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/d7c75720d675c5f2fd524d0c597e83957fecee138392b3fc6dfa5610e8f301ccffecc8fbacb6c5a0700e4f5b9f95496029d0eb05320c92e23bbbeaa428ed9f87 + languageName: node + linkType: hard + "@agoric/base-zone@npm:0.1.1-dev-e596a01.0+e596a01": version: 0.1.1-dev-e596a01.0 resolution: "@agoric/base-zone@npm:0.1.1-dev-e596a01.0" @@ -101,24 +101,24 @@ __metadata: languageName: node linkType: hard -"@agoric/casting@npm:0.4.3-dev-02c06c4.0+02c06c4": - version: 0.4.3-dev-02c06c4.0 - resolution: "@agoric/casting@npm:0.4.3-dev-02c06c4.0" +"@agoric/casting@npm:0.4.3-dev-c1ae023.0+c1ae023": + version: 0.4.3-dev-c1ae023.0 + resolution: "@agoric/casting@npm:0.4.3-dev-c1ae023.0" dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" "@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.7" - "@endo/far": "npm:^1.1.8" - "@endo/init": "npm:^1.1.6" - "@endo/lockdown": "npm:^1.0.12" - "@endo/marshal": "npm:^1.6.1" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/e0fbef620ff0b358961f23d0545f962e2255dd0c490ee0c2635ba47fbe77f5b0f0c1b64a2bd638ca0030d9e81a099253feeef74b236652a8cb80dbc4932f4e08 + "@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" + checksum: 10c0/e4a8985d94ad49b785102f9db08415aaf07052178974dd2007fa0e359c50f83b9fead0934e9f0e7e81090dddde2c0e1b42e6f9b149989ec29e6887d980153dd6 languageName: node linkType: hard @@ -143,27 +143,6 @@ __metadata: languageName: node linkType: hard -"@agoric/client-utils@npm:0.1.1-dev-02c06c4.0": - version: 0.1.1-dev-02c06c4.0 - resolution: "@agoric/client-utils@npm:0.1.1-dev-02c06c4.0" - dependencies: - "@agoric/casting": "npm:0.4.3-dev-02c06c4.0+02c06c4" - "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/smart-wallet": "npm:0.5.4-dev-02c06c4.0+02c06c4" - "@agoric/vats": "npm:0.15.2-dev-02c06c4.0+02c06c4" - "@cosmjs/stargate": "npm:^0.32.3" - "@cosmjs/tendermint-rpc": "npm:^0.32.3" - "@endo/common": "npm:^1.2.7" - "@endo/errors": "npm:^1.2.7" - "@endo/marshal": "npm:^1.6.1" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/75009c017319e9d641d2653ee582307185363bb54a091aad3d85cbf59e514e3243c05f06e4ef7dd96bd5de1a702bd037e15bf03331c41333ce089664de13966f - languageName: node - linkType: hard - "@agoric/client-utils@npm:0.1.1-dev-e596a01.0+e596a01": version: 0.1.1-dev-e596a01.0 resolution: "@agoric/client-utils@npm:0.1.1-dev-e596a01.0" @@ -185,42 +164,44 @@ __metadata: languageName: node linkType: hard -"@agoric/cosmic-proto@npm:0.4.1-dev-02c06c4.0+02c06c4": - version: 0.4.1-dev-02c06c4.0 - resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-02c06c4.0" +"@agoric/client-utils@npm:dev": + version: 0.1.1-dev-c1ae023.0 + resolution: "@agoric/client-utils@npm:0.1.1-dev-c1ae023.0" dependencies: - "@endo/base64": "npm:^1.0.8" - "@endo/init": "npm:^1.1.6" - checksum: 10c0/a691d32d5aeb4152ee75ed1a9dd6fcaa49500da939fb3ca8a3b2949b5c3d67afe5ac27f824966850be42831e4bba7a0c83702fc525da800a5a1721ec2566548a + "@agoric/casting": "npm:0.4.3-dev-c1ae023.0+c1ae023" + "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/smart-wallet": "npm:0.5.4-dev-c1ae023.0+c1ae023" + "@agoric/vats": "npm:0.15.2-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/be944d730e4b3c5a0f811d999a9a707f90c447ef8a35f5fabf6db104671252c1c549d8c62c297508de40406d8a8965e8650b7cd827271fd9f6cbad2291a2e9ed languageName: node linkType: hard -"@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0+e596a01": - version: 0.4.1-dev-e596a01.0 - resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0" +"@agoric/cosmic-proto@npm:0.4.1-dev-c1ae023.0+c1ae023": + version: 0.4.1-dev-c1ae023.0 + resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-c1ae023.0" dependencies: "@endo/base64": "npm:^1.0.9" "@endo/init": "npm:^1.1.7" - checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35 + checksum: 10c0/78571d7f2c64df92d7f186ffad8c1e4c31c428495344555dc38ce74fc66397a4ac44f8d121b0929e6bb64a919bd7ecac708d04b4050021d69c68e388a2ea2de7 languageName: node linkType: hard -"@agoric/ertp@npm:0.16.3-dev-02c06c4.0+02c06c4": - version: 0.16.3-dev-02c06c4.0 - resolution: "@agoric/ertp@npm:0.16.3-dev-02c06c4.0" +"@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0+e596a01": + version: 0.4.1-dev-e596a01.0 + resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0" dependencies: - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/079356fee7cb840873effc2a78b3659d1979f57f3aecdbbaea5dc876f506671d8d6a4e8b169f739457e7fb1e96e5c1e3806d88fab2cec8cd2c4b370d7a70aeef + "@endo/base64": "npm:^1.0.9" + "@endo/init": "npm:^1.1.7" + checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35 languageName: node linkType: hard @@ -243,6 +224,25 @@ __metadata: languageName: node linkType: hard +"@agoric/ertp@npm:0.16.3-dev-c1ae023.0+c1ae023": + version: 0.16.3-dev-c1ae023.0 + resolution: "@agoric/ertp@npm:0.16.3-dev-c1ae023.0" + dependencies: + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/5a437d6a2b6b418dd016407c2095d7d98415818c422c3c53db217d99b3bbb2e476f5b7e9decbc628b82c8e85d2da939cf3846248eeb5d688b4789b21a1118194 + languageName: node + linkType: hard + "@agoric/ertp@npm:0.16.3-dev-e596a01.0+e596a01": version: 0.16.3-dev-e596a01.0 resolution: "@agoric/ertp@npm:0.16.3-dev-e596a01.0" @@ -262,27 +262,27 @@ __metadata: languageName: node linkType: hard -"@agoric/governance@npm:0.10.4-dev-02c06c4.0+02c06c4": - version: 0.10.4-dev-02c06c4.0 - resolution: "@agoric/governance@npm:0.10.4-dev-02c06c4.0" +"@agoric/governance@npm:0.10.4-dev-c1ae023.0+c1ae023": + version: 0.10.4-dev-c1ae023.0 + resolution: "@agoric/governance@npm:0.10.4-dev-c1ae023.0" dependencies: - "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4" - "@endo/bundle-source": "npm:^3.4.2" - "@endo/captp": "npm:^4.4.2" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/promise-kit": "npm:^1.1.7" + "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023" + "@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" - checksum: 10c0/888427200f47bc141ccc4dd07801d6b62c265edaae62abccf81d0bc0f4181fe544942d052a0f1f4a69e1c71fed287f60957b1667b1d951d4c61a1abfeec92c60 + checksum: 10c0/445a41d4d2f226bbb99ad274d94d9f90cd4b4277db0428cc62046d7fdc508bbac6745859dfc4d16159a7e83629f501aa22a0752b99481a99b76e7d31f628290c languageName: node linkType: hard @@ -336,11 +336,11 @@ __metadata: languageName: node linkType: hard -"@agoric/internal@npm:0.3.3-dev-02c06c4.0+02c06c4": - version: 0.3.3-dev-02c06c4.0 - resolution: "@agoric/internal@npm:0.3.3-dev-02c06c4.0" +"@agoric/internal@npm:0.3.3-dev-3b799b8.0+3b799b8": + version: 0.3.3-dev-3b799b8.0 + resolution: "@agoric/internal@npm:0.3.3-dev-3b799b8.0" dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4" + "@agoric/base-zone": "npm:0.1.1-dev-3b799b8.0+3b799b8" "@endo/common": "npm:^1.2.7" "@endo/errors": "npm:^1.2.7" "@endo/far": "npm:^1.1.8" @@ -352,27 +352,27 @@ __metadata: "@endo/stream": "npm:^1.2.7" anylogger: "npm:^0.21.0" jessie.js: "npm:^0.3.4" - checksum: 10c0/ec9ab609f0e55c777748e870f7f00e9e19c2f41b9ac0967d0f98ebf1559aa59b69cbfa4f2b95c698187bc1d6a578ff3b67e1c6e3fba7c501bcf4567c3a52e122 + checksum: 10c0/332369a9acb41e46a579c9e0d084a12e16a78ad71f794f10d631235694281580b06ea88e25bf31d9eadc353b9c8d62e561232a21bb4c45f17c41057d0fb4c171 languageName: node linkType: hard -"@agoric/internal@npm:0.3.3-dev-3b799b8.0+3b799b8": - version: 0.3.3-dev-3b799b8.0 - resolution: "@agoric/internal@npm:0.3.3-dev-3b799b8.0" +"@agoric/internal@npm:0.3.3-dev-c1ae023.0+c1ae023": + version: 0.3.3-dev-c1ae023.0 + resolution: "@agoric/internal@npm:0.3.3-dev-c1ae023.0" dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-3b799b8.0+3b799b8" - "@endo/common": "npm:^1.2.7" - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/init": "npm:^1.1.6" - "@endo/marshal": "npm:^1.6.1" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - "@endo/stream": "npm:^1.2.7" + "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@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" - checksum: 10c0/332369a9acb41e46a579c9e0d084a12e16a78ad71f794f10d631235694281580b06ea88e25bf31d9eadc353b9c8d62e561232a21bb4c45f17c41057d0fb4c171 + checksum: 10c0/6ef8c160be33be88adefa67a861fb0758d03933a4bcc6f225e3b4e41c592553555fc9d477c1731e9ce86d28e2db49c72053f53188a199ab0f8c81a06423adc2c languageName: node linkType: hard @@ -416,17 +416,6 @@ __metadata: languageName: node linkType: hard -"@agoric/kmarshal@npm:0.1.1-dev-02c06c4.0+02c06c4": - version: 0.1.1-dev-02c06c4.0 - resolution: "@agoric/kmarshal@npm:0.1.1-dev-02c06c4.0" - dependencies: - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/marshal": "npm:^1.6.1" - checksum: 10c0/f7a124e2d9876edeb72fe8d66f090acb7fbbb7ad8d6bbcad3d60a25e7eee98e005a52222d3c570b1e9ecc504dd7bea4444232fe756824c97000bba439ea142ee - languageName: node - linkType: hard - "@agoric/kmarshal@npm:0.1.1-dev-3b799b8.0+3b799b8": version: 0.1.1-dev-3b799b8.0 resolution: "@agoric/kmarshal@npm:0.1.1-dev-3b799b8.0" @@ -438,6 +427,17 @@ __metadata: languageName: node linkType: hard +"@agoric/kmarshal@npm:0.1.1-dev-c1ae023.0+c1ae023": + version: 0.1.1-dev-c1ae023.0 + resolution: "@agoric/kmarshal@npm:0.1.1-dev-c1ae023.0" + dependencies: + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/marshal": "npm:^1.6.2" + checksum: 10c0/5f4c1784fa4fa6de50f288722794ac0c98d0719e3558bc9147b726014a72dc3222a68f4c7f40e42f170e4b59481579a4d318e3cffb665720dafc23c80915ec6b + languageName: node + linkType: hard + "@agoric/kmarshal@npm:0.1.1-dev-e596a01.0+e596a01": version: 0.1.1-dev-e596a01.0 resolution: "@agoric/kmarshal@npm:0.1.1-dev-e596a01.0" @@ -449,20 +449,20 @@ __metadata: languageName: node linkType: hard -"@agoric/network@npm:0.1.1-dev-02c06c4.0+02c06c4": - version: 0.1.1-dev-02c06c4.0 - resolution: "@agoric/network@npm:0.1.1-dev-02c06c4.0" +"@agoric/network@npm:0.1.1-dev-c1ae023.0+c1ae023": + version: 0.1.1-dev-c1ae023.0 + resolution: "@agoric/network@npm:0.1.1-dev-c1ae023.0" dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@endo/base64": "npm:^1.0.8" - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/0e14d617b90a1bf63ebe5776182f6cab2b87c9f18e951740ce7cddcdd418d630835a21c88af3910c2d73b5b6dc28a455a8f32dc15f66f48089f414916f5c541e + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/93fd60ad6a0ce650427853677be076c77ce00d3201f29ec0922eb5fd38ce5ec2316fb9a564a76d3fae809299ef193e80109b89b79c4191ddb9525e5e4cb33302 languageName: node linkType: hard @@ -483,21 +483,6 @@ __metadata: languageName: node linkType: hard -"@agoric/notifier@npm:0.6.3-dev-02c06c4.0+02c06c4": - version: 0.6.3-dev-02c06c4.0 - resolution: "@agoric/notifier@npm:0.6.3-dev-02c06c4.0" - dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/marshal": "npm:^1.6.1" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/6b4698c179c1483231124c6f6abc535bf86cef0bf61f3db05821031e06a3c63e7676fbba88170c2fb4716cd6dd96dc18b5c90d10b04aeee89e7be80c3b825e92 - languageName: node - linkType: hard - "@agoric/notifier@npm:0.6.3-dev-3b799b8.0+3b799b8": version: 0.6.3-dev-3b799b8.0 resolution: "@agoric/notifier@npm:0.6.3-dev-3b799b8.0" @@ -513,6 +498,21 @@ __metadata: languageName: node linkType: hard +"@agoric/notifier@npm:0.6.3-dev-c1ae023.0+c1ae023": + version: 0.6.3-dev-c1ae023.0 + resolution: "@agoric/notifier@npm:0.6.3-dev-c1ae023.0" + dependencies: + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/b810e7c98305e3e398fc1b97fa611c48b6af9a0144a865d357c2e5ac10cb60fc55bd01d87f8165fbc09c009166c7bc3a0513e2b1bf35e0742c0607e0c6579060 + languageName: node + linkType: hard + "@agoric/notifier@npm:0.6.3-dev-e596a01.0+e596a01": version: 0.6.3-dev-e596a01.0 resolution: "@agoric/notifier@npm:0.6.3-dev-e596a01.0" @@ -528,26 +528,26 @@ __metadata: languageName: node linkType: hard -"@agoric/smart-wallet@npm:0.5.4-dev-02c06c4.0+02c06c4": - version: 0.5.4-dev-02c06c4.0 - resolution: "@agoric/smart-wallet@npm:0.5.4-dev-02c06c4.0" +"@agoric/smart-wallet@npm:0.5.4-dev-c1ae023.0+c1ae023": + version: 0.5.4-dev-c1ae023.0 + resolution: "@agoric/smart-wallet@npm:0.5.4-dev-c1ae023.0" dependencies: - "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/vats": "npm:0.15.2-dev-02c06c4.0+02c06c4" - "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4" - "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/a2bc7bf868bdc578f4c2251f04119b1e72eeae5ff14334eeffbd8bfd8706b4ded203e2f239d8a85283fd06dfa6910c9b01b9a7d55de0fe6767c0f729c3915034 + "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/vats": "npm:0.15.2-dev-c1ae023.0+c1ae023" + "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023" + "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/94096186933d72b4db40e965adcef8d2e36b4917e6f4e1ca5d103d949c201daeaa16ad4d48ce121aec7048defb6177f75270418f175ae7ba390f169e8e37c380 languageName: node linkType: hard @@ -574,19 +574,6 @@ __metadata: languageName: node linkType: hard -"@agoric/store@npm:0.9.3-dev-02c06c4.0+02c06c4": - version: 0.9.3-dev-02c06c4.0 - resolution: "@agoric/store@npm:0.9.3-dev-02c06c4.0" - dependencies: - "@endo/errors": "npm:^1.2.7" - "@endo/exo": "npm:^1.5.6" - "@endo/marshal": "npm:^1.6.1" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - checksum: 10c0/975d6d7f72bc3e0bb9087a1998c4c6092504cf084d1615a74d7bd7ea10d9032d5a0845e24399f787a7a9b1974e00a61a995f73d47bf8a8444ac1d9ed8aeb94a6 - languageName: node - linkType: hard - "@agoric/store@npm:0.9.3-dev-1dd4589.0+1dd4589": version: 0.9.3-dev-1dd4589.0 resolution: "@agoric/store@npm:0.9.3-dev-1dd4589.0" @@ -613,31 +600,29 @@ __metadata: languageName: node linkType: hard -"@agoric/store@npm:0.9.3-dev-e596a01.0+e596a01": - version: 0.9.3-dev-e596a01.0 - resolution: "@agoric/store@npm:0.9.3-dev-e596a01.0" +"@agoric/store@npm:0.9.3-dev-c1ae023.0+c1ae023": + version: 0.9.3-dev-c1ae023.0 + resolution: "@agoric/store@npm:0.9.3-dev-c1ae023.0" 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" - checksum: 10c0/b931aa2566d2ef2fea087938c34a79a6682a15f0fc9a5084e73c671d970f22ab3a1040febab4f7f0ae793858597834d76840b1d9c20a89048b725e3b5443b84f + checksum: 10c0/9fd6d5464906144140a868d38e63d1ee2f8f06240a8ba2e71ed73eb7df5ce9c03a74a79290b4dc2b2e4c3c3d59ba07228f7019965cf234a4178b815f8861f002 languageName: node linkType: hard -"@agoric/swing-store@npm:0.9.2-dev-02c06c4.0+02c06c4": - version: 0.9.2-dev-02c06c4.0 - resolution: "@agoric/swing-store@npm:0.9.2-dev-02c06c4.0" +"@agoric/store@npm:0.9.3-dev-e596a01.0+e596a01": + version: 0.9.3-dev-e596a01.0 + resolution: "@agoric/store@npm:0.9.3-dev-e596a01.0" dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@endo/base64": "npm:^1.0.8" - "@endo/bundle-source": "npm:^3.4.2" - "@endo/check-bundle": "npm:^1.0.11" - "@endo/errors": "npm:^1.2.7" - "@endo/nat": "npm:^5.0.12" - better-sqlite3: "npm:^9.1.1" - checksum: 10c0/71fd32035b20398c2a28eb8c7ada724c601cde1408f2ffadcbf6b06c06899ce9d0e595f75a570e9cc466c864c5ea29bdddf2b4a4f07e9031496588ea5904fabe + "@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" + checksum: 10c0/b931aa2566d2ef2fea087938c34a79a6682a15f0fc9a5084e73c671d970f22ab3a1040febab4f7f0ae793858597834d76840b1d9c20a89048b725e3b5443b84f languageName: node linkType: hard @@ -656,6 +641,21 @@ __metadata: languageName: node linkType: hard +"@agoric/swing-store@npm:0.9.2-dev-c1ae023.0+c1ae023": + version: 0.9.2-dev-c1ae023.0 + resolution: "@agoric/swing-store@npm:0.9.2-dev-c1ae023.0" + dependencies: + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/56adf70976c1c7f6f2437045fdd2c10f128b0d79224f83aed842b8b42f2253328d24151817748e2d4bc8c1f70a840d254646423a69496ff25e049bc3909233d5 + languageName: node + linkType: hard + "@agoric/swing-store@npm:0.9.2-dev-e596a01.0+e596a01": version: 0.9.2-dev-e596a01.0 resolution: "@agoric/swing-store@npm:0.9.2-dev-e596a01.0" @@ -671,27 +671,6 @@ __metadata: languageName: node linkType: hard -"@agoric/swingset-liveslots@npm:0.10.3-dev-02c06c4.0+02c06c4": - version: 0.10.3-dev-02c06c4.0 - resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-02c06c4.0" - dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@endo/env-options": "npm:^1.1.7" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/exo": "npm:^1.5.6" - "@endo/far": "npm:^1.1.8" - "@endo/init": "npm:^1.1.6" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/0c0b7a9ff81b173b6610ef4b7af296ae1b1dbb753d4f2ef36e4b276aeb8e4a54a7a53e7293b051f3e196e8175e085db71728e986f7d226e90a08f9c7eb25b874 - languageName: node - linkType: hard - "@agoric/swingset-liveslots@npm:0.10.3-dev-3b799b8.0+3b799b8": version: 0.10.3-dev-3b799b8.0 resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-3b799b8.0" @@ -713,6 +692,27 @@ __metadata: languageName: node linkType: hard +"@agoric/swingset-liveslots@npm:0.10.3-dev-c1ae023.0+c1ae023": + version: 0.10.3-dev-c1ae023.0 + resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-c1ae023.0" + dependencies: + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/a44a74766ce6be12d65f7328a544993a07a2b3b74f8f998c48c085a39b38746644005d285cb5d3e6282b1e327e7e809c9cd23e36667da2b7f11926808000b1f0 + languageName: node + linkType: hard + "@agoric/swingset-liveslots@npm:0.10.3-dev-e596a01.0+e596a01": version: 0.10.3-dev-e596a01.0 resolution: "@agoric/swingset-liveslots@npm:0.10.3-dev-e596a01.0" @@ -734,19 +734,19 @@ __metadata: languageName: node linkType: hard -"@agoric/swingset-vat@npm:0.32.3-dev-02c06c4.0+02c06c4": - version: 0.32.3-dev-02c06c4.0 - resolution: "@agoric/swingset-vat@npm:0.32.3-dev-02c06c4.0" +"@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0+3b799b8": + version: 0.32.3-dev-3b799b8.0 + resolution: "@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0" dependencies: - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/kmarshal": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/swing-store": "npm:0.9.2-dev-02c06c4.0+02c06c4" - "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4" - "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-02c06c4.0+02c06c4" - "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/xsnap-lockdown": "npm:0.14.1-dev-02c06c4.0+02c06c4" + "@agoric/internal": "npm:0.3.3-dev-3b799b8.0+3b799b8" + "@agoric/kmarshal": "npm:0.1.1-dev-3b799b8.0+3b799b8" + "@agoric/store": "npm:0.9.3-dev-3b799b8.0+3b799b8" + "@agoric/swing-store": "npm:0.9.2-dev-3b799b8.0+3b799b8" + "@agoric/swingset-liveslots": "npm:0.10.3-dev-3b799b8.0+3b799b8" + "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-3b799b8.0+3b799b8" + "@agoric/time": "npm:0.3.3-dev-3b799b8.0+3b799b8" + "@agoric/vat-data": "npm:0.5.3-dev-3b799b8.0+3b799b8" + "@agoric/xsnap-lockdown": "npm:0.14.1-dev-3b799b8.0+3b799b8" "@endo/base64": "npm:^1.0.8" "@endo/bundle-source": "npm:^3.4.2" "@endo/captp": "npm:^4.4.2" @@ -778,41 +778,41 @@ __metadata: ava: ^5.3.0 bin: vat: bin/vat - checksum: 10c0/43e4f64c6b157c7f343cd1a9a710061d8d81926986b5aec43d7b79e3a7b4ca46ab309285104767b780c6877f64ae79d8ecbb1847b84541a0f26cc38999e94ce4 + checksum: 10c0/661426721b4106f9e51bc5f86858b166a24b3954429ec8cfe20f3a6650017807c4af12a78b9f64aa549b317356d1a52f44aee9137dde738f74d077d789dad482 languageName: node linkType: hard -"@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0+3b799b8": - version: 0.32.3-dev-3b799b8.0 - resolution: "@agoric/swingset-vat@npm:0.32.3-dev-3b799b8.0" +"@agoric/swingset-vat@npm:0.32.3-dev-c1ae023.0+c1ae023": + version: 0.32.3-dev-c1ae023.0 + resolution: "@agoric/swingset-vat@npm:0.32.3-dev-c1ae023.0" dependencies: - "@agoric/internal": "npm:0.3.3-dev-3b799b8.0+3b799b8" - "@agoric/kmarshal": "npm:0.1.1-dev-3b799b8.0+3b799b8" - "@agoric/store": "npm:0.9.3-dev-3b799b8.0+3b799b8" - "@agoric/swing-store": "npm:0.9.2-dev-3b799b8.0+3b799b8" - "@agoric/swingset-liveslots": "npm:0.10.3-dev-3b799b8.0+3b799b8" - "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-3b799b8.0+3b799b8" - "@agoric/time": "npm:0.3.3-dev-3b799b8.0+3b799b8" - "@agoric/vat-data": "npm:0.5.3-dev-3b799b8.0+3b799b8" - "@agoric/xsnap-lockdown": "npm:0.14.1-dev-3b799b8.0+3b799b8" - "@endo/base64": "npm:^1.0.8" - "@endo/bundle-source": "npm:^3.4.2" - "@endo/captp": "npm:^4.4.2" - "@endo/check-bundle": "npm:^1.0.11" - "@endo/compartment-mapper": "npm:^1.3.1" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/import-bundle": "npm:^1.3.1" - "@endo/init": "npm:^1.1.6" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - "@endo/ses-ava": "npm:^1.2.7" - "@endo/stream": "npm:^1.2.7" - "@endo/zip": "npm:^1.0.8" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/kmarshal": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/swing-store": "npm:0.9.2-dev-c1ae023.0+c1ae023" + "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023" + "@agoric/swingset-xsnap-supervisor": "npm:0.10.3-dev-c1ae023.0+c1ae023" + "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/xsnap-lockdown": "npm:0.14.1-dev-c1ae023.0+c1ae023" + "@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" @@ -826,7 +826,7 @@ __metadata: ava: ^5.3.0 bin: vat: bin/vat - checksum: 10c0/661426721b4106f9e51bc5f86858b166a24b3954429ec8cfe20f3a6650017807c4af12a78b9f64aa549b317356d1a52f44aee9137dde738f74d077d789dad482 + checksum: 10c0/66482c449eeccd00167dec73899a5c510719620eba2ad457e77c04790b3573e8e82138e4d362f1b4ee859719278bdb49835df0007318d216ce6e54e67d08ee95 languageName: node linkType: hard @@ -878,13 +878,6 @@ __metadata: languageName: node linkType: hard -"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-02c06c4.0+02c06c4": - version: 0.10.3-dev-02c06c4.0 - resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-02c06c4.0" - checksum: 10c0/a269373b02fcfcb10a47d601ef13ee1c01c2a8666bed7119e0b6f47027ce5f8d2321d5aaf6d22cbd949db69f4403cfda4d439d84c27bb4d7dd0fe421173fcb58 - languageName: node - linkType: hard - "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-3b799b8.0+3b799b8": version: 0.10.3-dev-3b799b8.0 resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-3b799b8.0" @@ -892,6 +885,13 @@ __metadata: languageName: node linkType: hard +"@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-c1ae023.0+c1ae023": + version: 0.10.3-dev-c1ae023.0 + resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-c1ae023.0" + checksum: 10c0/9f5b3bfe1f76f74f0ab605a67a8c822ba76fd80f7da9a13ee7933425effce76877240b5bd155a677c20740259bab1f0087131784035ef8a85e1278d718450589 + languageName: node + linkType: hard + "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-e596a01.0+e596a01": version: 0.10.3-dev-e596a01.0 resolution: "@agoric/swingset-xsnap-supervisor@npm:0.10.3-dev-e596a01.0" @@ -914,18 +914,6 @@ __metadata: languageName: node linkType: hard -"@agoric/time@npm:0.3.3-dev-02c06c4.0+02c06c4": - version: 0.3.3-dev-02c06c4.0 - resolution: "@agoric/time@npm:0.3.3-dev-02c06c4.0" - dependencies: - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/nat": "npm:^5.0.12" - "@endo/patterns": "npm:^1.4.6" - checksum: 10c0/ffe92b98f6f0f0d88aa1ecc2782775af94e77c4ba23f55005c5d201abb7ecd7b75dcb703f5b11e13588ad15e643fff2a42ebe74b0934872446e6647ff8caf3ef - languageName: node - linkType: hard - "@agoric/time@npm:0.3.3-dev-3b799b8.0+3b799b8": version: 0.3.3-dev-3b799b8.0 resolution: "@agoric/time@npm:0.3.3-dev-3b799b8.0" @@ -938,6 +926,18 @@ __metadata: languageName: node linkType: hard +"@agoric/time@npm:0.3.3-dev-c1ae023.0+c1ae023": + version: 0.3.3-dev-c1ae023.0 + resolution: "@agoric/time@npm:0.3.3-dev-c1ae023.0" + dependencies: + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@endo/errors": "npm:^1.2.8" + "@endo/nat": "npm:^5.0.13" + "@endo/patterns": "npm:^1.4.7" + checksum: 10c0/f4c6c900f25eda4bc32ee045f0b87ad1f3b38aa400047d51fbac534aa69bceaaf4f07130c539276a96c51a885394847ccd0a42da950722c58276998bdd7555ed + languageName: node + linkType: hard + "@agoric/time@npm:0.3.3-dev-e596a01.0+e596a01": version: 0.3.3-dev-e596a01.0 resolution: "@agoric/time@npm:0.3.3-dev-e596a01.0" @@ -950,20 +950,6 @@ __metadata: languageName: node linkType: hard -"@agoric/vat-data@npm:0.5.3-dev-02c06c4.0+02c06c4": - version: 0.5.3-dev-02c06c4.0 - resolution: "@agoric/vat-data@npm:0.5.3-dev-02c06c4.0" - dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/exo": "npm:^1.5.6" - "@endo/patterns": "npm:^1.4.6" - checksum: 10c0/b381d8e22d6d51b3dbad23820e61c97e269117c822679405b149882269e26366f3f15fff4520ca3d72ceb30bdad3fa713599573235335220689e0c37f040af5a - languageName: node - linkType: hard - "@agoric/vat-data@npm:0.5.3-dev-3b799b8.0+3b799b8": version: 0.5.3-dev-3b799b8.0 resolution: "@agoric/vat-data@npm:0.5.3-dev-3b799b8.0" @@ -978,6 +964,20 @@ __metadata: languageName: node linkType: hard +"@agoric/vat-data@npm:0.5.3-dev-c1ae023.0+c1ae023": + version: 0.5.3-dev-c1ae023.0 + resolution: "@agoric/vat-data@npm:0.5.3-dev-c1ae023.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023" + "@endo/errors": "npm:^1.2.8" + "@endo/exo": "npm:^1.5.7" + "@endo/patterns": "npm:^1.4.7" + checksum: 10c0/009a8ca0f385770d4be37f8db2970ca03b035717193c18e43ce2f8ea6c212fba9a6f925dd376971e449416c6c3569178446318ecebdfc22016b03a50aed3fea4 + languageName: node + linkType: hard + "@agoric/vat-data@npm:0.5.3-dev-e596a01.0+e596a01": version: 0.5.3-dev-e596a01.0 resolution: "@agoric/vat-data@npm:0.5.3-dev-e596a01.0" @@ -992,34 +992,34 @@ __metadata: languageName: node linkType: hard -"@agoric/vats@npm:0.15.2-dev-02c06c4.0+02c06c4": - version: 0.15.2-dev-02c06c4.0 - resolution: "@agoric/vats@npm:0.15.2-dev-02c06c4.0" - dependencies: - "@agoric/cosmic-proto": "npm:0.4.1-dev-02c06c4.0+02c06c4" - "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4" - "@agoric/governance": "npm:0.10.4-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/network": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/swingset-vat": "npm:0.32.3-dev-02c06c4.0+02c06c4" - "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/zoe": "npm:0.26.3-dev-02c06c4.0+02c06c4" - "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/import-bundle": "npm:^1.3.1" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" +"@agoric/vats@npm:0.15.2-dev-c1ae023.0+c1ae023": + version: 0.15.2-dev-c1ae023.0 + resolution: "@agoric/vats@npm:0.15.2-dev-c1ae023.0" + dependencies: + "@agoric/cosmic-proto": "npm:0.4.1-dev-c1ae023.0+c1ae023" + "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023" + "@agoric/governance": "npm:0.10.4-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/network": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/swingset-vat": "npm:0.32.3-dev-c1ae023.0+c1ae023" + "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/zoe": "npm:0.26.3-dev-c1ae023.0+c1ae023" + "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023" + "@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" - checksum: 10c0/0b2b6b9a964f1194c68818e1b5b65fef15138b6b670e58fb35322b169d540a73fa453d7918290d7311caeef3cd4db5423bf0b8490a0b31087eb12230a429a9ce + checksum: 10c0/d8920290ce6cab7f7dccbc6890df6ee0dfb2d25a4b63b9e6d5794aec8379d17bc253196162668ab1c02c824af07bb2aa890053ef9c55206b62342d43079ef806 languageName: node linkType: hard @@ -1054,22 +1054,6 @@ __metadata: languageName: node linkType: hard -"@agoric/vow@npm:0.1.1-dev-02c06c4.0+02c06c4": - version: 0.1.1-dev-02c06c4.0 - resolution: "@agoric/vow@npm:0.1.1-dev-02c06c4.0" - dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@endo/env-options": "npm:^1.1.7" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" - checksum: 10c0/6da30cb8fe91333fa6d961df09ce293ee9ee24104c6e86ff87832f4975016b02e0c520e82dd9338a69059106417bdd86be0aaf2df59295f1424d8c86d9f0eb11 - languageName: node - linkType: hard - "@agoric/vow@npm:0.1.1-dev-3b799b8.0+3b799b8": version: 0.1.1-dev-3b799b8.0 resolution: "@agoric/vow@npm:0.1.1-dev-3b799b8.0" @@ -1086,6 +1070,22 @@ __metadata: languageName: node linkType: hard +"@agoric/vow@npm:0.1.1-dev-c1ae023.0+c1ae023": + version: 0.1.1-dev-c1ae023.0 + resolution: "@agoric/vow@npm:0.1.1-dev-c1ae023.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@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" + checksum: 10c0/094266768c8ff75032ce96faae9163e7dfa4e9ada55ce88354ca6de4b993d28252bcb6637900793f4e3f7b16afe62ac2f2bcc8825613b5cf95701ca46d4b4066 + languageName: node + linkType: hard + "@agoric/vow@npm:0.1.1-dev-e596a01.0+e596a01": version: 0.1.1-dev-e596a01.0 resolution: "@agoric/vow@npm:0.1.1-dev-e596a01.0" @@ -1102,13 +1102,6 @@ __metadata: languageName: node linkType: hard -"@agoric/xsnap-lockdown@npm:0.14.1-dev-02c06c4.0+02c06c4": - version: 0.14.1-dev-02c06c4.0 - resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-02c06c4.0" - checksum: 10c0/7b883c30a1ec8bc4fb727c5e442acc6ddd4af98067ce86f2f85c333ce8bafe525049a8b09668b4fec7671c368205095949d096df5c45be827a40e550863398a9 - languageName: node - linkType: hard - "@agoric/xsnap-lockdown@npm:0.14.1-dev-3b799b8.0+3b799b8": version: 0.14.1-dev-3b799b8.0 resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-3b799b8.0" @@ -1116,6 +1109,13 @@ __metadata: languageName: node linkType: hard +"@agoric/xsnap-lockdown@npm:0.14.1-dev-c1ae023.0+c1ae023": + version: 0.14.1-dev-c1ae023.0 + resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-c1ae023.0" + checksum: 10c0/65aefeb29497f8780849677ee81ba6f46f358d9f29ad5790541d5626ad8b08e34e27fa9063e24a4ddef5e2bf616e7aec16b6fff505a5bd3bbd0c87ceac110f49 + languageName: node + linkType: hard + "@agoric/xsnap-lockdown@npm:0.14.1-dev-e596a01.0+e596a01": version: 0.14.1-dev-e596a01.0 resolution: "@agoric/xsnap-lockdown@npm:0.14.1-dev-e596a01.0" @@ -1123,36 +1123,36 @@ __metadata: languageName: node linkType: hard -"@agoric/zoe@npm:0.26.3-dev-02c06c4.0+02c06c4": - version: 0.26.3-dev-02c06c4.0 - resolution: "@agoric/zoe@npm:0.26.3-dev-02c06c4.0" +"@agoric/zoe@npm:0.26.3-dev-c1ae023.0+c1ae023": + version: 0.26.3-dev-c1ae023.0 + resolution: "@agoric/zoe@npm:0.26.3-dev-c1ae023.0" dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/ertp": "npm:0.16.3-dev-02c06c4.0+02c06c4" - "@agoric/internal": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/notifier": "npm:0.6.3-dev-02c06c4.0+02c06c4" - "@agoric/store": "npm:0.9.3-dev-02c06c4.0+02c06c4" - "@agoric/swingset-liveslots": "npm:0.10.3-dev-02c06c4.0+02c06c4" - "@agoric/swingset-vat": "npm:0.32.3-dev-02c06c4.0+02c06c4" - "@agoric/time": "npm:0.3.3-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@agoric/vow": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/zone": "npm:0.2.3-dev-02c06c4.0+02c06c4" - "@endo/bundle-source": "npm:^3.4.2" - "@endo/captp": "npm:^4.4.2" - "@endo/common": "npm:^1.2.7" - "@endo/errors": "npm:^1.2.7" - "@endo/eventual-send": "npm:^1.2.7" - "@endo/exo": "npm:^1.5.6" - "@endo/far": "npm:^1.1.8" - "@endo/import-bundle": "npm:^1.3.1" - "@endo/marshal": "npm:^1.6.1" - "@endo/nat": "npm:^5.0.12" - "@endo/pass-style": "npm:^1.4.6" - "@endo/patterns": "npm:^1.4.6" - "@endo/promise-kit": "npm:^1.1.7" + "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/ertp": "npm:0.16.3-dev-c1ae023.0+c1ae023" + "@agoric/internal": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/notifier": "npm:0.6.3-dev-c1ae023.0+c1ae023" + "@agoric/store": "npm:0.9.3-dev-c1ae023.0+c1ae023" + "@agoric/swingset-liveslots": "npm:0.10.3-dev-c1ae023.0+c1ae023" + "@agoric/swingset-vat": "npm:0.32.3-dev-c1ae023.0+c1ae023" + "@agoric/time": "npm:0.3.3-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@agoric/vow": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/zone": "npm:0.2.3-dev-c1ae023.0+c1ae023" + "@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" - checksum: 10c0/9aa34ecf57ea7882241206da18e88235152c05be6bf267eda2b51156ca2c48730b70be3429b5881e7fa0a02dfd97334da94ece9c82537277b0fd0b2f125c6e48 + checksum: 10c0/3b54c53506206d7406c0ffb309cb59d90a5cae13d0697320055127be163379369114a032b2af7c272e5646b9d9b65f1131c88750544ba859d5e1a11b618210b0 languageName: node linkType: hard @@ -1222,19 +1222,6 @@ __metadata: languageName: node linkType: hard -"@agoric/zone@npm:0.2.3-dev-02c06c4.0+02c06c4": - version: 0.2.3-dev-02c06c4.0 - resolution: "@agoric/zone@npm:0.2.3-dev-02c06c4.0" - dependencies: - "@agoric/base-zone": "npm:0.1.1-dev-02c06c4.0+02c06c4" - "@agoric/vat-data": "npm:0.5.3-dev-02c06c4.0+02c06c4" - "@endo/errors": "npm:^1.2.7" - "@endo/far": "npm:^1.1.8" - "@endo/pass-style": "npm:^1.4.6" - checksum: 10c0/f4cf6df5a81cba46762a3ebfb63c3f13633974205eb3b7051c845d0ac2adb2cac2b9b6ab100c64c8dc63eec8ad9c051f2ddc04153f4f07f1046a763869f589fe - languageName: node - linkType: hard - "@agoric/zone@npm:0.2.3-dev-3b799b8.0+3b799b8": version: 0.2.3-dev-3b799b8.0 resolution: "@agoric/zone@npm:0.2.3-dev-3b799b8.0" @@ -1248,6 +1235,19 @@ __metadata: languageName: node linkType: hard +"@agoric/zone@npm:0.2.3-dev-c1ae023.0+c1ae023": + version: 0.2.3-dev-c1ae023.0 + resolution: "@agoric/zone@npm:0.2.3-dev-c1ae023.0" + dependencies: + "@agoric/base-zone": "npm:0.1.1-dev-c1ae023.0+c1ae023" + "@agoric/vat-data": "npm:0.5.3-dev-c1ae023.0+c1ae023" + "@endo/errors": "npm:^1.2.8" + "@endo/far": "npm:^1.1.9" + "@endo/pass-style": "npm:^1.4.7" + checksum: 10c0/292be1e4198ecdbc87a300efc1548190d26698c6c541dd8e0f6794dc0407b9e3bfc013f8dadd6788e995327044ce8f8e4181ff01b851b77562224aa273d066bf + languageName: node + linkType: hard + "@agoric/zone@npm:0.2.3-dev-e596a01.0+e596a01": version: 0.2.3-dev-e596a01.0 resolution: "@agoric/zone@npm:0.2.3-dev-e596a01.0" @@ -1749,7 +1749,7 @@ __metadata: languageName: node linkType: hard -"@endo/lockdown@npm:^1.0.12, @endo/lockdown@npm:^1.0.13": +"@endo/lockdown@npm:^1.0.13": version: 1.0.13 resolution: "@endo/lockdown@npm:1.0.13" dependencies: @@ -6349,7 +6349,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: - "@agoric/client-utils": "npm:0.1.1-dev-02c06c4.0" + "@agoric/client-utils": "npm:dev" "@agoric/ertp": "npm:dev" "@agoric/internal": "npm:dev" "@agoric/synthetic-chain": "npm:^0.4.3" From 6ef9705880187834431b9c23f0a234d481893d24 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Wed, 11 Dec 2024 15:18:47 +0000 Subject: [PATCH 14/42] chore(mintHolder): add mintHolder null upgrade core-eval --- .../proposals/p:upgrade-19/package.json | 2 +- golang/cosmos/app/upgrade.go | 24 ++++ .../scripts/vats/upgrade-mintHolder.js | 126 ++++++++++++++++++ .../proposals/upgrade-mintHolder-proposal.js | 74 ++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 packages/builders/scripts/vats/upgrade-mintHolder.js create mode 100644 packages/vats/src/proposals/upgrade-mintHolder-proposal.js diff --git a/a3p-integration/proposals/p:upgrade-19/package.json b/a3p-integration/proposals/p:upgrade-19/package.json index a8bb3cc998f..bdd9490ec35 100644 --- a/a3p-integration/proposals/p:upgrade-19/package.json +++ b/a3p-integration/proposals/p:upgrade-19/package.json @@ -11,7 +11,7 @@ "vats/upgrade-agoricNames.js agoricNamesCoreEvals/upgradeAgoricNames", "testing/add-USD-OLIVES.js agoricNamesCoreEvals/addUsdOlives", "testing/publish-test-info.js agoricNamesCoreEvals/publishTestInfo", - "vats/upgrade-mintHolder.js upgrade-mintHolder USDC_axl USDT_grv DAI_axl DAI_grv stATOM USDC_grv ATOM USDT_axl USDC BLD IST" + "vats/upgrade-mintHolder.js upgrade-mintHolder A3P_INTEGRATION" ] }, "type": "module", diff --git a/golang/cosmos/app/upgrade.go b/golang/cosmos/app/upgrade.go index 43cdb931055..8e6a2c68bcd 100644 --- a/golang/cosmos/app/upgrade.go +++ b/golang/cosmos/app/upgrade.go @@ -157,6 +157,22 @@ func replacePriceFeedsCoreProposal(upgradeName string) (vm.CoreProposalStep, err ) } +// func upgradeMintHolderCoreProposal(upgradeName string) (vm.CoreProposalStep, error) { +// variant := getVariantFromUpgradeName(upgradeName) + +// if variant == "" { +// return nil, nil +// } + +// return buildProposalStepWithArgs( +// "@agoric/builders/scripts/vats/upgrade-mintHolder.js", +// "defaultProposalBuilder", +// map[string]any{ +// "variant": variant, +// }, +// ) +// } + // unreleasedUpgradeHandler performs standard upgrade actions plus custom actions for the unreleased upgrade. func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Context, upgradetypes.Plan, module.VersionMap) (module.VersionMap, error) { return func(ctx sdk.Context, plan upgradetypes.Plan, fromVm module.VersionMap) (module.VersionMap, error) { @@ -216,6 +232,14 @@ func unreleasedUpgradeHandler(app *GaiaApp, targetUpgrade string) func(sdk.Conte // CoreProposals for Upgrade 19. These should not be introduced // before upgrade 18 is done because they would be run in n:upgrade-next + // + // upgradeMintHolderStep, err := upgradeMintHolderCoreProposal(targetUpgrade) + // if err != nil { + // return nil, err + // } else if upgradeMintHolderStep != nil { + // CoreProposalSteps = append(CoreProposalSteps, upgradeMintHolderStep) + // } + // // CoreProposalSteps = append(CoreProposalSteps, // vm.CoreProposalStepForModules( // "@agoric/builders/scripts/inter-protocol/replace-feeDistributor.js", diff --git a/packages/builders/scripts/vats/upgrade-mintHolder.js b/packages/builders/scripts/vats/upgrade-mintHolder.js new file mode 100644 index 00000000000..18cb47854c2 --- /dev/null +++ b/packages/builders/scripts/vats/upgrade-mintHolder.js @@ -0,0 +1,126 @@ +import { makeHelpers } from '@agoric/deploy-script-support'; +import { getManifestForUpgradingMintHolder } from '@agoric/vats/src/proposals/upgrade-mintHolder-proposal.js'; + +const configurations = { + A3P_INTEGRATION: { + labelList: [ + 'USDC_axl', + 'USDT_grv', + 'DAI_axl', + 'DAI_grv', + 'stATOM', + 'USDC_grv', + 'ATOM', + 'USDT_axl', + 'USDC', + 'BLD', + ], + }, + MAINNET: { + labelList: [ + 'USDT', + 'USDT_axl', + 'USDT_grv', + 'USDC', + 'USDC_axl', + 'USDC_grv', + 'DAI_axl', + 'DAI_grv', + 'ATOM', + 'stATOM', + 'stkATOM', + 'stTIA', + 'stOSMO', + ], + }, + DEVNET: { + labelList: [ + 'stATOM3', + 'stATOM', + 'dATOM', + 'stOSMO', + 'stkATOM', + 'stATOM2', + 'STOSMO', + 'stTIA', + 'ATOM', + 'AUSD', + 'USDT_grv', + 'USDC_axl', + 'USDC_grv', + 'USDT_axl', + 'BLD', + ], + }, + EMERYNET: { + labelList: [ + 'ATOM', + 'USDT', + 'DAI_axl', + 'DAI_grv', + 'USDC_axl', + 'stOSMO', + 'stATOM', + 'stkATOM', + 'stOSMO2', + 'ToyUSD', + 'BLD', + ], + }, +}; + +const { keys } = Object; +const knownVariants = keys(configurations); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async ({ publishRef, install }, opts) => { + const config = opts.config || configurations[opts.variant]; + if (!config) { + const error = `Unknown variant "${opts.variant}". Expected one of ${knownVariants.join(', ')}`; + console.error(error); + throw Error(error); + } + const { labelList } = config; + + return harden({ + sourceSpec: '@agoric/vats/src/proposals/upgrade-mintHolder-proposal.js', + getManifestCall: [ + getManifestForUpgradingMintHolder.name, + { + labelList, + contractRef: publishRef(install('@agoric/vats/src/mintHolder.js')), + }, + ], + }); +}; + +const Usage = `agoric run upgrade-mintHolder.js ${[...knownVariants, ''].join(' | ')}`; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + const { scriptArgs } = endowments; + const variantOrConfig = scriptArgs?.[0]; + console.log('upgrade-mintHolder', variantOrConfig); + + const opts = {}; + + if (typeof variantOrConfig === 'string') { + if (variantOrConfig[0] === '{') { + try { + opts.config = JSON.parse(variantOrConfig); + } catch (err) { + throw Error(`Failed to parse config argument ${variantOrConfig}`); + } + } else { + opts.variant = variantOrConfig; + } + } else { + console.error(Usage); + throw Error(Usage); + } + + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval(`upgrade-mintHolder`, utils => + defaultProposalBuilder(utils, opts), + ); +}; diff --git a/packages/vats/src/proposals/upgrade-mintHolder-proposal.js b/packages/vats/src/proposals/upgrade-mintHolder-proposal.js new file mode 100644 index 00000000000..4b231abdc16 --- /dev/null +++ b/packages/vats/src/proposals/upgrade-mintHolder-proposal.js @@ -0,0 +1,74 @@ +import { makeTracer } from '@agoric/internal'; +import { E } from '@endo/far'; + +const trace = makeTracer('upgrade mintHolder', true); + +export const upgradeMintHolder = async ( + { + consume: { + contractKits: contractKitsP, + instancePrivateArgs: instancePrivateArgsP, + }, + }, + options, +) => { + const { contractRef, labelList } = options.options; + assert(contractRef.bundleID, 'mintHolder bundleID not found'); + assert(labelList, 'mintHolder bank asset label list not found'); + + trace(`Start mintHolder contract upgrade`); + trace(`Assets: `, labelList); + + const [contractKits, instancePrivateArgs] = await Promise.all([ + contractKitsP, + instancePrivateArgsP, + ]); + + for (const assetLabel of labelList) { + const mintHolderKit = Array.from(contractKits.values()).find( + kit => kit.label && kit.label === assetLabel, + ); + if (!mintHolderKit) { + console.error( + `ERROR: failed to upgrade ${assetLabel} mintHolder, contractKit not found`, + ); + continue; + } + + trace(`${assetLabel} mintHolderKit: `, mintHolderKit); + + const { publicFacet, adminFacet, instance } = mintHolderKit; + + /* + * Ensure that publicFacet holds an issuer by verifying that has + * the makeEmptyPurse method. + */ + await E(publicFacet).makeEmptyPurse(); + + const privateArgs = instancePrivateArgs.get(instance); + + const upgradeResult = await E(adminFacet).upgradeContract( + contractRef.bundleID, + privateArgs, + ); + + trace(`${assetLabel} upgrade result: `, upgradeResult); + } + + trace(`Finished mintHolder contract upgrade`); +}; + +export const getManifestForUpgradingMintHolder = ( + _powers, + { contractRef, labelList }, +) => ({ + manifest: { + [upgradeMintHolder.name]: { + consume: { + contractKits: true, + instancePrivateArgs: true, + }, + }, + }, + options: { contractRef, labelList }, +}); From aa864ce73f6e183e96b1a4b72b15506fae48233f Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Thu, 12 Dec 2024 11:56:06 +0000 Subject: [PATCH 15/42] fix(a3p): remove usage of duplicated code --- .../proposals/p:upgrade-19/mintHolder.test.js | 6 +- .../test-lib/mintHolder-helpers.js | 14 +- .../p:upgrade-19/test-lib/psm-helpers.js | 192 ------------------ .../p:upgrade-19/test-lib/psm-lib.js | 27 ++- 4 files changed, 37 insertions(+), 202 deletions(-) delete mode 100644 a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js diff --git a/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js index b47a499411e..32a187bcb25 100644 --- a/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js +++ b/a3p-integration/proposals/p:upgrade-19/mintHolder.test.js @@ -10,11 +10,7 @@ import { getPSMChildren, upgradeMintHolder, } from './test-lib/mintHolder-helpers.js'; - -const networkConfig = { - rpcAddrs: ['http://0.0.0.0:26657'], - chainName: 'agoriclocal', -}; +import { networkConfig } from './test-lib/index.js'; test('mintHolder contract is upgraded', async t => { const receiver = await addUser('receiver'); diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js index 131de77d30e..9639fd98662 100644 --- a/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js +++ b/a3p-integration/proposals/p:upgrade-19/test-lib/mintHolder-helpers.js @@ -8,7 +8,7 @@ import { } from '@agoric/synthetic-chain'; import { makeVstorageKit, retryUntilCondition } from '@agoric/client-utils'; import { readFile, writeFile } from 'node:fs/promises'; -import { sendOfferAgd, psmSwap, snapshotAgoricNames } from './psm-helpers.js'; +import { psmSwap, snapshotAgoricNames } from './psm-lib.js'; /** * @param {string} fileName base file name without .tjs extension @@ -103,12 +103,18 @@ export const swap = async (t, address, assetList, want) => { const istBalanceBefore = await getISTBalance(address, 'uist'); const anchorBalanceBefore = await getISTBalance(address, denom); - await psmSwap(address, ['swap', '--pair', pair, '--wantMinted', want], { + const psmSwapIo = { now: Date.now, follow: agoric.follow, setTimeout, - sendOffer: sendOfferAgd, - }); + log: console.log, + }; + + await psmSwap( + address, + ['swap', '--pair', pair, '--wantMinted', want], + psmSwapIo, + ); const istBalanceAfter = await getISTBalance(address, 'uist'); const anchorBalanceAfter = await getISTBalance(address, denom); diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js deleted file mode 100644 index 954e954941c..00000000000 --- a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-helpers.js +++ /dev/null @@ -1,192 +0,0 @@ -/* eslint-env node */ - -import { execa } from 'execa'; -import { - boardSlottingMarshaller, - makeFromBoard, - waitUntilOfferResult, - fetchEnvNetworkConfig, -} from '@agoric/client-utils'; -import { - agopsLocation, - agoric, - executeCommand, - mkTemp, -} from '@agoric/synthetic-chain'; -import fsp from 'node:fs/promises'; - -/** @import {Result as ExecaResult, ExecaError} from 'execa'; */ -/** - * @typedef {ExecaResult & { all: string } & ( - * | { failed: false } - * | Pick< - * ExecaError & { failed: true }, - * | 'failed' - * | 'shortMessage' - * | 'cause' - * | 'exitCode' - * | 'signal' - * | 'signalDescription' - * > - * )} SendOfferResult - */ - -/** - * @typedef {object} PsmMetrics - * @property {import('@agoric/ertp').Amount<'nat'>} anchorPoolBalance - * @property {import('@agoric/ertp').Amount<'nat'>} feePoolBalance - * @property {import('@agoric/ertp').Amount<'nat'>} mintedPoolBalance - * @property {import('@agoric/ertp').Amount<'nat'>} totalAnchorProvided - * @property {import('@agoric/ertp').Amount<'nat'>} totalMintedProvided - */ - -const fromBoard = makeFromBoard(); -const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); - -/** - * @param {string} path - */ -const objectFromVstorageEntries = async path => { - const rawEntries = await agoric.follow('-lF', `:${path}`, '-o', 'text'); - return Object.fromEntries(marshaller.fromCapData(JSON.parse(rawEntries))); -}; - -export const snapshotAgoricNames = async () => { - const [brands, instances, vbankAssets] = await Promise.all([ - objectFromVstorageEntries('published.agoricNames.brand'), - objectFromVstorageEntries('published.agoricNames.instance'), - objectFromVstorageEntries('published.agoricNames.vbankAsset'), - ]); - return { brands, instances, vbankAssets }; -}; - -/** - * Similar to - * https://github.com/Agoric/agoric-3-proposals/blob/422b163fecfcf025d53431caebf6d476778b5db3/packages/synthetic-chain/src/lib/commonUpgradeHelpers.ts#L123-L139 - * However, for an address that is not provisioned, `agoric wallet send` is - * needed because `agops perf satisfaction` hangs when trying to follow - * nonexistent vstorage path ":published.wallet.${address}". - * - * @param {string} address - * @param {Promise} offerPromise - * @returns {Promise} - */ -export const sendOfferAgoric = async (address, offerPromise) => { - const offerPath = await mkTemp('agops.XXX'); - const offer = await offerPromise; - await fsp.writeFile(offerPath, offer); - - const [settlement] = await Promise.allSettled([ - execa({ - all: true, - })`agoric wallet --keyring-backend=test send --offer ${offerPath} --from ${address} --verbose`, - ]); - return settlement.status === 'fulfilled' - ? settlement.value - : settlement.reason; -}; - -/** - * A variant of {@link sendOfferAgoric} that uses `agd` directly to e.g. - * control gas calculation. - * - * @param {string} address - * @param {Promise} offerPromise - * @returns {Promise} - */ -export const sendOfferAgd = async (address, offerPromise) => { - const offer = await offerPromise; - const networkConfig = await fetchEnvNetworkConfig({ - env: process.env, - fetch, - }); - const { chainName, rpcAddrs } = networkConfig; - const args = /** @type {string[]} */ ( - // @ts-expect-error heterogeneous concat - [].concat( - [`--node=${rpcAddrs[0]}`, `--chain-id=${chainName}`], - [`--keyring-backend=test`, `--from=${address}`], - ['tx', 'swingset', 'wallet-action', '--allow-spend', offer], - '--yes', - '-bblock', - '-ojson', - ) - ); - - const [settlement] = await Promise.allSettled([ - execa('agd', args, { all: true }), - ]); - - // Upon successful exit, verify that the *output* also indicates success. - // cf. https://github.com/Agoric/agoric-sdk/blob/master/packages/agoric-cli/src/lib/wallet.js - if (settlement.status === 'fulfilled') { - const result = settlement.value; - try { - const tx = JSON.parse(result.stdout); - if (tx.code !== 0) { - return { ...result, failed: true, shortMessage: `code ${tx.code}` }; - } - } catch (err) { - return { - ...result, - failed: true, - shortMessage: 'unexpected output', - cause: err, - }; - } - } - - return settlement.status === 'fulfilled' - ? settlement.value - : settlement.reason; -}; - -/** - * @param {string} address - * @param {Array} params - * @param {{ - * follow: (...params: string[]) => Promise; - * sendOffer?: (address: string, offerPromise: Promise) => Promise; - * setTimeout: typeof global.setTimeout; - * now: () => number - * }} io - */ -export const psmSwap = async (address, params, io) => { - const { now, sendOffer = sendOfferAgoric, ...waitIO } = io; - const offerId = `${address}-psm-swap-${now()}`; - const newParams = ['psm', ...params, '--offerId', offerId]; - const offerPromise = executeCommand(agopsLocation, newParams); - const sendResult = await sendOffer(address, offerPromise); - if (sendResult.failed) { - const { - command, - durationMs, - shortMessage, - cause, - exitCode, - signal, - signalDescription, - all: output, - } = sendResult; - const summary = { - command, - durationMs, - shortMessage, - cause, - exitCode, - signal, - signalDescription, - output, - }; - console.error('psmSwap tx send failed', summary); - throw Error( - `psmSwap tx send failed: ${JSON.stringify({ exitCode, signal, signalDescription })}`, - { cause }, - ); - } - console.log('psmSwap tx send results', sendResult.all); - - await waitUntilOfferResult(address, offerId, true, waitIO, { - errorMessage: `${offerId} not succeeded`, - }); -}; diff --git a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js index 8f8d0abadc8..f98f5f6508c 100644 --- a/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js +++ b/a3p-integration/proposals/p:upgrade-19/test-lib/psm-lib.js @@ -3,10 +3,15 @@ import { execa } from 'execa'; import { getNetworkConfig } from 'agoric/src/helpers.js'; -import { waitUntilOfferResult } from '@agoric/client-utils'; +import { + waitUntilOfferResult, + makeFromBoard, + boardSlottingMarshaller, +} from '@agoric/client-utils'; import { deepMapObject } from '@agoric/internal'; import { agd, + agoric, agopsLocation, CHAINID, executeCommand, @@ -285,3 +290,23 @@ export const tryISTBalances = async (t, actualBalance, expectedBalance) => { const minFeeDebit = 200_000; t.is(actualBalance + minFeeDebit, expectedBalance); }; + +const fromBoard = makeFromBoard(); +const marshaller = boardSlottingMarshaller(fromBoard.convertSlotToVal); + +/** + * @param {string} path + */ +const objectFromVstorageEntries = async path => { + const rawEntries = await agoric.follow('-lF', `:${path}`, '-o', 'text'); + return Object.fromEntries(marshaller.fromCapData(JSON.parse(rawEntries))); +}; + +export const snapshotAgoricNames = async () => { + const [brands, instances, vbankAssets] = await Promise.all([ + objectFromVstorageEntries('published.agoricNames.brand'), + objectFromVstorageEntries('published.agoricNames.instance'), + objectFromVstorageEntries('published.agoricNames.vbankAsset'), + ]); + return { brands, instances, vbankAssets }; +}; From 12510e94355421108c06396b836df910835a998c Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Mon, 9 Dec 2024 13:58:33 -0500 Subject: [PATCH 16/42] chore: resolve `withdrawToSeat` TODO with comment --- packages/fast-usdc/src/exos/settler.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index 5d092dd87cb..b8952d8086a 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -237,13 +237,13 @@ export const prepareSettler = ( const split = calculateSplit(received); log('disbursing', split); - // TODO: what if this throws? - // arguably, it cannot. Even if deposits - // and notifications get out of order, - // we don't ever withdraw more than has been deposited. + // If this throws, which arguably can't occur since we don't ever + // withdraw more than has been deposited (as denoted by + // `FungibleTokenPacketData`), funds will remain in the + // `settlementAccount`. A remediation can occur in a future upgrade. await vowTools.when( withdrawToSeat( - // @ts-expect-error Vow vs. Promise stuff. TODO: is this OK??? + // @ts-expect-error LocalAccountMethods vs OrchestrationAccount settlementAccount, settlingSeat, harden({ In: received }), From d04c5eac94e1954456cd23e9006e9f4daabb3759 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 12:00:24 -0500 Subject: [PATCH 17/42] fix: do not stringify logs --- packages/fast-usdc/src/exos/advancer.js | 27 +++--- packages/fast-usdc/test/exos/advancer.test.ts | 84 ++++++++++++++----- .../src/exos/local-orchestration-account.js | 2 +- 3 files changed, 78 insertions(+), 35 deletions(-) diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index 5fc01abfa38..9608b9de1cb 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -3,7 +3,6 @@ import { assertAllDefined, makeTracer } from '@agoric/internal'; import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration'; import { pickFacet } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; -import { q } from '@endo/errors'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; import { @@ -153,6 +152,7 @@ export const prepareAdvancerKit = ( recipientAddress, EudParamShape, ); + log(`decoded EUD: ${EUD}`); // throws if the bech32 prefix is not found const destination = chainHub.makeChainAddress(EUD); @@ -182,8 +182,8 @@ export const prepareAdvancerKit = ( tmpSeat, txHash: evidence.txHash, }); - } catch (e) { - log('Advancer error:', q(e).toString()); + } catch (error) { + log('Advancer error:', error); statusManager.observe(evidence); } }, @@ -217,13 +217,13 @@ export const prepareAdvancerKit = ( */ onRejected(error, { tmpSeat }) { // TODO return seat allocation from ctx to LP? - log('🚨 advance deposit failed', q(error).toString()); - // TODO #10510 (comprehensive error testing) determine - // course of action here log( - 'TODO live payment on seat to return to LP', - q(tmpSeat).toString(), + '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP', + error, ); + // TODO #10510 (comprehensive error testing) determine + // course of action here + log('TODO live payment on seat to return to LP', tmpSeat); }, }, transferHandler: { @@ -234,10 +234,11 @@ export const prepareAdvancerKit = ( onFulfilled(result, ctx) { const { notifyFacet } = this.state; const { advanceAmount, destination, ...detail } = ctx; - log( - 'Advance transfer fulfilled', - q({ advanceAmount, destination, result }).toString(), - ); + log('Advance transfer fulfilled', { + advanceAmount, + destination, + result, + }); // During development, due to a bug, this call threw. // The failure was silent (no diagnostics) due to: // - #10576 Vows do not report unhandled rejections @@ -252,7 +253,7 @@ export const prepareAdvancerKit = ( */ onRejected(error, ctx) { const { notifyFacet } = this.state; - log('Advance transfer rejected', q(error).toString()); + log('Advance transfer rejected', error); notifyFacet.notifyAdvancingResult(ctx, false); }, }, diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 908880d3fb4..7c860d138d2 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -181,9 +181,23 @@ test('updates status to ADVANCING in happy path', async t => { 'ADVANCED status in happy path', ); - t.deepEqual(inspectLogs(0), [ - 'Advance transfer fulfilled', - '{"advanceAmount":{"brand":"[Alleged: USDC brand]","value":"[146999999n]"},"destination":{"chainId":"osmosis-1","encoding":"bech32","value":"osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"},"result":"[undefined]"}', + t.deepEqual(inspectLogs(), [ + ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + [ + 'Advance transfer fulfilled', + { + advanceAmount: { + brand: usdc.brand, + value: 146999999n, + }, + destination: { + chainId: 'osmosis-1', + encoding: 'bech32', + value: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + }, + result: undefined, + }, + ], ]); // We expect to see an `Advanced` update, but that is now Settler's job. @@ -232,9 +246,15 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { 'OBSERVED status on insufficient pool funds', ); - t.deepEqual(inspectLogs(0), [ - 'Advancer error:', - '"[Error: Cannot borrow. Requested {\\"brand\\":\\"[Alleged: USDC brand]\\",\\"value\\":\\"[294999999n]\\"} must be less than pool balance {\\"brand\\":\\"[Alleged: USDC brand]\\",\\"value\\":\\"[1n]\\"}.]"', + t.deepEqual(inspectLogs(), [ + ['decoded EUD: dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + [ + 'Advancer error:', + Error( + 'Cannot borrow. Requested {"brand":"[Alleged: USDC brand]","value":"[294999999n]"} ' + + 'must be less than pool balance {"brand":"[Alleged: USDC brand]","value":"[1n]"}.', + ), + ], ]); }); @@ -256,9 +276,12 @@ test('updates status to OBSERVED if makeChainAddress fails', async t => { 'OBSERVED status on makeChainAddress failure', ); - t.deepEqual(inspectLogs(0), [ - 'Advancer error:', - '"[Error: Chain info not found for bech32Prefix \\"random\\"]"', + t.deepEqual(inspectLogs(), [ + ['decoded EUD: random1addr'], + [ + 'Advancer error:', + Error('Chain info not found for bech32Prefix "random"'), + ], ]); }); @@ -289,9 +312,9 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t mockPoolAccount.transferVResolver.reject(new Error('simulated error')); await eventLoopIteration(); - t.deepEqual(inspectLogs(0), [ - 'Advance transfer rejected', - '"[Error: simulated error]"', + t.deepEqual(inspectLogs(), [ + ['decoded EUD: dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + ['Advance transfer rejected', Error('simulated error')], ]); // We expect to see an `AdvancedFailed` update, but that is now Settler's job. @@ -334,9 +357,13 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { 'tx is recorded as OBSERVED', ); - t.deepEqual(inspectLogs(0), [ - 'Advancer error:', - '"[Error: Unable to parse query params: \\"agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek\\"]"', + t.deepEqual(inspectLogs(), [ + [ + 'Advancer error:', + Error( + 'Unable to parse query params: "agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek"', + ), + ], ]); }); @@ -347,6 +374,7 @@ test('will not advance same txHash:chainId evidence twice', async t => { helpers: { inspectLogs }, mocks: { mockPoolAccount, resolveLocalTransferV }, }, + brands: { usdc }, } = t.context; const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); @@ -357,17 +385,31 @@ test('will not advance same txHash:chainId evidence twice', async t => { mockPoolAccount.transferVResolver.resolve(); await eventLoopIteration(); - t.deepEqual(inspectLogs(0), [ - 'Advance transfer fulfilled', - '{"advanceAmount":{"brand":"[Alleged: USDC brand]","value":"[146999999n]"},"destination":{"chainId":"osmosis-1","encoding":"bech32","value":"osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"},"result":"[undefined]"}', + t.deepEqual(inspectLogs(), [ + ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + [ + 'Advance transfer fulfilled', + { + advanceAmount: { brand: usdc.brand, value: 146999999n }, + destination: { + chainId: 'osmosis-1', + encoding: 'bech32', + value: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + }, + result: undefined, + }, + ], ]); // Second attempt void advancer.handleTransactionEvent(mockEvidence); await eventLoopIteration(); - t.deepEqual(inspectLogs(1), [ - 'txHash already seen:', - '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', + const [, , ...remainingLogs] = inspectLogs(); + t.deepEqual(remainingLogs, [ + [ + 'txHash already seen:', + '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761702', + ], ]); }); diff --git a/packages/orchestration/src/exos/local-orchestration-account.js b/packages/orchestration/src/exos/local-orchestration-account.js index 362ac8950d7..41d151475fd 100644 --- a/packages/orchestration/src/exos/local-orchestration-account.js +++ b/packages/orchestration/src/exos/local-orchestration-account.js @@ -690,7 +690,7 @@ export const prepareLocalOrchestrationAccountKit = ( 'agoric', forwardOpts, ); - trace('got transfer route', q(route).toString()); + trace('got transfer route', route); // set a `timeoutTimestamp` if caller does not supply either `timeoutHeight` or `timeoutTimestamp` // TODO #9324 what's a reasonable default? currently 5 minutes From b7065e715a68c6b73a3e5325eb88211509d3b1e2 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 14:28:25 -0500 Subject: [PATCH 18/42] chore: return advance payment to LP if `zoeTools.localTransfer` fails --- packages/fast-usdc/src/exos/advancer.js | 23 ++- packages/fast-usdc/src/exos/liquidity-pool.js | 29 ++- packages/fast-usdc/test/exos/advancer.test.ts | 177 ++++++++++++++++-- 3 files changed, 204 insertions(+), 25 deletions(-) diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index 9608b9de1cb..cc1facdb9eb 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -212,18 +212,31 @@ export const prepareAdvancerKit = ( }); }, /** + * We do not expect this to be a common failure. it should only occur + * if USDC is not registered in vbank or the tmpSeat has less than + * `advanceAmount`. + * + * If we do hit this path, we return funds to the Liquidity Pool and + * notify of Advancing failure. + * * @param {Error} error * @param {AdvancerVowCtx & { tmpSeat: ZCFSeat }} ctx */ - onRejected(error, { tmpSeat }) { - // TODO return seat allocation from ctx to LP? + onRejected(error, { tmpSeat, advanceAmount, ...restCtx }) { log( '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP', error, ); - // TODO #10510 (comprehensive error testing) determine - // course of action here - log('TODO live payment on seat to return to LP', tmpSeat); + try { + const { borrowerFacet, notifyFacet } = this.state; + notifyFacet.notifyAdvancingResult(restCtx, false); + borrowerFacet.returnToPool( + tmpSeat, + harden({ USDC: advanceAmount }), + ); + } catch (e) { + log('🚨 deposit to localOrchAccount failure recovery failed', e); + } }, }, transferHandler: { diff --git a/packages/fast-usdc/src/exos/liquidity-pool.js b/packages/fast-usdc/src/exos/liquidity-pool.js index d8b2991a4df..21a7f612dfd 100644 --- a/packages/fast-usdc/src/exos/liquidity-pool.js +++ b/packages/fast-usdc/src/exos/liquidity-pool.js @@ -28,7 +28,7 @@ import { * @import {PoolStats} from '../types.js'; */ -const { add, isEqual, makeEmpty } = AmountMath; +const { add, isEqual, isGTE, makeEmpty } = AmountMath; /** @param {Brand} brand */ const makeDust = brand => AmountMath.make(brand, 1n); @@ -88,6 +88,10 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { SeatShape, harden({ USDC: makeNatAmountShape(USDC, 1n) }), ).returns(), + returnToPool: M.call( + SeatShape, + harden({ USDC: makeNatAmountShape(USDC, 1n) }), + ).returns(), }), repayer: M.interface('repayer', { repay: M.call( @@ -178,7 +182,28 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { Object.assign(this.state, post); this.facets.external.publishPoolMetrics(); }, - // TODO method to repay failed `LOA.deposit()` + /** + * If something fails during advance, return funds to the pool. + * + * @param {ZCFSeat} borrowSeat + * @param {{ USDC: Amount<'nat'>}} amountKWR + */ + returnToPool(borrowSeat, amountKWR) { + const { zcfSeat: repaySeat } = zcf.makeEmptySeatKit(); + const returnAmounts = harden({ + Principal: amountKWR.USDC, + PoolFee: makeEmpty(USDC), + ContractFee: makeEmpty(USDC), + }); + const borrowSeatAllocation = borrowSeat.getCurrentAllocation(); + isGTE(borrowSeatAllocation.USDC, amountKWR.USDC) || + Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amountKWR)}`; + // arrange payments in a format repay is expecting + zcf.atomicRearrange( + harden([[borrowSeat, repaySeat, amountKWR, returnAmounts]]), + ); + return this.facets.repayer.repay(repaySeat, returnAmounts); + }, }, repayer: { /** diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index 7c860d138d2..b6323e586a7 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -6,7 +6,7 @@ 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 { Fail, q } from '@endo/errors'; import { PendingTxStatus } from '../../src/constants.js'; import { prepareAdvancer } from '../../src/exos/advancer.js'; import type { SettlerKit } from '../../src/exos/settler.js'; @@ -20,6 +20,7 @@ import { makeTestLogger, prepareMockOrchAccounts, } from '../mocks.js'; +import type { LiquidityPoolKit } from '../../src/types.js'; const LOCAL_DENOM = `ibc/${denomHash({ denom: 'uusdc', @@ -62,6 +63,11 @@ const createTestExtensions = (t, common: CommonSetup) => { // pretend funds move from tmpSeat to poolAccount localTransferVK.resolver.resolve(); }; + const rejectLocalTransfeferV = () => { + localTransferVK.resolver.reject( + new Error('One or more deposits failed: simulated error'), + ); + }; const mockZoeTools = Far('MockZoeTools', { localTransfer(...args: Parameters) { console.log('ZoeTools.localTransfer called with', args); @@ -94,18 +100,17 @@ const createTestExtensions = (t, common: CommonSetup) => { }, }); + const mockBorrowerFacetCalls: { + borrow: Parameters[]; + returnToPool: Parameters[]; + } = { borrow: [], returnToPool: [] }; + const mockBorrowerF = Far('LiquidityPool Borrow Facet', { borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { - console.log('LP.borrow called with', amounts); + mockBorrowerFacetCalls.borrow.push([seat, amounts]); }, - }); - - const mockBorrowerErrorF = Far('LiquidityPool Borrow Facet', { - borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { - console.log('LP.borrow called with', amounts); - throw new Error( - `Cannot borrow. Requested ${q(amounts.USDC)} must be less than pool balance ${q(usdc.make(1n))}.`, - ); + returnToPool: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + mockBorrowerFacetCalls.returnToPool.push([seat, amounts]); }, }); @@ -124,12 +129,13 @@ const createTestExtensions = (t, common: CommonSetup) => { helpers: { inspectLogs, inspectNotifyCalls: () => harden(notifyAdvancingResultCalls), + inspectBorrowerFacetCalls: () => harden(mockBorrowerFacetCalls), }, mocks: { ...mockAccounts, - mockBorrowerErrorF, mockNotifyF, resolveLocalTransferV, + rejectLocalTransfeferV, }, services: { advancer, @@ -220,17 +226,27 @@ test('updates status to ADVANCING in happy path', async t => { test('updates status to OBSERVED on insufficient pool funds', async t => { const { + brands: { usdc }, bootstrap: { storage }, extensions: { services: { makeAdvancer, statusManager }, helpers: { inspectLogs }, - mocks: { mockPoolAccount, mockBorrowerErrorF, mockNotifyF }, + mocks: { mockPoolAccount, mockNotifyF }, }, } = t.context; + const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', { + borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + throw new Error( + `Cannot borrow. Requested ${q(amounts.USDC)} must be less than pool balance ${q(usdc.make(1n))}.`, + ); + }, + returnToPool: () => {}, // not expecting this to be called + }); + // make a new advancer that intentionally throws const advancer = makeAdvancer({ - borrowerFacet: mockBorrowerErrorF, + borrowerFacet: mockBorrowerFacet, notifyFacet: mockNotifyF, poolAccount: mockPoolAccount.account, intermediateRecipient, @@ -251,8 +267,7 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { [ 'Advancer error:', Error( - 'Cannot borrow. Requested {"brand":"[Alleged: USDC brand]","value":"[294999999n]"} ' + - 'must be less than pool balance {"brand":"[Alleged: USDC brand]","value":"[1n]"}.', + `Cannot borrow. Requested ${q(usdc.make(294999999n))} must be less than pool balance ${q(usdc.make(1n))}.`, ), ], ]); @@ -413,6 +428,132 @@ test('will not advance same txHash:chainId evidence twice', async t => { ]); }); -test.todo( - '#10510 zoeTools.localTransfer fails to deposit borrowed USDC to LOA', -); +test('returns payment to LP if zoeTools.localTransfer fails', async t => { + const { + extensions: { + services: { advancer }, + helpers: { inspectLogs, inspectBorrowerFacetCalls, inspectNotifyCalls }, + mocks: { rejectLocalTransfeferV }, + }, + brands: { usdc }, + } = t.context; + const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + + void advancer.handleTransactionEvent(mockEvidence); + rejectLocalTransfeferV(); + + await eventLoopIteration(); + + t.deepEqual( + inspectLogs(), + [ + ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + [ + '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP', + Error('One or more deposits failed: simulated error'), + ], + ], + 'contract logs report error', + ); + + const { borrow, returnToPool } = inspectBorrowerFacetCalls(); + + const expectedArguments = [ + Far('MockZCFSeat', {}), + { USDC: usdc.make(146999999n) }, // net of fees + ]; + + t.is(borrow.length, 1, 'borrow is called before zt.localTransfer fails'); + t.deepEqual(borrow[0], expectedArguments, 'borrow arguments match expected'); + + t.is( + returnToPool.length, + 1, + 'returnToPool is called after zt.localTransfer fails', + ); + t.deepEqual( + returnToPool[0], + expectedArguments, + 'same amount borrowed is returned to LP', + ); + + t.like( + inspectNotifyCalls(), + [ + [ + { + txHash: mockEvidence.txHash, + forwardingAddress: mockEvidence.tx.forwardingAddress, + }, + false, // indicates advance failed + ], + ], + 'Advancing tx is recorded as AdvanceFailed', + ); +}); + +test('alerts if `returnToPool` fallback fails', async t => { + const { + brands: { usdc }, + extensions: { + services: { makeAdvancer }, + helpers: { inspectLogs, inspectNotifyCalls }, + mocks: { mockPoolAccount, mockNotifyF, rejectLocalTransfeferV }, + }, + } = t.context; + + const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', { + borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + // note: will not be tracked by `inspectBorrowerFacetCalls` + }, + returnToPool: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + throw new Error( + `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(amounts)}`, + ); + }, + }); + + // make a new advancer that intentionally throws during returnToPool + const advancer = makeAdvancer({ + borrowerFacet: mockBorrowerFacet, + notifyFacet: mockNotifyF, + poolAccount: mockPoolAccount.account, + intermediateRecipient, + }); + + const mockEvidence = MockCctpTxEvidences.AGORIC_PLUS_OSMO(); + void advancer.handleTransactionEvent(mockEvidence); + rejectLocalTransfeferV(); + + await eventLoopIteration(); + + t.deepEqual(inspectLogs(), [ + ['decoded EUD: osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men'], + [ + '⚠️ deposit to localOrchAccount failed, attempting to return payment to LP', + Error('One or more deposits failed: simulated error'), + ], + [ + '🚨 deposit to localOrchAccount failure recovery failed', + Error( + `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q({ USDC: usdc.make(146999999n) })}`, + ), + ], + ]); + + await eventLoopIteration(); + + t.like( + inspectNotifyCalls(), + [ + [ + { + txHash: mockEvidence.txHash, + forwardingAddress: mockEvidence.tx.forwardingAddress, + }, + false, // indicates advance failed + ], + ], + 'Advancing tx is recorded as AdvanceFailed', + ); +}); From 81517e21746d3b6d7be1642a4e68a72643741e65 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 16:53:03 -0500 Subject: [PATCH 19/42] chore: do not call `shutdownWithFailure()` if `atomicRearrange()` fails - wait until #10684, where we can terminate an incarnation without terminating the contract - see https://github.com/Agoric/agoric-sdk/pull/10659#discussion_r1878631017 - note: try/catch/finally remains for `borrow()` and `deposit()` so we can exit seats --- packages/fast-usdc/src/exos/liquidity-pool.js | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/packages/fast-usdc/src/exos/liquidity-pool.js b/packages/fast-usdc/src/exos/liquidity-pool.js index 21a7f612dfd..9cdd37fee94 100644 --- a/packages/fast-usdc/src/exos/liquidity-pool.js +++ b/packages/fast-usdc/src/exos/liquidity-pool.js @@ -171,13 +171,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { ); // COMMIT POINT - try { - zcf.atomicRearrange(harden([[poolSeat, toSeat, amountKWR]])); - } catch (cause) { - const reason = Error('🚨 cannot commit borrow', { cause }); - console.error(reason.message, cause); - zcf.shutdownWithFailure(reason); - } + // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract + zcf.atomicRearrange(harden([[poolSeat, toSeat, amountKWR]])); Object.assign(this.state, post); this.facets.external.publishPoolMetrics(); @@ -233,23 +228,18 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { const { ContractFee, ...rest } = amounts; // COMMIT POINT - try { - zcf.atomicRearrange( - harden([ - [ - fromSeat, - poolSeat, - rest, - { USDC: add(amounts.PoolFee, amounts.Principal) }, - ], - [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }], - ]), - ); - } catch (cause) { - const reason = Error('🚨 cannot commit repay', { cause }); - console.error(reason.message, cause); - zcf.shutdownWithFailure(reason); - } + // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract + zcf.atomicRearrange( + harden([ + [ + fromSeat, + poolSeat, + rest, + { USDC: add(amounts.PoolFee, amounts.Principal) }, + ], + [fromSeat, feeSeat, { ContractFee }, { USDC: ContractFee }], + ]), + ); Object.assign(this.state, post); this.facets.external.publishPoolMetrics(); @@ -284,9 +274,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { const post = depositCalc(shareWorth, proposal); // COMMIT POINT - + const mint = shareMint.mintGains(post.payouts); try { - const mint = shareMint.mintGains(post.payouts); this.state.shareWorth = post.shareWorth; zcf.atomicRearrange( harden([ @@ -296,12 +285,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { [mint, lp, post.payouts], ]), ); + } catch (cause) { + // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract + throw new Error('🚨 cannot commit deposit', { cause }); + } finally { lp.exit(); mint.exit(); - } catch (cause) { - const reason = Error('🚨 cannot commit deposit', { cause }); - console.error(reason.message, cause); - zcf.shutdownWithFailure(reason); } external.publishPoolMetrics(); }, @@ -321,7 +310,6 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { const post = withdrawCalc(shareWorth, proposal); // COMMIT POINT - try { this.state.shareWorth = post.shareWorth; zcf.atomicRearrange( @@ -333,12 +321,12 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { ]), ); shareMint.burnLosses(proposal.give, burn); + } catch (cause) { + // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract + throw new Error('🚨 cannot commit withdraw', { cause }); + } finally { lp.exit(); burn.exit(); - } catch (cause) { - const reason = Error('🚨 cannot commit withdraw', { cause }); - console.error(reason.message, cause); - zcf.shutdownWithFailure(reason); } external.publishPoolMetrics(); }, From 50c1bd13affc72375802a061dbf58ba84088fc0c Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 12 Dec 2024 17:08:58 -0500 Subject: [PATCH 20/42] refactor: `LP.borrowerFacet` expects `Amount`, not `AmountKWR` --- packages/fast-usdc/src/exos/advancer.js | 10 ++----- packages/fast-usdc/src/exos/liquidity-pool.js | 30 ++++++++----------- packages/fast-usdc/test/exos/advancer.test.ts | 22 +++++++------- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index cc1facdb9eb..4fc29f6c253 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -161,9 +161,8 @@ export const prepareAdvancerKit = ( const advanceAmount = feeTools.calculateAdvance(fullAmount); const { zcfSeat: tmpSeat } = zcf.makeEmptySeatKit(); - const amountKWR = harden({ USDC: advanceAmount }); // throws if the pool has insufficient funds - borrowerFacet.borrow(tmpSeat, amountKWR); + borrowerFacet.borrow(tmpSeat, advanceAmount); // this cannot throw since `.isSeen()` is called in the same turn statusManager.advance(evidence); @@ -172,7 +171,7 @@ export const prepareAdvancerKit = ( tmpSeat, // @ts-expect-error LocalAccountMethods vs OrchestrationAccount poolAccount, - amountKWR, + harden({ USDC: advanceAmount }), ); void watch(depositV, this.facets.depositHandler, { fullAmount, @@ -230,10 +229,7 @@ export const prepareAdvancerKit = ( try { const { borrowerFacet, notifyFacet } = this.state; notifyFacet.notifyAdvancingResult(restCtx, false); - borrowerFacet.returnToPool( - tmpSeat, - harden({ USDC: advanceAmount }), - ); + borrowerFacet.returnToPool(tmpSeat, advanceAmount); } catch (e) { log('🚨 deposit to localOrchAccount failure recovery failed', e); } diff --git a/packages/fast-usdc/src/exos/liquidity-pool.js b/packages/fast-usdc/src/exos/liquidity-pool.js index 9cdd37fee94..5df4c86bbf2 100644 --- a/packages/fast-usdc/src/exos/liquidity-pool.js +++ b/packages/fast-usdc/src/exos/liquidity-pool.js @@ -84,14 +84,8 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { 'Liquidity Pool', { borrower: M.interface('borrower', { - borrow: M.call( - SeatShape, - harden({ USDC: makeNatAmountShape(USDC, 1n) }), - ).returns(), - returnToPool: M.call( - SeatShape, - harden({ USDC: makeNatAmountShape(USDC, 1n) }), - ).returns(), + borrow: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(), + returnToPool: M.call(SeatShape, makeNatAmountShape(USDC, 1n)).returns(), }), repayer: M.interface('repayer', { repay: M.call( @@ -157,14 +151,14 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { borrower: { /** * @param {ZCFSeat} toSeat - * @param {{ USDC: Amount<'nat'>}} amountKWR + * @param {Amount<'nat'>} amount */ - borrow(toSeat, amountKWR) { + borrow(toSeat, amount) { const { encumberedBalance, poolSeat, poolStats } = this.state; // Validate amount is available in pool const post = borrowCalc( - amountKWR.USDC, + amount, poolSeat.getAmountAllocated('USDC', USDC), encumberedBalance, poolStats, @@ -172,7 +166,7 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { // COMMIT POINT // UNTIL #10684: ability to terminate an incarnation w/o terminating the contract - zcf.atomicRearrange(harden([[poolSeat, toSeat, amountKWR]])); + zcf.atomicRearrange(harden([[poolSeat, toSeat, { USDC: amount }]])); Object.assign(this.state, post); this.facets.external.publishPoolMetrics(); @@ -181,21 +175,21 @@ export const prepareLiquidityPoolKit = (zone, zcf, USDC, tools) => { * If something fails during advance, return funds to the pool. * * @param {ZCFSeat} borrowSeat - * @param {{ USDC: Amount<'nat'>}} amountKWR + * @param {Amount<'nat'>} amount */ - returnToPool(borrowSeat, amountKWR) { + returnToPool(borrowSeat, amount) { const { zcfSeat: repaySeat } = zcf.makeEmptySeatKit(); const returnAmounts = harden({ - Principal: amountKWR.USDC, + Principal: amount, PoolFee: makeEmpty(USDC), ContractFee: makeEmpty(USDC), }); const borrowSeatAllocation = borrowSeat.getCurrentAllocation(); - isGTE(borrowSeatAllocation.USDC, amountKWR.USDC) || - Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amountKWR)}`; + isGTE(borrowSeatAllocation.USDC, amount) || + Fail`⚠️ borrowSeatAllocation ${q(borrowSeatAllocation)} less than amountKWR ${q(amount)}`; // arrange payments in a format repay is expecting zcf.atomicRearrange( - harden([[borrowSeat, repaySeat, amountKWR, returnAmounts]]), + harden([[borrowSeat, repaySeat, { USDC: amount }, returnAmounts]]), ); return this.facets.repayer.repay(repaySeat, returnAmounts); }, diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index b6323e586a7..d724e4a1cf8 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -106,11 +106,11 @@ const createTestExtensions = (t, common: CommonSetup) => { } = { borrow: [], returnToPool: [] }; const mockBorrowerF = Far('LiquidityPool Borrow Facet', { - borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { - mockBorrowerFacetCalls.borrow.push([seat, amounts]); + borrow: (seat: ZCFSeat, amount: NatAmount) => { + mockBorrowerFacetCalls.borrow.push([seat, amount]); }, - returnToPool: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { - mockBorrowerFacetCalls.returnToPool.push([seat, amounts]); + returnToPool: (seat: ZCFSeat, amount: NatAmount) => { + mockBorrowerFacetCalls.returnToPool.push([seat, amount]); }, }); @@ -236,9 +236,9 @@ test('updates status to OBSERVED on insufficient pool funds', async t => { } = t.context; const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', { - borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + borrow: (seat: ZCFSeat, amount: NatAmount) => { throw new Error( - `Cannot borrow. Requested ${q(amounts.USDC)} must be less than pool balance ${q(usdc.make(1n))}.`, + `Cannot borrow. Requested ${q(amount)} must be less than pool balance ${q(usdc.make(1n))}.`, ); }, returnToPool: () => {}, // not expecting this to be called @@ -460,7 +460,7 @@ test('returns payment to LP if zoeTools.localTransfer fails', async t => { const expectedArguments = [ Far('MockZCFSeat', {}), - { USDC: usdc.make(146999999n) }, // net of fees + usdc.make(146999999n), // net of fees ]; t.is(borrow.length, 1, 'borrow is called before zt.localTransfer fails'); @@ -503,12 +503,12 @@ test('alerts if `returnToPool` fallback fails', async t => { } = t.context; const mockBorrowerFacet = Far('LiquidityPool Borrow Facet', { - borrow: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + borrow: (seat: ZCFSeat, amount: NatAmount) => { // note: will not be tracked by `inspectBorrowerFacetCalls` }, - returnToPool: (seat: ZCFSeat, amounts: { USDC: NatAmount }) => { + returnToPool: (seat: ZCFSeat, amount: NatAmount) => { throw new Error( - `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(amounts)}`, + `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(amount)}`, ); }, }); @@ -536,7 +536,7 @@ test('alerts if `returnToPool` fallback fails', async t => { [ '🚨 deposit to localOrchAccount failure recovery failed', Error( - `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q({ USDC: usdc.make(146999999n) })}`, + `⚠️ borrowSeatAllocation ${q({ USDC: usdc.make(0n) })} less than amountKWR ${q(usdc.make(146999999n))}`, ), ], ]); From e3c26655258f43c639c6b5e3e66c49e5cb6f0afd Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Wed, 11 Dec 2024 14:57:59 -0600 Subject: [PATCH 21/42] fix(address-hooks): throw if the version is unsupported --- packages/cosmic-proto/src/address-hooks.js | 70 +++++++++---------- .../cosmic-proto/test/address-hooks.test.js | 56 +++++++++++++++ 2 files changed, 91 insertions(+), 35 deletions(-) diff --git a/packages/cosmic-proto/src/address-hooks.js b/packages/cosmic-proto/src/address-hooks.js index 073f0783c71..819a38a2251 100644 --- a/packages/cosmic-proto/src/address-hooks.js +++ b/packages/cosmic-proto/src/address-hooks.js @@ -39,13 +39,13 @@ if ((ADDRESS_HOOK_VERSION & 0x0f) !== ADDRESS_HOOK_VERSION) { throw Error(`ADDRESS_HOOK_VERSION ${ADDRESS_HOOK_VERSION} exceeds 0x0f`); } -// AddressHookMagic is a magic byte prefix that identifies a hooked address. +// ADDRESS_HOOK_BYTE_PREFIX is a magic prefix that identifies a hooked address. // Chosen to make bech32 address hooks that look like "agoric10rch..." -const ADDRESS_HOOK_MAGIC = new Uint8Array([ +const ADDRESS_HOOK_BYTE_PREFIX = [ 0x78, 0xf1, - 0x70 | ADDRESS_HOOK_VERSION, -]); + 0x70, // | ADDRESS_HOOK_VERSION +]; /** * The default maximum number of characters in a bech32-encoded hooked address. @@ -140,13 +140,14 @@ export const joinHookedAddress = ( throw RangeError(`Hook data length ${hd} is not a non-negative integer`); } - const magicLength = ADDRESS_HOOK_MAGIC.length; + const prefixLength = ADDRESS_HOOK_BYTE_PREFIX.length; const hookBuf = new Uint8Array( - magicLength + b + hd + BASE_ADDRESS_LENGTH_BYTES, + prefixLength + b + hd + BASE_ADDRESS_LENGTH_BYTES, ); - hookBuf.set(ADDRESS_HOOK_MAGIC, 0); - hookBuf.set(bytes, magicLength); - hookBuf.set(hookData, magicLength + b); + hookBuf.set(ADDRESS_HOOK_BYTE_PREFIX, 0); + hookBuf[prefixLength - 1] |= ADDRESS_HOOK_VERSION; + hookBuf.set(bytes, prefixLength); + hookBuf.set(hookData, prefixLength + b); // Append the address length bytes, since we've already ensured these do not // exceed maxBaseAddressLength above. These are big-endian because the length @@ -195,56 +196,55 @@ export const decodeAddressHook = (addressHook, charLimit) => { /** * @param {string} specimen * @param {number} [charLimit] - * @returns {string | { baseAddress: string; hookData: Uint8Array }} + * @returns {{ baseAddress: string; hookData: Uint8Array }} */ -export const splitHookedAddressUnsafe = ( +export const splitHookedAddress = ( specimen, charLimit = DEFAULT_HOOKED_ADDRESS_CHAR_LIMIT, ) => { const { prefix, bytes } = decodeBech32(specimen, charLimit); - const magicLength = ADDRESS_HOOK_MAGIC.length; - for (let i = 0; i < magicLength; i += 1) { - if (bytes[i] !== ADDRESS_HOOK_MAGIC[i]) { + const prefixLength = ADDRESS_HOOK_BYTE_PREFIX.length; + let version = 0xff; + for (let i = 0; i < prefixLength; i += 1) { + let maybeMagicByte = bytes[i]; + if (i === prefixLength - 1) { + // Final byte has a low version nibble and a high magic nibble. + version = maybeMagicByte & 0x0f; + maybeMagicByte &= 0xf0; + } + if (maybeMagicByte !== ADDRESS_HOOK_BYTE_PREFIX[i]) { return { baseAddress: specimen, hookData: new Uint8Array() }; } } + if (version !== ADDRESS_HOOK_VERSION) { + throw TypeError(`Unsupported address hook version ${version}`); + } + let len = 0; for (let i = BASE_ADDRESS_LENGTH_BYTES - 1; i >= 0; i -= 1) { const byte = bytes.at(-i - 1); if (byte === undefined) { - return `Cannot get base address length from byte ${-i - 1} of ${bytes.length}`; + throw TypeError( + `Cannot get base address length from byte ${-i - 1} of ${bytes.length}`, + ); } len <<= 8; len |= byte; } const b = len; - if (b > bytes.length - BASE_ADDRESS_LENGTH_BYTES - magicLength) { - return `Base address length 0x${b.toString(16)} is longer than specimen length ${bytes.length - BASE_ADDRESS_LENGTH_BYTES - magicLength}`; + if (b > bytes.length - BASE_ADDRESS_LENGTH_BYTES - prefixLength) { + throw TypeError( + `Base address length 0x${b.toString(16)} is longer than specimen length ${bytes.length - BASE_ADDRESS_LENGTH_BYTES - prefixLength}`, + ); } - const baseAddressBuf = bytes.subarray(magicLength, magicLength + b); + const baseAddressBuf = bytes.subarray(prefixLength, prefixLength + b); const baseAddress = encodeBech32(prefix, baseAddressBuf, charLimit); - const hookData = bytes.subarray(magicLength + b, -BASE_ADDRESS_LENGTH_BYTES); + const hookData = bytes.subarray(prefixLength + b, -BASE_ADDRESS_LENGTH_BYTES); return { baseAddress, hookData }; }; - -/** - * @param {string} specimen - * @param {number} [charLimit] - * @returns {{ - * baseAddress: string; - * hookData: Uint8Array; - * }} - */ -export const splitHookedAddress = (specimen, charLimit) => { - const result = splitHookedAddressUnsafe(specimen, charLimit); - if (typeof result === 'object') { - return result; - } - throw Error(result); -}; diff --git a/packages/cosmic-proto/test/address-hooks.test.js b/packages/cosmic-proto/test/address-hooks.test.js index 31ce2334f10..a216fc3159d 100644 --- a/packages/cosmic-proto/test/address-hooks.test.js +++ b/packages/cosmic-proto/test/address-hooks.test.js @@ -42,6 +42,62 @@ test.before(async t => { t.context = await makeTestContext(); }); +/** + * @type {import('ava').Macro< + * [addressHook: string, baseAddress: string, hookDataStr: string, error?: any], + * { addressHooks: import('../src/address-hooks.js') } + * >} + */ +const splitMacro = test.macro({ + title(providedTitle = '', addressHook, _baseAddress, _hookDataStr, _error) { + return `${providedTitle} split ${addressHook}`; + }, + exec(t, addressHook, baseAddress, hookDataStr, error) { + const { splitHookedAddress } = t.context.addressHooks; + if (error) { + t.throws(() => splitHookedAddress(addressHook), error); + return; + } + const { baseAddress: ba, hookData: hd } = splitHookedAddress(addressHook); + t.is(ba, baseAddress); + const hookData = new TextEncoder().encode(hookDataStr); + t.deepEqual(hd, hookData); + }, +}); + +test('empty', splitMacro, '', '', '', { message: ' too short' }); +test('no hook', splitMacro, 'agoric1qqp0e5ys', 'agoric1qqp0e5ys', '', ''); +test( + 'Fast USDC', + splitMacro, + 'agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423padaek6me38qekget2vdhx66mtvy6kg7nrw5uhsaekd4uhwufswqex6dtsv44hxv3cd4jkuqpqvduyhf', + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + '?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', +); +test( + 'version 0', + splitMacro, + 'agoric10rchqqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9qx0p9wp', + 'agoric1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn3tn9p0', + '\x04\x03\x02\x01', +); +test( + 'version 1 reject', + splitMacro, + 'agoric10rchzqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q04n2fg', + '', + '', + { message: 'Unsupported address hook version 1' }, +); +test( + 'version 15 reject', + splitMacro, + 'agoric10rch7qqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q25ez2d', + '', + '', + { message: 'Unsupported address hook version 15' }, +); + /** * @type {import('ava').Macro< * [string, ArrayLike | undefined, ArrayLike, string], From d17e55b5d5c0a178e49ed9a0402ed52827074426 Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Wed, 11 Dec 2024 14:59:31 -0600 Subject: [PATCH 22/42] fix(cosmos): return an error if version is unsupported --- golang/cosmos/types/address_hooks.go | 20 +++++++--- golang/cosmos/types/address_hooks_test.go | 47 +++++++++++++++++++++++ 2 files changed, 61 insertions(+), 6 deletions(-) diff --git a/golang/cosmos/types/address_hooks.go b/golang/cosmos/types/address_hooks.go index b26fe1e85f4..073e9d48cf4 100644 --- a/golang/cosmos/types/address_hooks.go +++ b/golang/cosmos/types/address_hooks.go @@ -23,9 +23,9 @@ const ( BaseAddressLengthBytes = 2 ) -// AddressHookMagic is a magic byte prefix that identifies a hooked address. +// AddressHookBytePrefix is a magic prefix that identifies a hooked address. // Chosen to make bech32 address hooks that look like "agoric10rch..." -var AddressHookMagic = []byte{0x78, 0xf1, 0x70 | AddressHookVersion} +var AddressHookBytePrefix = []byte{0x78, 0xf1, 0x70 /* | AddressHookVersion */} func init() { if AddressHookVersion&0x0f != AddressHookVersion { @@ -51,12 +51,19 @@ func SplitHookedAddress(addr string) (string, []byte, error) { return "", []byte{}, err } - bz := bytes.TrimPrefix(payload, AddressHookMagic) - if len(bz) == len(payload) { + lastPrefixHighNibble := AddressHookBytePrefix[len(AddressHookBytePrefix)-1] + bz := bytes.TrimPrefix(payload, AddressHookBytePrefix[:len(AddressHookBytePrefix)-1]) + if len(bz) == len(payload) || len(bz) == 0 || bz[0]&0xf0 != lastPrefixHighNibble { // Return an unhooked address. return addr, []byte{}, nil } + version := bz[0] & 0x0f + bz = bz[1:] + if version != AddressHookVersion { + return "", []byte{}, fmt.Errorf("unsupported address hook version %d", version) + } + if len(bz) < BaseAddressLengthBytes { return "", []byte{}, fmt.Errorf("hooked address must have at least %d bytes", BaseAddressLengthBytes) } @@ -97,8 +104,9 @@ func JoinHookedAddress(baseAddr string, hookData []byte) (string, error) { return "", fmt.Errorf("base address length 0x%x is longer than the maximum 0x%x", b, maxB) } - payload := make([]byte, 0, len(AddressHookMagic)+b+len(hookData)+BaseAddressLengthBytes) - payload = append(payload, AddressHookMagic...) + payload := make([]byte, 0, len(AddressHookBytePrefix)+b+len(hookData)+BaseAddressLengthBytes) + payload = append(payload, AddressHookBytePrefix...) + payload[len(payload)-1] |= byte(AddressHookVersion) payload = append(payload, bz...) payload = append(payload, hookData...) baLen := make([]byte, BaseAddressLengthBytes) diff --git a/golang/cosmos/types/address_hooks_test.go b/golang/cosmos/types/address_hooks_test.go index 8ae9faad1e7..8dd7ed6c5b7 100644 --- a/golang/cosmos/types/address_hooks_test.go +++ b/golang/cosmos/types/address_hooks_test.go @@ -15,6 +15,53 @@ import ( "github.com/Agoric/agoric-sdk/golang/cosmos/types" ) +func TestSplitHookedAddress(t *testing.T) { + cases := []struct { + name string + hook string + baseAddr string + hookData []byte + err string + }{ + {"empty", "", "", []byte{}, "decoding bech32 failed: invalid bech32 string length 0"}, + {"no hook", "agoric1qqp0e5ys", "agoric1qqp0e5ys", []byte{}, ""}, + {"Fast USDC", "agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423padaek6me38qekget2vdhx66mtvy6kg7nrw5uhsaekd4uhwufswqex6dtsv44hxv3cd4jkuqpqvduyhf", + "agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek", + []byte("?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men"), + ""}, + {"version 0", + "agoric10rchqqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9qx0p9wp", + "agoric1qqqsyqcyq5rqwzqfpg9scrgwpugpzysn3tn9p0", + []byte{4, 3, 2, 1}, + ""}, + {"version 1 reject", + "agoric10rchzqqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q04n2fg", + "", + []byte{}, + "unsupported address hook version 1"}, + {"version 15 reject", + "agoric10rch7qqpqgpsgpgxquyqjzstpsxsurcszyfpxpqrqgqsq9q25ez2d", + "", + []byte{}, + "unsupported address hook version 15"}, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + baseAddr, hookData, err := types.SplitHookedAddress(tc.hook) + if len(tc.err) > 0 { + require.Error(t, err) + require.Equal(t, tc.err, err.Error()) + } else { + require.NoError(t, err) + require.Equal(t, tc.baseAddr, baseAddr) + require.Equal(t, string(tc.hookData), string(hookData)) + } + }) + } +} + func TestExtractBaseAddress(t *testing.T) { bases := []struct { name string From 80fee6036eb186c8479ec5ddb66d34e09ba20f2b Mon Sep 17 00:00:00 2001 From: Michael FIG Date: Wed, 11 Dec 2024 15:17:53 -0600 Subject: [PATCH 23/42] fix(address-hooks): use `harden` (or `freeze`) --- packages/cosmic-proto/src/address-hooks.js | 32 +++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/cosmic-proto/src/address-hooks.js b/packages/cosmic-proto/src/address-hooks.js index 819a38a2251..aaa119f43a1 100644 --- a/packages/cosmic-proto/src/address-hooks.js +++ b/packages/cosmic-proto/src/address-hooks.js @@ -23,7 +23,7 @@ * const decoded = decodeAddressHook(addressHook); * // { * // baseAddress: 'agoric1qqp0e5ys', - * // query: [Object: null prototype] { foo: [ 'bar', 'baz' ], key: 'value' } + * // query: { foo: [ 'bar', 'baz' ], key: 'value' } * // } */ @@ -31,6 +31,10 @@ import { bech32 } from 'bech32'; import queryString from 'query-string'; +/* global globalThis */ +/** @type {(x: T) => T} */ +const harden = globalThis.harden || Object.freeze; + // ADDRESS_HOOK_VERSION is the version of the address hook format used in this // module. const ADDRESS_HOOK_VERSION = 0; @@ -46,6 +50,7 @@ const ADDRESS_HOOK_BYTE_PREFIX = [ 0xf1, 0x70, // | ADDRESS_HOOK_VERSION ]; +harden(ADDRESS_HOOK_BYTE_PREFIX); /** * The default maximum number of characters in a bech32-encoded hooked address. @@ -63,6 +68,9 @@ export const DEFAULT_HOOKED_ADDRESS_CHAR_LIMIT = 1024; * { key: ['value1', null, 'value3'] } // '?key=value1&key&key=value3' */ +/** + * How many bytes are used to store the length of the base address. + */ export const BASE_ADDRESS_LENGTH_BYTES = 2; /** @@ -78,8 +86,9 @@ export const decodeBech32 = ( const rawBytes = bech32.fromWords(words); const bytes = new Uint8Array(rawBytes); - return { prefix, bytes }; + return harden({ prefix, bytes }); }; +harden(decodeBech32); /** * @param {string} humanReadablePart @@ -95,6 +104,7 @@ export const encodeBech32 = ( const words = bech32.toWords(bytes); return bech32.encode(humanReadablePart, words, charLimit); }; +harden(encodeBech32); /** * Join raw base address bytes and hook data into a bech32-encoded hooked @@ -162,6 +172,7 @@ export const joinHookedAddress = ( return encodeBech32(prefix, hookBuf, charLimit); }; +harden(joinHookedAddress); /** * @param {string} baseAddress @@ -175,6 +186,7 @@ export const encodeAddressHook = (baseAddress, query, charLimit) => { const hookData = te.encode(`?${queryStr}`); return joinHookedAddress(baseAddress, hookData, charLimit); }; +harden(encodeAddressHook); /** * @param {string} addressHook @@ -188,10 +200,15 @@ export const decodeAddressHook = (addressHook, charLimit) => { throw Error(`Hook data does not start with '?': ${hookStr}`); } - /** @type {HookQuery} */ - const query = queryString.parse(hookStr); - return { baseAddress, query }; + const parsedQuery = queryString.parse(hookStr); + + /** + * @type {HookQuery} + */ + const query = harden({ ...parsedQuery }); + return harden({ baseAddress, query }); }; +harden(decodeAddressHook); /** * @param {string} specimen @@ -214,7 +231,7 @@ export const splitHookedAddress = ( maybeMagicByte &= 0xf0; } if (maybeMagicByte !== ADDRESS_HOOK_BYTE_PREFIX[i]) { - return { baseAddress: specimen, hookData: new Uint8Array() }; + return harden({ baseAddress: specimen, hookData: new Uint8Array() }); } } @@ -246,5 +263,6 @@ export const splitHookedAddress = ( const hookData = bytes.subarray(prefixLength + b, -BASE_ADDRESS_LENGTH_BYTES); - return { baseAddress, hookData }; + return harden({ baseAddress, hookData }); }; +harden(splitHookedAddress); From e86a5e16c3e1f68a05658ec0a4f153526c01f50f Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 11 Dec 2024 15:36:28 -0500 Subject: [PATCH 24/42] chore: `decodeAddressHook` `throws` annotation --- packages/cosmic-proto/src/address-hooks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cosmic-proto/src/address-hooks.js b/packages/cosmic-proto/src/address-hooks.js index aaa119f43a1..c1dcb2e415a 100644 --- a/packages/cosmic-proto/src/address-hooks.js +++ b/packages/cosmic-proto/src/address-hooks.js @@ -192,6 +192,7 @@ harden(encodeAddressHook); * @param {string} addressHook * @param {number} [charLimit] * @returns {{ baseAddress: string; query: HookQuery }} + * @throws {Error} if no hook string or hook string does not start with `?` */ export const decodeAddressHook = (addressHook, charLimit) => { const { baseAddress, hookData } = splitHookedAddress(addressHook, charLimit); From 6091992746dfc49dbe0dde135b2d3fd4ac8ea4b0 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 11 Dec 2024 17:10:51 -0500 Subject: [PATCH 25/42] chore: use address-hook encoding --- packages/fast-usdc/package.json | 1 + packages/fast-usdc/src/cli/transfer.js | 13 +-- packages/fast-usdc/src/exos/advancer.js | 16 ++-- packages/fast-usdc/src/exos/settler.js | 23 +++-- packages/fast-usdc/src/type-guards.js | 10 +- packages/fast-usdc/src/types.ts | 9 ++ packages/fast-usdc/src/utils/address.js | 71 -------------- .../test/cli/snapshots/transfer.test.ts.md | 2 +- .../test/cli/snapshots/transfer.test.ts.snap | Bin 548 -> 603 bytes packages/fast-usdc/test/cli/transfer.test.ts | 25 +++-- packages/fast-usdc/test/exos/advancer.test.ts | 34 +++++-- .../fast-usdc/test/fast-usdc.contract.test.ts | 13 +-- packages/fast-usdc/test/fixtures.ts | 18 +++- packages/fast-usdc/test/utils/address.test.ts | 87 ------------------ 14 files changed, 110 insertions(+), 212 deletions(-) delete mode 100644 packages/fast-usdc/src/utils/address.js delete mode 100644 packages/fast-usdc/test/utils/address.test.ts diff --git a/packages/fast-usdc/package.json b/packages/fast-usdc/package.json index 9f8e87b89ad..30e20a49253 100644 --- a/packages/fast-usdc/package.json +++ b/packages/fast-usdc/package.json @@ -33,6 +33,7 @@ }, "dependencies": { "@agoric/client-utils": "^0.1.0", + "@agoric/cosmic-proto": "^0.4.0", "@agoric/ertp": "^0.16.2", "@agoric/internal": "^0.3.2", "@agoric/notifier": "^0.6.2", diff --git a/packages/fast-usdc/src/cli/transfer.js b/packages/fast-usdc/src/cli/transfer.js index 9120f93be0a..41719ac1c37 100644 --- a/packages/fast-usdc/src/cli/transfer.js +++ b/packages/fast-usdc/src/cli/transfer.js @@ -6,6 +6,7 @@ import { makeVStorage, pickEndpoint, } from '@agoric/client-utils'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { queryFastUSDCLocalChainAccount } from '../util/agoric.js'; import { depositForBurn, makeProvider } from '../util/cctp.js'; import { @@ -22,7 +23,7 @@ import { const transfer = async ( /** @type {File} */ configFile, /** @type {string} */ amount, - /** @type {string} */ destination, + /** @type {string} */ EUD, out = console, fetch = globalThis.fetch, /** @type {VStorage | undefined} */ vstorage, @@ -39,13 +40,13 @@ const transfer = async ( { chainName: 'agoric', rpcAddrs: [pickEndpoint(netConfig)] }, ); const agoricAddr = await queryFastUSDCLocalChainAccount(vstorage, out); - const appendedAddr = `${agoricAddr}?EUD=${destination}`; - out.log(`forwarding destination ${appendedAddr}`); + const encodedAddr = encodeAddressHook(agoricAddr, { EUD }); + out.log(`forwarding destination ${encodedAddr}`); const { exists, address } = await queryForwardingAccount( config.nobleApi, config.nobleToAgoricChannel, - appendedAddr, + encodedAddr, out, fetch, ); @@ -58,13 +59,13 @@ const transfer = async ( signer, signerAddress, config.nobleToAgoricChannel, - appendedAddr, + encodedAddr, out, ); out.log(res); } catch (e) { out.error( - `Error registering noble forwarding account for ${appendedAddr} on channel ${config.nobleToAgoricChannel}`, + `Error registering noble forwarding account for ${encodedAddr} on channel ${config.nobleToAgoricChannel}`, ); throw e; } diff --git a/packages/fast-usdc/src/exos/advancer.js b/packages/fast-usdc/src/exos/advancer.js index 4fc29f6c253..f63c2b7474c 100644 --- a/packages/fast-usdc/src/exos/advancer.js +++ b/packages/fast-usdc/src/exos/advancer.js @@ -1,16 +1,16 @@ +import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { AmountMath } from '@agoric/ertp'; import { assertAllDefined, makeTracer } from '@agoric/internal'; import { AnyNatAmountShape, ChainAddressShape } from '@agoric/orchestration'; import { pickFacet } from '@agoric/vat-data'; import { VowShape } from '@agoric/vow'; import { E } from '@endo/far'; -import { M } from '@endo/patterns'; +import { M, mustMatch } from '@endo/patterns'; import { CctpTxEvidenceShape, - EudParamShape, + AddressHookShape, EvmHashShape, } from '../type-guards.js'; -import { addressTools } from '../utils/address.js'; import { makeFeeTools } from '../utils/fees.js'; /** @@ -21,7 +21,7 @@ import { makeFeeTools } from '../utils/fees.js'; * @import {ZoeTools} from '@agoric/orchestration/src/utils/zoe-tools.js'; * @import {VowTools} from '@agoric/vow'; * @import {Zone} from '@agoric/zone'; - * @import {CctpTxEvidence, EvmHash, FeeConfig, LogFn, NobleAddress} from '../types.js'; + * @import {CctpTxEvidence, AddressHook, EvmHash, FeeConfig, LogFn, NobleAddress} from '../types.js'; * @import {StatusManager} from './status-manager.js'; * @import {LiquidityPoolKit} from './liquidity-pool.js'; */ @@ -147,11 +147,9 @@ export const prepareAdvancerKit = ( const { borrowerFacet, poolAccount } = this.state; const { recipientAddress } = evidence.aux; - // throws if EUD is not found - const { EUD } = addressTools.getQueryParams( - recipientAddress, - EudParamShape, - ); + const decoded = decodeAddressHook(recipientAddress); + mustMatch(decoded, AddressHookShape); + const { EUD } = /** @type {AddressHook['query']} */ (decoded.query); log(`decoded EUD: ${EUD}`); // throws if the bech32 prefix is not found const destination = chainHub.makeChainAddress(EUD); diff --git a/packages/fast-usdc/src/exos/settler.js b/packages/fast-usdc/src/exos/settler.js index b8952d8086a..931961c01b7 100644 --- a/packages/fast-usdc/src/exos/settler.js +++ b/packages/fast-usdc/src/exos/settler.js @@ -5,8 +5,8 @@ import { atob } from '@endo/base64'; import { E } from '@endo/far'; import { M } from '@endo/patterns'; +import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import { PendingTxStatus } from '../constants.js'; -import { addressTools } from '../utils/address.js'; import { makeFeeTools } from '../utils/fees.js'; import { EvmHashShape } from '../type-guards.js'; @@ -151,14 +151,19 @@ export const prepareSettler = ( return; } - if (!addressTools.hasQueryParams(tx.receiver)) { - console.log('not query params', tx.receiver); - return; - } - - const { EUD } = addressTools.getQueryParams(tx.receiver); - if (!EUD) { - console.log('no EUD parameter', tx.receiver); + let EUD; + try { + ({ EUD } = decodeAddressHook(tx.receiver).query); + if (!EUD) { + log('no EUD parameter', tx.receiver); + return; + } + if (typeof EUD !== 'string') { + log('EUD is not a string', EUD); + return; + } + } catch (e) { + log('no query params', tx.receiver); return; } diff --git a/packages/fast-usdc/src/type-guards.js b/packages/fast-usdc/src/type-guards.js index ebc50505267..5281521ef12 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} from './types.js'; + * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook} from './types.js'; */ /** @@ -67,10 +67,12 @@ export const PendingTxShape = { }; harden(PendingTxShape); -export const EudParamShape = { - EUD: M.string(), +/** @type {TypedPattern} */ +export const AddressHookShape = { + baseAddress: M.string(), + query: { EUD: M.string() }, }; -harden(EudParamShape); +harden(AddressHookShape); const NatAmountShape = { brand: BrandShape, value: M.nat() }; /** @type {TypedPattern} */ diff --git a/packages/fast-usdc/src/types.ts b/packages/fast-usdc/src/types.ts index eac08e8a5b5..30dd64acbbc 100644 --- a/packages/fast-usdc/src/types.ts +++ b/packages/fast-usdc/src/types.ts @@ -85,5 +85,14 @@ export type FastUSDCConfig = { assetInfo: [Denom, DenomDetail & { brandKey?: string }][]; } & CopyRecord; +/** decoded address hook parameters */ +export type AddressHook = { + baseAddress: string; + query: { + /** end user destination address */ + EUD: string; + }; +}; + export type * from './constants.js'; export type { LiquidityPoolKit } from './exos/liquidity-pool.js'; diff --git a/packages/fast-usdc/src/utils/address.js b/packages/fast-usdc/src/utils/address.js deleted file mode 100644 index a84e8f0c5c9..00000000000 --- a/packages/fast-usdc/src/utils/address.js +++ /dev/null @@ -1,71 +0,0 @@ -import { makeError, q } from '@endo/errors'; -import { M, mustMatch } from '@endo/patterns'; - -/** - * @import {Pattern} from '@endo/patterns'; - */ - -/** - * Default pattern matcher for `getQueryParams`. - * Does not assert keys exist, but ensures existing keys are strings. - */ -const QueryParamsShape = M.splitRecord( - {}, - {}, - M.recordOf(M.string(), M.string()), -); - -/** - * Very minimal 'URL query string'-like parser that handles: - * - Query string delimiter (?) - * - Key-value separator (=) - * - Query parameter separator (&) - * - * Does not handle: - * - Subpaths (`agoric1bech32addr/opt/account?k=v`) - * - URI encoding/decoding (`%20` -> ` `) - * - note: `decodeURIComponent` seems to be available in XS - * - Multiple question marks (foo?bar=1?baz=2) - * - Empty parameters (foo=) - * - Array parameters (`foo?k=v1&k=v2` -> k: [v1, v2]) - * - Parameters without values (foo&bar=2) - */ -export const addressTools = { - /** - * @param {string} address - * @returns {boolean} - */ - hasQueryParams: address => { - try { - const params = addressTools.getQueryParams(address); - return Object.keys(params).length > 0; - } catch { - return false; - } - }, - /** - * @param {string} address - * @param {Pattern} [shape] - * @returns {Record} - * @throws {Error} if the address cannot be parsed or params do not match `shape` - */ - getQueryParams: (address, shape = QueryParamsShape) => { - const parts = address.split('?'); - if (parts.length !== 2) { - throw makeError(`Unable to parse query params: ${q(address)}`); - } - /** @type {Record} */ - const result = {}; - const paramPairs = parts[1].split('&'); - for (const pair of paramPairs) { - const [key, value] = pair.split('='); - if (!key || !value) { - throw makeError(`Invalid parameter format in pair: ${q(pair)}`); - } - result[key] = value; - } - harden(result); - mustMatch(result, shape); - return result; - }, -}; diff --git a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md index d88e5f3f969..156d050eba9 100644 --- a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md +++ b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.md @@ -15,7 +15,7 @@ Generated by [AVA](https://avajs.dev). typeUrl: '/noble.forwarding.v1.MsgRegisterAccount', value: { channel: 'channel-test-7', - recipient: 'agoric123456?EUD=dydx1234', + recipient: 'agoric10rchp4vc53apxn32q42c3zryml8xq3xshyzuhjk6405wtxy7tl3d7e0f8az423pav3ukg7p3xgengqpq4066gy', signer: 'noble09876', }, }, diff --git a/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap b/packages/fast-usdc/test/cli/snapshots/transfer.test.ts.snap index 4bce5856ec4461c2b2b2d46befce29a7d09bca7b..816eae485271501c45f2333e766b8706161e9b21 100644 GIT binary patch literal 603 zcmV-h0;K&xRzVgoI$I5W~g3 z*lwJ&b9YIdY?W9M12aSUQ}{FZ9~ck=6B5{QQf&36_fGHb`~AH4ZYJX>cBkt4E7zfp zc>3avWI|22v?TXKrMXm=4!9-aam1}jEU%dKLg8D?b>oH5RyeUjZFw(mjYF!ROUYJ5+o;`cgZ4l*&;uNi zfrn&*>W8$K`>~&mh6B)jqA%Icl!xE4&?p{|xqb2Yb-`nu7tV81=ISsOnJeQ5fL|3S zM#)Kw%s&830v=IO*myO*;D|0F*X@VzQ+mZe){{3PHvl~Eccl#QQ~Zd0!k{#HiY{K?b2$=%zbcb6yK zm&)IEvS?(EMaC^weaWH)|E~wOQB1z}&H$JJd@_Iov%*oUa+pICI5PoOEp3)d_mN4L zY21Jb!FMzVMSiTg(#OL}^*zbmFbTQP+ne{yk7ekd*wPJ>{?a{lSdt2-H}CgcXDwH= zXq3*KR0XT`BDkCm`u6FSPFF)6Io^=llM!3@drrcZ&SL5h6DRe#@aM_AZx06ksv_S| pp)a_+bGz@DRIxX^e)l#zQmUzYT*R|owpb|7{R_neYM|}|006_0Colj2 literal 548 zcmV+<0^9vTRzV&roAs_uAhDy+AV8XqD#kI8gd#wsq(n%F6cN>U zcf1~OW~`ZUu*-Y^qM)V-pF+te@DCIy1)@L-yWVx!Ri=7xbZ759@9p_;FgEdfclK3! z<;QY%@Wu-5hSG8?Q{}w0j{A}1+6=~$4~_jGY@&3^MI4){_FN6Q@;oupacw-8Gv&N; zT1?!?cz1T5B*Kg1;6;EYvO_HjcL6*Da10;;U;u1Tv`*o^wPH?GR_%5hv;t~?ZefEM zZc_jX*J&ls(|fwRvkkgQ^dj}mWW@st$`|)u7d(8wNS>35*ej#6RO}~!i&_#^ zNz$U=FMxo6yHp6HSA%yl_L)Udb~>Fr^din4<G1Aem;>$c3k!k9_B;tUM;?QMLmbJB~kyELb m_S!%5nkg4MU(Tw(*l$G>CQ_S|WjCF=B)$X%9dyE~0{{TmI0ShB diff --git a/packages/fast-usdc/test/cli/transfer.test.ts b/packages/fast-usdc/test/cli/transfer.test.ts index 729f40f63cc..28cd3d41569 100644 --- a/packages/fast-usdc/test/cli/transfer.test.ts +++ b/packages/fast-usdc/test/cli/transfer.test.ts @@ -1,4 +1,5 @@ import test from 'ava'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; import transfer from '../../src/cli/transfer.js'; import { mockOut, @@ -63,14 +64,18 @@ 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 = 'agoric123456'; + const agoricSettlementAccount = + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek'; const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount'; const vstorageMock = makeVstorageMock({ [settlementAccountVstoragePath]: agoricSettlementAccount, }); const amount = '150'; - const destination = 'dydx1234'; - const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${agoricSettlementAccount}${encodeURIComponent('?EUD=')}${destination}/`; + const EUD = 'dydx1234'; + const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${encodeAddressHook( + agoricSettlementAccount, + { EUD }, + )}/`; const fetchMock = makeFetchMock({ [nobleFwdAccountQuery]: { address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', @@ -84,7 +89,7 @@ test('Transfer registers the noble forwarding account if it does not exist', asy await transfer.transfer( file, amount, - destination, + EUD, // @ts-expect-error mocking console out, fetchMock.fetch, @@ -114,14 +119,18 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy }; const out = mockOut(); const file = mockFile(path, JSON.stringify(config)); - const agoricSettlementAccount = 'agoric123456'; + const agoricSettlementAccount = + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek'; const settlementAccountVstoragePath = 'published.fastUsdc.settlementAccount'; const vstorageMock = makeVstorageMock({ [settlementAccountVstoragePath]: agoricSettlementAccount, }); const amount = '150'; - const destination = 'dydx1234'; - const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${agoricSettlementAccount}${encodeURIComponent('?EUD=')}${destination}/`; + const EUD = 'dydx1234'; + const nobleFwdAccountQuery = `${nobleApi}/noble/forwarding/v1/address/${nobleToAgoricChannel}/${encodeAddressHook( + agoricSettlementAccount, + { EUD }, + )}/`; const fetchMock = makeFetchMock({ [nobleFwdAccountQuery]: { address: 'noble14lwerrcfzkzrv626w49pkzgna4dtga8c5x479h', @@ -135,7 +144,7 @@ test('Transfer signs and broadcasts the depositForBurn message on Ethereum', asy await transfer.transfer( file, amount, - destination, + EUD, // @ts-expect-error mocking console out, fetchMock.fetch, diff --git a/packages/fast-usdc/test/exos/advancer.test.ts b/packages/fast-usdc/test/exos/advancer.test.ts index d724e4a1cf8..b91e52485a9 100644 --- a/packages/fast-usdc/test/exos/advancer.test.ts +++ b/packages/fast-usdc/test/exos/advancer.test.ts @@ -6,13 +6,16 @@ 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 { Fail, q } from '@endo/errors'; +import { q } from '@endo/errors'; +import { + decodeAddressHook, + encodeAddressHook, +} from '@agoric/cosmic-proto/address-hooks.js'; 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 { makeFeeTools } from '../../src/utils/fees.js'; -import { addressTools } from '../../src/utils/address.js'; import { commonSetup } from '../supports.js'; import { MockCctpTxEvidences, intermediateRecipient } from '../fixtures.js'; import { @@ -215,8 +218,7 @@ test('updates status to ADVANCING in happy path', async t => { forwardingAddress: mockEvidence.tx.forwardingAddress, fullAmount: usdc.make(mockEvidence.tx.amount), destination: { - value: addressTools.getQueryParams(mockEvidence.aux.recipientAddress) - .EUD, + value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD, }, }, true, // indicates transfer succeeded @@ -344,8 +346,7 @@ test('calls notifyAdvancingResult (AdvancedFailed) on failed transfer', async t usdc.make(mockEvidence.tx.amount), ), destination: { - value: addressTools.getQueryParams(mockEvidence.aux.recipientAddress) - .EUD, + value: decodeAddressHook(mockEvidence.aux.recipientAddress).query.EUD, }, }, false, // this indicates transfer failed @@ -373,10 +374,29 @@ test('updates status to OBSERVED if pre-condition checks fail', async t => { ); t.deepEqual(inspectLogs(), [ + [ + 'Advancer error:', + Error('query: {} - Must have missing properties ["EUD"]'), + ], + ]); + + await advancer.handleTransactionEvent({ + ...MockCctpTxEvidences.AGORIC_NO_PARAMS( + encodeAddressHook( + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + { EUD: 'osmo1234', extra: 'value' }, + ), + ), + txHash: + '0xc81bc6105b60a234c7c50ac17816ebcd5561d366df8bf3be59ff387552761799', + }); + + const [, ...remainingLogs] = inspectLogs(); + t.deepEqual(remainingLogs, [ [ 'Advancer error:', Error( - 'Unable to parse query params: "agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek"', + 'query: {"EUD":"osmo1234","extra":"value"} - Must not have unexpected properties: ["extra"]', ), ], ]); diff --git a/packages/fast-usdc/test/fast-usdc.contract.test.ts b/packages/fast-usdc/test/fast-usdc.contract.test.ts index 872bffc2c0a..f7869f3def1 100644 --- a/packages/fast-usdc/test/fast-usdc.contract.test.ts +++ b/packages/fast-usdc/test/fast-usdc.contract.test.ts @@ -27,11 +27,14 @@ import { E } from '@endo/far'; import { matches, objectMap } 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'; import type { CctpTxEvidence, FeeConfig, PoolMetrics } from '../src/types.js'; -import { addressTools } from '../src/utils/address.js'; import { makeFeeTools } from '../src/utils/fees.js'; import { MockCctpTxEvidences } from './fixtures.js'; import { commonSetup, uusdcOnAgoric } from './supports.js'; @@ -382,7 +385,7 @@ const makeCustomer = ( return enough; }, sendFast: async (t: ExecutionContext, amount: bigint, EUD: string) => { - const recipientAddress = `${settleAddr}?EUD=${EUD}`; + const recipientAddress = encodeAddressHook(settleAddr, { EUD }); // KLUDGE: UI would ask noble for a forwardingAddress // "cctp" here has some noble stuff mixed in. const tx = cctp.makeTx(amount, recipientAddress); @@ -411,9 +414,7 @@ const makeCustomer = ( t.deepEqual(bank, []); // no vbank GIVE / GRAB } - const { EUD } = addressTools.getQueryParams( - evidence.aux.recipientAddress, - ); + const { EUD } = decodeAddressHook(evidence.aux.recipientAddress).query; const myMsg = local.find(lm => { if (lm.type !== 'VLOCALCHAIN_EXECUTE_TX') return false; @@ -442,7 +443,7 @@ const makeCustomer = ( 'C4', ); t.log(who, 'sees', ibcTransferMsg.token, 'sent to', EUD); - if (!EUD.startsWith('noble')) { + if (!(EUD as string).startsWith('noble')) { t.like( JSON.parse(ibcTransferMsg.memo), { diff --git a/packages/fast-usdc/test/fixtures.ts b/packages/fast-usdc/test/fixtures.ts index cbd83ccb657..7ffcedafb73 100644 --- a/packages/fast-usdc/test/fixtures.ts +++ b/packages/fast-usdc/test/fixtures.ts @@ -1,7 +1,8 @@ -import type { VTransferIBCEvent } from '@agoric/vats'; +import { encodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js'; 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'; const mockScenarios = [ @@ -31,7 +32,10 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + encodeAddressHook( + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + { EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' }, + ), }, chainId: 1, }), @@ -49,7 +53,10 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', + encodeAddressHook( + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + { EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men' }, + ), }, chainId: 1, }), @@ -85,7 +92,10 @@ export const MockCctpTxEvidences: Record< forwardingChannel: 'channel-21', recipientAddress: receiverAddress || - 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek?EUD=random1addr', + encodeAddressHook( + 'agoric16kv2g7snfc4q24vg3pjdlnnqgngtjpwtetd2h689nz09lcklvh5s8u37ek', + { EUD: 'random1addr' }, + ), }, chainId: 1, }), diff --git a/packages/fast-usdc/test/utils/address.test.ts b/packages/fast-usdc/test/utils/address.test.ts deleted file mode 100644 index d1c6ea23a3f..00000000000 --- a/packages/fast-usdc/test/utils/address.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { test } from '@agoric/zoe/tools/prepare-test-env-ava.js'; -import { M } from '@endo/patterns'; - -import { addressTools } from '../../src/utils/address.js'; -import { EudParamShape } from '../../src/type-guards.js'; - -const FIXTURES = { - AGORIC_WITH_DYDX: - 'agoric1bech32addr?EUD=dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', - AGORIC_WITH_OSMO: - 'agoric1bech32addr?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', - AGORIC_WITH_MULTIPLE: - 'agoric1bech32addr?EUD=osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men&CID=dydx-mainnet-1', - AGORIC_NO_PARAMS: 'agoric1bech32addr', - INVALID_MULTIPLE_QUESTION: 'agoric1bech32addr?param1=value1?param2=value2', - INVALID_PARAM_FORMAT: 'agoric1bech32addr?invalidparam', -} as const; - -// hasQueryParams tests -test('hasQueryParams: returns true when address has parameters', t => { - t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_DYDX)); - t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_OSMO)); - t.true(addressTools.hasQueryParams(FIXTURES.AGORIC_WITH_MULTIPLE)); -}); - -test('hasQueryParams: returns false when address has no parameters', t => { - t.false(addressTools.hasQueryParams(FIXTURES.AGORIC_NO_PARAMS)); -}); - -test('hasQueryParams: returns false for invalid parameter formats', t => { - t.false(addressTools.hasQueryParams(FIXTURES.INVALID_MULTIPLE_QUESTION)); - t.false(addressTools.hasQueryParams(FIXTURES.INVALID_PARAM_FORMAT)); -}); - -// getQueryParams tests - positive cases -test('getQueryParams: correctly parses address with single EUD parameter', t => { - const result = addressTools.getQueryParams( - FIXTURES.AGORIC_WITH_DYDX, - EudParamShape, - ); - t.deepEqual(result, { - EUD: 'dydx183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', - }); -}); - -test('getQueryParams: correctly parses address with multiple parameters', t => { - const pattern = harden({ EUD: M.string(), CID: M.string() }); - const result = addressTools.getQueryParams( - FIXTURES.AGORIC_WITH_MULTIPLE, - pattern, - ); - t.deepEqual(result, { - EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', - CID: 'dydx-mainnet-1', - }); -}); - -test('getQueryParams: returns all parameters when no shape is provided', t => { - const result = addressTools.getQueryParams(FIXTURES.AGORIC_WITH_MULTIPLE); - t.deepEqual(result, { - EUD: 'osmo183dejcnmkka5dzcu9xw6mywq0p2m5peks28men', - CID: 'dydx-mainnet-1', - }); -}); - -test('getQueryParams: correctly handles address with no parameters', t => { - t.throws(() => addressTools.getQueryParams(FIXTURES.AGORIC_NO_PARAMS), { - message: 'Unable to parse query params: "agoric1bech32addr"', - }); -}); - -// getQueryParams tests - negative cases -test('getQueryParams: throws error for multiple question marks', t => { - t.throws( - () => addressTools.getQueryParams(FIXTURES.INVALID_MULTIPLE_QUESTION), - { - message: - 'Unable to parse query params: "agoric1bech32addr?param1=value1?param2=value2"', - }, - ); -}); - -test('getQueryParams: throws error for invalid parameter format', t => { - t.throws(() => addressTools.getQueryParams(FIXTURES.INVALID_PARAM_FORMAT), { - message: 'Invalid parameter format in pair: "invalidparam"', - }); -}); From 14fa39b8e29da56315ea1c0c225e1592b674d0b6 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 3 Dec 2024 23:06:25 -0500 Subject: [PATCH 26/42] chore: `setupTestKeys` optionally takes mnemonics --- multichain-testing/test/support.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/multichain-testing/test/support.ts b/multichain-testing/test/support.ts index 18e8006f155..656c282df46 100644 --- a/multichain-testing/test/support.ts +++ b/multichain-testing/test/support.ts @@ -42,13 +42,19 @@ const makeKeyring = async ( e2eTools: Pick, ) => { let _keys = ['user1']; - const setupTestKeys = async (keys = ['user1']) => { + const setupTestKeys = async ( + keys = ['user1'], + mnemonics?: (string | undefined)[], + ) => { _keys = keys; const wallets: Record = {}; - for (const name of keys) { - const res = await e2eTools.addKey(name, generateMnemonic()); + for (const i in keys) { + const res = await e2eTools.addKey( + keys[i], + mnemonics?.[i] || generateMnemonic(), + ); const { address } = JSON.parse(res); - wallets[name] = address; + wallets[keys[i]] = address; } return wallets; }; @@ -117,10 +123,7 @@ export const commonSetup = async (t: ExecutionContext) => { ? objectMap( // eslint-disable-next-line @typescript-eslint/no-explicit-any builderOpts as Record, - value => { - if (typeof value === 'string') return value; - return JSON.stringify(value); - }, + value => (typeof value === 'string' ? value : JSON.stringify(value)), ) : undefined; await deployBuilder(contractBuilder, formattedOpts); From 6cb025af9158f72b491f3d5fb492b108aa8b5f34 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 3 Dec 2024 23:06:57 -0500 Subject: [PATCH 27/42] chore: export denom tools --- multichain-testing/tools/asset-info.ts | 46 +++++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/multichain-testing/tools/asset-info.ts b/multichain-testing/tools/asset-info.ts index ef4faf1d5ac..568cf6019c3 100644 --- a/multichain-testing/tools/asset-info.ts +++ b/multichain-testing/tools/asset-info.ts @@ -6,6 +6,31 @@ import { } from '@agoric/orchestration'; import type { IBCChannelID } from '@agoric/vats'; +export const makeDenomTools = (chainInfo: Record) => { + const getTransferChannelId = ( + destChainId: string, + fromChainName: string, + ): IBCChannelID | undefined => + chainInfo[fromChainName]?.connections?.[destChainId]?.transferChannel + .channelId; + + const toDenomHash = ( + denom: Denom, + destChainId: string, + fromChainName: string, + ): Denom => { + const channelId = getTransferChannelId(destChainId, fromChainName); + if (!channelId) { + throw new Error( + `No channel found for ${destChainId} -> ${fromChainName}`, + ); + } + return `ibc/${denomHash({ denom, channelId })}`; + }; + + return harden({ getTransferChannelId, toDenomHash }); +}; + /** * Make asset info for the current environment. * @@ -21,26 +46,7 @@ export const makeAssetInfo = ( osmosis: ['uosmo', 'uion'], }, ): [Denom, DenomDetail][] => { - const getChannelId = ( - issuingChainId: string, - holdingChainName: string, - ): IBCChannelID | undefined => - chainInfo[holdingChainName]?.connections?.[issuingChainId]?.transferChannel - .channelId; - - const toDenomHash = ( - denom: Denom, - issuingChainId: string, - holdingChainName: string, - ): Denom => { - const channelId = getChannelId(issuingChainId, holdingChainName); - if (!channelId) { - throw new Error( - `No channel found for ${issuingChainId} -> ${holdingChainName}`, - ); - } - return `ibc/${denomHash({ denom, channelId })}`; - }; + const { toDenomHash } = makeDenomTools(chainInfo); // only include chains present in `chainInfo` const tokens = Object.entries(tokenMap) From 1f4b4c6219061972bb7d7ee62114e0ed93522457 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 3 Dec 2024 23:09:02 -0500 Subject: [PATCH 28/42] chore: `WalletDriver` type --- multichain-testing/tools/e2e-tools.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js index f820e7c8077..b2a77f1a4fb 100644 --- a/multichain-testing/tools/e2e-tools.js +++ b/multichain-testing/tools/e2e-tools.js @@ -297,6 +297,8 @@ export const provisionSmartWallet = async ( return { offers, deposit, peek, query: q }; }; +/** @typedef {Awaited>} WalletDriver */ + /** * @param {{ * agd: import('./agd-lib.js').Agd; From 46f94d5ed69a296fb0692433263ce4e56df9f2a0 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 4 Dec 2024 23:45:30 -0500 Subject: [PATCH 29/42] refactor: `commonBuilderOpts` - include `chainInfo` and `assetInfo` as common builder options for orchestration contracts --- multichain-testing/test/auto-stake-it.test.ts | 8 ++------ multichain-testing/test/basic-flows.test.ts | 7 ++----- .../test/deposit-withdraw-lca.test.ts | 7 ++----- .../test/deposit-withdraw-portfolio.test.ts | 7 ++----- .../test/ica-channel-close.test.ts | 7 ++----- multichain-testing/test/send-anywhere.test.ts | 8 ++------ multichain-testing/test/support.ts | 18 +++++++----------- 7 files changed, 19 insertions(+), 43 deletions(-) diff --git a/multichain-testing/test/auto-stake-it.test.ts b/multichain-testing/test/auto-stake-it.test.ts index d4bfded2086..01afae775f2 100644 --- a/multichain-testing/test/auto-stake-it.test.ts +++ b/multichain-testing/test/auto-stake-it.test.ts @@ -18,15 +18,11 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, startContract } = common; + const { commonBuilderOpts, deleteTestKeys, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); }); test.after(async t => { diff --git a/multichain-testing/test/basic-flows.test.ts b/multichain-testing/test/basic-flows.test.ts index 689db323524..9e9ff738a4d 100644 --- a/multichain-testing/test/basic-flows.test.ts +++ b/multichain-testing/test/basic-flows.test.ts @@ -17,14 +17,11 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, startContract } = common; + const { commonBuilderOpts, deleteTestKeys, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); }); test.after(async t => { diff --git a/multichain-testing/test/deposit-withdraw-lca.test.ts b/multichain-testing/test/deposit-withdraw-lca.test.ts index ad7fd4824d9..e9127f3919a 100644 --- a/multichain-testing/test/deposit-withdraw-lca.test.ts +++ b/multichain-testing/test/deposit-withdraw-lca.test.ts @@ -15,14 +15,11 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, startContract } = common; + const { commonBuilderOpts, deleteTestKeys, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); }); test.after(async t => { diff --git a/multichain-testing/test/deposit-withdraw-portfolio.test.ts b/multichain-testing/test/deposit-withdraw-portfolio.test.ts index ea97f1e7f17..0bccf0bad60 100644 --- a/multichain-testing/test/deposit-withdraw-portfolio.test.ts +++ b/multichain-testing/test/deposit-withdraw-portfolio.test.ts @@ -15,14 +15,11 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, startContract } = common; + const { commonBuilderOpts, deleteTestKeys, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); }); test.after(async t => { diff --git a/multichain-testing/test/ica-channel-close.test.ts b/multichain-testing/test/ica-channel-close.test.ts index 03b0ef9ac95..f7799dac1e0 100644 --- a/multichain-testing/test/ica-channel-close.test.ts +++ b/multichain-testing/test/ica-channel-close.test.ts @@ -23,14 +23,11 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, startContract } = common; + const { commonBuilderOpts, deleteTestKeys, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); }); test.after(async t => { diff --git a/multichain-testing/test/send-anywhere.test.ts b/multichain-testing/test/send-anywhere.test.ts index 11508f22cc6..c33084f4eff 100644 --- a/multichain-testing/test/send-anywhere.test.ts +++ b/multichain-testing/test/send-anywhere.test.ts @@ -21,16 +21,12 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); - const { assetInfo, chainInfo, deleteTestKeys, faucetTools, startContract } = + const { commonBuilderOpts, deleteTestKeys, faucetTools, startContract } = common; deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; - - await startContract(contractName, contractBuilder, { - chainInfo, - assetInfo, - }); + await startContract(contractName, contractBuilder, commonBuilderOpts); await faucetTools.fundFaucet([ ['cosmoshub', 'uatom'], diff --git a/multichain-testing/test/support.ts b/multichain-testing/test/support.ts index 656c282df46..f71e2c112cc 100644 --- a/multichain-testing/test/support.ts +++ b/multichain-testing/test/support.ts @@ -4,7 +4,6 @@ import { execa } from 'execa'; import fse from 'fs-extra'; import childProcess from 'node:child_process'; import { withChainCapabilities } from '@agoric/orchestration'; -import { objectMap } from '@endo/patterns'; import { makeAgdTools } from '../tools/agd-tools.js'; import { type E2ETools } from '../tools/e2e-tools.js'; import { @@ -97,6 +96,10 @@ export const commonSetup = async (t: ExecutionContext) => { retryUntilCondition, useChain, ); + const commonBuilderOpts = harden({ + assetInfo: JSON.stringify(assetInfo), + chainInfo: JSON.stringify(chainInfo), + }); /** * Starts a contract if instance not found. Takes care of installing @@ -108,7 +111,7 @@ export const commonSetup = async (t: ExecutionContext) => { const startContract = async ( contractName: string, contractBuilder: string, - builderOpts?: Record, + builderOpts?: Record, ) => { const { vstorageClient } = tools; const instances = Object.fromEntries( @@ -118,15 +121,7 @@ export const commonSetup = async (t: ExecutionContext) => { return t.log('Contract found. Skipping installation...'); } t.log('bundle and install contract', contractName); - - const formattedOpts = builderOpts - ? objectMap( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - builderOpts as Record, - value => (typeof value === 'string' ? value : JSON.stringify(value)), - ) - : undefined; - await deployBuilder(contractBuilder, formattedOpts); + await deployBuilder(contractBuilder, builderOpts); await retryUntilCondition( () => vstorageClient.queryData(`published.agoricNames.instance`), res => contractName in Object.fromEntries(res), @@ -145,6 +140,7 @@ export const commonSetup = async (t: ExecutionContext) => { startContract, assetInfo, chainInfo, + commonBuilderOpts, faucetTools, }; }; From e124d855ffa6c659c50330aa4953500411d676bf Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Thu, 5 Dec 2024 00:03:16 -0500 Subject: [PATCH 30/42] chore: `flags` supports mutli option --- multichain-testing/tools/agd-lib.js | 9 +++++++-- multichain-testing/tools/deploy.ts | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/multichain-testing/tools/agd-lib.js b/multichain-testing/tools/agd-lib.js index a28d408493b..71ed0f69cbd 100644 --- a/multichain-testing/tools/agd-lib.js +++ b/multichain-testing/tools/agd-lib.js @@ -16,7 +16,7 @@ const binaryArgs = [ ]; /** - * @param {Record} record - e.g. { color: 'blue' } + * @param {Record} record - e.g. { color: 'blue' } * @returns {string[]} - e.g. ['--color', 'blue'] */ export const flags = record => { @@ -25,7 +25,12 @@ export const flags = record => { /** @type {[string, string][]} */ // @ts-expect-error undefined is filtered out const skipUndef = Object.entries(record).filter(([_k, v]) => v !== undefined); - return skipUndef.map(([k, v]) => [`--${k}`, v]).flat(); + return skipUndef.flatMap(([key, value]) => { + if (Array.isArray(value)) { + return value.flatMap(v => [`--${key}`, v]); + } + return [`--${key}`, value]; + }); }; /** diff --git a/multichain-testing/tools/deploy.ts b/multichain-testing/tools/deploy.ts index 52a460f6094..289c4d971e9 100755 --- a/multichain-testing/tools/deploy.ts +++ b/multichain-testing/tools/deploy.ts @@ -13,7 +13,7 @@ export const makeDeployBuilder = ( ) => async function deployBuilder( builder: string, - builderOpts?: Record, + builderOpts?: Record, ) { console.log(`building plan: ${builder}`); const args = ['run', builder]; From e60589f52358441642bb879747d208172d88da15 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Tue, 10 Dec 2024 16:18:11 -0500 Subject: [PATCH 31/42] chore: ensure latest view on vbank entries - in the testing environment, we might see multiple USDC entries in `vbankAsset`. This change ensures the `byName` record contains the values needed for the test, reliant on the consistent ordering currently present in `vbankAsset` entries --- multichain-testing/tools/e2e-tools.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js index b2a77f1a4fb..6ad5575acb7 100644 --- a/multichain-testing/tools/e2e-tools.js +++ b/multichain-testing/tools/e2e-tools.js @@ -144,9 +144,9 @@ export const provisionSmartWallet = async ( // TODO: skip this query if balances is {} const vbankEntries = await q.queryData('published.agoricNames.vbankAsset'); const byName = Object.fromEntries( - vbankEntries.map(([denom, info]) => { - /// XXX better way to filter out old ATOM denom? - if (denom === 'ibc/toyatom') return [undefined, undefined]; + // reverse entries, so we get the latest view on the denom since there are + // multiple entries in the testing environment + [...vbankEntries].reverse().map(([_, info]) => { return [info.issuerName, info]; }), ); From 46f574333a6f25ed92340f22827fceefba72cdca Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 4 Dec 2024 00:33:26 -0500 Subject: [PATCH 32/42] test: fast-usdc advance happy path --- multichain-testing/test/fast-usdc/config.ts | 28 ++ .../test/fast-usdc/fast-usdc.test.ts | 386 ++++++++++++++++++ multichain-testing/tools/noble-tools.ts | 23 +- multichain-testing/tools/purse.ts | 10 + multichain-testing/tools/random.ts | 11 + multichain-testing/yarn.lock | 47 ++- 6 files changed, 494 insertions(+), 11 deletions(-) create mode 100644 multichain-testing/test/fast-usdc/config.ts create mode 100644 multichain-testing/test/fast-usdc/fast-usdc.test.ts create mode 100644 multichain-testing/tools/purse.ts create mode 100644 multichain-testing/tools/random.ts diff --git a/multichain-testing/test/fast-usdc/config.ts b/multichain-testing/test/fast-usdc/config.ts new file mode 100644 index 00000000000..c7b1833ec6d --- /dev/null +++ b/multichain-testing/test/fast-usdc/config.ts @@ -0,0 +1,28 @@ +import type { IBCChannelID } from '@agoric/vats'; + +export const oracleMnemonics = { + oracle1: + 'cause eight cattle slot course mail more aware vapor slab hobby match', + oracle2: + 'flower salute inspire label latin cattle believe sausage match total bless refuse', + oracle3: + 'surge magnet typical drive cement artist stay latin chief obey word always', +}; +harden(oracleMnemonics); + +export const makeFeedPolicy = (nobleAgoricChannelId: IBCChannelID) => { + return { + nobleAgoricChannelId, + nobleDomainId: 4, + chainPolicies: { + Arbitrum: { + attenuatedCttpBridgeAddress: + '0xe298b93ffB5eA1FB628e0C0D55A43aeaC268e347', + cctpTokenMessengerAddress: '0x19330d10D9Cc8751218eaf51E8885D058642E08A', + chainId: 42161, + confirmations: 2, + }, + }, + }; +}; +harden(makeFeedPolicy); diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts new file mode 100644 index 00000000000..1c169197cb0 --- /dev/null +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -0,0 +1,386 @@ +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'; +import type { Denom } from '@agoric/orchestration'; +import { divideBy, multiplyBy } from '@agoric/zoe/src/contractSupport/ratio.js'; +import type { IBCChannelID } from '@agoric/vats'; +import { makeDoOffer, type WalletDriver } from '../../tools/e2e-tools.js'; +import { makeDenomTools } from '../../tools/asset-info.js'; +import { createWallet } from '../../tools/wallet.js'; +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'; + +const { keys, values, fromEntries } = Object; +const { isGTE, isEmpty, make } = AmountMath; + +const makeRandomNumber = () => Math.random(); + +const test = anyTest as TestFn< + SetupContextWithWallets & { + lpUser: WalletDriver; + oracleWds: WalletDriver[]; + nobleAgoricChannelId: IBCChannelID; + usdcOnOsmosis: Denom; + /** usdc on agoric */ + usdcDenom: Denom; + } +>; + +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; + +test.before(async t => { + const { setupTestKeys, ...common } = await commonSetup(t); + const { + chainInfo, + commonBuilderOpts, + deleteTestKeys, + faucetTools, + provisionSmartWallet, + startContract, + } = common; + deleteTestKeys(accounts).catch(); + const wallets = await setupTestKeys(accounts, values(oracleMnemonics)); + + // provision oracle wallets first so invitation deposits don't fail + const oracleWdPs = keys(oracleMnemonics).map(n => + provisionSmartWallet(wallets[n], { + BLD: 100n, + }), + ); + // execute sequentially, to avoid "published.wallet.${addr}.current: fetch failed" + const oracleWds: WalletDriver[] = []; + for (const p of oracleWdPs) { + const wd = await p; + oracleWds.push(wd); + } + + // calculate denomHash and channelId for privateArgs / builder opts + const { getTransferChannelId, toDenomHash } = makeDenomTools(chainInfo); + const usdcDenom = toDenomHash('uusdc', 'noblelocal', 'agoric'); + const usdcOnOsmosis = toDenomHash('uusdc', 'noblelocal', 'osmosis'); + const nobleAgoricChannelId = getTransferChannelId('agoriclocal', 'noble'); + if (!nobleAgoricChannelId) throw new Error('nobleAgoricChannelId not found'); + t.log('nobleAgoricChannelId', nobleAgoricChannelId); + t.log('usdcDenom', usdcDenom); + + await startContract(contractName, contractBuilder, { + oracle: keys(oracleMnemonics).map(n => `${n}:${wallets[n]}`), + usdcDenom, + feedPolicy: JSON.stringify(makeFeedPolicy(nobleAgoricChannelId)), + ...commonBuilderOpts, + }); + + // provide faucet funds for LPs + await faucetTools.fundFaucet([['noble', 'uusdc']]); + + // save an LP in test context + const lpUser = await provisionSmartWallet(wallets['lp'], { + USDC: 100n, + BLD: 100n, + }); + + t.context = { + ...common, + lpUser, + oracleWds, + nobleAgoricChannelId, + usdcOnOsmosis, + usdcDenom, + wallets, + }; +}); + +test.after(async t => { + const { deleteTestKeys } = t.context; + deleteTestKeys(accounts); +}); + +const toOracleOfferId = (idx: number) => `oracle${idx + 1}-accept`; + +test.serial('oracles accept', async t => { + const { oracleWds, retryUntilCondition, vstorageClient, wallets } = t.context; + + const instances = await vstorageClient.queryData( + 'published.agoricNames.instance', + ); + const instance = fromEntries(instances)[contractName]; + + // accept oracle operator invitations + await Promise.all( + oracleWds.map(makeDoOffer).map((doOffer, i) => + doOffer({ + id: toOracleOfferId(i), + invitationSpec: { + source: 'purse', + instance, + description: 'oracle operator invitation', // TODO export/import INVITATION_MAKERS_DESC + }, + proposal: {}, + }), + ), + ); + + for (const name of keys(oracleMnemonics)) { + const addr = wallets[name]; + await t.notThrowsAsync(() => + retryUntilCondition( + () => vstorageClient.queryData(`published.wallet.${addr}.current`), + ({ offerToUsedInvitation }) => { + return offerToUsedInvitation[0][0] === `${name}-accept`; + }, + `${name} invitation used`, + ), + ); + } +}); + +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 { shareWorth: currShareWorth } = await vstorageClient.queryData( + `published.${contractName}.poolMetrics`, + ); + const poolSharesWanted = divideBy(usdcToGive, currShareWorth); + + await lpDoOffer({ + id: `lp-deposit-${Date.now()}`, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeDepositInvitation']], + }, + proposal: { + give: { USDC: usdcToGive }, + want: { PoolShare: poolSharesWanted }, + }, + }); + + await t.notThrowsAsync(() => + retryUntilCondition( + () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + ({ shareWorth }) => + !isGTE(currShareWorth.numerator, shareWorth.numerator), + 'share worth numerator increases from deposit', + ), + ); + + await t.notThrowsAsync(() => + retryUntilCondition( + () => + vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`), + ({ purses }) => { + const currentPoolShares = balancesFromPurses(purses)[FastLP]; + return currentPoolShares && isGTE(currentPoolShares, poolSharesWanted); + }, + 'lp has pool shares', + ), + ); +}); + +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 recipientAddress = encodeAddressHook(settlementAccount, { EUD }); + t.log('recipientAddress', recipientAddress); + + // register forwarding address on noble + const txRes = nobleTools.registerForwardingAcct( + nobleAgoricChannelId, + recipientAddress, + ); + t.is(txRes?.code, 0, 'registered forwarding account'); + + 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, + 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(), + ); + + 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 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(mintAmount, userForwardingAddr); + await t.notThrowsAsync(() => + retryUntilCondition( + () => vstorageClient.queryData(`published.${contractName}.poolMetrics`), + ({ encumberedBalance }) => + encumberedBalance && isEmpty(encumberedBalance), + 'encumberedBalance returns to 0', + ), + ); + + await assertTxStatus('DISBURSED'); +}); + +test.serial('lp withdraws', async t => { + const { + lpUser, + retryUntilCondition, + useChain, + usdcDenom, + vstorageClient, + wallets, + } = t.context; + const queryClient = makeQueryClient( + await useChain('agoric').getRestEndpoint(), + ); + const lpDoOffer = makeDoOffer(lpUser); + const brands = await vstorageClient.queryData('published.agoricNames.brand'); + const { FastLP } = Object.fromEntries(brands); + 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 currentPoolShares = balancesFromPurses(purses)[FastLP]; + t.log('currentPoolShares', currentPoolShares); + const usdcWanted = multiplyBy(currentPoolShares, currShareWorth); + t.log('usdcWanted', usdcWanted); + + const { balance: currentUSDCBalance } = await queryClient.queryBalance( + wallets['lp'], + usdcDenom, + ); + t.log(`current ${usdcDenom} balance`, currentUSDCBalance); + + await lpDoOffer({ + id: `lp-withdraw-${Date.now()}`, + invitationSpec: { + source: 'agoricContract', + instancePath: [contractName], + callPipe: [['makeWithdrawInvitation']], + }, + proposal: { + give: { PoolShare: currentPoolShares }, + want: { USDC: usdcWanted }, + }, + }); + + await t.notThrowsAsync(() => + retryUntilCondition( + () => + vstorageClient.queryData(`published.wallet.${wallets['lp']}.current`), + ({ purses }) => { + const currentPoolShares = balancesFromPurses(purses)[FastLP]; + return !currentPoolShares || isEmpty(currentPoolShares); + }, + 'lp no longer has pool shares', + ), + ); + + await t.notThrowsAsync(() => + retryUntilCondition( + () => queryClient.queryBalance(wallets['lp'], usdcDenom), + ({ balance }) => + !!balance?.amount && + BigInt(balance.amount) - BigInt(currentUSDCBalance!.amount!) > + LP_DEPOSIT_AMOUNT, + "lp's USDC balance increases", + ), + ); +}); diff --git a/multichain-testing/tools/noble-tools.ts b/multichain-testing/tools/noble-tools.ts index 0ece8dfd8b8..8a08e6a85bb 100644 --- a/multichain-testing/tools/noble-tools.ts +++ b/multichain-testing/tools/noble-tools.ts @@ -19,11 +19,14 @@ const makeKubeArgs = () => { ]; }; -export const makeNobleTools = ({ - execFileSync, -}: { - execFileSync: ExecSync; -}) => { +export const makeNobleTools = ( + { + execFileSync, + }: { + execFileSync: ExecSync; + }, + log: (...args: unknown[]) => void = console.log, +) => { const exec = ( args: string[], opts = { encoding: 'utf-8' as const, stdio: ['ignore', 'pipe', 'ignore'] }, @@ -38,8 +41,9 @@ export const makeNobleTools = ({ const registerForwardingAcct = ( channelId: IBCChannelID, address: ChainAddress['value'], - ) => { + ): { txhash: string; code: number; data: string; height: string } => { checkEnv(); + log('creating forwarding address', address, channelId); return JSON.parse( exec([ 'tx', @@ -57,6 +61,8 @@ export const makeNobleTools = ({ const mockCctpMint = (amount: bigint, destination: ChainAddress['value']) => { checkEnv(); + const denomAmount = `${Number(amount)}uusdc`; + log('mock cctp mint', destination, denomAmount); return JSON.parse( exec([ 'tx', @@ -64,7 +70,7 @@ export const makeNobleTools = ({ 'send', 'faucet', destination, - `${Number(amount)}uusdc`, + denomAmount, '--from=faucet', '-y', '-b', @@ -76,8 +82,9 @@ export const makeNobleTools = ({ const queryForwardingAddress = ( channelId: IBCChannelID, address: ChainAddress['value'], - ) => { + ): { address: string; exists: boolean } => { checkEnv(); + log('querying forwarding address', address, channelId); return JSON.parse( exec([ 'query', diff --git a/multichain-testing/tools/purse.ts b/multichain-testing/tools/purse.ts new file mode 100644 index 00000000000..82a76d2a3f4 --- /dev/null +++ b/multichain-testing/tools/purse.ts @@ -0,0 +1,10 @@ +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])); diff --git a/multichain-testing/tools/random.ts b/multichain-testing/tools/random.ts new file mode 100644 index 00000000000..1928bb1ebd3 --- /dev/null +++ b/multichain-testing/tools/random.ts @@ -0,0 +1,11 @@ +/** + * @param randomN pseudorandom number between 0 and 1, e.g. Math.random() + * @param digits number of digits to generate + * @returns a string of digits + */ +export function makeRandomDigits(randomN: number, digits = 2n) { + if (digits < 1n) throw new Error('digits must be positive'); + const maxValue = Math.pow(10, Number(digits)) - 1; + const num = Math.floor(randomN * (maxValue + 1)); + return num.toString().padStart(Number(digits), '0'); +} diff --git a/multichain-testing/yarn.lock b/multichain-testing/yarn.lock index 66b1b0557dc..fd3e9510370 100644 --- a/multichain-testing/yarn.lock +++ b/multichain-testing/yarn.lock @@ -6,12 +6,14 @@ __metadata: cacheKey: 10c0 "@agoric/cosmic-proto@npm:dev": - version: 0.4.1-dev-e596a01.0 - resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-e596a01.0" + version: 0.4.1-dev-bdf5c17.0 + resolution: "@agoric/cosmic-proto@npm:0.4.1-dev-bdf5c17.0" dependencies: "@endo/base64": "npm:^1.0.9" "@endo/init": "npm:^1.1.7" - checksum: 10c0/2048e794ec9a346fb3a618b1b64d54985241967930b8b34c9220316b206fca4d3ecdf738e23e56021d45c3818f4513842e6d4c4d917a537dad59c13651d0ae35 + bech32: "npm:^2.0.0" + query-string: "npm:^9.1.1" + checksum: 10c0/20d4f8763a091b0b741c754fcceb82d666c4eb55bab2eaaef8821f8f7da644e2ee70c1134ef0e1cf90cc940150d61437d935913549d0da8ea17a8f0c80f2d36c languageName: node linkType: hard @@ -1028,6 +1030,13 @@ __metadata: languageName: node linkType: hard +"bech32@npm:^2.0.0": + version: 2.0.0 + resolution: "bech32@npm:2.0.0" + checksum: 10c0/45e7cc62758c9b26c05161b4483f40ea534437cf68ef785abadc5b62a2611319b878fef4f86ddc14854f183b645917a19addebc9573ab890e19194bc8f521942 + languageName: node + linkType: hard + "bfs-path@npm:^1.0.2": version: 1.0.2 resolution: "bfs-path@npm:1.0.2" @@ -1369,6 +1378,13 @@ __metadata: languageName: node linkType: hard +"decode-uri-component@npm:^0.4.1": + version: 0.4.1 + resolution: "decode-uri-component@npm:0.4.1" + checksum: 10c0/a180bbdb5398ec8270d236a3ac07cb988bbf6097428481780b85840f088951dc0318a8d8f9d56796e1a322b55b29859cea29982f22f9b03af0bc60974c54e591 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -1764,6 +1780,13 @@ __metadata: languageName: node linkType: hard +"filter-obj@npm:^5.1.0": + version: 5.1.0 + resolution: "filter-obj@npm:5.1.0" + checksum: 10c0/716e8ad2bc352e206556b3e5695b3cdff8aab80c53ea4b00c96315bbf467b987df3640575100aef8b84e812cf5ea4251db4cd672bbe33b1e78afea88400c67dd + languageName: node + linkType: hard + "find-up-simple@npm:^1.0.0": version: 1.0.0 resolution: "find-up-simple@npm:1.0.0" @@ -2924,6 +2947,17 @@ __metadata: languageName: node linkType: hard +"query-string@npm:^9.1.1": + version: 9.1.1 + resolution: "query-string@npm:9.1.1" + dependencies: + decode-uri-component: "npm:^0.4.1" + filter-obj: "npm:^5.1.0" + split-on-first: "npm:^3.0.0" + checksum: 10c0/16481f17754f660aec3cae7abb838a70e383dfcf152414d184e0d0f81fae426acf112b4d51bf754f9c256eaf83ba4241241ba907c8d58b6ed9704425e1712e8c + languageName: node + linkType: hard + "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" @@ -3183,6 +3217,13 @@ __metadata: languageName: node linkType: hard +"split-on-first@npm:^3.0.0": + version: 3.0.0 + resolution: "split-on-first@npm:3.0.0" + checksum: 10c0/a1262eae12b68de235e1a08e011bf5b42c42621985ddf807e6221fb1e2b3304824913ae7019f18436b96b8fab8aef5f1ad80dedd2385317fdc51b521c3882cd0 + languageName: node + linkType: hard + "sprintf-js@npm:~1.0.2": version: 1.0.3 resolution: "sprintf-js@npm:1.0.3" From 2c4d7cd77a3113f1a43df536c001e1e2ab6b9180 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 11 Dec 2024 13:34:01 -0500 Subject: [PATCH 33/42] chore: `await` `deleteTestKeys` - get rid of dangling promise and await something we actually rely on --- multichain-testing/test/account-balance-queries.test.ts | 2 +- multichain-testing/test/auto-stake-it.test.ts | 2 +- multichain-testing/test/basic-flows.test.ts | 2 +- multichain-testing/test/chain-queries.test.ts | 2 +- multichain-testing/test/deposit-withdraw-lca.test.ts | 2 +- multichain-testing/test/deposit-withdraw-portfolio.test.ts | 2 +- multichain-testing/test/fast-usdc/fast-usdc.test.ts | 2 +- multichain-testing/test/ica-channel-close.test.ts | 2 +- multichain-testing/test/send-anywhere.test.ts | 2 +- multichain-testing/test/stake-ica.test.ts | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/multichain-testing/test/account-balance-queries.test.ts b/multichain-testing/test/account-balance-queries.test.ts index 6707d9b102e..c067ced9446 100644 --- a/multichain-testing/test/account-balance-queries.test.ts +++ b/multichain-testing/test/account-balance-queries.test.ts @@ -20,7 +20,7 @@ const contractBuilder = test.before(async t => { const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...rest, wallets, deleteTestKeys }; const { startContract } = rest; diff --git a/multichain-testing/test/auto-stake-it.test.ts b/multichain-testing/test/auto-stake-it.test.ts index 01afae775f2..10e3bac8db8 100644 --- a/multichain-testing/test/auto-stake-it.test.ts +++ b/multichain-testing/test/auto-stake-it.test.ts @@ -19,7 +19,7 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/basic-flows.test.ts b/multichain-testing/test/basic-flows.test.ts index 9e9ff738a4d..1d53b4aae8d 100644 --- a/multichain-testing/test/basic-flows.test.ts +++ b/multichain-testing/test/basic-flows.test.ts @@ -18,7 +18,7 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/chain-queries.test.ts b/multichain-testing/test/chain-queries.test.ts index a9b91c97fe3..56673742582 100644 --- a/multichain-testing/test/chain-queries.test.ts +++ b/multichain-testing/test/chain-queries.test.ts @@ -28,7 +28,7 @@ const contractBuilder = test.before(async t => { const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...rest, wallets, deleteTestKeys }; const { startContract } = rest; diff --git a/multichain-testing/test/deposit-withdraw-lca.test.ts b/multichain-testing/test/deposit-withdraw-lca.test.ts index e9127f3919a..7d1cbafa97c 100644 --- a/multichain-testing/test/deposit-withdraw-lca.test.ts +++ b/multichain-testing/test/deposit-withdraw-lca.test.ts @@ -16,7 +16,7 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/deposit-withdraw-portfolio.test.ts b/multichain-testing/test/deposit-withdraw-portfolio.test.ts index 0bccf0bad60..49b7f3d8ad7 100644 --- a/multichain-testing/test/deposit-withdraw-portfolio.test.ts +++ b/multichain-testing/test/deposit-withdraw-portfolio.test.ts @@ -16,7 +16,7 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 1c169197cb0..3b3d7f79dce 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -46,7 +46,7 @@ test.before(async t => { provisionSmartWallet, startContract, } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts, values(oracleMnemonics)); // provision oracle wallets first so invitation deposits don't fail diff --git a/multichain-testing/test/ica-channel-close.test.ts b/multichain-testing/test/ica-channel-close.test.ts index f7799dac1e0..6ee59dc825f 100644 --- a/multichain-testing/test/ica-channel-close.test.ts +++ b/multichain-testing/test/ica-channel-close.test.ts @@ -24,7 +24,7 @@ const contractBuilder = test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/send-anywhere.test.ts b/multichain-testing/test/send-anywhere.test.ts index c33084f4eff..df4bbdca8d6 100644 --- a/multichain-testing/test/send-anywhere.test.ts +++ b/multichain-testing/test/send-anywhere.test.ts @@ -23,7 +23,7 @@ test.before(async t => { const { setupTestKeys, ...common } = await commonSetup(t); const { commonBuilderOpts, deleteTestKeys, faucetTools, startContract } = common; - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...common, wallets }; await startContract(contractName, contractBuilder, commonBuilderOpts); diff --git a/multichain-testing/test/stake-ica.test.ts b/multichain-testing/test/stake-ica.test.ts index af73531bf61..7ef65ad33eb 100644 --- a/multichain-testing/test/stake-ica.test.ts +++ b/multichain-testing/test/stake-ica.test.ts @@ -18,7 +18,7 @@ test.before(async t => { const { deleteTestKeys, setupTestKeys, ...rest } = await commonSetup(t); // XXX not necessary for CI, but helpful for unexpected failures in // active development (test.after cleanup doesn't run). - deleteTestKeys(accounts).catch(); + await deleteTestKeys(accounts).catch(); const wallets = await setupTestKeys(accounts); t.context = { ...rest, wallets, deleteTestKeys }; }); From a56f407129e73cc57e024f9abd758825e44b5569 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Wed, 11 Dec 2024 14:36:36 -0500 Subject: [PATCH 34/42] chore: ava `failFast: true` --- multichain-testing/ava.main.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/multichain-testing/ava.main.config.js b/multichain-testing/ava.main.config.js index 37c7ca0b467..da0d373e10c 100644 --- a/multichain-testing/ava.main.config.js +++ b/multichain-testing/ava.main.config.js @@ -9,4 +9,5 @@ export default { concurrency: 1, serial: true, timeout: '125s', + failFast: true, }; From adbd7d3480373ce2b99a7bcaa478cd16d81e6f4e Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Fri, 6 Dec 2024 16:46:05 +0000 Subject: [PATCH 35/42] chore(provisionPool): add governedParamOverrides to privateArgs --- .../upgrade-provisionPool-proposal.js | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js index a94fd6ef418..264b57fa51f 100644 --- a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js +++ b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js @@ -2,7 +2,7 @@ import { E } from '@endo/far'; import { deeplyFulfilled } from '@endo/marshal'; import { makeTracer } from '@agoric/internal'; -const tracer = makeTracer('UpgradeProvisionPool'); +const trace = makeTracer('UpgradeProvisionPool'); /** * @param {BootstrapPowers & { @@ -30,7 +30,7 @@ export const upgradeProvisionPool = async ( const { provisionPoolRef } = options.options; assert(provisionPoolRef.bundleID); - tracer(`PROVISION POOL BUNDLE ID: `, provisionPoolRef); + trace(`PROVISION POOL BUNDLE ID: `, provisionPoolRef); const [ provisionPoolStartResult, @@ -49,6 +49,7 @@ export const upgradeProvisionPool = async ( adminFacet, instance, creatorFacet: ppCreatorFacet, + publicFacet: ppPublicFacet, } = provisionPoolStartResult; const { creatorFacet: wfCreatorFacet } = walletFactoryStartResult; @@ -59,9 +60,21 @@ export const upgradeProvisionPool = async ( E(electorateCreatorFacet).getPoserInvitation(), ]); + const readCurrentGovernedParams = async () => { + await null; + + const params = await E(ppPublicFacet).getGovernedParams(); + return harden({ + PerAccountInitialAmount: params.PerAccountInitialAmount.value, + }); + }; + const governedParamOverrides = await readCurrentGovernedParams(); + trace('governedParamOverrides: ', { governedParamOverrides }); + const newPrivateArgs = harden({ ...originalPrivateArgs, initialPoserInvitation: poserInvitation, + governedParamOverrides, }); const upgradeResult = await E(adminFacet).upgradeContract( @@ -69,7 +82,7 @@ export const upgradeProvisionPool = async ( newPrivateArgs, ); - tracer('ProvisionPool upgraded: ', upgradeResult); + trace('ProvisionPool upgraded: ', upgradeResult); const references = { bankManager, @@ -77,17 +90,17 @@ export const upgradeProvisionPool = async ( walletFactory: wfCreatorFacet, }; - tracer('Calling setReferences with: ', references); + trace('Calling setReferences with: ', references); await E(ppCreatorFacet).setReferences(references); - tracer('Creating bridgeHandler...'); + trace('Creating bridgeHandler...'); const bridgeHandler = await E(ppCreatorFacet).makeHandler(); - tracer('Setting new bridgeHandler...'); + trace('Setting new bridgeHandler...'); // @ts-expect-error casting await E(provisionWalletBridgeManager).setHandler(bridgeHandler); - tracer('Done.'); + trace('Done.'); }; export const getManifestForUpgradingProvisionPool = ( From e4fc720152f5b508afde6bfa3e6bf16ee1562ed6 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Mon, 9 Dec 2024 11:02:46 +0000 Subject: [PATCH 36/42] chore(provisionPool): simplify defining of governedParamOverrides --- .../src/proposals/upgrade-provisionPool-proposal.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js index 264b57fa51f..c2d8e7c02b9 100644 --- a/packages/vats/src/proposals/upgrade-provisionPool-proposal.js +++ b/packages/vats/src/proposals/upgrade-provisionPool-proposal.js @@ -60,15 +60,10 @@ export const upgradeProvisionPool = async ( E(electorateCreatorFacet).getPoserInvitation(), ]); - const readCurrentGovernedParams = async () => { - await null; - - const params = await E(ppPublicFacet).getGovernedParams(); - return harden({ - PerAccountInitialAmount: params.PerAccountInitialAmount.value, - }); - }; - const governedParamOverrides = await readCurrentGovernedParams(); + const params = await E(ppPublicFacet).getGovernedParams(); + const governedParamOverrides = harden({ + PerAccountInitialAmount: params.PerAccountInitialAmount.value, + }); trace('governedParamOverrides: ', { governedParamOverrides }); const newPrivateArgs = harden({ From be7c97f30c8fa89e5e3166346774c330aa22ead6 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 10 Dec 2024 11:54:48 +0000 Subject: [PATCH 37/42] chore(governance): add overrides argument to handleParamGovernance --- packages/governance/src/contractHelper.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/governance/src/contractHelper.js b/packages/governance/src/contractHelper.js index c3a0896ea1d..e47b0709f54 100644 --- a/packages/governance/src/contractHelper.js +++ b/packages/governance/src/contractHelper.js @@ -250,6 +250,7 @@ const facetHelpers = (zcf, paramManager) => { * @param {M} paramTypesMap * @param {ERef} [storageNode] * @param {ERef} [marshaller] + * @param {object} [overrides] */ const handleParamGovernance = ( zcf, @@ -257,6 +258,7 @@ const handleParamGovernance = ( paramTypesMap, storageNode, marshaller, + overrides, ) => { /** @type {import('@agoric/notifier').StoredPublisherKit} */ const publisherKit = makeStoredPublisherKit( @@ -269,6 +271,7 @@ const handleParamGovernance = ( zcf, { Electorate: initialPoserInvitation }, paramTypesMap, + overrides, ); return facetHelpers(zcf, paramManager); From 6c5ccde9800bd22a3ba1effa7024e6646dfff036 Mon Sep 17 00:00:00 2001 From: Jorge-Lopes Date: Tue, 10 Dec 2024 11:55:27 +0000 Subject: [PATCH 38/42] chore(provisionPool): allow the overriding of governed param --- packages/inter-protocol/src/provisionPool.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/inter-protocol/src/provisionPool.js b/packages/inter-protocol/src/provisionPool.js index de96cfabaab..ee002f1a011 100644 --- a/packages/inter-protocol/src/provisionPool.js +++ b/packages/inter-protocol/src/provisionPool.js @@ -53,6 +53,7 @@ harden(meta); * storageNode: StorageNode; * marshaller: Marshal; * metricsOverride?: import('./provisionPoolKit.js').MetricsNotification; + * governedParamOverrides?: Record; * }} privateArgs * @param {import('@agoric/vat-data').Baggage} baggage */ @@ -74,6 +75,7 @@ export const start = async (zcf, privateArgs, baggage) => { }, privateArgs.storageNode, privateArgs.marshaller, + privateArgs.governedParamOverrides, ); const zone = makeDurableZone(baggage); From c883c39bbe4ec236a758030508fdf9f4fbd3ba9b Mon Sep 17 00:00:00 2001 From: Chris Hibbert Date: Wed, 11 Dec 2024 10:31:24 -0800 Subject: [PATCH 39/42] feat: record instances that will be replaced so we can manage them --- .../proposals/z:acceptance/.gitignore | 1 + .../proposals/z:acceptance/package.json | 1 + .../z:acceptance/recorded-retired.test.js | 11 +++ .../proposals/z:acceptance/test.sh | 3 + .../bootstrapTests/price-feed-replace.test.ts | 2 +- .../updateGovernedParams.test.ts | 2 +- .../inter-protocol/updatePriceFeeds.js | 10 +++ .../testing/recorded-retired-instances.js | 73 +++++++++++++++++++ .../src/proposals/add-auction.js | 13 ++++ .../src/proposals/deploy-price-feeds.js | 32 +++++++- .../src/proposals/replaceElectorate.js | 39 ++++++++-- .../inter-protocol/src/proposals/utils.js | 14 ++++ 12 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 a3p-integration/proposals/z:acceptance/recorded-retired.test.js create mode 100644 packages/builders/scripts/testing/recorded-retired-instances.js diff --git a/a3p-integration/proposals/z:acceptance/.gitignore b/a3p-integration/proposals/z:acceptance/.gitignore index 3d143254692..7f5da265d56 100644 --- a/a3p-integration/proposals/z:acceptance/.gitignore +++ b/a3p-integration/proposals/z:acceptance/.gitignore @@ -2,3 +2,4 @@ restart-valueVow start-valueVow localchaintest-submission +recorded-instances-submission diff --git a/a3p-integration/proposals/z:acceptance/package.json b/a3p-integration/proposals/z:acceptance/package.json index 8a906d701b8..fd4b89562ae 100644 --- a/a3p-integration/proposals/z:acceptance/package.json +++ b/a3p-integration/proposals/z:acceptance/package.json @@ -3,6 +3,7 @@ "type": "/agoric.swingset.CoreEvalProposal", "sdk-generate": [ "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" ] diff --git a/a3p-integration/proposals/z:acceptance/recorded-retired.test.js b/a3p-integration/proposals/z:acceptance/recorded-retired.test.js new file mode 100644 index 00000000000..a5a00d01107 --- /dev/null +++ b/a3p-integration/proposals/z:acceptance/recorded-retired.test.js @@ -0,0 +1,11 @@ +import test from 'ava'; + +import { evalBundles } from '@agoric/synthetic-chain'; + +const SUBMISSION_DIR = 'recorded-instances-submission'; + +test(`recorded instances in u18`, async t => { + const result = await evalBundles(SUBMISSION_DIR); + console.log('recorded retired instance result:', result); + t.pass('checked names'); +}); diff --git a/a3p-integration/proposals/z:acceptance/test.sh b/a3p-integration/proposals/z:acceptance/test.sh index a029b8d6e8a..e45cced45d1 100755 --- a/a3p-integration/proposals/z:acceptance/test.sh +++ b/a3p-integration/proposals/z:acceptance/test.sh @@ -12,6 +12,9 @@ yarn ava core-eval.test.js scripts/test-vaults.ts +echo ACCEPTANCE TESTING recorded instances +yarn ava recorded-retired.test.js + echo ACCEPTANCE TESTING kread yarn ava kread.test.js diff --git a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts index c9a6178f0fd..d2cd27af919 100644 --- a/packages/boot/test/bootstrapTests/price-feed-replace.test.ts +++ b/packages/boot/test/bootstrapTests/price-feed-replace.test.ts @@ -105,7 +105,7 @@ test.serial('setupVaults; run updatePriceFeeds proposals', async t => { t.log('building all relevant CoreEvals'); const coreEvals = await Promise.all([ - buildProposal(priceFeedBuilder, ['MAINNET']), + buildProposal(priceFeedBuilder, ['BOOT_TEST']), buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), buildProposal('@agoric/builders/scripts/vats/add-auction.js'), ]); diff --git a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts index 5410fcc59d7..07c4e711289 100644 --- a/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts +++ b/packages/boot/test/bootstrapTests/updateGovernedParams.test.ts @@ -134,7 +134,7 @@ test('modify manager & director params; update vats, check', async t => { const priceFeedBuilder = '@agoric/builders/scripts/inter-protocol/updatePriceFeeds.js'; const coreEvals = await Promise.all([ - buildProposal(priceFeedBuilder, ['MAINNET']), + buildProposal(priceFeedBuilder, ['BOOT_TEST']), buildProposal('@agoric/builders/scripts/vats/upgradeVaults.js'), buildProposal('@agoric/builders/scripts/vats/add-auction.js'), ]); diff --git a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js index f5e71a6c137..f99db1caa59 100644 --- a/packages/builders/scripts/inter-protocol/updatePriceFeeds.js +++ b/packages/builders/scripts/inter-protocol/updatePriceFeeds.js @@ -41,6 +41,16 @@ const configurations = { ], inBrandNames: ['ATOM', 'stATOM', 'stOSMO', 'stTIA', 'stkATOM'], }, + BOOT_TEST: { + oracleAddresses: [ + 'agoric144rrhh4m09mh7aaffhm6xy223ym76gve2x7y78', // DSRV + 'agoric19d6gnr9fyp6hev4tlrg87zjrzsd5gzr5qlfq2p', // Stakin + 'agoric19uscwxdac6cf6z7d5e26e0jm0lgwstc47cpll8', // 01node + 'agoric1krunjcqfrf7la48zrvdfeeqtls5r00ep68mzkr', // Simply Staking + 'agoric1n4fcxsnkxe4gj6e24naec99hzmc4pjfdccy5nj', // P2P + ], + inBrandNames: ['ATOM'], + }, }; const { keys } = Object; diff --git a/packages/builders/scripts/testing/recorded-retired-instances.js b/packages/builders/scripts/testing/recorded-retired-instances.js new file mode 100644 index 00000000000..58bc79c969e --- /dev/null +++ b/packages/builders/scripts/testing/recorded-retired-instances.js @@ -0,0 +1,73 @@ +import { makeTracer } from '@agoric/internal'; +import { E } from '@endo/far'; + +const trace = makeTracer('RecordedRetired', true); + +/** + * @param {BootstrapPowers & + * PromiseSpaceOf<{ retiredContractInstances: MapStore; + * }> + * } powers + */ +export const testRecordedRetiredInstances = async ({ + consume: { + contractKits, + // governedContractKits, + retiredContractInstances: retiredContractInstancesP, + }, +}) => { + trace('Start'); + const retiredContractInstances = await retiredContractInstancesP; + + const auctionIDs = Array.from(retiredContractInstances.keys()).filter(k => + k.startsWith('auction'), + ); + assert(auctionIDs); + assert(auctionIDs.length === 1); + const auctionInstance = retiredContractInstances.get(auctionIDs[0]); + trace({ auctionInstance }); + // I don't know why it's neither in governedContractKits nor contractKits + // assert(await E(governedContractKits).get(auctionInstance)); + + const committeeIDs = Array.from(retiredContractInstances.keys()).filter(k => + k.startsWith('economicCommittee'), + ); + assert(committeeIDs); + assert(committeeIDs.length === 1); + const committeeInstance = retiredContractInstances.get(committeeIDs[0]); + assert(await E(contractKits).get(committeeInstance)); + + trace('done'); +}; +harden(testRecordedRetiredInstances); + +export const getManifestForRecordedRetiredInstances = () => { + return { + manifest: { + [testRecordedRetiredInstances.name]: { + consume: { + contractKits: true, + // governedContractKits: true, + retiredContractInstances: true, + }, + }, + }, + }; +}; + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').CoreEvalBuilder} */ +export const defaultProposalBuilder = async () => + harden({ + sourceSpec: + '@agoric/builders/scripts/testing/recorded-retired-instances.js', + getManifestCall: ['getManifestForRecordedRetiredInstances', {}], + }); + +/** @type {import('@agoric/deploy-script-support/src/externalTypes.js').DeployScriptFunction} */ +export default async (homeP, endowments) => { + // import dynamically so the module can work in CoreEval environment + const dspModule = await import('@agoric/deploy-script-support'); + const { makeHelpers } = dspModule; + const { writeCoreEval } = await makeHelpers(homeP, endowments); + await writeCoreEval('recorded-retired', defaultProposalBuilder); +}; diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js index 6814fbdcc87..e2cada43d97 100644 --- a/packages/inter-protocol/src/proposals/add-auction.js +++ b/packages/inter-protocol/src/proposals/add-auction.js @@ -3,6 +3,7 @@ import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js'; import { E } from '@endo/far'; import { Stable } from '@agoric/internal/src/tokens.js'; import { makeGovernedTerms as makeGovernedATerms } from '../auction/params.js'; +import { parallelCreateMap } from './utils.js'; const trace = makeTracer('NewAuction', true); @@ -11,6 +12,7 @@ const trace = makeTracer('NewAuction', true); * auctionUpgradeNewInstance: Instance; * auctionUpgradeNewGovCreator: any; * newContractGovBundleId: string; + * retiredContractInstances: MapStore; * }>} interlockPowers */ @@ -35,6 +37,7 @@ export const addAuction = async ( economicCommitteeCreatorFacet: electorateCreatorFacet, governedContractKits: governedContractKitsP, priceAuthority8400, + retiredContractInstances: retiredContractInstancesP, zoe, }, produce: { @@ -42,6 +45,7 @@ export const addAuction = async ( auctionUpgradeNewInstance, auctionUpgradeNewGovCreator, newContractGovBundleId, + retiredContractInstances: produceRetiredInstances, }, instance: { consume: { reserve: reserveInstance }, @@ -79,6 +83,13 @@ export const addAuction = async ( auctioneerInstallationP, ]); + await parallelCreateMap(produceRetiredInstances, 'retiredContractInstances'); + + // save the auctioneer instance so we can manage it later + const boardID = await E(board).getId(legacyKit.instance); + const identifier = `auctioneer-${boardID}`; + await E(retiredContractInstancesP).init(identifier, legacyKit.instance); + // Each field has an extra layer of type + value: // AuctionStartDelay: { type: 'relativeTime', value: { relValue: 2n, timerBrand: Object [Alleged: timerBrand] {} } } /** @type {any} */ @@ -210,6 +221,7 @@ export const ADD_AUCTION_MANIFEST = harden({ economicCommitteeCreatorFacet: true, governedContractKits: true, priceAuthority8400: true, + retiredContractInstances: true, zoe: true, }, produce: { @@ -217,6 +229,7 @@ export const ADD_AUCTION_MANIFEST = harden({ auctionUpgradeNewInstance: true, auctionUpgradeNewGovCreator: true, newContractGovBundleId: true, + retiredContractInstances: true, }, instance: { consume: { reserve: true }, diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js index f98f62223f2..e21fafcfb76 100644 --- a/packages/inter-protocol/src/proposals/deploy-price-feeds.js +++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js @@ -5,6 +5,7 @@ import { E } from '@endo/far'; import { unitAmount } from '@agoric/zoe/src/contractSupport/priceQuote.js'; import { oracleBrandFeedName, + parallelCreateMap, reserveThenDeposit, sanitizePathSegment, } from './utils.js'; @@ -84,7 +85,8 @@ export const ensureOracleBrand = async ( }; /** - * @param {EconomyBootstrapPowers} powers + * @param {EconomyBootstrapPowers & + * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers * @param {{ * AGORIC_INSTANCE_NAME: string; * contractTerms: import('@agoric/inter-protocol/src/price/fluxAggregatorKit.js').ChainlinkConfig; @@ -96,6 +98,7 @@ export const ensureOracleBrand = async ( const startPriceAggregatorInstance = async ( { consume: { + agoricNames, board, chainStorage, chainTimerService, @@ -103,6 +106,7 @@ const startPriceAggregatorInstance = async ( highPrioritySendersManager, namesByAddressAdmin, startGovernedUpgradable, + retiredContractInstances: retiredContractInstancesP, }, instance: { produce: produceInstance }, }, @@ -139,6 +143,19 @@ const startPriceAggregatorInstance = async ( // @ts-expect-error GovernableStartFn vs. fluxAggregatorContract.js start installation, }); + const retiredContractInstances = await retiredContractInstancesP; + + // save the instance so we can manage it later + const retiringInstance = await E(agoricNames).lookup( + 'instance', + AGORIC_INSTANCE_NAME, + ); + const boardID = await E(board).getId(retiringInstance); + retiredContractInstances.init( + `priceFeed-${AGORIC_INSTANCE_NAME}-${boardID}`, + retiringInstance, + ); + produceInstance[AGORIC_INSTANCE_NAME].reset(); produceInstance[AGORIC_INSTANCE_NAME].resolve(governedKit.instance); trace( @@ -191,7 +208,9 @@ const distributeInvitations = async ( }; /** - * @param {EconomyBootstrapPowers & NamedVatPowers} powers + * @param {EconomyBootstrapPowers & + * NamedVatPowers & + * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers * @param {{ * options: PriceFeedConfig & { * priceAggregatorRef: { bundleID: string }; @@ -221,6 +240,11 @@ export const deployPriceFeeds = async (powers, config) => { priceAggregatorRef.bundleID, ); + await parallelCreateMap( + powers.produce.retiredContractInstances, + 'retiredContractInstances', + ); + const { priceAuthorityAdmin, priceAuthority } = powers.consume; trace({ oracleAddresses }); @@ -300,6 +324,7 @@ export const getManifestForPriceFeeds = async ( namesByAddressAdmin: t, priceAuthority: t, priceAuthorityAdmin: t, + retiredContractInstances: t, startGovernedUpgradable: t, startUpgradable: t, zoe: t, @@ -307,9 +332,10 @@ export const getManifestForPriceFeeds = async ( installation: { produce: { priceAggregator: t } }, instance: { produce: t, + consume: t, }, oracleBrand: { produce: t }, - produce: { priceAuthority8400: t }, + produce: { priceAuthority8400: t, retiredContractInstances: t }, }, }, options: { ...priceFeedOptions }, diff --git a/packages/inter-protocol/src/proposals/replaceElectorate.js b/packages/inter-protocol/src/proposals/replaceElectorate.js index cb862be5a67..a0c4c1db28d 100644 --- a/packages/inter-protocol/src/proposals/replaceElectorate.js +++ b/packages/inter-protocol/src/proposals/replaceElectorate.js @@ -15,7 +15,7 @@ import { assertPathSegment, makeStorageNodeChild, } from '@agoric/internal/src/lib-chainStorage.js'; -import { reserveThenDeposit } from './utils.js'; +import { parallelCreateMap, reserveThenDeposit } from './utils.js'; /** @import {EconomyBootstrapPowers} from './econ-behaviors.js' */ /** @import {EconCharterStartResult} from './econ-behaviors.js' */ @@ -181,8 +181,10 @@ const inviteToEconCharter = async ( * Starts a new Economic Committee (EC) by creating an instance with the * provided committee specifications. * - * @param {EconomyBootstrapPowers} powers - The resources and capabilities - * required to start the committee. + * @param {EconomyBootstrapPowers & + * PromiseSpaceOf<{ retiredContractInstances: MapStore }>} powers + * - The resources and capabilities required to start the committee. + * * @param {{ * options: { * committeeName: string; @@ -196,12 +198,22 @@ const inviteToEconCharter = async ( */ const startNewEconomicCommittee = async ( { - consume: { board, chainStorage, startUpgradable }, - produce: { economicCommitteeKit, economicCommitteeCreatorFacet }, + consume: { + board, + chainStorage, + startUpgradable, + retiredContractInstances: retiredInstancesP, + }, + produce: { + economicCommitteeKit, + economicCommitteeCreatorFacet, + retiredContractInstances: produceRetiredInstances, + }, installation: { consume: { committee }, }, instance: { + consume: { economicCommittee: economicCommitteeOriginalP }, produce: { economicCommittee }, }, }, @@ -214,6 +226,18 @@ const startNewEconomicCommittee = async ( trace(`committeeName ${committeeName}`); trace(`committeeSize ${committeeSize}`); + await parallelCreateMap(produceRetiredInstances, 'retiredContractInstances'); + + // get the actual retiredContractInstances + const retiredInstances = await retiredInstancesP; + // Record the retired electorate instance so we can manage it later. + const economicCommitteeOriginal = await economicCommitteeOriginalP; + const boardID = await E(board).getId(economicCommitteeOriginal); + await E(retiredInstances).init( + `economicCommittee-${boardID}`, + economicCommitteeOriginal, + ); + const committeesNode = await makeStorageNodeChild( chainStorage, COMMITTEES_ROOT, @@ -309,6 +333,7 @@ const startNewEconCharter = async ({ * @typedef {PromiseSpaceOf<{ * auctionUpgradeNewInstance: Instance; * auctionUpgradeNewGovCreator: any; + * retiredContractInstances: MapStore; * }>} interlockPowers */ @@ -485,6 +510,7 @@ export const getManifestForReplaceAllElectorates = async ( manifest: { [replaceAllElectorates.name]: { consume: { + agoricNames: true, auctionUpgradeNewGovCreator: true, auctionUpgradeNewInstance: true, psmKit: true, @@ -492,6 +518,7 @@ export const getManifestForReplaceAllElectorates = async ( chainStorage: true, highPrioritySendersManager: true, namesByAddressAdmin: true, + retiredContractInstances: true, // Rest of these are designed to be widely shared board: true, startUpgradable: true, @@ -501,6 +528,7 @@ export const getManifestForReplaceAllElectorates = async ( economicCommitteeKit: true, economicCommitteeCreatorFacet: true, auctionUpgradeNewGovCreator: true, + retiredContractInstances: true, }, installation: { consume: { @@ -514,6 +542,7 @@ export const getManifestForReplaceAllElectorates = async ( economicCommittee: true, econCommitteeCharter: true, }, + consume: { economicCommittee: true }, }, }, }, diff --git a/packages/inter-protocol/src/proposals/utils.js b/packages/inter-protocol/src/proposals/utils.js index 42894a27148..07c9a8269d2 100644 --- a/packages/inter-protocol/src/proposals/utils.js +++ b/packages/inter-protocol/src/proposals/utils.js @@ -3,6 +3,7 @@ import { E } from '@endo/far'; import { WalletName } from '@agoric/internal'; import { getCopyMapEntries, makeCopyMap } from '@agoric/store'; import { assertPathSegment } from '@agoric/internal/src/lib-chainStorage.js'; +import { makeScalarBigMapStore } from '@agoric/vat-data'; /** @import {CopyMap} from '@endo/patterns'; */ @@ -171,3 +172,16 @@ export const sanitizePathSegment = name => { assertPathSegment(candidate); return candidate; }; + +/** + * Idempotently create and store a durable MapStore for the promise space. + * `resolve()` silently fails if called again after a successful call, so it's + * safe for multiple proposals to call in parallel, as long as they all use the + * value from consume rather than the value they produced. + * + * @param {Producer} producer + * @param {string} [name] + */ +export const parallelCreateMap = async (producer, name = 'mapStore') => { + await producer.resolve(makeScalarBigMapStore(name, { durable: true })); +}; From 1581127d325afab428f4616c3428f53eea51e131 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 12 Dec 2024 15:19:25 -0800 Subject: [PATCH 40/42] refactor: provideRetiredInstances --- .../src/proposals/add-auction.js | 11 ++++++---- .../src/proposals/deploy-price-feeds.js | 13 +++++------ .../src/proposals/replaceElectorate.js | 11 +++++----- .../inter-protocol/src/proposals/utils.js | 22 ++++++++++++------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/inter-protocol/src/proposals/add-auction.js b/packages/inter-protocol/src/proposals/add-auction.js index e2cada43d97..76dd57a0c6b 100644 --- a/packages/inter-protocol/src/proposals/add-auction.js +++ b/packages/inter-protocol/src/proposals/add-auction.js @@ -1,9 +1,9 @@ import { deeplyFulfilledObject, makeTracer } from '@agoric/internal'; import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js'; -import { E } from '@endo/far'; import { Stable } from '@agoric/internal/src/tokens.js'; +import { E } from '@endo/far'; import { makeGovernedTerms as makeGovernedATerms } from '../auction/params.js'; -import { parallelCreateMap } from './utils.js'; +import { provideRetiredInstances } from './utils.js'; const trace = makeTracer('NewAuction', true); @@ -83,12 +83,15 @@ export const addAuction = async ( auctioneerInstallationP, ]); - await parallelCreateMap(produceRetiredInstances, 'retiredContractInstances'); + const retiredInstances = await provideRetiredInstances( + retiredContractInstancesP, + produceRetiredInstances, + ); // save the auctioneer instance so we can manage it later const boardID = await E(board).getId(legacyKit.instance); const identifier = `auctioneer-${boardID}`; - await E(retiredContractInstancesP).init(identifier, legacyKit.instance); + retiredInstances.init(identifier, legacyKit.instance); // Each field has an extra layer of type + value: // AuctionStartDelay: { type: 'relativeTime', value: { relValue: 2n, timerBrand: Object [Alleged: timerBrand] {} } } diff --git a/packages/inter-protocol/src/proposals/deploy-price-feeds.js b/packages/inter-protocol/src/proposals/deploy-price-feeds.js index e21fafcfb76..0ecbea49098 100644 --- a/packages/inter-protocol/src/proposals/deploy-price-feeds.js +++ b/packages/inter-protocol/src/proposals/deploy-price-feeds.js @@ -5,7 +5,7 @@ import { E } from '@endo/far'; import { unitAmount } from '@agoric/zoe/src/contractSupport/priceQuote.js'; import { oracleBrandFeedName, - parallelCreateMap, + provideRetiredInstances, reserveThenDeposit, sanitizePathSegment, } from './utils.js'; @@ -109,6 +109,7 @@ const startPriceAggregatorInstance = async ( retiredContractInstances: retiredContractInstancesP, }, instance: { produce: produceInstance }, + produce: { retiredContractInstances: produceRetiredInstances }, }, { AGORIC_INSTANCE_NAME, contractTerms, brandIn, brandOut }, installation, @@ -143,7 +144,10 @@ const startPriceAggregatorInstance = async ( // @ts-expect-error GovernableStartFn vs. fluxAggregatorContract.js start installation, }); - const retiredContractInstances = await retiredContractInstancesP; + const retiredContractInstances = await provideRetiredInstances( + retiredContractInstancesP, + produceRetiredInstances, + ); // save the instance so we can manage it later const retiringInstance = await E(agoricNames).lookup( @@ -240,11 +244,6 @@ export const deployPriceFeeds = async (powers, config) => { priceAggregatorRef.bundleID, ); - await parallelCreateMap( - powers.produce.retiredContractInstances, - 'retiredContractInstances', - ); - const { priceAuthorityAdmin, priceAuthority } = powers.consume; trace({ oracleAddresses }); diff --git a/packages/inter-protocol/src/proposals/replaceElectorate.js b/packages/inter-protocol/src/proposals/replaceElectorate.js index a0c4c1db28d..adde9adf747 100644 --- a/packages/inter-protocol/src/proposals/replaceElectorate.js +++ b/packages/inter-protocol/src/proposals/replaceElectorate.js @@ -15,7 +15,7 @@ import { assertPathSegment, makeStorageNodeChild, } from '@agoric/internal/src/lib-chainStorage.js'; -import { parallelCreateMap, reserveThenDeposit } from './utils.js'; +import { provideRetiredInstances, reserveThenDeposit } from './utils.js'; /** @import {EconomyBootstrapPowers} from './econ-behaviors.js' */ /** @import {EconCharterStartResult} from './econ-behaviors.js' */ @@ -226,14 +226,15 @@ const startNewEconomicCommittee = async ( trace(`committeeName ${committeeName}`); trace(`committeeSize ${committeeSize}`); - await parallelCreateMap(produceRetiredInstances, 'retiredContractInstances'); + const retiredInstances = await provideRetiredInstances( + retiredInstancesP, + produceRetiredInstances, + ); - // get the actual retiredContractInstances - const retiredInstances = await retiredInstancesP; // Record the retired electorate instance so we can manage it later. const economicCommitteeOriginal = await economicCommitteeOriginalP; const boardID = await E(board).getId(economicCommitteeOriginal); - await E(retiredInstances).init( + retiredInstances.init( `economicCommittee-${boardID}`, economicCommitteeOriginal, ); diff --git a/packages/inter-protocol/src/proposals/utils.js b/packages/inter-protocol/src/proposals/utils.js index 07c9a8269d2..165731e4838 100644 --- a/packages/inter-protocol/src/proposals/utils.js +++ b/packages/inter-protocol/src/proposals/utils.js @@ -174,14 +174,20 @@ export const sanitizePathSegment = name => { }; /** - * Idempotently create and store a durable MapStore for the promise space. - * `resolve()` silently fails if called again after a successful call, so it's - * safe for multiple proposals to call in parallel, as long as they all use the - * value from consume rather than the value they produced. + * Idempotently provide an empty MapStore for the `retiredContractInstances` + * value in promise space * - * @param {Producer} producer - * @param {string} [name] + * @param {Promise} consume + * @param {Producer} produce + * @returns {Promise} */ -export const parallelCreateMap = async (producer, name = 'mapStore') => { - await producer.resolve(makeScalarBigMapStore(name, { durable: true })); +export const provideRetiredInstances = async (consume, produce) => { + // Promise space has no way to look for an existing value other than awaiting a promise, + // but it does allow extra production so it's safe to do this redundantly. + produce.resolve( + makeScalarBigMapStore('retiredContractInstances', { + durable: true, + }), + ); + return consume; }; From 6b6a241add95d139abcb57370a4d9c161c21b85c Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Fri, 13 Dec 2024 11:45:09 -0500 Subject: [PATCH 41/42] test: add retry logic to `provisionSmartWallet` - motivated after observing "cannot read data of published.wallet.agoric1ujmk0492mauq2f2vrcn7ylq3w3x55k0ap9mt2p.current: fetch failed" in https://github.com/Agoric/agoric-sdk/actions/runs/12313012295/job/34369641775?pr=10638 - this likely indicates a race between `provision-one`, the vstorage update, or the RPCs view of vstorage - to address this, retry the vstorage query with `retryUntilCondition` --- .../test/fast-usdc/fast-usdc.test.ts | 16 ++++++---------- multichain-testing/tools/e2e-tools.js | 18 ++++++++++++++++-- multichain-testing/tools/sleep.ts | 6 +++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/multichain-testing/test/fast-usdc/fast-usdc.test.ts b/multichain-testing/test/fast-usdc/fast-usdc.test.ts index 3b3d7f79dce..8997384e031 100644 --- a/multichain-testing/test/fast-usdc/fast-usdc.test.ts +++ b/multichain-testing/test/fast-usdc/fast-usdc.test.ts @@ -50,17 +50,13 @@ test.before(async t => { const wallets = await setupTestKeys(accounts, values(oracleMnemonics)); // provision oracle wallets first so invitation deposits don't fail - const oracleWdPs = keys(oracleMnemonics).map(n => - provisionSmartWallet(wallets[n], { - BLD: 100n, - }), + const oracleWds = await Promise.all( + keys(oracleMnemonics).map(n => + provisionSmartWallet(wallets[n], { + BLD: 100n, + }), + ), ); - // execute sequentially, to avoid "published.wallet.${addr}.current: fetch failed" - const oracleWds: WalletDriver[] = []; - for (const p of oracleWdPs) { - const wd = await p; - oracleWds.push(wd); - } // calculate denomHash and channelId for privateArgs / builder opts const { getTransferChannelId, toDenomHash } = makeDenomTools(chainInfo); diff --git a/multichain-testing/tools/e2e-tools.js b/multichain-testing/tools/e2e-tools.js index 6ad5575acb7..4710761e014 100644 --- a/multichain-testing/tools/e2e-tools.js +++ b/multichain-testing/tools/e2e-tools.js @@ -8,8 +8,12 @@ import { flags, makeAgd, makeCopyFiles } from './agd-lib.js'; import { makeHttpClient, makeAPI } from './makeHttpClient.js'; import { dedup, makeQueryKit, poll } from './queryKit.js'; import { makeVStorage } from './batchQuery.js'; +import { makeRetryUntilCondition } from './sleep.js'; -/** @import { EnglishMnemonic } from '@cosmjs/crypto'; */ +/** + * @import { EnglishMnemonic } from '@cosmjs/crypto'; + * @import { RetryUntilCondition } from './sleep.js'; + */ const BLD = '000000ubld'; @@ -121,6 +125,7 @@ const installBundle = async (fullPath, opts) => { * blockTool: BlockTool; * lcd: import('./makeHttpClient.js').LCD; * delay: (ms: number) => Promise; + * retryUntilCondition: RetryUntilCondition; * chainId?: string; * whale?: string; * progress?: typeof console.log; @@ -139,6 +144,7 @@ export const provisionSmartWallet = async ( whale = 'faucet', progress = console.log, q = makeQueryKit(makeVStorage(lcd)).query, + retryUntilCondition, }, ) => { // TODO: skip this query if balances is {} @@ -187,7 +193,12 @@ export const provisionSmartWallet = async ( { chainId, from: address, yes: true }, ); - const info = await q.queryData(`published.wallet.${address}.current`); + const info = await retryUntilCondition( + () => q.queryData(`published.wallet.${address}.current`), + result => !!result, + `wallet in vstorage ${address}`, + { log: () => {} }, // suppress logs as this is already noisy + ); progress({ provisioned: address, purses: info.purses.length, @@ -428,6 +439,7 @@ const runCoreEval = async ( * @param {string} [io.rpcAddress] * @param {string} [io.apiAddress] * @param {(...parts: string[]) => string} [io.join] + * * @param {RetryUntilCondition} [io.retryUntilCondition] */ export const makeE2ETools = async ( log, @@ -438,6 +450,7 @@ export const makeE2ETools = async ( setTimeout, rpcAddress = 'http://localhost:26657', apiAddress = 'http://localhost:1317', + retryUntilCondition = makeRetryUntilCondition({ log, setTimeout }), }, ) => { const agd = makeAgd({ execFileSync }).withOpts({ keyringBackend: 'test' }); @@ -535,6 +548,7 @@ export const makeE2ETools = async ( lcd, delay, q: vstorageClient, + retryUntilCondition, }), /** * @param {string} name diff --git a/multichain-testing/tools/sleep.ts b/multichain-testing/tools/sleep.ts index 1b0d1a58807..eca0392c1b7 100644 --- a/multichain-testing/tools/sleep.ts +++ b/multichain-testing/tools/sleep.ts @@ -28,11 +28,11 @@ const retryUntilCondition = async ( { maxRetries = 6, retryIntervalMs = 3500, - log = () => {}, + log = console.log, setTimeout = ambientSetTimeout, }: RetryOptions = {}, ): Promise => { - console.log({ maxRetries, retryIntervalMs, message }); + log({ maxRetries, retryIntervalMs, message }); let retries = 0; while (retries < maxRetries) { @@ -50,7 +50,7 @@ const retryUntilCondition = async ( } retries++; - console.log( + log( `Retry ${retries}/${maxRetries} - Waiting for ${retryIntervalMs}ms for ${message}...`, ); await sleep(retryIntervalMs, { log, setTimeout }); From 0cdb981db08d59d7c3e73396af97c20b56fa9442 Mon Sep 17 00:00:00 2001 From: 0xPatrick Date: Fri, 13 Dec 2024 11:46:10 -0500 Subject: [PATCH 42/42] chore: restore skipped test --- packages/boot/test/fast-usdc/fast-usdc.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/boot/test/fast-usdc/fast-usdc.test.ts b/packages/boot/test/fast-usdc/fast-usdc.test.ts index 0853f6b183b..6eae95b9ad2 100644 --- a/packages/boot/test/fast-usdc/fast-usdc.test.ts +++ b/packages/boot/test/fast-usdc/fast-usdc.test.ts @@ -187,7 +187,7 @@ test.serial('writes account addresses to vstorage', async t => { await documentStorageSchema(t, storage, doc); }); -test.skip('makes usdc advance', async t => { +test.serial('makes usdc advance', async t => { const { walletFactoryDriver: wd, storage,