Skip to content

Commit

Permalink
Add estimate message fee (#312)
Browse files Browse the repository at this point in the history
* [skip ci]
  • Loading branch information
Nathan-SL committed Feb 22, 2023
1 parent 9ea9067 commit 67f5ff4
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 6 deletions.
9 changes: 5 additions & 4 deletions src/devnet-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Block, MintResponse, L2ToL1Message } from "./starknet-types";
import { REQUEST_TIMEOUT } from "./constants";
import { hash } from "starknet";
import { numericToHexString } from "./utils";
import { Numeric } from "./types";

interface L1ToL2Message {
address: string;
Expand Down Expand Up @@ -134,14 +135,14 @@ Make sure you really want to interact with Devnet and that it is running and ava

public async sendMessageToL2(
l2ContractAddress: string,
funcionName: string,
functionName: string,
l1ContractAddress: string,
payload: number[],
nonce: number
payload: Numeric[],
nonce: Numeric
) {
const body = {
l2_contract_address: l2ContractAddress,
entry_point_selector: hash.getSelectorFromName(funcionName),
entry_point_selector: hash.getSelectorFromName(functionName),
l1_contract_address: l1ContractAddress,
payload: payload.map((item) => numericToHexString(item)),
nonce: numericToHexString(nonce)
Expand Down
31 changes: 31 additions & 0 deletions src/starknet-wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import { getPrefixedCommand, normalizeVenvPath } from "./utils/venv";
import { ExternalServer } from "./external-server";
import { StarknetPluginError } from "./starknet-plugin-error";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { FeeEstimation } from "./starknet-types";
import { hash } from "starknet";
import { toBN, toHex } from "starknet/utils/number";
import axios from "axios";

interface CompileWrapperOptions {
file: string;
Expand Down Expand Up @@ -394,6 +398,33 @@ export abstract class StarknetWrapper {
}
return executed;
}

public async estimateMessageFee(
functionName: string,
fromAddress: string,
toAddress: string,
inputs: string[]
): Promise<FeeEstimation> {
const body = {
from_address: fromAddress,
to_address: toAddress,
entry_point_selector: hash.getSelectorFromName(functionName),
payload: inputs.map((item) => toHex(toBN(item)))
};

const response = await axios.post(
`${this.hre.starknet.networkConfig.url}/feeder_gateway/estimate_message_fee`,
body
);

const { gas_price, gas_usage, overall_fee, unit } = response.data;
return {
amount: BigInt(overall_fee),
unit,
gas_price: BigInt(gas_price),
gas_usage: BigInt(gas_usage)
};
}
}

function getFullImageName(image: Image): string {
Expand Down
5 changes: 3 additions & 2 deletions src/types/devnet.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Numeric } from ".";
import {
FlushResponse,
IncreaseTimeResponse,
Expand Down Expand Up @@ -49,8 +50,8 @@ export interface Devnet {
l2ContractAddress: string,
functionName: string,
l1ContractAddress: string,
payload: Array<number>,
nonce: number
payload: Array<Numeric>,
nonce: Numeric
) => Promise<L1ToL2MockTxResponse>;

/**
Expand Down
26 changes: 26 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,32 @@ export class StarknetContract {
return this.adaptOutput(functionName, executed.stdout.toString());
}

/**
* Computes L1-to-L2 message fee estimation
* @param {string} functionName Function name for entry point selector
* @param {StringMap} args - Arguments to Starknet contract function
* @returns Fee estimation
*/
async estimateMessageFee(functionName: string, args: StringMap) {
// Check if functionName is annotated with @l1_handler
const func = <starknet.CairoFunction>this.abi[functionName];

if (!func?.type || func.type.toString() !== "l1_handler") {
throw new StarknetPluginError(
`Cannot estimate message fee on "${functionName}" - not an @l1_handler`
);
}
const adaptedInput = this.adaptInput(functionName, args);
// Remove value of from_address from the input array
const fromAddress = adaptedInput.shift();
return this.hre.starknetWrapper.estimateMessageFee(
functionName,
fromAddress,
this.address,
adaptedInput
);
}

/**
* Estimate the gas fee of executing `functionName` with `args`.
* @param functionName
Expand Down
10 changes: 10 additions & 0 deletions www/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ it("should estimate fee", async function () {

const invokeFee = await account.estimateFee(contract, "method", { arg1: 10n });
await account.invoke(contract, "method", { arg1: 10n }); // computes max fee implicitly

// computes message estimate fee
const estimatedMessageFee = await l2contract.estimateMessageFee(
"deposit",
{
from_address: L1_CONTRACT_ADDRESS,
amount: 123,
user: 1
}
);
});
```
Expand Down

0 comments on commit 67f5ff4

Please sign in to comment.