Skip to content

Commit

Permalink
2532 optimize estimation for manager operations (#2812)
Browse files Browse the repository at this point in the history
* refactor: (incompleted) slight refactoring with logging

* refactor: storageLImit and gasLImit optimization

re #2532

* fix: purged DEFAULT_FEE and DEFAULT_GAS_LIMIT and updated getRevealGasLimit ratio

* style: removed unneeded comments

* fix: increase gasLimit ratio to fix permit ci tests

* perf: optimized all single manager operations

re #2532

* fix: fine tune fee and gasLImit ratio to fix ci test fails

* refactor: refactored to use less magic number and better naming also fix ci fails

* test: updated ci assertion and deprecated old constants

* perf: replace magic number 166 with half of reveal opSize

* test: integration test estimation assertion changes

* fix: typo fix a bug

* test: updated estimation test after fixing typo bug

* test: test: updated estimation test

* feat: adding stub signature for talentNet compatibility for simulate_operation rpc

* fix: merge conflicts mistake

* refactor: address comment removed getRevealFeeInternal in favour of getRevealFee
  • Loading branch information
hui-an-yang authored Feb 20, 2024
1 parent c97c4f1 commit c8bf8c7
Show file tree
Hide file tree
Showing 22 changed files with 368 additions and 290 deletions.
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"nairobinet",
"objkt",
"octez",
"opbytes",
"opkind",
"originations",
"oxfordbox",
Expand Down
8 changes: 4 additions & 4 deletions docs/drain_account.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ In the following example, we have not revealed the account that we want to empty

```js live noInline
// const Tezos = new TezosToolkit('https://ghostnet.ecadinfra.com');
// import { DEFAULT_FEE } from "@taquito/taquito";
// import { getRevealFee } from "@taquito/taquito";

Tezos.signer
.publicKeyHash()
Expand All @@ -37,18 +37,18 @@ Tezos.signer
return Tezos.estimate
.transfer({
to: 'tz1PgQt52JMirBUhhkq1eanX8hVd1Fsg71Lr',
amount: balance.toNumber() - DEFAULT_FEE.REVEAL, // Remove default reveal fee
amount: balance.toNumber() - getRevealFee(address), // Remove default reveal fee
mutez: true
})
.then((estimate) => {
const maxAmount = balance.minus(
estimate.suggestedFeeMutez + DEFAULT_FEE.REVEAL
estimate.suggestedFeeMutez + getRevealFee(address)
).toNumber();
println(
`The estimated fees related to the emptying operation are ${
estimate.suggestedFeeMutez
} mutez.\nThe fees related to the reveal operation are ${
DEFAULT_FEE.REVEAL
getRevealFee(address)
} mutez.\nConsidering those fees, the amount we need to send to empty the account is ${
maxAmount / 1000000
} ꜩ.`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CONFIGS } from "./config";
import { DEFAULT_FEE } from "@taquito/taquito";
import { getRevealFee } from "@taquito/taquito";

CONFIGS().forEach(({ lib, rpc, setup, createAddress }) => {
const Tezos = lib;
Expand All @@ -15,10 +15,10 @@ CONFIGS().forEach(({ lib, rpc, setup, createAddress }) => {

// A transfer from an unrevealed account will require an additional fee (reveal operation)
const balance = await Tezos.tz.getBalance(await LocalTez.signer.publicKeyHash())
const estimate = await LocalTez.estimate.transfer({ to: await Tezos.signer.publicKeyHash(), mutez: true, amount: balance.minus(DEFAULT_FEE.REVEAL).toNumber() });
const estimate = await LocalTez.estimate.transfer({ to: await Tezos.signer.publicKeyHash(), mutez: true, amount: balance.minus(getRevealFee(await LocalTez.signer.publicKeyHash())).toNumber() });

// The max amount that can be sent now is the total balance minus the fees + reveal fees (assuming the dest is already allocated)
const maxAmount = balance.minus(estimate.suggestedFeeMutez + DEFAULT_FEE.REVEAL).toNumber();
const maxAmount = balance.minus(estimate.suggestedFeeMutez + getRevealFee(await LocalTez.signer.publicKeyHash())).toNumber();
const op3 = await LocalTez.contract.transfer({ to: await Tezos.signer.publicKeyHash(), mutez: true, amount: maxAmount, fee: estimate.suggestedFeeMutez, gasLimit: estimate.gasLimit, storageLimit: 0 })
await op3.confirmation();

Expand Down
109 changes: 55 additions & 54 deletions integration-tests/contract-estimation-tests.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DEFAULT_FEE, MANAGER_LAMBDA, TezosToolkit } from '@taquito/taquito';
import { MANAGER_LAMBDA, TezosToolkit, getRevealFee } from '@taquito/taquito';
import { Contract } from '@taquito/taquito';
import { CONFIGS } from './config';
import { originate, originate2, transferImplicit2 } from './data/lambda';
Expand All @@ -12,22 +12,23 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {
describe(`Test estimate scenarios using: ${rpc}`, () => {
let LowAmountTez: TezosToolkit;
let contract: Contract;
const amt = 2000000 + DEFAULT_FEE.REVEAL;
let amt = 2000000

beforeAll(async () => {
try {
await setup();
LowAmountTez = await createAddress();
const pkh = await LowAmountTez.signer.publicKeyHash();
amt += getRevealFee(await LowAmountTez.signer.publicKeyHash());
const transfer = await Tezos.contract.transfer({ to: pkh, mutez: true, amount: amt });
await transfer.confirmation();
const op = await Tezos.contract.originate({
balance: '1',
code: managerCode,
init: { 'string': pkh },
});
contract = await op.contract();
contract = await LowAmountTez.contract.at(contract.address);
await op.confirmation();
contract = await LowAmountTez.contract.at((await op.contract()).address);
expect(op.status).toEqual('applied');
}
catch (ex: any) {
Expand All @@ -38,25 +39,25 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {

it('Verify .estimate.transfer with allocated destination', async () => {
const estimate = await LowAmountTez.estimate.transfer({ to: await Tezos.signer.publicKeyHash(), amount: 0.019 });
expect(estimate.gasLimit).toEqual(201);
expect(estimate.gasLimit).toEqual(101);
expect(estimate.storageLimit).toEqual(0);
expect(estimate.suggestedFeeMutez).toEqual(374);
expect(estimate.suggestedFeeMutez).toEqual(187);
expect(estimate.burnFeeMutez).toEqual(0);
expect(estimate.minimalFeeMutez).toEqual(274);
expect(estimate.totalCost).toEqual(274);
expect(estimate.usingBaseFeeMutez).toEqual(274);
expect(estimate.minimalFeeMutez).toEqual(167);
expect(estimate.totalCost).toEqual(167);
expect(estimate.usingBaseFeeMutez).toEqual(167);
expect(estimate.consumedMilligas).toEqual(100040);
});

it('Verify .estimate.transfer with unallocated destination', async () => {
const estimate = await LowAmountTez.estimate.transfer({ to: await (await createAddress()).signer.publicKeyHash(), amount: 0.017 });
expect(estimate.gasLimit).toEqual(201);
expect(estimate.gasLimit).toEqual(101);
expect(estimate.storageLimit).toEqual(257);
expect(estimate.suggestedFeeMutez).toEqual(374);
expect(estimate.suggestedFeeMutez).toEqual(187);
expect(estimate.burnFeeMutez).toEqual(64250);
expect(estimate.minimalFeeMutez).toEqual(274);
expect(estimate.totalCost).toEqual(64524);
expect(estimate.usingBaseFeeMutez).toEqual(274);
expect(estimate.minimalFeeMutez).toEqual(167);
expect(estimate.totalCost).toEqual(64417);
expect(estimate.usingBaseFeeMutez).toEqual(167);
expect(estimate.consumedMilligas).toEqual(100040);
});

Expand All @@ -68,26 +69,26 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {
});
expect(estimate.gasLimit).toEqual(677);
expect(estimate.storageLimit).toEqual(571);
expect(estimate.suggestedFeeMutez).toEqual(713);
expect(estimate.suggestedFeeMutez).toEqual(536);
expect(estimate.burnFeeMutez).toEqual(142750);
expect(estimate.minimalFeeMutez).toEqual(613);
expect(estimate.totalCost).toEqual(143363);
expect(estimate.usingBaseFeeMutez).toEqual(613);
expect(estimate.consumedMilligas).toEqual(576402);
expect(estimate.minimalFeeMutez).toEqual(516);
expect(estimate.totalCost).toEqual(143266);
expect(estimate.usingBaseFeeMutez).toEqual(516);
expect(estimate.consumedMilligas).toEqual(676402);
});

it('Verify .estimate.setDelegate result', async () => {
const estimate = await LowAmountTez.estimate.setDelegate({
delegate: knownBaker,
source: await LowAmountTez.signer.publicKeyHash(),
});
expect(estimate.gasLimit).toEqual(200);
expect(estimate.gasLimit).toEqual(100);
expect(estimate.storageLimit).toEqual(0);
expect(estimate.suggestedFeeMutez).toEqual(369);
expect(estimate.suggestedFeeMutez).toEqual(182);
expect(estimate.burnFeeMutez).toEqual(0);
expect(estimate.minimalFeeMutez).toEqual(269);
expect(estimate.totalCost).toEqual(269);
expect(estimate.usingBaseFeeMutez).toEqual(269);
expect(estimate.minimalFeeMutez).toEqual(162);
expect(estimate.totalCost).toEqual(162);
expect(estimate.usingBaseFeeMutez).toEqual(162);
expect(estimate.consumedMilligas).toEqual(100000);
});

Expand All @@ -96,12 +97,12 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {
const estimate = await LowAmountTez.estimate.transfer(tx);
expect(estimate.gasLimit).toEqual(1457);
expect(estimate.storageLimit).toEqual(0);
expect(estimate.suggestedFeeMutez).toEqual(572);
expect(estimate.suggestedFeeMutez).toEqual(395);
expect(estimate.burnFeeMutez).toEqual(0);
expect(estimate.minimalFeeMutez).toEqual(472);
expect(estimate.totalCost).toEqual(472);
expect(estimate.usingBaseFeeMutez).toEqual(472);
expect(estimate.consumedMilligas).toEqual(1356228);
expect(estimate.minimalFeeMutez).toEqual(375);
expect(estimate.totalCost).toEqual(375);
expect(estimate.usingBaseFeeMutez).toEqual(375);
expect(estimate.consumedMilligas).toEqual(1456228);
});

it('Verify .estimate.transfer for multiple internal transfers to unallocated account', async () => {
Expand All @@ -113,38 +114,38 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {
const estimate = await LowAmountTez.estimate.transfer(tx);
expect(estimate.gasLimit).toEqual(1571);
expect(estimate.storageLimit).toEqual(514);
expect(estimate.suggestedFeeMutez).toEqual(643);
expect(estimate.suggestedFeeMutez).toEqual(466);
expect(estimate.burnFeeMutez).toEqual(128500);
expect(estimate.minimalFeeMutez).toEqual(543);
expect(estimate.totalCost).toEqual(129043);
expect(estimate.usingBaseFeeMutez).toEqual(543);
expect(estimate.consumedMilligas).toEqual(1470757);
expect(estimate.minimalFeeMutez).toEqual(446);
expect(estimate.totalCost).toEqual(128946);
expect(estimate.usingBaseFeeMutez).toEqual(446);
expect(estimate.consumedMilligas).toEqual(1570757);
});

it('Verify .estimate.transfer for internal origination', async () => {
const tx = contract.methods.do(originate()).toTransferParams();
const estimate = await LowAmountTez.estimate.transfer(tx);
expect(estimate.gasLimit).toEqual(1867);
expect(estimate.storageLimit).toEqual(317);
expect(estimate.suggestedFeeMutez).toEqual(619);
expect(estimate.suggestedFeeMutez).toEqual(442);
expect(estimate.burnFeeMutez).toEqual(79250);
expect(estimate.minimalFeeMutez).toEqual(519);
expect(estimate.totalCost).toEqual(79769);
expect(estimate.usingBaseFeeMutez).toEqual(519);
expect(estimate.consumedMilligas).toEqual(1766852);
expect(estimate.minimalFeeMutez).toEqual(422);
expect(estimate.totalCost).toEqual(79672);
expect(estimate.usingBaseFeeMutez).toEqual(422);
expect(estimate.consumedMilligas).toEqual(1866852);
});

it('Verify .estimate.transfer for multiple internal originations', async () => {
const tx = contract.methods.do(originate2()).toTransferParams();
const estimate = await LowAmountTez.estimate.transfer(tx);
expect(estimate.gasLimit).toEqual(2393);
expect(estimate.storageLimit).toEqual(634);
expect(estimate.suggestedFeeMutez).toEqual(737);
expect(estimate.suggestedFeeMutez).toEqual(560);
expect(estimate.burnFeeMutez).toEqual(158500);
expect(estimate.minimalFeeMutez).toEqual(637);
expect(estimate.totalCost).toEqual(159137);
expect(estimate.usingBaseFeeMutez).toEqual(637);
expect(estimate.consumedMilligas).toEqual(2292005);
expect(estimate.minimalFeeMutez).toEqual(540);
expect(estimate.totalCost).toEqual(159040);
expect(estimate.usingBaseFeeMutez).toEqual(540);
expect(estimate.consumedMilligas).toEqual(2392005);
// Do the actual operation
const op2 = await contract.methods.do(originate2()).send();
await op2.confirmation();
Expand All @@ -160,32 +161,32 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {

describe(`Test estimate scenarios with very low balance using: ${rpc}`, () => {
let LowAmountTez: TezosToolkit;
const amt = 2000 + DEFAULT_FEE.REVEAL;
let amt = 2000

beforeAll(async () => {
await setup();
LowAmountTez = await createAddress();
const pkh = await LowAmountTez.signer.publicKeyHash();
amt += getRevealFee(await LowAmountTez.signer.publicKeyHash());
const transfer = await Tezos.contract.transfer({ to: pkh, mutez: true, amount: amt });
await transfer.confirmation();
});

it('Verify .estimate.transfer to regular address', async () => {
let estimate = await LowAmountTez.estimate.transfer({ to: await Tezos.signer.publicKeyHash(), mutez: true, amount: amt - (1382 + DEFAULT_FEE.REVEAL) });
expect(estimate.gasLimit).toEqual(201);
let estimate = await LowAmountTez.estimate.transfer({ to: await Tezos.signer.publicKeyHash(), mutez: true, amount: amt - (1382 + getRevealFee(await LowAmountTez.signer.publicKeyHash())) });
expect(estimate.gasLimit).toEqual(101);
expect(estimate.storageLimit).toEqual(0);
expect(estimate.suggestedFeeMutez).toEqual(372);
expect(estimate.suggestedFeeMutez).toEqual(185);
expect(estimate.burnFeeMutez).toEqual(0);
expect(estimate.minimalFeeMutez).toEqual(272);
expect(estimate.totalCost).toEqual(272);
expect(estimate.usingBaseFeeMutez).toEqual(272);
expect(estimate.minimalFeeMutez).toEqual(165);
expect(estimate.totalCost).toEqual(165);
expect(estimate.usingBaseFeeMutez).toEqual(165);
expect(estimate.consumedMilligas).toEqual(100040);
});

it('Estimate transfer to regular address with a fixed fee', async () => {

const params = { fee: 2000, to: await Tezos.signer.publicKeyHash(), mutez: true, amount: amt - (1382 + DEFAULT_FEE.REVEAL) };

const params = { fee: 2000, to: await Tezos.signer.publicKeyHash(), mutez: true, amount: amt - (1382 + getRevealFee(await LowAmountTez.signer.publicKeyHash())) };
await expect(LowAmountTez.estimate.transfer(params)).rejects.toMatchObject({
id: expect.stringContaining('empty_implicit_contract'),
});
Expand All @@ -201,7 +202,7 @@ CONFIGS().forEach(({ lib, setup, knownBaker, createAddress, rpc }) => {

it('Estimate transfer to regular address with insufficient balance to pay storage for allocation', async () => {
await expect(
LowAmountTez.estimate.transfer({ to: await (await createAddress()).signer.publicKeyHash(), mutez: true, amount: amt - (1382 + DEFAULT_FEE.REVEAL) })
LowAmountTez.estimate.transfer({ to: await (await createAddress()).signer.publicKeyHash(), mutez: true, amount: amt - (1382 + getRevealFee(await LowAmountTez.signer.publicKeyHash())) })
).rejects.toEqual(
expect.objectContaining({
message: expect.stringContaining('storage_exhausted'),
Expand Down
5 changes: 0 additions & 5 deletions integration-tests/contract-simple-delegation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { CONFIGS } from "./config";
import { DEFAULT_FEE, DEFAULT_GAS_LIMIT } from "@taquito/taquito";

CONFIGS().forEach(({ lib, rpc, setup, knownBaker }) => {
const Tezos = lib;
Expand All @@ -15,16 +14,12 @@ CONFIGS().forEach(({ lib, rpc, setup, knownBaker }) => {
const op = await Tezos.contract.setDelegate({
delegate,
source: pkh,
fee: DEFAULT_FEE.DELEGATION,
gasLimit: DEFAULT_GAS_LIMIT.DELEGATION
})
await op.confirmation()
expect(op.hash).toBeDefined();
expect(op.includedInBlock).toBeLessThan(Number.POSITIVE_INFINITY);
expect(Number(op.consumedGas)).toBeGreaterThan(0);
expect(op.delegate).toEqual(delegate);
expect(op.fee).toEqual(DEFAULT_FEE.DELEGATION);
expect(op.gasLimit).toEqual(DEFAULT_GAS_LIMIT.DELEGATION);
expect(op.storageLimit).toEqual(0);
expect(op.isRegisterOperation).toBeFalsy();
expect(op.source).toEqual(pkh);
Expand Down
Loading

0 comments on commit c8bf8c7

Please sign in to comment.