-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support offer signing with keplr #28
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file was taken from wallet-app and trimmed down a bit to remove the non-spend-action stuff.
bcd1575
to
cdad864
Compare
We can see from https://github.com/Agoric/ui-kit/actions/runs/5864651371/job/15900068743?pr=28 that the test now requires ses because of the dependencies on casting and notifiers. After adding ses to the test environment, I now get the below error. Maybe it's possible to migrate these tests to Ava, but vitest is not cooperating for some reason in this context.
|
vitest-dev/vitest#3527 has the fix. Released in 0.32.3. This repo is on 0.32.0. |
*/ | ||
fromBoard: (slot, iface) => { | ||
- isDefaultBoardId(slot) || Fail`bad board slot ${q(slot)}`; | ||
+ isDefaultBoardId(slot) || slot === null || Fail`bad board slot ${q(slot)}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how do we stop patching this?
This app only needs the board marshaller, not the whole import context the smart-wallet itself needs.
Would this work? https://github.com/Agoric/agoric-sdk/blob/c6d8a278ad7d7c0ad758f57c7e4db858d6a67e53/packages/internal/src/marshal.js#L32-L41
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think that will work, but while working on productizing the bidding CLI, I realized that relying on remotables to know their slot/boadID is awkward.
Also, the BoardRemote${nonalleged}
idiom is over-kill. IMO it's better, conceptually, to just use ${nonalleged}
as the debug name. But more importantly: users pay by the byte when they submit offers.
The way I've been teaching it lately is to use a typical translation table, parameterized by what to do when you get a cache miss...
And the board slotting marshaller synthesizes a remotable when slotToVal
has a cache miss:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay I got something like Dan's example working
* @param {Keplr} keplr | ||
* @param {typeof import('@cosmjs/stargate').SigningStargateClient.connectWithSigner} connectWithSigner |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Glad to see the use of explicit authority is still here. :)
076a3e9
to
baef932
Compare
packages/rpc/package.json
Outdated
@@ -29,6 +30,6 @@ | |||
"postinstall-postinstall": "^2.1.0", | |||
"prettier": "^2.7.1", | |||
"typescript": "^5.1.3", | |||
"vitest": "^0.32.0" | |||
"vitest": "0.34.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"vitest": "0.34.1" | |
"vitest": "^0.34.1" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, but what is the benefit of this? Doesn't this make our build less deterministic?
packages/rpc/package.json
Outdated
@@ -20,6 +20,7 @@ | |||
"vite-tsconfig-paths": "^4.2.0" | |||
}, | |||
"devDependencies": { | |||
"@endo/marshal": "0.8.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"@endo/marshal": "0.8.8", | |
"@endo/marshal": "^0.8.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
/* eslint-disable import/no-extraneous-dependencies */ | ||
import { makeMarshal } from 'marshal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really avoid undeclared dependencies. I think this is just as simple as:
/* eslint-disable import/no-extraneous-dependencies */ | |
import { makeMarshal } from 'marshal'; | |
import { makeMarshal } from './marshal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting... done
onError?: (e: Error) => void, | ||
marshal = makeMarshal(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consider calling it "marshaller" since "marshal" is a verb and this is an object that holds functions/verbs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, but then shouldn't the endo export be named makeMarshaller
instead also?
packages/rpc/src/marshal.ts
Outdated
@@ -0,0 +1,40 @@ | |||
/* eslint-disable import/no-extraneous-dependencies */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't it declared?
/* eslint-disable import/no-extraneous-dependencies */ | |
/* eslint-disable import/no-extraneous-dependencies */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'@endo/marshal' should be listed in the project's dependencies, not devDependencies.
I didn't think it was worth putting in dependencies, but done
packages/rpc/src/marshal.ts
Outdated
export const makeMarshal = () => | ||
endoMakeMarshal(convertValToSlot, convertSlotToVal, { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if someone is familiar with Endo, makeMarshal
has a learned meaning.
consider exporting makeTranslationMarshaller
or makeClientMarshaller
and allowing Endo's to keep its name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
unserialize: unmarshal, | ||
serialize: marshal, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could drop these. they're deprecated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed to satisfy the type
); | ||
|
||
try { | ||
// eslint-disable-next-line @jessie.js/safe-await-separator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try an await null
before the this try{}
. the lint rule shouldn't complain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, I just wasn't sure that was any better.
@@ -60,4 +69,32 @@ describe('makeAgoricWalletConnection', () => { | |||
Errors.noSmartWallet, | |||
); | |||
}); | |||
|
|||
it('submits a spend action', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remark: yay tests!
@@ -1,9 +1,9 @@ | |||
/* eslint-disable no-use-before-define */ | |||
/* eslint-disable import/extensions */ | |||
import type { FromCapData } from '@endo/marshal'; | |||
import type { UpdateHandler } from './types'; | |||
import { makeClientMarshaller } from './marshal'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See "marshal.ts" for an example that should work with null slots.
}; | ||
|
||
const convertSlotToVal = (slot: unknown, iface: string | undefined) => { | ||
if (slotToVal.has(slot)) return slotToVal.get(slot); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm. a slot of null
should probably be treated as a cache miss here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean we should just do something like:
if (slot === null) {
return Far('null', {})
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see clearly why it's bad for all null slots to resolve to the same presence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if on-chain code uses the read-only marshaller to marshal distinct unpublished remotables X and Y, they both come across with null
slots. This current code unmarshalls them to one object. That could cause a client to think that 2 different brands are the same or all sorts of other stuff... if it's not exploitable now, we'll have to carefully check every change to what our code (ALL of our code) does to make sure it continues to be not exploitable.
The down side of treating null
as a cache-miss is that two references to the same X get unmarshalled as distinct objects. Given that null
is supposed to not communicate anything about the identity of what was in that slot, that seems fail-safe, to me. It's not without some risk, though. Do we know where the null is coming from? It's supposed to indicate a bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean we should just do something like:
if (slot === null) { return Far('null', {}) }
something like that, yes. But specifically: it should return makeVal(slot, iface);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Yea, I was thinking along the lines of "null slot means null value on-chain", so thought it was okay if they were treated as null === null
, but unpublished values that are actually different makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know where the null is coming from? It's supposed to indicate a bug. - @dckc
I observe(d) null slots in mainnet but not on devnet, so this may already be addressed.
When i query published.vaultFactory.managers.manager0.quotes
and pass the result into importContext.fromBoard.fromCapData()
, it throws with Error: bad board slot null
.
The offending data blob:
Object <[Object: null prototype] {}> {
body: '#{"quoteAmount":{"brand":"$0.Alleged: quote brand","value":[{"amountIn":{"brand":"$1.Alleged: ATOM brand","value":"+1000000"},"amountOut":{"brand":"$2.Alleged: IST brand","value":"+6525815"},"timer":"$3.Alleged: timerService","timestamp":{"absValue":"+1694631252","timerBrand":"$4.Alleged: timerBrand"}}]},"quotePayment":"$5.Alleged: quote payment"}',
slots: [ null, 'board05557', 'board0257', 'board05674', 'board0425', null ]
}
Happy to create an issue in the main repo if needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's expected for vstorage to have null slots because not all objects referenced are necessarily public. For instance, the final slot in the quote example is for a quote payment, which must not be published.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. But I'm not certain of the point DC is making about cache miss.
fixes #29
Tested with Agoric/dapp-inter#195
I'd like to follow up with documentation/code examples in the README for reading vstorage, reading users' purse balances, and making offers.