Skip to content
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(cosmosStakingAccount): publish chain address to vstorage #9482

Merged
merged 6 commits into from
Jun 17, 2024

Conversation

0xpatrickdev
Copy link
Member

@0xpatrickdev 0xpatrickdev commented Jun 11, 2024

refs: #9042
refs: #9193
refs: #9066

Description

  • Motivation: wallet clients need a way to view their address so they can send funds to it

  • Updates stakeAtom.contract.js to create a vstorage entry for newly created accounts, keyed by ChainAccount['address'] (e.g. cosmos1testing1234)

    • TODO: if we hit UNPARSABLE_ADDRESS in parseAddress we should throw, or use a fallback value
  • Writes an empty string to provided storageNode in exos/cosmosOrchestrationAccount.js

  • Drive-by fixes:

    • use AmountArg consistently in /exos/cosmosOrchestrationAccount.js
    • remove delegatorAddress from undelegate(Delegations[]) interface and implementation

Security Considerations

Scaling Considerations

This is some experimentation within a contract in order to get experience with what should be pushed down into the platform.

The approach delegates vstorage publishing responsibilities to guest contracts. We might consider posting information for all accounts to a shared global namespace.

Documentation Considerations

Testing Considerations

Tests, including ones for swapExample.contract.js and facade.js, were updated to accommodate these changes. Mocking facilities for .getAddress() are light - including in boostrap tests - so using ChainAddress['address'] might lead to unexpected behavior (accounts overwriting each other in storage) in a testing environment.

Upgrade Considerations

@0xpatrickdev 0xpatrickdev changed the title feat(cosmosStakingAccount): write chain address to vstorage feat(cosmosStakingAccount): publish chain address to vstorage Jun 11, 2024

// FIXME mock remoteAddress in ibc bridge
const storagePath =
'mockChainStorageRoot.stakeAtom.accounts.UNPARSABLE_CHAIN_ADDRESS';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might consider throwing if the address is unparsable, or falling back to a different identifier like Port Address + ControllerConnectionID: icacontroller-1-connection-0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the solution but we definitely shouldn't write UNPARSABLE_CHAIN_ADDRESS to vstorage

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a FIXME to chainAccount.js with a link to #9066

@@ -158,6 +158,7 @@ export const prepareCosmosOrchestrationAccountKit = (
// must be the fully synchronous maker because the kit is held in durable state
// @ts-expect-error XXX Patterns
const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]);
void E(topicKit.recorder).write(harden({ sequence: 0n }));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've selected sequence since it seems we need to create an initial write. I considered the ChainAddress object but that didn't seem to make sense when we're keying by ChainAddress['address'].

If folks think storing sequence makes sense, we can increment this after each successful executeEncodedTx.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems useful but it does have a cost. Is it just helpful for diagnostics or is there a product use case to publish each sequence?

If we do include it, consider a more transparent property name like executedSequence

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed for now in favor of an empty string ''. Will wait for use cases.

Copy link

cloudflare-workers-and-pages bot commented Jun 11, 2024

Deploying agoric-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: 11aea65
Status: ✅  Deploy successful!
Preview URL: https://215182fe.agoric-sdk.pages.dev
Branch Preview URL: https://pc-9042-stake-atom-vstorage.agoric-sdk.pages.dev

View logs

@0xpatrickdev 0xpatrickdev marked this pull request as ready for review June 11, 2024 16:17
@0xpatrickdev 0xpatrickdev force-pushed the pc/9042-stake-atom-vstorage branch 3 times, most recently from ca6d46a to b313ac8 Compare June 12, 2024 21:42
@0xpatrickdev 0xpatrickdev requested a review from turadg June 12, 2024 23:24
Copy link
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is some experimentation within a contract in order to get experience with what should be pushed down into the platform.

Very well!

The approach delegates vstorage publishing responsibilities to guest contracts.

I agree that's appropriate at this point and expect we'll develop the abstractions for cleaner start functions after we've got most of the pieces working end to end.

I left some suggestions but no blockers. I did have some questions so I'm holding Approve for those.

Comment on lines +73 to +74
const { accountsStorageNode } = await provideAll(baggage, {
accountsStorageNode: () => E(storageNode).makeChildNode('accounts'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take it you say accountNode below but StorageNode here because it's going in baggage. Consider noting that rationale since this is an example contract.

Comment on lines +83 to +85
const { accountsStorageNode } = await provideAll(baggage, {
accountsStorageNode: () => E(storageNode).makeChildNode('accounts'),
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the thought behind the parent of orchestration being accounts? It will need to put other info in there, won't it?

I won't block on this since the code is still experimental and we have #9066 ahead of us. But consider makeChildNode('orchestration') since that's the scope it's being handed to.

Suggested change
const { accountsStorageNode } = await provideAll(baggage, {
accountsStorageNode: () => E(storageNode).makeChildNode('accounts'),
});
const { orchestrationStorageNode } = await provideAll(baggage, {
orchestrationStorageNode: () => E(storageNode).makeChildNode('orchestration'),
});

We should try to be consistent across contracts so that we can have a helper that does all this setup in one call from start.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We make separate nodes for stakeAtom and stakeOsmo in the start-*.js scripts, and each has an accounts child node. Presumably other info or child nodes can be written to the stakeAtom and stakeOsmo paths.

This seems to be in line with "delegates vstorage publishing responsibilities to guest contracts" in the PR description.

Agree it may make sense to globally publish something for all accounts, unless explicitly opted out, and that's where I think an orchestration node makes sense.

@@ -158,6 +158,7 @@ export const prepareCosmosOrchestrationAccountKit = (
// must be the fully synchronous maker because the kit is held in durable state
// @ts-expect-error XXX Patterns
const topicKit = makeRecorderKit(storageNode, PUBLIC_TOPICS.account[1]);
void E(topicKit.recorder).write(harden({ sequence: 0n }));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems useful but it does have a cost. Is it just helpful for diagnostics or is there a product use case to publish each sequence?

If we do include it, consider a more transparent property name like executedSequence

@@ -363,6 +366,7 @@ export const prepareCosmosOrchestrationAccountKit = (
*/
async getBalance(denom) {
const { chainAddress, icqConnection } = this.state;
if (!icqConnection) throw Error('Queries not enabled.');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reads like something the developer could change.

Suggested change
if (!icqConnection) throw Error('Queries not enabled.');
if (!icqConnection) throw Fail'Queries not enabled for chain ${chainAddress.chainId}`.`;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, updated

const storageNode = await makeStorageNodeChild(chainStorage, VSTORAGE_PATH);
const marshaller = await E(board).getPublishingMarshaller();

// TODO add osmo to bank
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when, why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Came to realize the contract is not using the issuerKeywordRecord (depositing will be done via an LCA). Removed from here and start-stakeAtom.js

// t.regex(address.address, /agoric1/);
t.like(address, { chainId: 'cosmoshub-4', addressEncoding: 'bech32' });
const chainAddress = await E(account).getAddress();
// t.regex(address.address, /cosmos1/);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why disable?

Copy link
Member Author

@0xpatrickdev 0xpatrickdev Jun 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem to be a meaningful test, since the value is currently UNPARSABLE_CHAIN_ADDRESS. Added a comment with FIXME mock remoteAddress in ibc bridge to here as well.

t.log('inv', inv);

const seat = await E(zoe).offer(inv);
t.log('seat', seat);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logging values is useful when diagnosing a failure but noise when the tests are passing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged and removed. My interpretation of @dckc's stance on this topic leads me to be believe there are differing views, so trying to strike a balance.


// FIXME mock remoteAddress in ibc bridge
const storagePath =
'mockChainStorageRoot.stakeAtom.accounts.UNPARSABLE_CHAIN_ADDRESS';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure the solution but we definitely shouldn't write UNPARSABLE_CHAIN_ADDRESS to vstorage

// const { rootNode } = makeFakeStorageKit('mockChainStorageRoot');

const storageNode = Far('StorageNode', {}) as unknown as StorageNode;
const { rootNode } = makeFakeStorageKit('mockChainStorageRoot', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider a unique value for easier string search

Suggested change
const { rootNode } = makeFakeStorageKit('mockChainStorageRoot', {
const { rootNode } = makeFakeStorageKit('stakingOpsTest', {

const { makeRecorderKit, storageNode, zcf, icqConnection, zone } = s;
const make = prepareCosmosOrchestrationAccountKit(zone, makeRecorderKit, zcf);

// Higher fidelity tests below use invitationMakers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helpful comment

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not actually the case 😅 . The main motivation for adding the test here was the TODO: when we write to chainStorage, test it. comment on L187.

I think this functionality is sufficiently tested elsewhere. There's a bit of overlap between staking-ops.test.ts and stake-atom.test.ts we might want to reduce at some point. My preference is to favor the former since it relies on fewer hand-rolled/localized mocks.

@@ -160,6 +160,8 @@ export const prepareChainAccountKit = zone =>
this.state.remoteAddress = remoteAddr;
this.state.localAddress = localAddr;
this.state.chainAddress = harden({
// FIXME need a fallback value like icacontroller-1-connection-1 if this fails
Copy link
Member Author

@0xpatrickdev 0xpatrickdev Jun 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// FIXME need a fallback value like icacontroller-1-connection-1 if this fails
// FIXME need a fallback value like icacontroller-1-connection-1 if this fails
// Or, we should throw since a consumer can't do much w/o an address.

@0xpatrickdev 0xpatrickdev force-pushed the pc/9042-stake-atom-vstorage branch 2 times, most recently from 4818f50 to 30bcdfa Compare June 14, 2024 20:09
@@ -151,7 +151,9 @@ export interface StakingAccountActions {
* The unbonding time is padded by 10 minutes to account for clock skew.
* @param delegations - the delegation to undelegate
*/
undelegate: (delegations: Delegation[]) => Promise<void>;
undelegate: (
delegations: Omit<Delegation, 'delegatorAddress'>[],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before release we should name these different types and define them additively (instead of subtracting)

but I think this is appropriate for now before we we've nailed down all the cases

@0xpatrickdev 0xpatrickdev added the automerge:rebase Automatically rebase updates, then merge label Jun 17, 2024
- given the ChainInfo type is inferred from KnownChains, ensure the icqEnabled key is present on all cosmos chains to facilitate TS types
- a better approach seems to be refactoring start-stakeAtom.js to start-stakeIca.js with parameters. buildProposal doesn't seem to accept options so punted for now
- TODO: register OSMO in bank
@mergify mergify bot merged commit 24665a9 into master Jun 17, 2024
77 checks passed
@mergify mergify bot deleted the pc/9042-stake-atom-vstorage branch June 17, 2024 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants