# Protocol limit estimation

Certain actions in the protocol require looping over dynamic size arrays. To avoid hitting the block gas limit, special protocol limits were introduced which revert the transaction before the loop even starts. Values for these limits are then determined through estimation process, described here.

### Identifying the limits <a href="#identifying-the-limits" id="identifying-the-limits"></a>

First we identify which limits we use at the moment and which functions (or chain of functions) use them. The goal is to identify the external functions which can be called during the estimation.

#### List of limits <a href="#list-of-limits" id="list-of-limits"></a>

<table><thead><tr><th width="217.5">limit</th><th>used in</th><th>remarks</th></tr></thead><tbody><tr><td>maxExchangesPerBatch</td><td><strong>completeExchangeBatch</strong></td><td></td></tr><tr><td>maxOffersPerGroup</td><td>createGroupInternal -> <strong>createGroup</strong></td><td></td></tr><tr><td>maxOffersPerGroup</td><td>createGroupInternal -> <strong>createOfferWithCondition</strong></td><td>not a problem, always length 1</td></tr><tr><td>maxOffersPerGroup</td><td>preUpdateChecks -> addOffersToGroupInternal -> <strong>addOffersToGroup</strong></td><td></td></tr><tr><td>maxOffersPerGroup</td><td>preUpdateChecks -> addOffersToGroupInternal -> <strong>createOfferAddToGroup</strong></td><td>not a problem, always length 1</td></tr><tr><td>maxOffersPerGroup</td><td>preUpdateChecks -> <strong>removeOffersFromGroup</strong></td><td></td></tr><tr><td>maxOffersPerBundle</td><td>createBundleInternal -> <strong>createBundle</strong></td><td></td></tr><tr><td>maxOffersPerBundle</td><td>createBundleInternal -> <strong>createTwinAndBundleAfterOffer</strong></td><td>not a problem, always length 1</td></tr><tr><td>maxTwinsPerBundle</td><td>createBundleInternal -> <strong>createBundle</strong></td><td></td></tr><tr><td>maxTwinsPerBundle</td><td>createBundleInternal -> <strong>createTwinAndBundleAfterOffer</strong></td><td>not a problem, always length 1</td></tr><tr><td>maxOffersPerBatch</td><td><strong>createOfferBatch</strong></td><td></td></tr><tr><td>maxOffersPerBatch</td><td><strong>voidOfferBatch</strong></td><td></td></tr><tr><td>maxOffersPerBatch</td><td><strong>extendOfferBatch</strong></td><td></td></tr><tr><td>maxTokensPerWithdrawal</td><td>withdrawFundsInternal -> <strong>withdrawFunds</strong></td><td></td></tr><tr><td>maxTokensPerWithdrawal</td><td>withdrawFundsInternal -> <strong>withdrawProtocolFees</strong></td><td></td></tr><tr><td>maxFeesPerDisputeResolver</td><td><strong>createDisputeResolver</strong></td><td></td></tr><tr><td>maxFeesPerDisputeResolver</td><td><strong>addFeesToDisputeResolver</strong></td><td></td></tr><tr><td>maxFeesPerDisputeResolver</td><td><strong>removeFeesFromDisputeResolver</strong></td><td></td></tr><tr><td>maxDisputesPerBatch</td><td><strong>expireDisputeBatch</strong></td><td></td></tr><tr><td>maxAllowedSellers</td><td><strong>createDisputeResolver</strong></td><td></td></tr><tr><td>maxAllowedSellers</td><td><strong>addSellersToAllowList</strong></td><td></td></tr><tr><td>maxAllowedSellers</td><td><strong>removeSellersFromAllowList</strong></td><td></td></tr></tbody></table>

### Estimation config <a href="#estimation-config" id="estimation-config"></a>

Config file is placed in `scripts/config/limit-estimation.js`. It has the following fields:

* `blockGasLimit`: block gas limit against which you want to make the estimate
* `safeGasLimitPercent`: percent of total gas block limit that you consider safe for a transaction to actually be included in the block. For example if `blockGasLimit` is `30M` and you don't want your transaction to exceed `15M`, set `safeGasLimitPercent` to `50`.
* `maxArrayLength`: maximum length of the array used during the estimation. This value is typically smaller than actual limits calculated at the end. Increasing this value makes estimation more precise, however it also takes more time. Improvement in the estimate is increasing slower than run time, so setting this to `100` should be more than enough. If you want to speed up the process, setting this to `10` will still give you very good results.
* `limits`: list of limits you want to estimate. Each limit is an object with fields:
  * `name`: name of the limit
  * `methods`: object of pairs `"methodName":"handlerName"` where `methodName` is the name of the external function that uses the limit and `handlerName` is the name of the handler where this function is implemented. Example for limit `maxOffersPerGroup`:

    ```json
    {
      name: "maxOffersPerGroup",
      methods: {
        createGroup: "IBosonGroupHandler",
        addOffersToGroup: "IBosonGroupHandler",
        removeOffersFromGroup: "IBosonGroupHandler",
      },
    },
    ```

### Setting up the environment <a href="#setting-up-the-environment" id="setting-up-the-environment"></a>

For each of the limits you must prepare an evironment, before it can be tested. For example, before `maxOffersPerGroup` can be tested, protocol contracts must be deployed and enough offers must be created so the limit can actually be tested. A similar setup is needed for all other methods.

This is done in file `scripts/util/estimate-limits.js`. Each of the limits must have a setup function which accepts `maxArrayLength`, prepares the environment and returns the invocation details that can be then used when invoking the `methods` during the estimation.

Invocation details contain

* `account`: account that calls the method (important if access is restricted)
* `args`: array of arguments that needs to be passed into method
* `arrayIndex`: index that tells which parameter's length should be varied during the estimation
* `structField`: if array is part of a struct, specify the field name

The returned object must be in form `{ methodName_1: invocationDetails_1, methodName_2: invocationDetails_2, ..., methodName_n: invocationDetails_2}` with details for all methods specified in estimation config.

### Running the script <a href="#running-the-script" id="running-the-script"></a>

Scrip is run by calling

`npm run estimate-limits`

During the estimation it outputs the information about the method it is estimating. At the end it stores the estimation details into two files:

* `logs/limit_estimates.json` Data in JSON format
* `logs/limit_estimates.md` Data in MD table

### Results <a href="#results" id="results"></a>

The results for parameters

* `blockGasLimit`: `30,000,000` (current ethereum mainnet block gas limit)
* `safeGasLimitPercent`: `60`

| limit                     | max value | safe value |
| ------------------------- | --------: | ---------: |
| maxExchangesPerBatch      |       557 |        333 |
| maxOffersPerGroup         |       388 |        232 |
| maxOffersPerBundle        |       508 |        303 |
| maxTwinsPerBundle         |       510 |        304 |
| maxOffersPerBatch         |        51 |         31 |
| maxTokensPerWithdrawal    |       491 |        293 |
| maxFeesPerDisputeResolver |       305 |        181 |
| maxDisputesPerBatch       |       302 |        181 |
| maxAllowedSellers         |       597 |        352 |

`max value` is determined based on `blockGasLimit`, while safe value also applies `safeGasLimitPercent`.

#### Gas spent for different sizes of arrays <a href="#gas-spent-for-different-sizes-of-arrays" id="gas-spent-for-different-sizes-of-arrays"></a>

<table><thead><tr><th width="93.5">#</th><th align="right">maxExchangesPerBatch</th><th align="right">maxOffersPerGroup</th><th align="right">maxOffersPerGroup</th><th align="right">maxOffersPerGroup</th><th align="right">maxOffersPerBundle</th><th align="right">maxTwinsPerBundle</th><th align="right">maxOffersPerBatch</th><th align="right">maxOffersPerBatch</th><th align="right">maxOffersPerBatch</th><th align="right">maxTokensPerWithdrawal</th><th align="right">maxTokensPerWithdrawal</th><th align="right">maxFeesPerDisputeResolver</th><th align="right">maxFeesPerDisputeResolver</th><th align="right">maxFeesPerDisputeResolver</th><th align="right">maxDisputesPerBatch</th><th align="right">maxAllowedSellers</th><th align="right">maxAllowedSellers</th><th align="right">maxAllowedSellers</th></tr></thead><tbody><tr><td></td><td align="right">completeExchangeBatch</td><td align="right">createGroup</td><td align="right">addOffersToGroup</td><td align="right">removeOffersFromGroup</td><td align="right">createBundle</td><td align="right">createBundle</td><td align="right">createOfferBatch</td><td align="right">voidOfferBatch</td><td align="right">extendOfferBatch</td><td align="right">withdrawFunds</td><td align="right">withdrawProtocolFees</td><td align="right">createDisputeResolver</td><td align="right">addFeesToDisputeResolver</td><td align="right">removeFeesFromDisputeResolver</td><td align="right">expireDisputeBatch</td><td align="right">createDisputeResolver</td><td align="right">addSellersToAllowList</td><td align="right">removeSellersFromAllowList</td></tr><tr><td>1</td><td align="right">184357</td><td align="right">216179</td><td align="right">166813</td><td align="right">339950</td><td align="right">266339</td><td align="right">266339</td><td align="right">645410</td><td align="right">76369</td><td align="right">63841</td><td align="right">98246</td><td align="right">124263</td><td align="right">456727</td><td align="right">168014</td><td align="right">99325</td><td align="right">223643</td><td align="right">720355</td><td align="right">120611</td><td align="right">76720</td></tr><tr><td>2</td><td align="right">237945</td><td align="right">292824</td><td align="right">243899</td><td align="right">362917</td><td align="right">324373</td><td align="right">324237</td><td align="right">1220883</td><td align="right">111203</td><td align="right">85650</td><td align="right">144880</td><td align="right">193424</td><td align="right">552740</td><td align="right">264455</td><td align="right">145349</td><td align="right">322061</td><td align="right">769463</td><td align="right">169117</td><td align="right">99602</td></tr><tr><td>3</td><td align="right">290692</td><td align="right">369287</td><td align="right">319811</td><td align="right">385956</td><td align="right">382685</td><td align="right">382414</td><td align="right">1796358</td><td align="right">145208</td><td align="right">107442</td><td align="right">191521</td><td align="right">262643</td><td align="right">649449</td><td align="right">360736</td><td align="right">191089</td><td align="right">420849</td><td align="right">817790</td><td align="right">217760</td><td align="right">122522</td></tr><tr><td>4</td><td align="right">344271</td><td align="right">446010</td><td align="right">396802</td><td align="right">409687</td><td align="right">440789</td><td align="right">440369</td><td align="right">2371848</td><td align="right">179853</td><td align="right">129223</td><td align="right">238345</td><td align="right">330958</td><td align="right">745985</td><td align="right">457657</td><td align="right">236552</td><td align="right">519034</td><td align="right">866852</td><td align="right">266659</td><td align="right">145744</td></tr><tr><td>5</td><td align="right">397506</td><td align="right">522438</td><td align="right">473499</td><td align="right">432743</td><td align="right">498656</td><td align="right">498102</td><td align="right">2947330</td><td align="right">213982</td><td align="right">150777</td><td align="right">284285</td><td align="right">399900</td><td align="right">842313</td><td align="right">553655</td><td align="right">282583</td><td align="right">617217</td><td align="right">915916</td><td align="right">315181</td><td align="right">168453</td></tr><tr><td>6</td><td align="right">450933</td><td align="right">599145</td><td align="right">549901</td><td align="right">455724</td><td align="right">556830</td><td align="right">556142</td><td align="right">3522863</td><td align="right">248993</td><td align="right">172476</td><td align="right">330931</td><td align="right">468759</td><td align="right">939354</td><td align="right">650340</td><td align="right">327624</td><td align="right">716072</td><td align="right">964978</td><td align="right">364020</td><td align="right">191603</td></tr><tr><td>7</td><td align="right">504557</td><td align="right">675705</td><td align="right">626011</td><td align="right">478855</td><td align="right">615481</td><td align="right">614658</td><td align="right">4098400</td><td align="right">282740</td><td align="right">194322</td><td align="right">377398</td><td align="right">538021</td><td align="right">1038389</td><td align="right">746851</td><td align="right">373526</td><td align="right">814350</td><td align="right">1015980</td><td align="right">412672</td><td align="right">214102</td></tr><tr><td>8</td><td align="right">557350</td><td align="right">752116</td><td align="right">703168</td><td align="right">502121</td><td align="right">673490</td><td align="right">672532</td><td align="right">4673951</td><td align="right">317493</td><td align="right">216313</td><td align="right">423687</td><td align="right">606770</td><td align="right">1135642</td><td align="right">843190</td><td align="right">418787</td><td align="right">912629</td><td align="right">1065136</td><td align="right">462015</td><td align="right">237182</td></tr><tr><td>9</td><td align="right">610704</td><td align="right">829174</td><td align="right">779581</td><td align="right">525383</td><td align="right">731386</td><td align="right">730295</td><td align="right">5289900</td><td align="right">351745</td><td align="right">237643</td><td align="right">470697</td><td align="right">675733</td><td align="right">1232882</td><td align="right">940232</td><td align="right">464621</td><td align="right">1013746</td><td align="right">1114293</td><td align="right">510385</td><td align="right">260262</td></tr><tr><td>10</td><td align="right">664157</td><td align="right">905366</td><td align="right">855847</td><td align="right">548648</td><td align="right">789928</td><td align="right">788700</td><td align="right">5869922</td><td align="right">386681</td><td align="right">259853</td><td align="right">516720</td><td align="right">744561</td><td align="right">1325047</td><td align="right">1039257</td><td align="right">510454</td><td align="right">1112302</td><td align="right">1163448</td><td align="right">559101</td><td align="right">283342</td></tr><tr><td>20</td><td align="right">1199674</td><td align="right">1672031</td><td align="right">1622868</td><td align="right">780097</td><td align="right">1371424</td><td align="right">1368854</td><td align="right">11585194</td><td align="right">730484</td><td align="right">476329</td><td align="right">981216</td><td align="right">1435505</td><td align="right">2293894</td><td align="right">2003996</td><td align="right">966566</td><td align="right">2097899</td><td align="right">1648704</td><td align="right">1050125</td><td align="right">511799</td></tr><tr><td>30</td><td align="right">1731595</td><td align="right">2440464</td><td align="right">2391564</td><td align="right">1012387</td><td align="right">1955241</td><td align="right">1951326</td><td align="right">17350904</td><td align="right">1078743</td><td align="right">693892</td><td align="right">1446838</td><td align="right">2126474</td><td align="right">3256561</td><td align="right">2967075</td><td align="right">1424971</td><td align="right">3083565</td><td align="right">2138411</td><td align="right">1535807</td><td align="right">740419</td></tr><tr><td>40</td><td align="right">2271836</td><td align="right">3202792</td><td align="right">3154246</td><td align="right">1244680</td><td align="right">2539116</td><td align="right">2533856</td><td align="right">23112733</td><td align="right">1423827</td><td align="right">911454</td><td align="right">1913450</td><td align="right">2817507</td><td align="right">4248050</td><td align="right">3934100</td><td align="right">1882668</td><td align="right">4069301</td><td align="right">2628126</td><td align="right">2025507</td><td align="right">969085</td></tr><tr><td>50</td><td align="right">2800719</td><td align="right">3969835</td><td align="right">3921550</td><td align="right">1476974</td><td align="right">3117065</td><td align="right">3110472</td><td align="right">28911628</td><td align="right">1768963</td><td align="right">1135500</td><td align="right">2380130</td><td align="right">3503226</td><td align="right">5220856</td><td align="right">4929416</td><td align="right">2340381</td><td align="right">5055106</td><td align="right">3111881</td><td align="right">2515218</td><td align="right">1199241</td></tr><tr><td>60</td><td align="right">3333793</td><td align="right">4764194</td><td align="right">4715895</td><td align="right">1542105</td><td align="right">3699938</td><td align="right">3692002</td><td align="right"></td><td align="right">2114152</td><td align="right">1353506</td><td align="right">2841377</td><td align="right">3983943</td><td align="right">6192222</td><td align="right">5902160</td><td align="right">2409313</td><td align="right">6040982</td><td align="right">3600680</td><td align="right">2999184</td><td align="right">1220202</td></tr><tr><td>70</td><td align="right">3866927</td><td align="right">5535734</td><td align="right">5487697</td><td align="right">1607235</td><td align="right">4307529</td><td align="right">4298195</td><td align="right"></td><td align="right">2459395</td><td align="right">1566348</td><td align="right">3307259</td><td align="right">4471569</td><td align="right">7137316</td><td align="right">6853941</td><td align="right">2478233</td><td align="right">7030675</td><td align="right">4113038</td><td align="right">3487977</td><td align="right">1241164</td></tr><tr><td>80</td><td align="right">4424168</td><td align="right">6302543</td><td align="right">6256137</td><td align="right">1672369</td><td align="right">4893873</td><td align="right">4883188</td><td align="right"></td><td align="right">2804690</td><td align="right">1783781</td><td align="right">3773180</td><td align="right">4953126</td><td align="right">8125585</td><td align="right">7799011</td><td align="right">2547183</td><td align="right">8046950</td><td align="right">4604672</td><td align="right">3976781</td><td align="right">1262132</td></tr><tr><td>90</td><td align="right">4960338</td><td align="right">7052123</td><td align="right">7005985</td><td align="right">1737566</td><td align="right">5480275</td><td align="right">5468239</td><td align="right"></td><td align="right">3144491</td><td align="right">2001293</td><td align="right">4263556</td><td align="right">5434728</td><td align="right">9068993</td><td align="right">8785898</td><td align="right">2616114</td><td align="right">9014128</td><td align="right">5096317</td><td align="right">4491310</td><td align="right">1283105</td></tr><tr><td>100</td><td align="right">5496569</td><td align="right">7801814</td><td align="right">7755932</td><td align="right">1802826</td><td align="right">6066735</td><td align="right">6053349</td><td align="right"></td><td align="right">3489284</td><td align="right">2218882</td><td align="right">4732249</td><td align="right">5916387</td><td align="right">10051836</td><td align="right">9729258</td><td align="right">2685059</td><td align="right">9977691</td><td align="right">5587972</td><td align="right">4982950</td><td align="right">1304081</td></tr><tr><td><strong>max</strong></td><td align="right"><strong>557</strong></td><td align="right"><strong>388</strong></td><td align="right"><strong>389</strong></td><td align="right"><strong>1733</strong></td><td align="right"><strong>508</strong></td><td align="right"><strong>510</strong></td><td align="right"><strong>51</strong></td><td align="right"><strong>868</strong></td><td align="right"><strong>1375</strong></td><td align="right"><strong>641</strong></td><td align="right"><strong>491</strong></td><td align="right"><strong>305</strong></td><td align="right"><strong>309</strong></td><td align="right"><strong>932</strong></td><td align="right"><strong>302</strong></td><td align="right"><strong>597</strong></td><td align="right"><strong>610</strong></td><td align="right"><strong>1906</strong></td></tr><tr><td>safe</td><td align="right">333</td><td align="right">232</td><td align="right">232</td><td align="right">1031</td><td align="right">303</td><td align="right">304</td><td align="right">31</td><td align="right">520</td><td align="right">824</td><td align="right">384</td><td align="right">293</td><td align="right">181</td><td align="right">185</td><td align="right">557</td><td align="right">181</td><td align="right">352</td><td align="right">365</td><td align="right">1141</td></tr></tbody></table>

### Methodology <a href="#methodology" id="methodology"></a>

As seen from the results above, some limits are relatively high and to actually hit the limit, already the setup would take a lot of time (e.g. for making `>1700` offers to hit limit in `removeOffersFromGroup`). To get the estimates we therefore use the following approach:

* get the actual estimates for relatively small number of different array lengths
* given how gas is determined, there exist approximate linear relation, which can be written as `gasSpent = intrinsicGas + arrayLength*costPerLoop`. Intrinsic costs here contains all costs that are fixed regardless of the array size.
* use linear regression to estimate `intrinsicGas` and `costPerLoop`
* use these estimates to calculate the biggest `arrayLength` where `gasSpent <= blockGasLimit` which gives the maximum value. To get the safe value we find the biggest `arrayLength` where `gasSpent <= safeGasLimitPercent*blockGasLimit`


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.bosonprotocol.io/v2.4.2/legacy-docs/technical-documentation/smart-contracts/protocol-limit-estimation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
