Skip to content

Commit

Permalink
simulate extension for fee granter param (#243)
Browse files Browse the repository at this point in the history
* simulate extension for fee granter param

* changeset

* fix standalone simulate call by appropriately transforming message and signerAddress

* export grantee signer client type
  • Loading branch information
BurntVal authored Dec 23, 2024
1 parent 683a738 commit 9fad9c4
Show file tree
Hide file tree
Showing 5 changed files with 6,732 additions and 5,447 deletions.
5 changes: 5 additions & 0 deletions .changeset/eighty-plants-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@burnt-labs/abstraxion-core": minor
---

GranteeSignerClient simulate extension for fee granter param
1 change: 1 addition & 0 deletions packages/abstraxion-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@cosmjs/cosmwasm-stargate": "^0.32.4",
"@cosmjs/crypto": "^0.32.4",
"@cosmjs/encoding": "^0.32.4",
"@cosmjs/math": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4",
"@cosmjs/stargate": "^0.32.4",
"@cosmjs/tendermint-rpc": "^0.32.4",
Expand Down
121 changes: 110 additions & 11 deletions packages/abstraxion-core/src/GranteeSignerClient.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { customAccountFromAny } from "@burnt-labs/signers";
import {
DeliverTxResponse,
SigningCosmWasmClient,
Expand All @@ -6,23 +7,31 @@ import {
import {
AccountData,
EncodeObject,
encodePubkey,
OfflineSigner,
} from "@cosmjs/proto-signing";
import {
calculateFee,
createProtobufRpcClient,
GasPrice,
type Account,
type SignerData,
type StdFee,
} from "@cosmjs/stargate";
import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { AuthInfo, Fee, TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { MsgExec } from "cosmjs-types/cosmos/authz/v1beta1/tx";
import {
HttpEndpoint,
Tendermint37Client,
TendermintClient,
} from "@cosmjs/tendermint-rpc";
import { customAccountFromAny } from "@burnt-labs/signers";
import { Uint53 } from "@cosmjs/math";
import { encodeSecp256k1Pubkey } from "@cosmjs/amino";
import {
ServiceClientImpl,
SimulateRequest,
} from "cosmjs-types/cosmos/tx/v1beta1/service";
import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing";

export interface GranteeSignerOptions {
readonly granterAddress: string;
Expand Down Expand Up @@ -104,16 +113,13 @@ export class GranteeSignerClient extends SigningCosmWasmClient {
return customAccountFromAny(account);
}

public async signAndBroadcast(
private transformForMsgExec(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee | "auto" | number,
memo = "",
): Promise<DeliverTxResponse> {
// Figure out if the signerAddress is a granter
): { signerAddress: string; messages: readonly EncodeObject[] } {
if (signerAddress === this.granterAddress) {
signerAddress = this.granteeAddress;
// Wrap the signerAddress in a MsgExec

messages = [
{
typeUrl: "/cosmos.authz.v1beta1.MsgExec",
Expand All @@ -125,6 +131,94 @@ export class GranteeSignerClient extends SigningCosmWasmClient {
];
}

return { signerAddress, messages };
}

public async simulate(
signerAddress: string,
messages: readonly EncodeObject[],
memo: string | undefined,
feeGranter?: string,
): Promise<number> {
const {
signerAddress: transformedSignerAddress,
messages: transformedMessages,
} = this.transformForMsgExec(signerAddress, messages);

const { sequence } = await this.getSequence(transformedSignerAddress);
const accountFromSigner = (await this._signer.getAccounts()).find(
(account) => account.address === transformedSignerAddress,
);

if (!accountFromSigner) {
throw new Error("No account found.");
}

const pubkey = encodeSecp256k1Pubkey(accountFromSigner.pubkey);

const queryClient = this.getQueryClient();
if (!queryClient) {
throw new Error("Couldn't get query client");
}

const rpc = createProtobufRpcClient(queryClient);
const queryService = new ServiceClientImpl(rpc);

const authInfo = AuthInfo.fromPartial({
fee: Fee.fromPartial({ granter: feeGranter }),
signerInfos: [
{
publicKey: encodePubkey(pubkey),
modeInfo: {
single: {
mode: SignMode.SIGN_MODE_DIRECT,
},
},
sequence: BigInt(sequence),
},
],
});
const authInfoBytes = AuthInfo.encode(authInfo).finish();

const txBodyEncodeObject = {
typeUrl: "/cosmos.tx.v1beta1.TxBody",
value: {
messages: transformedMessages,
memo: memo,
},
};
const bodyBytes = this.registry.encode(txBodyEncodeObject);

const tx = TxRaw.fromPartial({
bodyBytes,
authInfoBytes,
signatures: [new Uint8Array([10])],
});

const request = SimulateRequest.fromPartial({
txBytes: TxRaw.encode(tx).finish(),
});

const { gasInfo } = await queryService.Simulate(request);

if (!gasInfo) {
throw new Error("No gas info returned");
}

return Uint53.fromString(gasInfo.gasUsed.toString()).toNumber();
}

public async signAndBroadcast(
signerAddress: string,
messages: readonly EncodeObject[],
fee: StdFee | "auto" | number,
memo = "",
): Promise<DeliverTxResponse> {
const {
signerAddress: transformedSignerAddress,
messages: transformedMessages,
} = this.transformForMsgExec(signerAddress, messages);

let usedFee: StdFee;

const granter = this._treasury ? this._treasury : this.granterAddress;
Expand All @@ -135,7 +229,12 @@ export class GranteeSignerClient extends SigningCosmWasmClient {
"Gas price must be set in the client options when auto gas is used",
);
}
const gasEstimation = await this.simulate(signerAddress, messages, memo);
const gasEstimation = await this.simulate(
transformedSignerAddress,
transformedMessages,
memo,
granter,
);
const multiplier =
typeof fee == "number" ? fee : this._defaultGasMultiplier;
const calculatedFee = calculateFee(
Expand All @@ -152,8 +251,8 @@ export class GranteeSignerClient extends SigningCosmWasmClient {
}

const txRaw = await this.sign(
signerAddress,
messages,
transformedSignerAddress,
transformedMessages,
usedFee,
memo,
undefined,
Expand Down
3 changes: 2 additions & 1 deletion packages/abstraxion/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export {
useModal,
} from "./hooks";

export { ContractGrantDescription } from "./components/AbstraxionContext";
export type { ContractGrantDescription } from "./components/AbstraxionContext";
export type { GranteeSignerClient } from "@burnt-labs/abstraxion-core";
Loading

0 comments on commit 9fad9c4

Please sign in to comment.