mirror of
https://github.com/cosmos/cosmjs.git
synced 2025-03-11 14:09:15 +00:00
Merge pull request #556 from cosmos/501-cw1-subkey-support
Add support for CW1 contracts
This commit is contained in:
commit
dec867e0fc
118
packages/cosmwasm/src/cw1cosmwasmclient.spec.ts
Normal file
118
packages/cosmwasm/src/cw1cosmwasmclient.spec.ts
Normal file
@ -0,0 +1,118 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { coins, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
|
||||
import { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
|
||||
import {
|
||||
alice,
|
||||
deployedCw1,
|
||||
launchpad,
|
||||
makeRandomAddress,
|
||||
pendingWithoutCw1,
|
||||
pendingWithoutLaunchpad,
|
||||
} from "./testutils.spec";
|
||||
|
||||
describe("Cw1CosmWasmClient", () => {
|
||||
const contractAddress = deployedCw1.instances[0];
|
||||
const defaultToAddress = makeRandomAddress();
|
||||
const defaultMsg = {
|
||||
bank: {
|
||||
send: {
|
||||
from_address: contractAddress,
|
||||
to_address: defaultToAddress,
|
||||
amount: coins(1, "ucosm"),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("constructor", () => {
|
||||
it("can be constructed", async () => {
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(launchpad.endpoint, alice.address0, wallet, contractAddress);
|
||||
expect(client).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("canSend", () => {
|
||||
it("returns true if client signer can send", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.canSend(defaultMsg);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it("returns false if client signer cannot send", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address1,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.canSend(defaultMsg);
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("returns true if supplied signer can send", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address1,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.canSend(defaultMsg, alice.address0);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it("returns false if supplied signer cannot send", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.canSend(defaultMsg, alice.address1);
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("executeCw1", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1CosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.executeCw1([defaultMsg]);
|
||||
|
||||
expect(result.transactionHash).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
45
packages/cosmwasm/src/cw1cosmwasmclient.ts
Normal file
45
packages/cosmwasm/src/cw1cosmwasmclient.ts
Normal file
@ -0,0 +1,45 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Account, BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launchpad";
|
||||
|
||||
import { CosmosMsg } from "./cosmosmsg";
|
||||
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
|
||||
export class Cw1CosmWasmClient extends SigningCosmWasmClient {
|
||||
public readonly cw1ContractAddress: string;
|
||||
|
||||
public constructor(
|
||||
apiUrl: string,
|
||||
signerAddress: string,
|
||||
signer: OfflineSigner,
|
||||
cw1ContractAddress: string,
|
||||
gasPrice?: GasPrice,
|
||||
gasLimits?: Partial<GasLimits<CosmWasmFeeTable>>,
|
||||
broadcastMode?: BroadcastMode,
|
||||
) {
|
||||
super(apiUrl, signerAddress, signer, gasPrice, gasLimits, broadcastMode);
|
||||
this.cw1ContractAddress = cw1ContractAddress;
|
||||
}
|
||||
|
||||
public async getAccount(address?: string): Promise<Account | undefined> {
|
||||
return super.getAccount(address || this.cw1ContractAddress);
|
||||
}
|
||||
|
||||
public async canSend(msg: CosmosMsg, address = this.senderAddress): Promise<boolean> {
|
||||
const result = await this.queryContractSmart(this.cw1ContractAddress, {
|
||||
can_send: {
|
||||
sender: address,
|
||||
msg: msg,
|
||||
},
|
||||
});
|
||||
return result.can_send;
|
||||
}
|
||||
|
||||
public async executeCw1(msgs: readonly CosmosMsg[], memo = ""): Promise<ExecuteResult> {
|
||||
const handleMsg = {
|
||||
execute: {
|
||||
msgs: msgs,
|
||||
},
|
||||
};
|
||||
return this.execute(this.cw1ContractAddress, handleMsg, memo);
|
||||
}
|
||||
}
|
323
packages/cosmwasm/src/cw1subkeycosmwasmclient.spec.ts
Normal file
323
packages/cosmwasm/src/cw1subkeycosmwasmclient.spec.ts
Normal file
@ -0,0 +1,323 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { coin, coins, Secp256k1HdWallet } from "@cosmjs/launchpad";
|
||||
|
||||
import { Cw1SubkeyCosmWasmClient } from "./cw1subkeycosmwasmclient";
|
||||
import {
|
||||
alice,
|
||||
deployedCw1,
|
||||
launchpad,
|
||||
makeRandomAddress,
|
||||
pendingWithoutCw1,
|
||||
pendingWithoutLaunchpad,
|
||||
} from "./testutils.spec";
|
||||
|
||||
describe("Cw1SubkeyCosmWasmClient", () => {
|
||||
describe("getAdmins", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getAdmins();
|
||||
|
||||
expect(result).toEqual([alice.address0]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isAdmin", () => {
|
||||
it("returns true if client signer is admin", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.isAdmin();
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it("returns false if client signer is not admin", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address1,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.isAdmin();
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("returns true if supplied signer is admin", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address1,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.isAdmin(alice.address0);
|
||||
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it("returns false if supplied signer is not admin", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.isAdmin(alice.address1);
|
||||
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAllAllowances", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getAllAllowances();
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAllowance", () => {
|
||||
it("works for client signer", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getAllowance();
|
||||
|
||||
expect(result).toEqual({ balance: [], expires: { never: {} } });
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAllPermissions", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getAllPermissions();
|
||||
expect(result.length).toEqual(1);
|
||||
// TODO: test content of permissions
|
||||
});
|
||||
});
|
||||
|
||||
describe("getPermissions", () => {
|
||||
it("works for client signer", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getPermissions();
|
||||
|
||||
expect(result).toEqual({
|
||||
delegate: false,
|
||||
redelegate: false,
|
||||
undelegate: false,
|
||||
withdraw: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("works for supplied signer", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const result = await client.getPermissions(alice.address1);
|
||||
|
||||
expect(result).toEqual({
|
||||
delegate: false,
|
||||
redelegate: false,
|
||||
undelegate: false,
|
||||
withdraw: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("addAdmin and removeAdmin", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const newAdmin = makeRandomAddress();
|
||||
expect(await client.isAdmin(newAdmin)).toBeFalse();
|
||||
|
||||
const addResult = await client.addAdmin(newAdmin);
|
||||
expect(addResult.transactionHash).toBeTruthy();
|
||||
expect(await client.isAdmin(newAdmin)).toBeTrue();
|
||||
|
||||
const removeResult = await client.removeAdmin(newAdmin);
|
||||
expect(removeResult.transactionHash).toBeTruthy();
|
||||
expect(await client.isAdmin(newAdmin)).toBeFalse();
|
||||
});
|
||||
});
|
||||
|
||||
describe("increaseAllowance and decreaseAllowance", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const spender = makeRandomAddress();
|
||||
expect(await client.getAllowance(spender)).toEqual({ balance: [], expires: { never: {} } });
|
||||
|
||||
const increaseAmount = coin(100, "ucosm");
|
||||
const increaseResult = await client.increaseAllowance(spender, increaseAmount);
|
||||
expect(increaseResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getAllowance(spender)).toEqual({
|
||||
balance: [increaseAmount],
|
||||
expires: { never: {} },
|
||||
});
|
||||
|
||||
const decreaseAmount = coin(20, "ucosm");
|
||||
const decreaseResult = await client.decreaseAllowance(spender, decreaseAmount);
|
||||
expect(decreaseResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getAllowance(spender)).toEqual({
|
||||
balance: coins(80, "ucosm"),
|
||||
expires: { never: {} },
|
||||
});
|
||||
});
|
||||
|
||||
it("works with expiration", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const spender = makeRandomAddress();
|
||||
expect(await client.getAllowance(spender)).toEqual({ balance: [], expires: { never: {} } });
|
||||
|
||||
const increaseAmount = coin(100, "ucosm");
|
||||
const increaseExpiration = { at_height: 88888888888 };
|
||||
const increaseResult = await client.increaseAllowance(spender, increaseAmount, increaseExpiration);
|
||||
expect(increaseResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getAllowance(spender)).toEqual({
|
||||
balance: [increaseAmount],
|
||||
expires: increaseExpiration,
|
||||
});
|
||||
|
||||
const decreaseAmount = coin(20, "ucosm");
|
||||
const decreaseExpiration = { at_height: 99999999999 };
|
||||
const decreaseResult = await client.decreaseAllowance(spender, decreaseAmount, decreaseExpiration);
|
||||
expect(decreaseResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getAllowance(spender)).toEqual({
|
||||
balance: coins(80, "ucosm"),
|
||||
expires: decreaseExpiration,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("setPermissions", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutLaunchpad();
|
||||
pendingWithoutCw1();
|
||||
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new Cw1SubkeyCosmWasmClient(
|
||||
launchpad.endpoint,
|
||||
alice.address0,
|
||||
wallet,
|
||||
deployedCw1.instances[0],
|
||||
);
|
||||
const spender = makeRandomAddress();
|
||||
const defaultPermissions = {
|
||||
delegate: false,
|
||||
redelegate: false,
|
||||
undelegate: false,
|
||||
withdraw: false,
|
||||
};
|
||||
expect(await client.getPermissions(spender)).toEqual(defaultPermissions);
|
||||
|
||||
const newPermissions = {
|
||||
delegate: true,
|
||||
redelegate: true,
|
||||
undelegate: true,
|
||||
withdraw: false,
|
||||
};
|
||||
const setPermissionsResult = await client.setPermissions(spender, newPermissions);
|
||||
expect(setPermissionsResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getPermissions(spender)).toEqual(newPermissions);
|
||||
|
||||
const resetPermissionsResult = await client.setPermissions(spender, defaultPermissions);
|
||||
expect(resetPermissionsResult.transactionHash).toBeTruthy();
|
||||
expect(await client.getPermissions(spender)).toEqual(defaultPermissions);
|
||||
});
|
||||
});
|
||||
});
|
152
packages/cosmwasm/src/cw1subkeycosmwasmclient.ts
Normal file
152
packages/cosmwasm/src/cw1subkeycosmwasmclient.ts
Normal file
@ -0,0 +1,152 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import { Coin } from "@cosmjs/launchpad";
|
||||
|
||||
import { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
|
||||
import { Expiration } from "./interfaces";
|
||||
import { ExecuteResult } from "./signingcosmwasmclient";
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L88
|
||||
*/
|
||||
export interface Cw1SubkeyAllowanceInfo {
|
||||
readonly balance: readonly Coin[];
|
||||
readonly expires: Expiration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L83
|
||||
*/
|
||||
interface AllAllowancesResponse {
|
||||
readonly allowances: readonly Cw1SubkeyAllowanceInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/state.rs#L15
|
||||
*/
|
||||
export interface Cw1SubkeyPermissions {
|
||||
readonly delegate: boolean;
|
||||
readonly redelegate: boolean;
|
||||
readonly undelegate: boolean;
|
||||
readonly withdraw: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L95
|
||||
*/
|
||||
export interface Cw1SubkeyPermissionsInfo {
|
||||
/** Spender address */
|
||||
readonly spender: string;
|
||||
readonly permissions: readonly Cw1SubkeyPermissions[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L101
|
||||
*/
|
||||
interface AllPermissionsResponse {
|
||||
readonly permissions: readonly Cw1SubkeyPermissionsInfo[];
|
||||
}
|
||||
|
||||
export class Cw1SubkeyCosmWasmClient extends Cw1CosmWasmClient {
|
||||
private async setAdmins(admins: readonly string[], memo = ""): Promise<ExecuteResult> {
|
||||
const handleMsg = {
|
||||
update_admins: {
|
||||
admins: admins,
|
||||
},
|
||||
};
|
||||
return this.execute(this.cw1ContractAddress, handleMsg, memo);
|
||||
}
|
||||
|
||||
public async getAdmins(): Promise<readonly string[]> {
|
||||
const { admins } = await this.queryContractSmart(this.cw1ContractAddress, { admin_list: {} });
|
||||
return admins;
|
||||
}
|
||||
|
||||
public async isAdmin(address = this.senderAddress): Promise<boolean> {
|
||||
const admins = await this.getAdmins();
|
||||
return admins.includes(address);
|
||||
}
|
||||
|
||||
public async getAllAllowances(): Promise<readonly Cw1SubkeyAllowanceInfo[]> {
|
||||
const response: AllAllowancesResponse = await this.queryContractSmart(this.cw1ContractAddress, {
|
||||
all_allowances: {},
|
||||
});
|
||||
return response.allowances;
|
||||
}
|
||||
|
||||
public async getAllowance(address = this.senderAddress): Promise<Cw1SubkeyAllowanceInfo> {
|
||||
return this.queryContractSmart(this.cw1ContractAddress, {
|
||||
allowance: { spender: address },
|
||||
});
|
||||
}
|
||||
|
||||
public async getAllPermissions(): Promise<readonly Cw1SubkeyPermissionsInfo[]> {
|
||||
const response: AllPermissionsResponse = await this.queryContractSmart(this.cw1ContractAddress, {
|
||||
all_permissions: {},
|
||||
});
|
||||
return response.permissions;
|
||||
}
|
||||
|
||||
public async getPermissions(address = this.senderAddress): Promise<Cw1SubkeyPermissions> {
|
||||
return this.queryContractSmart(this.cw1ContractAddress, {
|
||||
permissions: { spender: address },
|
||||
});
|
||||
}
|
||||
|
||||
public async addAdmin(address: string, memo = ""): Promise<ExecuteResult> {
|
||||
const admins = await this.getAdmins();
|
||||
const newAdmins = admins.includes(address) ? admins : [...admins, address];
|
||||
return this.setAdmins(newAdmins, memo);
|
||||
}
|
||||
|
||||
public async removeAdmin(address: string, memo = ""): Promise<ExecuteResult> {
|
||||
const admins = await this.getAdmins();
|
||||
const newAdmins = admins.filter((admin) => admin !== address);
|
||||
return this.setAdmins(newAdmins, memo);
|
||||
}
|
||||
|
||||
public async increaseAllowance(
|
||||
address: string,
|
||||
amount: Coin,
|
||||
expires?: Expiration,
|
||||
memo = "",
|
||||
): Promise<ExecuteResult> {
|
||||
const handleMsg = {
|
||||
increase_allowance: {
|
||||
spender: address,
|
||||
amount: amount,
|
||||
expires: expires,
|
||||
},
|
||||
};
|
||||
return this.execute(this.cw1ContractAddress, handleMsg, memo);
|
||||
}
|
||||
|
||||
public async decreaseAllowance(
|
||||
address: string,
|
||||
amount: Coin,
|
||||
expires?: Expiration,
|
||||
memo = "",
|
||||
): Promise<ExecuteResult> {
|
||||
const handleMsg = {
|
||||
decrease_allowance: {
|
||||
spender: address,
|
||||
amount: amount,
|
||||
expires: expires,
|
||||
},
|
||||
};
|
||||
return this.execute(this.cw1ContractAddress, handleMsg, memo);
|
||||
}
|
||||
|
||||
public async setPermissions(
|
||||
address: string,
|
||||
permissions: Cw1SubkeyPermissions,
|
||||
memo = "",
|
||||
): Promise<ExecuteResult> {
|
||||
const handleMsg = {
|
||||
set_permissions: {
|
||||
spender: address,
|
||||
permissions: permissions,
|
||||
},
|
||||
};
|
||||
return this.execute(this.cw1ContractAddress, handleMsg, memo);
|
||||
}
|
||||
}
|
@ -3,16 +3,12 @@ import { BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launc
|
||||
|
||||
import { CosmosMsg } from "./cosmosmsg";
|
||||
import { Account } from "./cosmwasmclient";
|
||||
import { Expiration } from "./interfaces";
|
||||
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
|
||||
export type Expiration =
|
||||
| {
|
||||
readonly at_height: number;
|
||||
}
|
||||
| {
|
||||
readonly at_time: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw3/src/msg.rs#L35
|
||||
*/
|
||||
export enum Vote {
|
||||
Yes = "yes",
|
||||
No = "no",
|
||||
|
@ -1,4 +1,6 @@
|
||||
export { Expiration } from "./interfaces";
|
||||
export { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
|
||||
|
||||
export { BankMsg, CosmosMsg, CustomMsg, StakingMsg, WasmMsg } from "./cosmosmsg";
|
||||
export {
|
||||
Account,
|
||||
@ -17,9 +19,9 @@ export {
|
||||
SearchTxQuery,
|
||||
SearchTxFilter,
|
||||
} from "./cosmwasmclient";
|
||||
export { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
|
||||
export {
|
||||
Cw3CosmWasmClient,
|
||||
Expiration,
|
||||
ProposalResult,
|
||||
ProposalsResult,
|
||||
ThresholdResult,
|
||||
|
15
packages/cosmwasm/src/interfaces/cw0.ts
Normal file
15
packages/cosmwasm/src/interfaces/cw0.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw0/src/expiration.rs#L14
|
||||
*/
|
||||
export type Expiration =
|
||||
| {
|
||||
readonly at_height: number;
|
||||
}
|
||||
| {
|
||||
readonly at_time: number;
|
||||
}
|
||||
| {
|
||||
readonly never: Record<any, never>;
|
||||
};
|
1
packages/cosmwasm/src/interfaces/index.ts
Normal file
1
packages/cosmwasm/src/interfaces/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Expiration } from "./cw0";
|
@ -103,6 +103,14 @@ export const deployedCw3 = {
|
||||
],
|
||||
};
|
||||
|
||||
/** Deployed as part of scripts/launchpad/init.sh */
|
||||
export const deployedCw1 = {
|
||||
codeId: 4,
|
||||
source: "https://crates.io/api/v1/crates/cw1-subkeys/0.3.1/download",
|
||||
builder: "cosmwasm/rust-optimizer:0.10.4",
|
||||
instances: ["cosmos1vs2vuks65rq7xj78mwtvn7vvnm2gn7ad5me0d2"],
|
||||
};
|
||||
|
||||
export const launchpad = {
|
||||
endpoint: "http://localhost:1317",
|
||||
chainId: "testing",
|
||||
@ -141,6 +149,16 @@ export function pendingWithoutCw3(): void {
|
||||
}
|
||||
}
|
||||
|
||||
export function cw1Enabled(): boolean {
|
||||
return !!process.env.CW1_ENABLED;
|
||||
}
|
||||
|
||||
export function pendingWithoutCw1(): void {
|
||||
if (!cw1Enabled()) {
|
||||
return pending("Set CW1_ENABLED to enable CW1-based tests");
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns first element. Throws if array has a different length than 1. */
|
||||
export function fromOneElementArray<T>(elements: ArrayLike<T>): T {
|
||||
if (elements.length !== 1) throw new Error(`Expected exactly one element but got ${elements.length}`);
|
||||
|
18
packages/cosmwasm/types/cw1cosmwasmclient.d.ts
vendored
Normal file
18
packages/cosmwasm/types/cw1cosmwasmclient.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import { Account, BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launchpad";
|
||||
import { CosmosMsg } from "./cosmosmsg";
|
||||
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
export declare class Cw1CosmWasmClient extends SigningCosmWasmClient {
|
||||
readonly cw1ContractAddress: string;
|
||||
constructor(
|
||||
apiUrl: string,
|
||||
signerAddress: string,
|
||||
signer: OfflineSigner,
|
||||
cw1ContractAddress: string,
|
||||
gasPrice?: GasPrice,
|
||||
gasLimits?: Partial<GasLimits<CosmWasmFeeTable>>,
|
||||
broadcastMode?: BroadcastMode,
|
||||
);
|
||||
getAccount(address?: string): Promise<Account | undefined>;
|
||||
canSend(msg: CosmosMsg, address?: string): Promise<boolean>;
|
||||
executeCw1(msgs: readonly CosmosMsg[], memo?: string): Promise<ExecuteResult>;
|
||||
}
|
52
packages/cosmwasm/types/cw1subkeycosmwasmclient.d.ts
vendored
Normal file
52
packages/cosmwasm/types/cw1subkeycosmwasmclient.d.ts
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
import { Coin } from "@cosmjs/launchpad";
|
||||
import { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
|
||||
import { Expiration } from "./interfaces";
|
||||
import { ExecuteResult } from "./signingcosmwasmclient";
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L88
|
||||
*/
|
||||
export interface Cw1SubkeyAllowanceInfo {
|
||||
readonly balance: readonly Coin[];
|
||||
readonly expires: Expiration;
|
||||
}
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/state.rs#L15
|
||||
*/
|
||||
export interface Cw1SubkeyPermissions {
|
||||
readonly delegate: boolean;
|
||||
readonly redelegate: boolean;
|
||||
readonly undelegate: boolean;
|
||||
readonly withdraw: boolean;
|
||||
}
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/contracts/cw1-subkeys/src/msg.rs#L95
|
||||
*/
|
||||
export interface Cw1SubkeyPermissionsInfo {
|
||||
/** Spender address */
|
||||
readonly spender: string;
|
||||
readonly permissions: readonly Cw1SubkeyPermissions[];
|
||||
}
|
||||
export declare class Cw1SubkeyCosmWasmClient extends Cw1CosmWasmClient {
|
||||
private setAdmins;
|
||||
getAdmins(): Promise<readonly string[]>;
|
||||
isAdmin(address?: string): Promise<boolean>;
|
||||
getAllAllowances(): Promise<readonly Cw1SubkeyAllowanceInfo[]>;
|
||||
getAllowance(address?: string): Promise<Cw1SubkeyAllowanceInfo>;
|
||||
getAllPermissions(): Promise<readonly Cw1SubkeyPermissionsInfo[]>;
|
||||
getPermissions(address?: string): Promise<Cw1SubkeyPermissions>;
|
||||
addAdmin(address: string, memo?: string): Promise<ExecuteResult>;
|
||||
removeAdmin(address: string, memo?: string): Promise<ExecuteResult>;
|
||||
increaseAllowance(
|
||||
address: string,
|
||||
amount: Coin,
|
||||
expires?: Expiration,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult>;
|
||||
decreaseAllowance(
|
||||
address: string,
|
||||
amount: Coin,
|
||||
expires?: Expiration,
|
||||
memo?: string,
|
||||
): Promise<ExecuteResult>;
|
||||
setPermissions(address: string, permissions: Cw1SubkeyPermissions, memo?: string): Promise<ExecuteResult>;
|
||||
}
|
11
packages/cosmwasm/types/cw3cosmwasmclient.d.ts
vendored
11
packages/cosmwasm/types/cw3cosmwasmclient.d.ts
vendored
@ -1,14 +1,11 @@
|
||||
import { BroadcastMode, GasLimits, GasPrice, OfflineSigner } from "@cosmjs/launchpad";
|
||||
import { CosmosMsg } from "./cosmosmsg";
|
||||
import { Account } from "./cosmwasmclient";
|
||||
import { Expiration } from "./interfaces";
|
||||
import { CosmWasmFeeTable, ExecuteResult, SigningCosmWasmClient } from "./signingcosmwasmclient";
|
||||
export declare type Expiration =
|
||||
| {
|
||||
readonly at_height: number;
|
||||
}
|
||||
| {
|
||||
readonly at_time: number;
|
||||
};
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw3/src/msg.rs#L35
|
||||
*/
|
||||
export declare enum Vote {
|
||||
Yes = "yes",
|
||||
No = "no",
|
||||
|
3
packages/cosmwasm/types/index.d.ts
vendored
3
packages/cosmwasm/types/index.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
export { Expiration } from "./interfaces";
|
||||
export { setupWasmExtension, WasmExtension } from "./lcdapi/wasm";
|
||||
export { BankMsg, CosmosMsg, CustomMsg, StakingMsg, WasmMsg } from "./cosmosmsg";
|
||||
export {
|
||||
@ -17,9 +18,9 @@ export {
|
||||
SearchTxQuery,
|
||||
SearchTxFilter,
|
||||
} from "./cosmwasmclient";
|
||||
export { Cw1CosmWasmClient } from "./cw1cosmwasmclient";
|
||||
export {
|
||||
Cw3CosmWasmClient,
|
||||
Expiration,
|
||||
ProposalResult,
|
||||
ProposalsResult,
|
||||
ThresholdResult,
|
||||
|
13
packages/cosmwasm/types/interfaces/cw0.d.ts
vendored
Normal file
13
packages/cosmwasm/types/interfaces/cw0.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @see https://github.com/CosmWasm/cosmwasm-plus/blob/v0.3.2/packages/cw0/src/expiration.rs#L14
|
||||
*/
|
||||
export declare type Expiration =
|
||||
| {
|
||||
readonly at_height: number;
|
||||
}
|
||||
| {
|
||||
readonly at_time: number;
|
||||
}
|
||||
| {
|
||||
readonly never: Record<any, never>;
|
||||
};
|
1
packages/cosmwasm/types/interfaces/index.d.ts
vendored
Normal file
1
packages/cosmwasm/types/interfaces/index.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export { Expiration } from "./cw0";
|
@ -1,3 +1,4 @@
|
||||
c478a6d9d6303e67f28d7863ea6e07426e9f0082744557d503e723bc1c46ccf8 cw1_subkeys.wasm
|
||||
1a4a376ef1099ad3edc33aa1d3105e4621bc49e44b1ac0a449d7b6912e40fb0a cw3_fixed_multisig.wasm
|
||||
ebc2b11e2afa50d5dcd4234840cd581e948a59d888bb8d651598bba3732cd8ee cw-nameservice.wasm
|
||||
d04368320ad55089384adb171aaea39e43d710d7608829adba0300ed30aa2988 cw_erc20.wasm
|
||||
|
BIN
scripts/launchpad/contracts/cw1_subkeys.wasm
(Stored with Git LFS)
Normal file
BIN
scripts/launchpad/contracts/cw1_subkeys.wasm
(Stored with Git LFS)
Normal file
Binary file not shown.
58
scripts/launchpad/deploy_cw1.js
Executable file
58
scripts/launchpad/deploy_cw1.js
Executable file
@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
const { SigningCosmWasmClient } = require("@cosmjs/cosmwasm");
|
||||
const { Secp256k1HdWallet } = require("@cosmjs/launchpad");
|
||||
const fs = require("fs");
|
||||
|
||||
const httpUrl = "http://localhost:1317";
|
||||
const alice = {
|
||||
mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park",
|
||||
address0: "cosmos14qemq0vw6y3gc3u3e0aty2e764u4gs5le3hada",
|
||||
// address1: "cosmos1hhg2rlu9jscacku2wwckws7932qqqu8x3gfgw0",
|
||||
// address2: "cosmos1xv9tklw7d82sezh9haa573wufgy59vmwe6xxe5",
|
||||
// address3: "cosmos17yg9mssjenmc3jkqth6ulcwj9cxujrxxzezwta",
|
||||
// address4: "cosmos1f7j7ryulwjfe9ljplvhtcaxa6wqgula3etktce",
|
||||
};
|
||||
|
||||
const codeMeta = {
|
||||
source: "https://crates.io/api/v1/crates/cw1-subkeys/0.3.1/download",
|
||||
builder: "cosmwasm/rust-optimizer:0.10.4",
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const wallet = await Secp256k1HdWallet.fromMnemonic(alice.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, alice.address0, wallet);
|
||||
|
||||
const wasm = fs.readFileSync(__dirname + "/contracts/cw1_subkeys.wasm");
|
||||
const uploadReceipt = await client.upload(wasm, codeMeta, "Upload CW1 subkeys contract");
|
||||
console.info(`Upload succeeded. Receipt: ${JSON.stringify(uploadReceipt)}`);
|
||||
|
||||
const initMsg = {
|
||||
admins: [alice.address0],
|
||||
mutable: true,
|
||||
};
|
||||
const label = "Subkey test";
|
||||
const { contractAddress } = await client.instantiate(uploadReceipt.codeId, initMsg, label, {
|
||||
memo: `Create a CW1 instance for ${alice.address0}`,
|
||||
admin: alice.address0,
|
||||
});
|
||||
await client.sendTokens(contractAddress, [
|
||||
{
|
||||
amount: "1000",
|
||||
denom: "ucosm",
|
||||
},
|
||||
]);
|
||||
console.info(`Contract instantiated for ${alice.address0} subkey at ${contractAddress}`);
|
||||
}
|
||||
|
||||
main().then(
|
||||
() => {
|
||||
console.info("All done, let the coins flow.");
|
||||
process.exit(0);
|
||||
},
|
||||
(error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
},
|
||||
);
|
@ -27,4 +27,5 @@ SCRIPT_DIR="$(realpath "$(dirname "$0")")"
|
||||
"$SCRIPT_DIR/deploy_hackatom.js"
|
||||
"$SCRIPT_DIR/deploy_erc20.js"
|
||||
"$SCRIPT_DIR/deploy_cw3.js"
|
||||
"$SCRIPT_DIR/deploy_cw1.js"
|
||||
# "$SCRIPT_DIR/deploy_nameservice.js"
|
||||
|
Loading…
x
Reference in New Issue
Block a user