@kyve/sdk-beta
Version:
<p align="center"> <a href="https://kyve.network"> <img src="https://user-images.githubusercontent.com/62398724/137493477-63868209-a19b-4efa-9413-f06d41197d6d.png" style="border-radius: 50%" height="96"> </a> <h3 align="center"><code>@kyve/sdk</
408 lines (389 loc) • 11.5 kB
text/typescript
import KyveClient from "../../src/clients/rpc-client/client";
import { createValidator } from "../helper";
import * as fs from "fs";
import { resolve } from "path";
// import { kyve, cosmos as cosmosProto } from "@kyve/proto";
/** pool **/
import {
MsgCancelRuntimeUpgrade,
MsgCreatePool,
MsgFundPool,
MsgPausePool, MsgScheduleRuntimeUpgrade,
MsgUnpausePool,
MsgUpdatePool
} from "@kyve/proto-beta/client/kyve/pool/v1beta1/tx";
import {MsgDefundPool} from "@kyve/proto-beta/client/kyve/pool/v1beta1/tx";
/** stakers **/
import {
MsgCreateStaker,
MsgUpdateParams as MsgUpdateParamsStakers
} from "@kyve/proto-beta/client/kyve/stakers/v1beta1/tx";
import {MsgUpdateMetadata} from "@kyve/proto-beta/client/kyve/stakers/v1beta1/tx";
import {MsgJoinPool} from "@kyve/proto-beta/client/kyve/stakers/v1beta1/tx";
import {MsgUpdateCommission} from "@kyve/proto-beta/client/kyve/stakers/v1beta1/tx";
import {MsgLeavePool} from "@kyve/proto-beta/client/kyve/stakers/v1beta1/tx";
/** delegations **/
import {
MsgDelegate,
MsgUpdateParams as MsgUpdateParamsDelegation
} from "@kyve/proto-beta/client/kyve/delegation/v1beta1/tx";
import {MsgWithdrawRewards} from "@kyve/proto-beta/client/kyve/delegation/v1beta1/tx";
import {MsgRedelegate} from "@kyve/proto-beta/client/kyve/delegation/v1beta1/tx";
import {MsgUndelegate} from "@kyve/proto-beta/client/kyve/delegation/v1beta1/tx";
/** bundles **/
import {
MsgSubmitBundleProposal,
MsgUpdateParams as MsgUpdateParamsBundles
} from "@kyve/proto-beta/client/kyve/bundles/v1beta1/tx";
import {MsgVoteBundleProposal} from "@kyve/proto-beta/client/kyve/bundles/v1beta1/tx";
import {MsgClaimUploaderRole} from "@kyve/proto-beta/client/kyve/bundles/v1beta1/tx";
import {MsgSkipUploaderRole} from "@kyve/proto-beta/client/kyve/bundles/v1beta1/tx";
/** gov **/
import Mock = jest.Mock;
import {DENOM, GOV_AUTHORITY} from "../../src/constants";
import { SigningStargateClient } from "@cosmjs/stargate";
import { cosmos } from "@keplr-wallet/cosmos";
import TxRaw = cosmos.tx.v1beta1.TxRaw;
import { OfflineAminoSigner } from "@cosmjs/amino/build/signer";
import {MsgUpdateParams as MsgUpdateParamsFees} from "@kyve/proto-beta/client/kyve/fees/v1beta1/tx";
function extractTsFromPath(path: string) {
return fs
.readdirSync(path)
.filter((files) => files.endsWith("d.ts"))
.map((dtsFiles) => resolve(path, dtsFiles));
}
const mockAccountData = {
address: "kyve19jc64sd773gtjljksjhls0n5mqay7xj83yeqvk",
algo: "secp256k1" as const,
pubkey: new Uint8Array(),
};
const TEST_MEMO = "test_memo";
const TEST_FEE = 1;
const TEST_AMOUNT = "1000000000";
const methodsByGroup = [
[
{
name: "bundles",
pathToTypes: extractTsFromPath(
"../proto/client/kyve/bundles/v1beta1"
),
},
[
{
methodName: "submitBundleProposal",
parameters: {
params: MsgSubmitBundleProposal.fromJSON({}),
schemaType: "MsgSubmitBundleProposal",
},
},
{
methodName: "voteBundleProposal",
parameters: {
params: MsgVoteBundleProposal.fromJSON({}),
schemaType: "MsgVoteBundleProposal",
},
},
{
methodName: "claimUploaderRole",
parameters: {
params: MsgClaimUploaderRole.fromJSON({}),
schemaType: "MsgClaimUploaderRole",
},
},
{
methodName: "skipUploaderRole",
parameters: {
params: MsgSkipUploaderRole.fromJSON({}),
schemaType: "MsgSkipUploaderRole",
},
},
],
],
[
{
name: "delegation",
pathToTypes: extractTsFromPath(
"../proto/client/kyve/delegation/v1beta1"
),
},
[
{
methodName: "delegate",
parameters: {
params: MsgDelegate.fromJSON({}),
schemaType: "MsgDelegate",
},
},
{
methodName: "withdrawRewards",
parameters: {
params: MsgWithdrawRewards.fromJSON({}),
schemaType: "MsgWithdrawRewards",
},
},
{
methodName: "undelegate",
parameters: {
params: MsgUndelegate.fromJSON({}),
schemaType: "MsgUndelegate",
},
},
{
methodName: "redelegate",
parameters: {
params: MsgRedelegate.fromJSON({}),
schemaType: "MsgRedelegate",
},
},
],
],
[
{
name: "pool",
pathToTypes: extractTsFromPath("../proto/client/kyve//pool/v1beta1"),
},
[
{
methodName: "fundPool",
parameters: {
params: MsgFundPool.fromJSON({}),
schemaType: "MsgFundPool",
},
},
{
methodName: "defundPool",
parameters: {
params: MsgDefundPool.fromJSON({}),
schemaType: "MsgDefundPool",
},
},
],
],
[
{
name: "stakers",
pathToTypes: extractTsFromPath(
"../proto/client/kyve/stakers/v1beta1"
),
},
[
{
methodName: "createStaker",
parameters: {
params: MsgCreateStaker.fromJSON({}),
schemaType: "MsgCreateStaker",
},
},
{
methodName: "updateMetadata",
parameters: {
params: MsgUpdateMetadata.fromJSON({}),
schemaType: "MsgUpdateMetadata",
},
},
{
methodName: "updateCommission",
parameters: {
params: MsgUpdateCommission.fromJSON({}),
schemaType: "MsgUpdateCommission",
},
},
{
methodName: "joinPool",
parameters: {
params: MsgJoinPool.fromJSON({}),
schemaType: "MsgJoinPool",
},
},
{
methodName: "leavePool",
parameters: {
params: MsgLeavePool.fromJSON({}),
schemaType: "MsgLeavePool",
},
},
],
],
] as const;
let kyveClient: KyveClient;
let mockSign: Mock;
let mockSendTokens: Mock;
let mockGetBalance: Mock;
beforeEach(() => {
mockSign = jest.fn(() => TxRaw.create());
mockSendTokens = jest.fn();
mockGetBalance = jest.fn(() => ({ amount: 0 }));
const mockNativeClient = {
simulate: () => Promise.resolve(1),
sign: mockSign,
sendTokens: mockSendTokens,
getBalance: mockGetBalance,
} as unknown as SigningStargateClient;
const mockAminoSigner = {
signAmino() {},
getAccounts() {},
} as unknown as OfflineAminoSigner;
kyveClient = new KyveClient(
mockNativeClient,
mockAccountData,
mockAminoSigner
);
});
for (let [bundleConfig, methods] of methodsByGroup) {
describe(`Methods ${bundleConfig.name}`, () => {
const validator = createValidator(bundleConfig.pathToTypes);
methods.forEach((method) => {
it(`method ${method.methodName}`, async () => {
// @ts-ignore
await kyveClient.kyve[bundleConfig.name].v1beta1[method.methodName](
//@ts-ignore have no idea how to create it generic. btw ts-ignore is ok, because we check params from json schema
method.parameters.params,
{ memo: TEST_MEMO, fee: TEST_FEE }
);
expect(mockSign).toHaveBeenCalledTimes(1);
const [[testAddress, [tx], fee, memo]] = mockSign.mock.calls;
expect(testAddress).toEqual(mockAccountData.address);
expect(tx).toEqual(
expect.objectContaining({
typeUrl: expect.any(String),
value: expect.any(Object),
})
);
expect(memo).toEqual(TEST_MEMO);
const validationResult = validator.validate(
validator.typeQuerySchemas.getSchemaForSymbol(
method.parameters.schemaType
),
tx.value
);
expect(validationResult.valid).toBeTruthy();
expect(Object.keys(fee).sort()).toEqual(["amount", "gas"].sort());
});
});
});
}
describe("Base methods", () => {
it("transfer", async () => {
const testRecipient = "kyveTestRecipient";
const testAmount = "10000000000";
await kyveClient.kyve.base.v1beta1.transfer(testRecipient, testAmount, {
memo: TEST_MEMO,
fee: TEST_FEE,
});
expect(mockSign).toHaveBeenCalledTimes(1);
const [[_, [tx], fee, memo]] = mockSign.mock.calls;
expect(tx.value.fromAddress).toEqual(mockAccountData.address);
expect(tx.value.toAddress).toEqual(testRecipient);
expect(memo).toEqual(TEST_MEMO);
expect(fee.gas.toString()).toEqual(TEST_FEE.toString());
expect(tx.value.amount[0]).toEqual({
denom: DENOM,
amount: testAmount
});
});
it("getKyveBalance", async () => {
const result = await kyveClient.kyve.base.v1beta1.getKyveBalance();
expect(mockGetBalance).toHaveBeenCalledTimes(1);
const [[ownerAddress, denom]] = mockGetBalance.mock.calls;
expect(ownerAddress).toEqual(mockAccountData.address);
expect(denom).toEqual(DENOM);
expect(result).toEqual(0);
});
});
const GovMethods = [
{
method: "createPool",
decoder: MsgCreatePool,
},
{
method: "updatePool",
decoder: MsgUpdatePool,
},
{
method: "pausePool",
decoder: MsgPausePool,
},
{
method: "unpausePool",
decoder: MsgUnpausePool,
},
{
method: "scheduleRuntimeUpgrade",
decoder: MsgScheduleRuntimeUpgrade,
},
{
method: "cancelRuntimeUpgrade",
decoder: MsgCancelRuntimeUpgrade,
},
{
method: "updateParamsStakers",
decoder: MsgUpdateParamsStakers,
},
{
method: "updateParamsDelegation",
decoder: MsgUpdateParamsDelegation,
},
{
method: "updateParamsBundles",
decoder: MsgUpdateParamsBundles,
},
{
method: "updateParamsFees",
decoder: MsgUpdateParamsFees,
}
] as const;
describe("Gov methods", () => {
GovMethods.forEach((method) => {
it(`${method.method}`, async () => {
const govParam = method.decoder.fromJSON({ authority: GOV_AUTHORITY});
//@ts-ignore
await kyveClient.kyve.gov.v1[method.method](govParam,TEST_AMOUNT, {
isExpedited: true,
});
expect(mockSign).toHaveBeenCalledTimes(1);
const [[testAddress, [tx], fee]] = mockSign.mock.calls;
expect(testAddress).toEqual(mockAccountData.address);
expect(tx).toEqual(
expect.objectContaining({
typeUrl: expect.any(String),
value: {
messages: [{
type_url: expect.any(String),
value: expect.any(Uint8Array),
}],
initial_deposit: [
{
denom: DENOM,
amount: TEST_AMOUNT,
},
],
proposer: mockAccountData.address,
metadata: {isExpedited: true}
},
})
);
expect(Object.keys(fee).sort()).toEqual(["amount", "gas"].sort());
expect(method.decoder.decode(tx.value.messages[0].value)).toEqual(govParam);
});
});
it("`govVote`", async () => {
const testProposalNumber = "1";
const testVoteOptions = "Yes";
await kyveClient.kyve.gov.v1.vote(
testProposalNumber,
testVoteOptions
);
expect(mockSign).toHaveBeenCalledTimes(1);
const [[testAddress, [tx], fee]] = mockSign.mock.calls;
expect(testAddress).toEqual(mockAccountData.address);
expect(Object.keys(fee).sort()).toEqual(["amount", "gas"].sort());
expect(tx).toEqual({
typeUrl: "/cosmos.gov.v1.MsgVote",
value: {
proposal_id: testProposalNumber,
voter: mockAccountData.address,
option: 1,
},
});
});
});