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: complete UndelegateAndTransfer and DepositAndDelegate flows #10045

Merged
merged 9 commits into from
Sep 10, 2024
9 changes: 5 additions & 4 deletions multichain-testing/test/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { RetryOptions } from '../tools/sleep.js';

/**
* Wait 90 seconds to ensure staking rewards are available.
* Wait up to 90 seconds to ensure staking rewards are available.
*
* While we expect staking rewards to be available after a
* single block (~5-12 seconds for most chains), this provides additional
Expand All @@ -18,7 +18,7 @@ export const STAKING_REWARDS_TIMEOUT: RetryOptions = {
};

/**
* Wait 2 minutes to ensure:
* Wait up to 2 minutes to ensure:
* - IBC Transfer from LocalAccount -> ICA Account Completes
* - Delegation from ICA Account (initiated from SwingSet) Completes
* - Delegations are visible via LCD (API Endpoint)
Expand All @@ -32,11 +32,12 @@ export const AUTO_STAKE_IT_DELEGATIONS_TIMEOUT: RetryOptions = {
};

/**
* Wait about 90s to ensure:
* Wait up to 2 minutes to ensure:
* - ICA Account is created
* - ICQ Connection is established (in some instances)
* - Query is executed (sometimes local, sometimes via ICQ)
*/
export const MAKE_ACCOUNT_AND_QUERY_BALANCE_TIMEOUT: RetryOptions = {
maxRetries: 25,
retryIntervalMs: 5000,
maxRetries: 24,
};
24 changes: 11 additions & 13 deletions multichain-testing/test/stake-ica.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,10 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => {
vstorageClient,
retryUntilCondition,
useChain,
deployBuilder,
startContract,
} = t.context;

t.log('bundle and install contract', scenario);
await deployBuilder(scenario.builder);
await retryUntilCondition(
() => vstorageClient.queryData(`published.agoricNames.instance`),
res => scenario.contractName in Object.fromEntries(res),
`${scenario.contractName} instance is available`,
);
await startContract(scenario.contractName, scenario.builder);
const wdUser1 = await provisionSmartWallet(wallets[scenario.wallet], {
BLD: 100n,
IST: 100n,
Expand Down Expand Up @@ -206,7 +200,7 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => {
);
t.log('Balance after claiming rewards:', rewards);

const SHARES = 50;
const TOKENS_TO_UNDELEGATE = 50n;
t.log('Undelegate offer from continuing inv');
const undelegateOfferId = `undelegate-${Date.now()}`;
await doOffer({
Expand All @@ -218,8 +212,11 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => {
invitationArgs: [
[
{
validatorAddress,
shares: String(SHARES),
validator: validatorChainAddress,
amount: {
denom: scenario.denom,
value: TOKENS_TO_UNDELEGATE,
},
},
],
],
Expand All @@ -235,7 +232,7 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => {
t.log('unbonding_responses:', unbonding_responses[0].entries);
t.is(
unbonding_responses[0].entries[0].balance,
String(SHARES),
String(TOKENS_TO_UNDELEGATE),
'undelegating 50 shares in progress',
);

Expand All @@ -250,7 +247,8 @@ const stakeScenario = test.macro(async (t, scenario: StakeIcaScenario) => {
const { balances: rewardsWithUndelegations } = await retryUntilCondition(
() => queryClient.queryBalances(address),
({ balances }) => {
const expectedBalance = Number(currentBalances[0].amount) + SHARES;
const expectedBalance =
Number(currentBalances[0].amount) + Number(TOKENS_TO_UNDELEGATE);
return Number(balances?.[0]?.amount) >= expectedBalance;
},
'claimed rewards available',
Expand Down
8 changes: 5 additions & 3 deletions packages/async-flow/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ export type GuestInterface<T> = {
? (...args: Parameters<T[K]>) => Promise<R>
: T[K] extends HostAsyncFuncWrapper
? GuestOf<T[K]>
: T[K] extends object
? GuestInterface<T[K]>
: T[K];
: T[K] extends (...args: any[]) => infer R
? T[K]
: T[K] extends object
? GuestInterface<T[K]>
: T[K];
};

/**
Expand Down
61 changes: 56 additions & 5 deletions packages/async-flow/test/types.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,73 @@
import { expectType } from 'tsd';
import type { Zone } from '@agoric/base-zone';
import type { Vow, VowTools } from '@agoric/vow';
import type { HostOf, GuestOf } from '../src/types.js';
import type {
HostOf,
GuestOf,
HostInterface,
GuestInterface,
} from '../src/types.js';

const castable: unknown = null;
const vt: VowTools = null as any;

const sumVow = (a: number, b: number) => vt.asVow(() => a + b);

const sumPromise = (a: number, b: number) => Promise.resolve(a + b);

expectType<(p1: number, p2: number) => Promise<number>>(
null as unknown as GuestOf<typeof sumVow>,
castable as GuestOf<typeof sumVow>,
);

expectType<(p1: number, p2: number) => Vow<number>>(
null as unknown as HostOf<typeof sumPromise>,
castable as HostOf<typeof sumPromise>,
);
expectType<(p1: number, p2: number) => Vow<void>>(
// @ts-expect-error incompatible return type
null as unknown as HostOf<typeof sumPromise>,
castable as HostOf<typeof sumPromise>,
);

// Test HostInterface and GuestInterface with an exoClass object
type ExoAPIBase = {
getValue: () => number;
setValue: (value: number) => void;
getCopyData: () => Record<string, number>[];
// TODO include `getRemote() => Guarded<...>`, since durable exos are passable
};
type ExoGuestAPI = ExoAPIBase & {
getValueAsync: () => Promise<number>;
};

type ExoHostAPI = ExoAPIBase & {
getValueAsync: () => Vow<number>;
};

expectType<
ExoAPIBase & {
getValueAsync: () => Vow<number>;
}
>(castable as HostInterface<ExoGuestAPI>);
expectType<
ExoAPIBase & {
getValueAsync: () => Promise<number>;
}
>(castable as GuestInterface<ExoHostAPI>);

// Test HostInterface and GuestInterface with classKit (nested) objects
expectType<{
facet: ExoAPIBase & {
getValueAsync: () => Vow<number>;
};
}>(
castable as HostInterface<{
facet: ExoGuestAPI;
}>,
);
expectType<{
facet: ExoAPIBase & {
getValueAsync: () => Promise<number>;
};
}>(
castable as GuestInterface<{
facet: ExoHostAPI;
}>,
);
4 changes: 2 additions & 2 deletions packages/orchestration/USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ See [`src/examples`](src/examples)
| [send-anywhere](/packages/orchestration/src/examples/send-anywhere.contract.js) | Ready 🟢 | Allows sending payments (tokens) over IBC to another chain. | - `LocalOrchestrationAccoun`t<br>- `Vtransfer` (IBC Hooks) |
| [stakeBld](/packages/orchestration/src/examples/stakeBld.contract.js) | Ready 🟢 | Returns a `LocalOrchestrationAccount` that can perform staking actions. | - `LocalOrchestrationAccount` | Ready 🟢 |
| [stakeIca](/packages/orchestration/src/examples/stakeIca.contract.js) | Ready 🟢 | Returns a `CosmosOrchestrationAccount` that can perform staking actions. | - `CosmosOrchestrationAccount` | Ready 🟢 |
| [staking-combinations](/packages/orchestration/src/examples/staking-combinations.contract.js) | Under Construction 🚧 | Combines actions into a single offer flow and demonstrates writing continuing offers. | - `CosmosOrchestrationAccount`<br>- `CombineInvitationMakers` <br>- Continuing Offers |
| [staking-combinations](/packages/orchestration/src/examples/staking-combinations.contract.js) | Ready 🟢 | Combines actions into a single offer flow and demonstrates writing continuing offers. | - `CosmosOrchestrationAccount`<br>- `CombineInvitationMakers` <br>- Continuing Offers |
Copy link
Member

Choose a reason for hiding this comment

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

🎉

| [swap](/packages/orchestration/src/examples/swap.contract.js) | Under Construction 🚧 | Demonstrates asset swapping on an external chain. | - `CosmosOrchestrationAccount`<br>- `ChainHub` |
| [unbond](/packages/orchestration/src/examples/unbond.contract.js) | Under Construction 🚧 | Undelegates tokens for an ICA and liquid stakes them. | - `CosmosOrchestrationAccount` |

Expand All @@ -43,4 +43,4 @@ See [`src/examples`](src/examples)
| [stakeBld](/packages/orchestration/src/examples/stakeBld.contract.js) | - Everything*, created before e2e test suite<br> - Consider folding under generic "stake" contract, once [interfaces are the same](https://github.com/Agoric/agoric-sdk/blob/1976c502bcaac2e7d21f42b30447671a61053236/packages/orchestration/src/exos/local-orchestration-account.js#L487)|
| [swap](/packages/orchestration/src/examples/swap.contract.js) | - Everything - contract incomplete ([#8863](https://github.com/Agoric/agoric-sdk/issues/8863)) |
| [unbond](/packages/orchestration/src/examples/unbond.contract.js) | - Everything - contract incomplete ([#9782](https://github.com/Agoric/agoric-sdk/issues/9782)) |
|
| [staking-combinations](/packages/orchestration/src/examples/staking-combinations.contract.js) | Only tested via [unit tests](/packages/orchestration/src/examples/staking-combinations.contract.js) |
2 changes: 1 addition & 1 deletion packages/orchestration/src/cosmos-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export interface StakingAccountActions {
* @param delegations - the delegation to undelegate
*/
undelegate: (
delegations: Omit<Delegation, 'delegatorAddress'>[],
delegations: { amount: AmountArg; validator: CosmosValidatorAddress }[],
) => Promise<void>;

/**
Expand Down
13 changes: 3 additions & 10 deletions packages/orchestration/src/examples/stakeIca.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ export const meta = harden({
chainId: M.string(),
hostConnectionId: M.string(),
controllerConnectionId: M.string(),
bondDenom: M.string(),
icqEnabled: M.boolean(),
},
privateArgsShape: {
Expand All @@ -49,7 +48,6 @@ harden(privateArgsShape);
* chainId: string;
* hostConnectionId: IBCConnectionID;
* controllerConnectionId: IBCConnectionID;
* bondDenom: string;
* icqEnabled: boolean;
* }} StakeIcaTerms
*/
Expand All @@ -66,13 +64,8 @@ harden(privateArgsShape);
* @param {Baggage} baggage
*/
export const start = async (zcf, privateArgs, baggage) => {
const {
chainId,
hostConnectionId,
controllerConnectionId,
bondDenom,
icqEnabled,
} = zcf.getTerms();
const { chainId, hostConnectionId, controllerConnectionId, icqEnabled } =
zcf.getTerms();
const {
agoricNames,
cosmosInterchainService: orchestration,
Expand Down Expand Up @@ -125,7 +118,7 @@ export const start = async (zcf, privateArgs, baggage) => {
chainAddress.value,
);
const holder = makeCosmosOrchestrationAccount(
{ chainAddress, bondDenom, localAddress, remoteAddress },
{ chainAddress, localAddress, remoteAddress },
{
account,
storageNode: accountNode,
Expand Down
Loading
Loading