Skip to content

Commit

Permalink
External contract support (#10)
Browse files Browse the repository at this point in the history
* add external contract support

* add sample usage of external contract to sample project

* move the external contract example to complex templates

* fix linter warnings

Co-authored-by: udit-gulati <[email protected]>
  • Loading branch information
Uditgulati and udit-gulati authored Jun 21, 2022
1 parent 0ba88a4 commit 8383b49
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 8 deletions.
2 changes: 1 addition & 1 deletion packages/junokit/sample-project/scripts/sample-script.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { Contract, getAccountByName, getLogs } = require("junokit");
const { Contract, ExternalContract, getAccountByName, getLogs } = require("junokit");

async function run() {
const contract_owner = getAccountByName("account_0");
Expand Down
3 changes: 2 additions & 1 deletion packages/junokit/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getAccountByName } from "./lib/account";
import { junokitChai } from "./lib/chai/chai";
// import { createAccounts } from "./lib/createAccounts";
import { Contract } from "./lib/deploy/contract";
import { ExternalContract } from "./lib/deploy/external_contract";
import { getLogs } from "./lib/response";

export { Contract, getAccountByName, junokitChai, getLogs };
export { Contract, ExternalContract, getAccountByName, junokitChai, getLogs };
28 changes: 28 additions & 0 deletions packages/junokit/src/internal/core/errors-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,34 @@ Please check that the configured keypair are correct.`,
title: "Object is not a function",
description: `Object is not a function.`,
shouldBeReported: false
},
EXT_CONTRACT_NOT_FOUND: {
number: 30,
message: "External contract %contractName% not present in config",
title: "External contract not found",
description: `External contract not found.`,
shouldBeReported: false
},
EXT_CONTRACT_NETWORK_NOT_FOUND: {
number: 31,
message: "Network for %networkName% external contract %contractName% not present in config",
title: "Network for external contract not found",
description: `Network for external contract not found.`,
shouldBeReported: false
},
EXT_CONTRACT_CONFIG_NOT_FOUND: {
number: 32,
message: "External contract config not present while reading for contract %contractName%",
title: "External contract config not found",
description: `External contract config not found.`,
shouldBeReported: false
},
EXT_CONTRACT_ADDR_INCORRECT: {
number: 33,
message: "External contract %contractName% address not of correct format",
title: "External contract addr not correct",
description: `External contract addr not correct.`,
shouldBeReported: false
}
},
NETWORK: {
Expand Down
113 changes: 113 additions & 0 deletions packages/junokit/src/lib/deploy/external_contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { CosmWasmClient } from "@cosmjs/cosmwasm-stargate";

import { JunokitContext } from "../../internal/context";
import { JunokitError } from "../../internal/core/errors";
import { ERRORS } from "../../internal/core/errors-list";
import { replaceAll } from "../../internal/util/strings";
import type {
Account,
Coin,
ExternalContractsConfig,
JunokitRuntimeEnvironment,
StdFee,
UserAccount
} from "../../types";
import { ExecuteResult, getClient, getSigningClient } from "../client";
import { defaultFees } from "../contants";

export interface ExecArgs {
account: Account | UserAccount
transferAmount: readonly Coin[] | undefined
customFees: StdFee | undefined
}

export class ExternalContract {
readonly contractName: string;

private readonly env: JunokitRuntimeEnvironment =
JunokitContext.getJunokitContext().getRuntimeEnv();

private client?: CosmWasmClient;

public contractAddress: string;

constructor (contractName: string) {
this.contractName = replaceAll(contractName, '-', '_');

// fetch junokit config from env
const externalContracts = (this.env.config.external_contracts as ExternalContractsConfig);

// check and use the address from the config for current network
if (externalContracts === undefined) {
// raise error that external contract config is NOT in config
throw new JunokitError(ERRORS.GENERAL.EXT_CONTRACT_CONFIG_NOT_FOUND, {
contractName: this.contractName
});
}
if (!(this.contractName in externalContracts)) {
// raise error that contract is NOT in config
throw new JunokitError(ERRORS.GENERAL.EXT_CONTRACT_NOT_FOUND, {
contractName: this.contractName
});
}
if (!(this.env.network.name in externalContracts[this.contractName])) {
// raise error that network is NOT in netwrok config
throw new JunokitError(ERRORS.GENERAL.EXT_CONTRACT_NETWORK_NOT_FOUND, {
networkName: this.env.network.name,
contractName: this.contractName
});
}

// check if contractAddress is of proper format
if (externalContracts[this.contractName][this.env.network.name].length !== 63 ||
externalContracts[this.contractName][this.env.network.name].slice(0, 4) !== "juno") {
// raise error that contract addess is NOT correct
throw new JunokitError(ERRORS.GENERAL.EXT_CONTRACT_ADDR_INCORRECT, {
contractName: this.contractName
});
}

// store the address of contract in the class
this.contractAddress = externalContracts[this.contractName][this.env.network.name];
}

async setUpclient (): Promise<void> {
this.client = await getClient(this.env.network);
}

async query (
methodName: string,
callArgs: Record<string, unknown>
): Promise<any> { // eslint-disable-line @typescript-eslint/no-explicit-any
// Query the contract
// console.log('Querying contract for', methodName);
const msgData: { [key: string]: Record<string, unknown> } = {};
msgData[methodName] = callArgs;
console.log(this.contractAddress, msgData);
return await this.client?.queryContractSmart(this.contractAddress, msgData);
}

async execute (
methodName: string,
{ account, transferAmount, customFees }: ExecArgs,
callArgs: Record<string, unknown>
): Promise<ExecuteResult> {
const accountVal: Account = (account as UserAccount).account !== undefined
? (account as UserAccount).account : (account as Account);
// Send execute msg to the contract
const signingClient = await getSigningClient(this.env.network, accountVal);

const msgData: { [key: string]: Record<string, unknown> } = {};
msgData[methodName] = callArgs;
console.log(this.contractAddress, msgData);
// Send the same handleMsg to increment multiple times
return await signingClient.execute(
accountVal.address,
this.contractAddress,
msgData,
customFees ?? defaultFees.exec,
"executing",
transferAmount
);
}
}
14 changes: 8 additions & 6 deletions packages/junokit/src/lib/schema/parse-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export * from './node-types';
export * from './rust-repr';

const reformatDefinitions = (definitions: {
[d: string]: { [d: string]: any }
}): any => {
[d: string]: { [d: string]: any } // eslint-disable-line @typescript-eslint/no-explicit-any
}): any => { // eslint-disable-line @typescript-eslint/no-explicit-any
if (definitions === undefined) {
return undefined;
}
Expand All @@ -20,12 +20,14 @@ const reformatDefinitions = (definitions: {
}));
};

export const parseSchema = async (schema: any): Promise<ParseNode> => {
export const parseSchema = async (
schema: any // eslint-disable-line @typescript-eslint/no-explicit-any
): Promise<ParseNode> => {
return _parse(
(await $RefParser.dereference({
...schema,
definitions: reformatDefinitions(schema.definitions)
})) as any
})) as any // eslint-disable-line @typescript-eslint/no-explicit-any
);
};

Expand Down Expand Up @@ -116,7 +118,7 @@ export const _parse = (schema: ParseSchema): ParseNode => { // eslint-disable-li
}

if (schema.type === 'object') {
const members: Struct.Node<any>['value']['members'] = {};
const members: Struct.Node<any>['value']['members'] = {}; // eslint-disable-line @typescript-eslint/no-explicit-any
Object.entries(schema.properties || {}).forEach(
([memberName, memberSchema]) => {
members[memberName] = _parse(memberSchema);
Expand Down Expand Up @@ -175,7 +177,7 @@ export const _parse = (schema: ParseSchema): ParseNode => { // eslint-disable-li
}

if (Array.isArray(schema.type) && schema.type.includes('null')) {
const newSchema: any = {
const newSchema: any = { // eslint-disable-line @typescript-eslint/no-explicit-any
...schema,
type: schema.type[0]
};
Expand Down
9 changes: 9 additions & 0 deletions packages/junokit/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ export interface DockerConfig {
runTestnet?: string
}

export interface ExternalContractsConfig {
[contractName: string]: ExternalContractConfig
}

export interface ExternalContractConfig {
[networkName: string]: string
}

// Project paths config

export interface ProjectPathsUserConfig {
Expand Down Expand Up @@ -190,6 +198,7 @@ export interface JunokitUserConfig {
networks?: NetworksUserConfig
mocha?: Mocha.MochaOptions
docker?: DockerConfig
external_contracts?: ExternalContractsConfig
}

export interface JunokitConfig {
Expand Down

0 comments on commit 8383b49

Please sign in to comment.