Factory

This document provides a comprehensive overview of the "Factory" smart contract messages and its sdk. The contract is the first entry point of a user to create a Super Account. This contract takes all the configuration wanted and creates the wallet, membership and vote contracts.

Contract Specification

The Factory contract acts as the main contract that connects and configures each one of the individual contracts that form the Super Accounts.

Instantiate Message

When the contract is instantiated, it requires the following parameters:

  • Wallet code id: wallet contract code id.

  • Membership code id: membership code id.

  • Vote code id: vote contract code id.

  • Cw ICA controller code id: the cw-ica-controller contract code id.

Message definition in rust:

#[cw_serde]
pub struct InstantiateMsg {
    pub wallet_code_id: u64,
    pub membership_code_id: u64,
    pub vote_code_id: u64,
    pub cw_ica_controller_code_id: u64,
}

Execute Messages

The contract supports the following execution messages:

  • Create account:

    • instantiate_multisig_msg: this message is a subset of the configuration for a voting contract. Refer to the instantiate message of vote for more explanation about each field.

    • channel_open_init_options: Configuration to instantiate an CW-ICA-Controller. Refer to its documentation for more information about it.

    • salt: Used to deploy the contracts deterministically.

    • post_msgs: Messages that the user wants the Super Account to execute after its creation. These messages won't require voting by the members.

    • ica_chain_id: Chain id of the ICA account that we want to create.

  • Update Factory Contracts:

    • Updates the code id of the contracts in the configuration.

    • Only callable by factory owner.

  • Update Pending Owner:

    • When transferring the factory ownership, we create a pending owner to know the receiver can actually receive the ownership.

    • Only callable by owner.

  • Claim Ownership:

    • Claims ownership of the contract.

    • Can only be called by the Pending Owner, set by the owner.

Rust messages definition:

#[cw_serde]
pub struct InstantiateMultisigMsg {
    pub members: Vec<Member>,
    pub threshold: Threshold,
    pub max_voting_period: Duration,
    pub proposal_deposit: Option<UncheckedDepositInfo>,
    pub revoting: bool,
    pub automatic_execution: bool,
    pub open_proposal_submission: bool,
    pub open_proposal_deposit: Option<UncheckedDepositInfo>,
}

#[cw_serde]
pub enum ExecuteMsg {
    CreateMultisig {
        instantiate_multisig_msg: InstantiateMultisigMsg,
        channel_open_init_options: ChannelOpenInitOptions,
        salt: String,
        ica_chain_id: String,
        post_msgs: Option<Vec<CosmosMsg>>,
    },
    UpdateFactoryContracts {
        wallet_code_id: Option<u64>,
        membership_code_id: Option<u64>,
        vote_code_id: Option<u64>,
        cw_ica_controller_code_id: Option<u64>,
    },
    UpdatePendingOwner {
        pending_owner: Addr,
    },
    ClaimOwnership {},
}

Here's a detailed description of each query message for the contract, suitable for integrating into your documentation:

Query Messages

Query operations supported by the contract include:

  • Get Factory State:

    • Returns comprehensive state information of the factory, including the owner, wallet code_id, and other relevant configuration details.

  • Query Multisig by Creator:

    • Fetches records of Super Accounts contracts created by a specific address. This query allows for filtering Super Accounts by their creator, making it easier to track entities initiated by particular users.

Rust message definitions:

#[cw_serde]
pub struct MultisigRecord {
    pub user: Addr,
    pub wallet_addr: Addr,
    pub membership: Addr,
    pub vote: Addr,
    pub ica_controller: Addr,
}

#[cw_serde]
#[derive(QueryResponses)]
pub enum QueryMsg {
    /// get factory state (owner, wallet code_id, etc)
    #[returns(FactoryStateResponse)]
    GetFactoryState(),
    /// get multisig record by creator
    #[returns(Vec<MultisigRecord>)]
    QueryMultisigByCreator(Addr)
}

In SDK

The JavaScript/TypeScript API provides a convenient interface for interacting with the Factory contract through the SigningCosmWasmClient.

Initialization

import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import {Factory} from "nomos-v2"

const client:SigningCosmwasmClient = // ...
const factory = new Factory(client,"<signer>", "<factory_contract_address>")

Here is a documentation section for the "Factory Client" SDK similar to the Wallet client example, tailored for interacting with a smart contract system designed to manage a factory of Super accounts and associated components:

Factory Client

  • Query methods:

    • getFactoryState(): Retrieves the current state of the factory, including owner details and code IDs for related contracts.

    • queryMultisigByCreator(): Retrieves all contracts created by a specific address on a specified chain. The contracts are wallets, memberships, vote modules and ica controllers.

  • Transaction methods:

    • createMultisig({channelOpenInitOptions, icaChainId, instantiateMultisigMsg, postMsgs, salt}, fee, memo, _funds): Creates a new multisig contract with optional post-transaction messages and initialization parameters.

    • updateFactoryContracts({cwIcaControllerCodeId, membershipCodeId, voteCodeId, walletCodeId}, fee, memo, _funds): Updates the contract code IDs used by the factory for creating new instances.

    • updatePendingOwner({pendingOwner}, fee, memo, _funds): Updates the pending owner of the factory, preparing for ownership transfer.

    • claimOwnership(fee, memo, _funds): Claims ownership of the factory, completing an ownership transfer process.

Usage

To interact with the Factory contract, instantiate a Factory with the appropriate CosmWasm client, sender address, and the contract's address. This setup allows for both querying and executing transactions based on the permissions and functionalities provided by the factory system.

import { CosmWasmClient, SigningCosmWasmClient, StdFee } from "@cosmjs/cosmwasm-stargate";
import { Factory } from "nomos-v2";

// Example: Initializing the client and querying factory state
const client: SigningCosmWasmClient = new SigningCosmWasmClient(...);
const factoryClient = new FactoryClient(client, "<signer>", "<factory_contract_address>");

// Get the state of the factory
const factoryState = await factoryClient.getFactoryState();
console.log("Factory State:", factoryState);

// Create a new multisig wallet
const executeResult = await factoryClient.createMultisig({
    channelOpenInitOptions: {
      connection_id: "<src_connection>",
      counterparty_connection_id: "<dest_connection>",
    },
    instantiateMultisigMsg: {
      automatic_execution: true,
      max_voting_period: {height: 10000},
      members: [
        {
          addr: "<member>",
          weight: 100,
        },
      ],
      open_proposal_submission: false,
      revoting: false,
      threshold: {absolute_count: {weight: 1}},
    },
    salt: "12345",
  }, "auto", "Creating a new multisig wallet", []);
console.log("Multisig Creation Result:", executeResult);

Super Account Structure

On creation, 3 contracts are created. These make the account work as expected and keeps modularity for future changes and modules. The contracts created are the Wallet, Membership and Vote module. There are other contracts such as the Cw ICA controller.

As you can see in the diagram above, the wallet of the account is the owner of all the contracts. So any transaction that modifies the account settings (voting settings, member list, ICA account) must be sent by the wallet. The wallet can only send transactions from the admin list, the only admin that is created with the factory is the Vote Module, so all transactions sent must go through the voting process. So usually when interacting with the super account you will only interact with the voting module or any other module installed.

Last updated