Skip to content

Commit

Permalink
test(a3p): stake-bld
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg committed Mar 19, 2024
1 parent a7e30a4 commit 3dbe0d8
Show file tree
Hide file tree
Showing 10 changed files with 6,088 additions and 0 deletions.
1 change: 1 addition & 0 deletions a3p-integration/proposals/c:stake-bld/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
5 changes: 5 additions & 0 deletions a3p-integration/proposals/c:stake-bld/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CoreEvalProposal to install stakeBld contract

The `submission` for the proposal is automatically generated during `yarn build`
in `a3p-integration` using the code in agoric-sdk through
`script/generate-a3p-submissions.sh`. and `script/generate-a3p-submission.sh`
28 changes: 28 additions & 0 deletions a3p-integration/proposals/c:stake-bld/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"agoricProposal": {
"type": "/agoric.swingset.CoreEvalProposal",
"source": "subdir",
"sdk-generate": [
"orchestration/init-stakeBld.js"
]
},
"type": "module",
"license": "Apache-2.0",
"dependencies": {
"@agoric/internal": "0.3.3-dev-5676146.0",
"@agoric/synthetic-chain": "^0.0.7",
"@cosmjs/stargate": "^0.32.3",
"@cosmjs/tendermint-rpc": "^0.32.3",
"@endo/errors": "^1.1.0",
"@endo/far": "^1.0.4",
"@endo/init": "^1.0.4",
"agoric": "0.21.2-dev-5676146.0",
"ava": "^5.3.1",
"execa": "^8.0.1",
"node-fetch": "^3.3.2"
},
"ava": {
"concurrency": 1
},
"packageManager": "yarn@4.1.0"
}
73 changes: 73 additions & 0 deletions a3p-integration/proposals/c:stake-bld/stakeBld.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* eslint-disable @jessie.js/safe-await-separator -- buggy version */
import test from 'ava';

import { QueryClient, setupStakingExtension } from '@cosmjs/stargate'; // fails to import after Endo/init

import '@endo/init';

import { GOV1ADDR } from '@agoric/synthetic-chain';
import { Tendermint34Client } from '@cosmjs/tendermint-rpc';
import assert from 'node:assert';
import { networkConfig, walletUtils } from './test-lib/index.js';

// from `agd query staking validators`
const VALIDATOR1 = 'agoricvaloper13lthtpnjef8kavel75c9d3sgvq66647ntqtyyg';

const currentDelegation = async () => {
const endpoint = networkConfig.rpcAddrs[0];
const tmClient = await Tendermint34Client.connect(endpoint);
const query = QueryClient.withExtensions(tmClient, setupStakingExtension);
const res = await query.staking.validatorDelegations(VALIDATOR1);

return res.delegationResponses;
};

test('basic', async t => {
assert(GOV1ADDR);

const { brand } = walletUtils.agoricNames;

t.is((await currentDelegation()).length, 1, 'just the initial delegation');

await walletUtils.broadcastBridgeAction(GOV1ADDR, {
method: 'executeOffer',
offer: {
id: 'request-stake',
invitationSpec: {
source: 'agoricContract',
instancePath: ['stakeBld'],
callPipe: [['makeStakeBldInvitation']],
},
proposal: {
give: {
In: { brand: brand.BLD, value: 10n },
},
},
},
});

await walletUtils.broadcastBridgeAction(GOV1ADDR, {
method: 'executeOffer',
offer: {
id: 'request-delegate-6',
invitationSpec: {
source: 'continuing',
previousOffer: 'request-stake',
invitationMakerName: 'Delegate',
invitationArgs: [VALIDATOR1, { brand: brand.BLD, value: 10n }],
},
proposal: {
give: {
In: { brand: brand.BLD, value: 10n },
},
},
},
});

const postDelegation = await currentDelegation();
t.is(postDelegation.length, 2, 'new delegation now');
t.like(postDelegation[1], {
balance: { amount: '10', denom: 'ubld' },
// omit 'delegation' because it has 'delgatorAddress' which is different every test run
});
});
140 changes: 140 additions & 0 deletions a3p-integration/proposals/c:stake-bld/test-lib/chain.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/** @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<string>} swingsetArgs
* @param {import('./rpc.js').MinimalNetworkConfig & {
* from: string,
* fees?: string,
* dryRun?: boolean,
* verbose?: boolean,
* keyring?: {home?: string, backend: string}
* stdout?: Pick<import('stream').Writable, 'write'>
* 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 ', 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<void>,
* period?: number,
* retryMessage?: string,
* }} opts
* @returns {<T>(l: (b: { time: string, height: string }) => Promise<T>) => Promise<T>}
*/
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<void>,
* 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);
};
23 changes: 23 additions & 0 deletions a3p-integration/proposals/c:stake-bld/test-lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* global setTimeout */
import fetch from 'node-fetch';
import { execFileSync } from 'child_process';
import { makeWalletUtils } from './wallet.js';

export const networkConfig = {
rpcAddrs: ['http://0.0.0.0:26657'],
chainName: 'agoriclocal',
};

/**
* Resolve after a delay in milliseconds.
*
* @param {number} ms
* @returns {Promise<void>}
*/
const delay = ms => new Promise(resolve => setTimeout(() => resolve(), ms));

// eslint-disable-next-line @jessie.js/safe-await-separator -- buggy version
export const walletUtils = await makeWalletUtils(
{ delay, execFileSync, fetch },
networkConfig,
);
Loading

0 comments on commit 3dbe0d8

Please sign in to comment.