Skip to content

Commit 96c9e83

Browse files
author
Dev Kalra
authored
[cosmwasm] Refactor deployer (#739)
* chain generic code * pyth wrapper * factory * add calc fee and correct raw log * add documentation * rename method * remove update fee response * add more documentation * remove chain specific things * minor tweak
1 parent e476199 commit 96c9e83

File tree

7 files changed

+1274
-32
lines changed

7 files changed

+1274
-32
lines changed

target_chains/cosmwasm/tools/package-lock.json

Lines changed: 331 additions & 32 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

target_chains/cosmwasm/tools/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"dependencies": {
1515
"@cosmjs/cosmwasm-stargate": "^0.29.5",
1616
"@cosmjs/encoding": "^0.26.2",
17+
"@cosmjs/proto-signing": "^0.30.1",
1718
"@injectivelabs/networks": "^1.0.55",
1819
"@injectivelabs/sdk-ts": "^1.0.354",
1920
"@injectivelabs/utils": "^1.0.47",
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
import { Coin } from "@cosmjs/stargate";
2+
// TODO: expose these executors and consume them in price pusher
3+
/**
4+
* Interface for classes that implements contract management for a chain.
5+
*
6+
* This interface has the methods to interact with the contract in a way that will change its state.
7+
* Hence any interaction with the contract will requires a transaction to be broadcasted.
8+
* Each class implementation will need a mnemonic key using which it will be able to sign and
9+
* broadcast transactions.
10+
*
11+
* Interactions can be one of the following:
12+
* - storing a code on chain
13+
* - instantiating a new contract
14+
* - executing a contract
15+
* - migrating a contract
16+
* - updating the contract's admin
17+
*
18+
* @interface ChainExecutor
19+
*/
20+
export interface ChainExecutor {
21+
/**
22+
* `storeCode` stores a cosmwasm contract code on chain.
23+
* @param {StoreCodeRequest} req
24+
* @param {Buffer} req.contractBytes - The contractBytes of the contract you want to store.
25+
* @returns {StoreCodeResponse}
26+
* - {number} res.codeId. The codeId of the stored code.
27+
* - {string} res.txHash. The broadcasted transaction hash.
28+
*
29+
* @throws an error if it fails.
30+
*/
31+
storeCode(req: StoreCodeRequest): Promise<StoreCodeResponse>;
32+
33+
/**
34+
* `instantiateContract` instantiates a new contract for the given code id and instMsg.
35+
* @param {InstantiateContractRequest} req
36+
* @param {number} req.codeId - The code id of the deployed code.
37+
* @param {object} req.instMsg - The instantiating msg as per the contract requirements.
38+
* @param {string} req.label - The label for the new contract.
39+
*
40+
* @returns {InstantiateContractResponse}
41+
* - {string} res.contractAddr. The address of the new contract.
42+
* - {string} res.txHash. The broadcasted transaction hash.
43+
*
44+
* @throws an error if it fails
45+
*/
46+
instantiateContract(
47+
req: InstantiateContractRequest
48+
): Promise<InstantiateContractResponse>;
49+
50+
/**
51+
* `executeContract` execute the contract identified via given contract address.
52+
* @param {ExecuteContractRequest} req
53+
* @param {string} req.contractAddr
54+
* @param {object} req.msg - The msg to be executed on the given contract. The message is contract dependent and hence its structure is not defined.
55+
* @param {Fund[]} [req.funds] - Funds one want to send to the given contract when executing.
56+
*
57+
* @returns {ExecuteContractResponse} - {string} res.txHash. The broadcasted transaction hash.
58+
*
59+
* @throws an error if it fails
60+
*/
61+
executeContract(
62+
req: ExecuteContractRequest
63+
): Promise<ExecuteContractResponse>;
64+
65+
/**
66+
* `migrateContract` migrates the given contract addr to the given new code id.
67+
* It assumes that the key used to sign the transaction is the current admin of the given contract.
68+
* If that is not the case this method will raise error.
69+
*
70+
* @param {MigrateContractRequest} req
71+
* @param {string} req.contractAddr
72+
* @param {number} req.newCodeId
73+
* @param {object | undefined} [req.migrateMsg] - It depends upon the contract and hence the structure is not defined. It accepts any msg given to it.
74+
*
75+
* @returns {MigrateContractResponse} - {string} res.txHash. The broadcasted transaction hash.
76+
*
77+
* @throws an error if it fails.
78+
*/
79+
migrateContract(
80+
req: MigrateContractRequest
81+
): Promise<MigrateContractResponse>;
82+
83+
/**
84+
* `updateContractAdmin` updates the admin of the given contract addr to the given new Admin address.
85+
* It assumes that the key used to sign the transaction is the current admin of the given contract.
86+
* If that is not the case, this method will raise error.
87+
*
88+
* @param {UpdateContractAdminRequest} req
89+
* @param {string} req.contractAddr
90+
* @param {string} req.newAdminAddr
91+
*
92+
* @returns {UpdateContractAdminResponse} - {string} res.txHash. The broadcasted transaction hash.
93+
*
94+
* @throws an error if it fails
95+
*/
96+
updateContractAdmin(
97+
req: UpdateContractAdminRequest
98+
): Promise<UpdateContractAdminResponse>;
99+
}
100+
101+
export type StoreCodeRequest = {
102+
contractBytes: Buffer;
103+
};
104+
export type StoreCodeResponse = {
105+
codeId: number;
106+
txHash: string;
107+
};
108+
109+
export type InstantiateContractRequest = {
110+
codeId: number;
111+
instMsg: object;
112+
label: string;
113+
};
114+
export type InstantiateContractResponse = {
115+
contractAddr: string;
116+
txHash: string;
117+
};
118+
119+
export type ExecuteContractRequest = {
120+
contractAddr: string;
121+
msg: object;
122+
funds?: Coin[];
123+
};
124+
export type ExecuteContractResponse = {
125+
txHash: string;
126+
};
127+
128+
export type MigrateContractRequest = {
129+
contractAddr: string;
130+
newCodeId: number;
131+
migrateMsg?: object;
132+
};
133+
export type MigrateContractResponse = {
134+
txHash: string;
135+
};
136+
137+
export type UpdateContractAdminRequest = {
138+
newAdminAddr: string;
139+
contractAddr: string;
140+
};
141+
export type UpdateContractAdminResponse = {
142+
txHash: string;
143+
};
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";
2+
import { QueryClient } from "@cosmjs/stargate";
3+
import { WasmExtension, setupWasmExtension } from "@cosmjs/cosmwasm-stargate";
4+
5+
// TODO: expose the querier and consume them in price pusher
6+
7+
/**
8+
* Interface for classes implementing a querier for a cosmwasm chain.
9+
*
10+
* The querier interacts with contracts only and can get it's info, stored state.
11+
* It can also query the `Query methods` defined in the contract.
12+
*
13+
* For contract dependent response, you need to look into contract specific schema in order
14+
* to know what to expect
15+
*
16+
* @interface ChainQuerier
17+
*/
18+
export interface ChainQuerier {
19+
/**
20+
* `getContractInfo` gets the contract info for the give contract address.
21+
* @param {ContractInfoRequest} req
22+
* @param {string} req.contractAddr
23+
* @returns {ContractInfoResponse}
24+
* - {number} res.codeId. The codeId of the contract's code.
25+
* - {string} res.creator. The creator of the contract.
26+
* - {string} res.adminAddr - Address of the current admin.
27+
* - {string} res.label - The label with which the contract was instantiated
28+
*
29+
* @throws an error if it fails.
30+
*/
31+
getContractInfo(req: ContractInfoRequest): Promise<ContractInfoResponse>;
32+
33+
/**
34+
* `getSmartContractState` query the `Query methods` implemented in the contract
35+
* @param {SmartContractRequest} req
36+
* @param {string} req.contractAddr
37+
* @param {Object} req.query - The query object for the contract. It accepts any object as it is contract dependent.
38+
* @returns {Object} - It returns an object. As the response is contract dependent we can't have a structure for it.
39+
*
40+
* @throws an error if it fails.
41+
*/
42+
getSmartContractState(req: SmartContractRequest): Promise<Object>;
43+
44+
/**
45+
* Contracts local storage on chain is structured as key-value pairs.
46+
* `getSmartContractState` query the local storage of a contract for the given key.
47+
* @param {RawContractStateRequest} req
48+
* @param {string} req.contractAddr
49+
* @param {Buffer} req.key
50+
* @returns {Object} - It returns an object. As the response is contract dependent we can't have a structure for it.
51+
*
52+
* @throws an error if it fails.
53+
*/
54+
getRawContractState(req: RawContractStateRequest): Promise<Object>;
55+
56+
/**
57+
* Contracts local storage on chain is structured as key-value pairs.
58+
* `getAllContractState` query the local storage of a contract for all such pairs.
59+
* @param {AllContractStateRequest} req
60+
* @param {string} req.contractAddr
61+
* @returns {Object} - It returns an object. As the response is contract dependent we can't have a structure for it.
62+
*
63+
* @throws an error if it fails.
64+
*/
65+
getAllContractState(req: AllContractStateRequest): Promise<Object>;
66+
}
67+
68+
export type ContractInfoRequest = {
69+
contractAddr: string;
70+
};
71+
72+
export type ContractInfoResponse = {
73+
codeId: number;
74+
creator: string;
75+
adminAddr: string;
76+
label: string;
77+
};
78+
79+
export type SmartContractRequest = {
80+
contractAddr: string;
81+
query: Object;
82+
};
83+
84+
export type RawContractStateRequest = {
85+
contractAddr: string;
86+
key: Buffer;
87+
};
88+
89+
export type AllContractStateRequest = {
90+
contractAddr: string;
91+
};
92+
93+
export class CosmwasmQuerier implements ChainQuerier {
94+
private readonly wasmQueryClient: WasmExtension;
95+
private constructor(readonly tendermintClient: Tendermint34Client) {
96+
this.wasmQueryClient = setupWasmExtension(
97+
new QueryClient(tendermintClient)
98+
);
99+
}
100+
101+
async getContractInfo(
102+
req: ContractInfoRequest
103+
): Promise<ContractInfoResponse> {
104+
const { contractAddr } = req;
105+
106+
const { wasm: wasmQueryClient } = this.wasmQueryClient;
107+
108+
const { contractInfo } = await wasmQueryClient.getContractInfo(
109+
contractAddr
110+
);
111+
112+
if (contractInfo === undefined)
113+
throw new Error("error fetching contract info");
114+
115+
return {
116+
...contractInfo,
117+
codeId: contractInfo.codeId.toNumber(),
118+
adminAddr: contractInfo.admin,
119+
};
120+
}
121+
122+
async getSmartContractState(req: SmartContractRequest): Promise<Object> {
123+
const { contractAddr, query } = req;
124+
125+
const { wasm: wasmQueryClient } = this.wasmQueryClient;
126+
127+
return await wasmQueryClient.queryContractSmart(contractAddr, query);
128+
}
129+
130+
async getRawContractState(req: RawContractStateRequest): Promise<Object> {
131+
const { contractAddr, key } = req;
132+
133+
const { wasm: wasmQueryClient } = this.wasmQueryClient;
134+
135+
const { data } = await wasmQueryClient.queryContractRaw(contractAddr, key);
136+
return JSON.parse(Buffer.from(data).toString());
137+
}
138+
139+
async getAllContractState(req: AllContractStateRequest): Promise<Object> {
140+
const { contractAddr } = req;
141+
142+
const { wasm: wasmQueryClient } = this.wasmQueryClient;
143+
144+
const { models } = await wasmQueryClient.getAllContractState(contractAddr);
145+
146+
const state = models.reduce((prevValue, model) => {
147+
const key = Buffer.from(model.key).toString();
148+
const value = Buffer.from(model.value).toString();
149+
150+
prevValue[key] = value;
151+
152+
return prevValue;
153+
}, {} as any);
154+
155+
return state;
156+
}
157+
158+
static async connect(endpoint: string): Promise<CosmwasmQuerier> {
159+
const tendermintClient = await Tendermint34Client.connect(endpoint);
160+
return new CosmwasmQuerier(tendermintClient);
161+
}
162+
}

0 commit comments

Comments
 (0)