secret-polar
Version:
Polar is a development environment to compile, deploy, test, run scrt contracts on different networks.
251 lines (250 loc) • 11.8 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Contract = void 0;
const fs_extra_1 = __importDefault(require("fs-extra"));
const path_1 = __importDefault(require("path"));
const context_1 = require("../../internal/context");
const errors_1 = require("../../internal/core/errors");
const errors_list_1 = require("../../internal/core/errors-list");
const project_structure_1 = require("../../internal/core/project-structure");
const strings_1 = require("../../internal/util/strings");
const compress_1 = require("../../lib/deploy/compress");
const checkpoints_1 = require("../checkpoints");
const client_1 = require("../client");
class Contract {
constructor(contractName, instantiateTag) {
this.env = context_1.PolarContext.getPolarContext().getRuntimeEnv();
this.contractName = (0, strings_1.replaceAll)(contractName, "-", "_");
this.codeId = 0;
this.contractCodeHash = "mock_hash";
this.contractAddress = "mock_address";
this.contractPath = path_1.default.join(project_structure_1.ARTIFACTS_DIR, "contracts", `${this.contractName}_compressed.wasm`);
this.instantiateTag = instantiateTag ?? "default_instantiate";
// Load checkpoints
this.checkpointPath = path_1.default.join(project_structure_1.ARTIFACTS_DIR, "checkpoints", `${this.contractName}.yaml`);
// file exist load it else create new checkpoint
// skip checkpoints if test command is run, or skip-checkpoints is passed
if (fs_extra_1.default.existsSync(this.checkpointPath) && this.env.runtimeArgs.useCheckpoints === true) {
this.checkpointData = (0, checkpoints_1.loadCheckpoint)(this.checkpointPath);
const contractHash = this.checkpointData[this.env.network.name]?.deployInfo?.contractCodeHash;
const contractCodeId = this.checkpointData[this.env.network.name]?.deployInfo?.codeId;
let contractAddr;
// Load instantiate info for tag
for (const value of this.checkpointData[this.env.network.name]?.instantiateInfo ?? []) {
if (value.instantiateTag === this.instantiateTag) {
contractAddr = value.contractAddress;
}
}
this.contractCodeHash = contractHash ?? "mock_hash";
this.codeId = contractCodeId ?? 0;
this.contractAddress = contractAddr ?? "mock_address";
}
else {
this.checkpointData = {};
}
}
async setupClient() {
this.client = (0, client_1.getClient)(this.env.network);
}
async deploy(account, customFees, source, builder) {
const accountVal = account.account !== undefined
? account.account
: account;
const info = this.checkpointData[this.env.network.name]?.deployInfo;
if (info) {
console.log("Warning: contract already deployed, using checkpoints");
return info;
}
await (0, compress_1.compress)(this.contractName);
const wasmFileContent = fs_extra_1.default.readFileSync(this.contractPath);
const inGasLimit = parseInt(customFees?.gas);
const inGasPrice = parseFloat(customFees?.amount[0].amount) /
parseFloat(customFees?.gas);
const signingClient = (0, client_1.getSigningClient)(this.env.network, accountVal);
const uploadReceipt = await signingClient.tx.compute.storeCode({
sender: accountVal.address,
wasm_byte_code: wasmFileContent,
source: source ?? "",
builder: builder ?? ""
}, {
gasLimit: Number.isNaN(inGasLimit) ? undefined : inGasLimit,
gasPriceInFeeDenom: Number.isNaN(inGasPrice) ? undefined : inGasPrice
});
const res = uploadReceipt?.arrayLog?.find((log) => log.type === "message" && log.key === "code_id");
if (res === undefined) {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.STORE_RESPONSE_NOT_RECEIVED, {
jsonLog: JSON.stringify(uploadReceipt, null, 2),
contractName: this.contractName
});
}
const codeId = Number(res.value);
const contractCodeHash = await signingClient.query.compute.codeHashByCodeId({
code_id: codeId.toString()
});
this.codeId = codeId;
const deployInfo = {
codeId: codeId,
contractCodeHash: contractCodeHash.code_hash,
deployTimestamp: String(new Date())
};
if (this.env.runtimeArgs.useCheckpoints === true) {
this.checkpointData[this.env.network.name] = {
...this.checkpointData[this.env.network.name],
deployInfo
};
(0, checkpoints_1.persistCheckpoint)(this.checkpointPath, this.checkpointData);
}
this.contractCodeHash = contractCodeHash.code_hash;
return deployInfo;
}
instantiatedWithAddress(address, timestamp) {
const initTimestamp = timestamp !== undefined ? String(timestamp) : String(new Date());
// contract address already exists
if (this.contractAddress !== "mock_address") {
console.log(`Contract ${this.contractName} already has address: ${this.contractAddress}, skipping`);
return;
}
else {
this.contractAddress = address;
}
const instantiateInfo = {
instantiateTag: this.instantiateTag,
contractAddress: address,
instantiateTimestamp: initTimestamp
};
// set init data (contract address, init timestamp) in checkpoints
const instInfo = this.checkpointData[this.env.network.name]?.instantiateInfo;
if (instInfo) {
this.checkpointData[this.env.network.name].instantiateInfo?.push(instantiateInfo);
}
else {
this.checkpointData[this.env.network.name].instantiateInfo = [instantiateInfo];
}
(0, checkpoints_1.persistCheckpoint)(this.checkpointPath, this.checkpointData);
}
async instantiate(initArgs, label, account, transferAmount, customFees) {
const accountVal = account.account !== undefined
? account.account
: account;
if (this.contractCodeHash === "mock_hash") {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.CONTRACT_NOT_DEPLOYED, {
param: this.contractName
});
}
let info;
// Load instantiate info for tag
for (const value of this.checkpointData[this.env.network.name]?.instantiateInfo ?? []) {
if (value.instantiateTag === this.instantiateTag) {
info = value;
}
}
if (info) {
console.log("Warning: contract already instantiated, using checkpoints");
return info;
}
const signingClient = (0, client_1.getSigningClient)(this.env.network, accountVal);
const inGasLimit = parseInt(customFees?.gas);
const inGasPrice = parseFloat(customFees?.amount[0].amount) /
parseFloat(customFees?.gas);
const initTimestamp = String(new Date());
label =
this.env.runtimeArgs.command === "test"
? `deploy ${this.contractName} ${initTimestamp}`
: label;
console.log(`Instantiating with label: ${label}`);
const tx = await signingClient.tx.compute.instantiateContract({
code_id: this.codeId,
sender: accountVal.address,
code_hash: this.contractCodeHash,
init_msg: initArgs,
label: label,
init_funds: transferAmount
}, {
gasLimit: Number.isNaN(inGasLimit) ? undefined : inGasLimit,
gasPriceInFeeDenom: Number.isNaN(inGasPrice) ? undefined : inGasPrice
});
// Find the contract_address in the logs
const res = tx?.arrayLog?.find((log) => log.type === "message" && log.key === "contract_address");
if (res === undefined) {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.INIT_RESPONSE_NOT_RECEIVED, {
jsonLog: JSON.stringify(tx, null, 2),
contractName: this.contractName
});
}
this.contractAddress = res.value;
const instantiateInfo = {
instantiateTag: this.instantiateTag,
contractAddress: this.contractAddress,
instantiateTimestamp: initTimestamp
};
if (this.env.runtimeArgs.useCheckpoints === true) {
const instInfo = this.checkpointData[this.env.network.name].instantiateInfo;
if (instInfo) {
this.checkpointData[this.env.network.name].instantiateInfo?.push(instantiateInfo);
}
else {
this.checkpointData[this.env.network.name].instantiateInfo = [instantiateInfo];
}
(0, checkpoints_1.persistCheckpoint)(this.checkpointPath, this.checkpointData);
}
return instantiateInfo;
}
async queryMsg(msgData) {
if (this.contractAddress === "mock_address") {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.CONTRACT_NOT_INSTANTIATED, {
param: this.contractName
});
}
// Query the contract
console.log("Querying", this.contractAddress, "=>", Object.keys(msgData)[0]);
console.log(this.contractAddress, msgData);
if (this.client === undefined) {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.CLIENT_NOT_LOADED);
}
return await this.client.query.compute.queryContract({
contract_address: this.contractAddress,
query: msgData,
code_hash: this.contractCodeHash
});
}
async executeMsg(msgData, account, customFees, memo, transferAmount) {
const accountVal = account.account !== undefined
? account.account
: account;
if (this.contractAddress === "mock_address") {
throw new errors_1.PolarError(errors_list_1.ERRORS.GENERAL.CONTRACT_NOT_INSTANTIATED, {
param: this.contractName
});
}
// Send execute msg to the contract
const signingClient = (0, client_1.getSigningClient)(this.env.network, accountVal);
const inGasLimit = parseInt(customFees?.gas);
const inGasPrice = parseFloat(customFees?.amount[0].amount) /
parseFloat(customFees?.gas);
console.log("Executing", this.contractAddress, msgData);
// Send the same handleMsg to increment multiple times
const txnResponse = await signingClient.tx.compute.executeContract({
sender: accountVal.address,
contract_address: this.contractAddress,
code_hash: this.contractCodeHash,
msg: msgData,
sent_funds: transferAmount
}, {
gasLimit: Number.isNaN(inGasLimit) ? undefined : inGasLimit,
gasPriceInFeeDenom: Number.isNaN(inGasPrice) ? undefined : inGasPrice,
memo: memo
});
if (txnResponse.code !== 0) {
throw new errors_1.PolarError(errors_list_1.ERRORS.INTERACTION.TRANSACTION_FAILURE, {
contractName: this.contractName,
transaction: JSON.stringify(msgData, null, 2),
message: JSON.stringify(txnResponse, null, 2)
});
}
return txnResponse;
}
}
exports.Contract = Contract;