CosmWasm / ts-codegen

Convert your CosmWasm smart contracts into dev-friendly TypeScript classes so you can focus on shipping code.
https://cosmology.zone/products/ts-codegen
Apache License 2.0
116 stars 27 forks source link

Abstract App Module Plugin #112

Open adairrr opened 1 year ago

adairrr commented 1 year ago

This change adds a new abstract-app plugin that generates clients for use in AbstractSDK's CosmWasm framework.

Users can enable abstractApp for their app module schemas to generate the app client. This significantly improves the user experience because they do not have to provide any of the wrapper boilerplate when using the framework.

Barebones example:

export interface IEtfAppQueryClient {
  moduleId: string;
  accountQueryClient: AbstractAccountQueryClient;
  _moduleAddress: string | undefined;
  state: () => Promise<StateResponse>;
  connectSigningClient: (
    signingClient: SigningCosmWasmClient,
    address: string
  ) => EtfAppClient;
  address: () => Promise<string>;
}
export class EtfAppQueryClient implements IEtfAppQueryClient {
  accountQueryClient: AbstractAccountQueryClient;
  moduleId: string;
  _moduleAddress: string | undefined;

  constructor({
    abstractQueryClient,
    accountId,
    managerAddress,
    proxyAddress,
    moduleId,
  }: {
    abstractQueryClient: AbstractQueryClient;
    accountId: number;
    managerAddress: string;
    proxyAddress: string;
    moduleId: string;
  }) {
    this.accountQueryClient = new AbstractAccountQueryClient({
      abstract: abstractQueryClient,
      accountId,
      managerAddress,
      proxyAddress,
    });
    this.moduleId = moduleId;
    this.state = this.state.bind(this);
  }

  state = async (): Promise<StateResponse> => {
    return this._query(EtfQueryMsgBuilder.state());
  };
  address = async (): Promise<string> => {
    if (!this._moduleAddress) {
      this._moduleAddress = await this.accountQueryClient.getModuleAddress(
        this.moduleId
      );
    }

    return this._moduleAddress;
  };
  connectSigningClient = (
    signingClient: SigningCosmWasmClient,
    address: string
  ): EtfAppClient => {
    return new EtfAppClient({
      accountId: this.accountQueryClient.accountId,
      managerAddress: this.accountQueryClient.managerAddress,
      proxyAddress: this.accountQueryClient.proxyAddress,
      moduleId: this.moduleId,
      abstractClient: this.accountQueryClient.abstract.connectSigningClient(
        signingClient,
        address
      ),
    });
  };
  _query = async (queryMsg: QueryMsg): Promise<any> => {
    return this.accountQueryClient.queryModule({
      moduleId: this.moduleId,
      moduleType: "app",
      queryMsg,
    });
  };
}
export interface IEtfAppClient extends IEtfAppQueryClient {
  accountClient: AbstractAccountClient;
  setFee: (
    params: CamelCasedProperties<
      Extract<
        ExecuteMsg,
        {
          set_fee: unknown;
        }
      >["set_fee"]
    >,
    fee?: number | StdFee | "auto",
    memo?: string,
    _funds?: Coin[]
  ) => Promise<ExecuteResult>;
}
export class EtfAppClient extends EtfAppQueryClient implements IEtfAppClient {
  accountClient: AbstractAccountClient;

  constructor({
    abstractClient,
    accountId,
    managerAddress,
    proxyAddress,
    moduleId,
  }: {
    abstractClient: AbstractClient;
    accountId: number;
    managerAddress: string;
    proxyAddress: string;
    moduleId: string;
  }) {
    super({
      abstractQueryClient: abstractClient,
      accountId,
      managerAddress,
      proxyAddress,
      moduleId,
    });
    this.accountClient = AbstractAccountClient.fromQueryClient(
      this.accountQueryClient,
      abstractClient
    );
    this.setFee = this.setFee.bind(this);
  }

  setFee = async (
    params: CamelCasedProperties<
      Extract<
        ExecuteMsg,
        {
          set_fee: unknown;
        }
      >["set_fee"]
    >,
    fee: number | StdFee | "auto" = "auto",
    memo?: string,
    _funds?: Coin[]
  ): Promise<ExecuteResult> => {
    return this._execute(
      EtfExecuteMsgBuilder.setFee(params),
      fee,
      memo,
      _funds
    );
  };
  _execute = async (
    msg: ExecuteMsg,
    fee: number | StdFee | "auto" = "auto",
    memo?: string,
    _funds?: Coin[]
  ): Promise<ExecuteResult> => {
    const moduleMsg: AppExecuteMsg<ExecuteMsg> =
      AppExecuteMsgFactory.executeApp(msg);
    return await this.accountClient.abstract.client.execute(
      this.accountClient.sender,
      await this.address(),
      moduleMsg,
      fee,
      memo,
      _funds
    );
  };
}
adairrr commented 1 year ago

Waiting on #110.

pyramation commented 1 year ago

this is lit 🔥