-
Notifications
You must be signed in to change notification settings - Fork 624
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat/test(CL Swaps): Swap fees for amount out given in #4097
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
67661ec
feat/test(CL Swaps): Swap fees for amount out given in
p0mvn 3b0a19e
clean up
p0mvn 29d53be
Update scripts/cl/common.py
p0mvn 265879a
reduce diff
p0mvn 8e7ba88
clean up
p0mvn b2db7d3
remove prints
p0mvn 3b26bc9
reduce diff
p0mvn 360c30e
clean up
p0mvn 34841a0
change name
p0mvn cf99ea7
Update x/concentrated-liquidity/fees.go
p0mvn a84d66d
fix
p0mvn 3b8da5a
clean up
p0mvn 3df2018
Update scripts/cl/common.py
p0mvn bbf188c
comment and round up
p0mvn 3b29850
docs
p0mvn File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Concentrated Liquidity Test Case Estimate Scripts | ||
|
||
## Context | ||
|
||
These scripts exist to estimate the results of the swap | ||
concentrated liqudity test cases. | ||
|
||
Each existing test case is estimated by calling the | ||
respective function in `scripts/cl/main.py` main function. | ||
|
||
The function defining a swap test case specifies which | ||
CL go test case it estimates. See the spec for details. | ||
|
||
## Running the scripts | ||
|
||
To run with sage installed: | ||
```bash | ||
sage -python scripts/cl/main.py | ||
``` | ||
|
||
Note, these scripts can also be run by installing `sympy` without sage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import sympy as sp | ||
|
||
precision = 30 | ||
|
||
# SqrtPriceRange represents a price range between the current and the next tick | ||
# as well as the liquidity in that price range. | ||
# When swapping token zero for one, sqrt_price_current >= sqrt_price_next. | ||
# When swapping token one for zero, sqrt_price_current <= sqrt_price_next. | ||
# | ||
# sqrt_price_next can be None. When it is None, that implies that the next sqrt | ||
# price must be calculated. In such a case, next sqrt price depends on the | ||
# remaining amount of token in to be swapped. This occurs for the last sqrt price | ||
# range in the collection of sqrt price ranges that represent a swap. | ||
# | ||
# For example, I might have a swap of 100 ETH in from 5000 to 5001 with liquidity | ||
# X, from 5001 to 5002 with liquidity Y, | ||
# and from 5002 to UNKNOWN with liquidity Z. In this case, the UNKNOWN | ||
# depends on how much ETH we have remaining after consuming liquidity X and Y. | ||
class SqrtPriceRange: | ||
def __init__(self, sqrt_price_current: int, sqrt_price_next: int, liquidity: sp.Float): | ||
self.sqrt_price_start = sp.sqrt(fixed_prec_dec(sqrt_price_current)) | ||
if sqrt_price_next is not None: | ||
self.sqrt_price_next = sp.sqrt(fixed_prec_dec(sqrt_price_next)) | ||
else: | ||
self.sqrt_price_next = None | ||
self.liquidity = liquidity | ||
|
||
def fixed_prec_dec(string: str) -> sp.Float: | ||
""" Return an equivalent of a Python Decimal with fixed precision. | ||
""" | ||
return sp.Float(string, precision) | ||
|
||
def get_fee_amount_per_share(token_in: sp.Float, swap_fee: sp.Float, liquidity: sp.Float) -> sp.Float: | ||
""" Returns the fee amount per share. | ||
""" | ||
fee_charge_total = token_in * swap_fee | ||
return fee_charge_total / liquidity | ||
|
||
zero = fixed_prec_dec("0") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
from typing import Tuple | ||
from common import * | ||
import zero_for_one as zfo | ||
import one_for_zero as ofz | ||
|
||
def estimate_test_case(tick_ranges: list[SqrtPriceRange], token_in_initial: sp.Float, swap_fee: sp.Float, is_zero_for_one: bool) -> Tuple[sp.Float, sp.Float]: | ||
""" Estimates a calc concentrated liquidity test case. | ||
|
||
Given | ||
- sqrt price range with the start sqrt price, next sqrt price and liquidity | ||
- initial token in | ||
- swap fee | ||
- zero for one boolean flag | ||
Estimates the final token out and the fee growth per share and prints it to stdout. | ||
Also, estimates these and other values at each range and prints them to stdout. | ||
|
||
Returns the total token out and the total fee growth per share. | ||
""" | ||
|
||
token_in_consumed_total, token_out_total, fee_growth_per_share_total = zero, zero, zero | ||
|
||
for i in range(len(tick_ranges)): | ||
tick_range = tick_ranges[i] | ||
|
||
# Normally, for the last swap range we swap until token in runs out | ||
# As a result, the next sqrt price for that range calculated at runtime. | ||
is_last_range = i == len(tick_ranges) - 1 | ||
# Except for the cases where we set price limit explicitly. Then, the | ||
# last price range may have the upper sqrt price limit configured. | ||
is_next_price_set = tick_range.sqrt_price_next != None | ||
|
||
is_with_next_sqrt_price = not is_last_range or is_next_price_set | ||
|
||
if is_with_next_sqrt_price: | ||
token_in_consumed, token_out, fee_growth_per_share = zero, zero, zero | ||
if is_zero_for_one: | ||
token_in_consumed, token_out, fee_growth_per_share = zfo.calc_test_case_with_next_sqrt_price(tick_range.liquidity, tick_range.sqrt_price_start, tick_range.sqrt_price_next, swap_fee) | ||
else: | ||
token_in_consumed, token_out, fee_growth_per_share = ofz.calc_test_case_with_next_sqrt_price(tick_range.liquidity, tick_range.sqrt_price_start, tick_range.sqrt_price_next, swap_fee) | ||
|
||
token_in_consumed_total += token_in_consumed | ||
token_out_total += token_out | ||
fee_growth_per_share_total += fee_growth_per_share | ||
|
||
else: | ||
token_in_remaining = token_in_initial - token_in_consumed_total | ||
|
||
if token_in_remaining < zero: | ||
raise Exception(F"token_in_remaining {token_in_remaining} is negative with token_in_initial {token_in_initial} and token_in_consumed_total {token_in_consumed_total}") | ||
|
||
token_out, fee_growth_per_share = zero, zero | ||
if is_zero_for_one: | ||
_, token_out, fee_growth_per_share = zfo.calc_test_case(tick_range.liquidity, tick_range.sqrt_price_start, token_in_remaining, swap_fee) | ||
else: | ||
_, token_out, fee_growth_per_share = ofz.calc_test_case(tick_range.liquidity, tick_range.sqrt_price_start, token_in_remaining, swap_fee) | ||
|
||
token_out_total += token_out | ||
fee_growth_per_share_total += fee_growth_per_share | ||
print("\n") | ||
print(F"After processing range {i}") | ||
print(F"current token_out_total: {token_out_total}") | ||
print(F"current current fee_growth_per_share_total: {fee_growth_per_share_total}") | ||
print("\n\n\n") | ||
|
||
print("\n\n") | ||
print("Final results:") | ||
print("token_out_total: ", token_out_total) | ||
print("fee_growth_per_share_total: ", fee_growth_per_share_total) | ||
|
||
return token_out_total, fee_growth_per_share_total | ||
|
||
def validate_confirmed_results(token_out_total: sp.Float, fee_growth_per_share_total: sp.Float, expected_token_out_total: sp.Float, expected_fee_growth_per_share_total: sp.Float): | ||
"""Validates the results of a calc concentrated liquidity test case estimates. | ||
|
||
This validation helper exists to make sure that subsequent changes to the script do not break test cases. | ||
""" | ||
|
||
if sp.N(token_out_total, 18) != sp.N(expected_token_out_total, 18): | ||
raise Exception(F"token_out_total {token_out_total} does not match expected_token_out_total {expected_token_out_total}") | ||
|
||
if sp.N(fee_growth_per_share_total, 18) != sp.N(expected_fee_growth_per_share_total, 18): | ||
raise Exception(F"fee_growth_per_share_total {fee_growth_per_share_total} does not match expected_fee_growth_per_share_total {expected_fee_growth_per_share_total}") | ||
|
||
def estimate_single_position_within_one_tick_ofz(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with a single position within one tick | ||
when swapping token one for token zero (ofz). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_1 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = False | ||
swap_fee = fixed_prec_dec("0.01") | ||
token_in_initial = fixed_prec_dec("42000000") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, None, fixed_prec_dec("1517882343.751510418088349649")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("8312.77961614650590788243077782") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.000276701288297452775064000000017") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_two_positions_within_one_tick_zfo(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with two positions within one tick | ||
when swapping token zero for one (zfo). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_2 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = True | ||
swap_fee = fixed_prec_dec("0.03") | ||
token_in_initial = fixed_prec_dec("13370") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, None, fixed_prec_dec("3035764687.503020836176699298")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("64824917.7760329489344598324379") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.000000132124865162033700093060000008") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_two_consecutive_positions_zfo(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with two consecutive positions | ||
when swapping token zero for one (zfo). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_3 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = True | ||
swap_fee = fixed_prec_dec("0.05") | ||
token_in_initial = fixed_prec_dec("2000000") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, 4545, fixed_prec_dec("1517882343.751510418088349649")), | ||
SqrtPriceRange(4545, None, fixed_prec_dec("1198735489.597250295669959398")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("8702563350.03654978407909736170") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.0000720353033851801313478676884502") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_overlapping_price_range_ofz_test(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with overlapping price ranges | ||
when swapping token one for token zero (ofz). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_4 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = False | ||
swap_fee = fixed_prec_dec("0.1") | ||
token_in_initial = fixed_prec_dec("10000000000") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, 5001, fixed_prec_dec("1517882343.751510418088349649")), | ||
SqrtPriceRange(5001, 5500, fixed_prec_dec("2188298432.35717914512760058700")), | ||
SqrtPriceRange(5500, None, fixed_prec_dec("670416088.605668727039250938")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("1708743.47809184831586199935191") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.598328101473707318285291820984") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_overlapping_price_range_zfo_test(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with overlapping price ranges | ||
when swapping token zero for one (zfo) and not consuming full liquidity of the second position. | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_5 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = True | ||
swap_fee = fixed_prec_dec("0.005") | ||
token_in_initial = fixed_prec_dec("1800000") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, 4999, fixed_prec_dec("1517882343.751510418088349649")), | ||
SqrtPriceRange(4999, 4545, fixed_prec_dec("1517882343.751510418088349649") + fixed_prec_dec("670416215.718827443660400594")), # first and second position's liquidity. | ||
SqrtPriceRange(4545, None, fixed_prec_dec("670416215.718827443660400594")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("8440821620.46523833169832895388") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.00000555275275702765744105956374059") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_consecutive_positions_gap_ofz_test(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with consecutive positions with a gap | ||
when swapping token one for zero (ofz). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_6 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = False | ||
swap_fee = fixed_prec_dec("0.03") | ||
token_in_initial = fixed_prec_dec("10000000000") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, 5500, fixed_prec_dec("1517882343.751510418088349649")), | ||
SqrtPriceRange(5501, None, fixed_prec_dec("1199528406.187413669220037261")), # last one must be computed based on remaining token in, therefore it is None | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("1772029.65214390801589935811000") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.218688507910948644574193665912") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def estimate_slippage_protection_zfo_test(): | ||
"""Estimates and prints the results of a calc concentrated liquidity test case with slippage protection | ||
when swapping token zero for one (zfo). | ||
|
||
go test -timeout 30s -v -run TestKeeperTestSuite/TestCalcAndSwapOutAmtGivenIn/fee_7 github.com/osmosis-labs/osmosis/v14/x/concentrated-liquidity | ||
""" | ||
|
||
is_zero_for_one = True | ||
swap_fee = fixed_prec_dec("0.01") | ||
token_in_initial = fixed_prec_dec("13370") | ||
|
||
tick_ranges = [ | ||
SqrtPriceRange(5000, 4994, fixed_prec_dec("1517882343.751510418088349649")), | ||
] | ||
|
||
token_out_total, fee_growth_per_share_total = estimate_test_case(tick_ranges, token_in_initial, swap_fee, is_zero_for_one) | ||
|
||
expected_token_out_total = fixed_prec_dec("64417624.9871649525380486017974") | ||
expected_fee_growth_per_share_total = fixed_prec_dec("0.0000000849292577225588233432564611676") | ||
|
||
validate_confirmed_results(token_out_total, fee_growth_per_share_total, expected_token_out_total, expected_fee_growth_per_share_total) | ||
|
||
def main(): | ||
# fee 1 | ||
estimate_single_position_within_one_tick_ofz() | ||
|
||
# fee 2 | ||
estimate_two_positions_within_one_tick_zfo() | ||
|
||
# fee 3 | ||
estimate_two_consecutive_positions_zfo() | ||
|
||
# fee 4 | ||
estimate_overlapping_price_range_ofz_test() | ||
|
||
# fee 5 | ||
estimate_overlapping_price_range_zfo_test() | ||
|
||
# fee 6 | ||
estimate_consecutive_positions_gap_ofz_test() | ||
|
||
# fee 7 | ||
estimate_slippage_protection_zfo_test() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import sympy as sp | ||
|
||
def calc_liquidity_0(amount_zero: sp.Float, sqrtPriceA: sp.Float, sqrtPriceB: sp.Float) -> sp.Float: | ||
"""Calculates and returns liquidity zero. | ||
""" | ||
return amount_zero * (sqrtPriceA * sqrtPriceB) / (sqrtPriceB - sqrtPriceA) | ||
|
||
def calc_liquidity_1(amount_one: sp.Float, sqrtPriceA: sp.Float, sqrtPriceB: sp.Float) -> sp.Float: | ||
"""Calculates and returns liquidity one. | ||
""" | ||
return amount_one * (sqrtPriceB - sqrtPriceA) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
from typing import Tuple | ||
import sympy as sp | ||
from common import * | ||
|
||
def get_next_sqrt_price(liquidity: sp.Float, sqrt_price_current: sp.Float, token_in: sp.Float, swap_fee: sp.Float) -> sp.Float: | ||
""" Return the next sqrt price when swapping token one for zero. | ||
""" | ||
return sqrt_price_current + (token_in * (1 - swap_fee) / liquidity) | ||
|
||
def get_token_out(liquidity: sp.Float, sqrt_price_current: sp.Float, sqrt_price_next: sp.Float) -> sp.Float: | ||
""" Returns the token out when swapping token one for zero. | ||
""" | ||
return liquidity * (sqrt_price_next - sqrt_price_current) / (sqrt_price_next * sqrt_price_current) | ||
|
||
def get_expected_token_in(liquidity: sp.Float, sqrt_price_current: sp.Float, sqrt_price_next: sp.Float): | ||
""" Returns the expected token in when swapping token one for zero. | ||
""" | ||
return liquidity * sp.Abs((sqrt_price_current - sqrt_price_next)) | ||
|
||
def calc_test_case(liquidity: sp.Float, sqrt_price_current: sp.Float, token_in: sp.Float, swap_fee: sp.Float) -> Tuple[sp.Float, sp.Float, sp.Float]: | ||
""" Computes and prints all one for zero test case parameters. Next sqrt price is computed from the given parameters. | ||
|
||
Returns the next square root price, token out and fee amount per share. | ||
""" | ||
sqrt_price_next = get_next_sqrt_price(liquidity, sqrt_price_current, token_in, swap_fee) | ||
price_next = sp.Pow(sqrt_price_next, 2) | ||
token_out = get_token_out(liquidity, sqrt_price_current, sqrt_price_next) | ||
fee_amount_per_share = get_fee_amount_per_share(token_in, swap_fee, liquidity) | ||
|
||
print(F"sqrt_price_next: {sqrt_price_next}") | ||
print(F"price_next: {price_next}") | ||
print(F"token_out: {token_out}") | ||
print(F"fee_amount_per_share: {fee_amount_per_share}") | ||
|
||
return sqrt_price_next, token_out, fee_amount_per_share | ||
|
||
def calc_test_case_with_next_sqrt_price(liquidity: sp.Float, sqrt_price_current: sp.Float, sqrt_price_next: sp.Float, swap_fee: sp.Float) -> Tuple[sp.Float, sp.Float, sp.Float]: | ||
""" Computes and prints one for zero test case parameters when next square root price is known. | ||
|
||
Returns the expected token in, token out and fee amount per share. | ||
""" | ||
price_next = sp.Pow(sqrt_price_next, 2) | ||
expected_token_in_before_fee = get_expected_token_in(liquidity, sqrt_price_current, sqrt_price_next) | ||
expected_token_in = expected_token_in_before_fee * (1 + swap_fee) | ||
|
||
token_out = get_token_out(liquidity, sqrt_price_current, sqrt_price_next) | ||
fee_amount_per_share = get_fee_amount_per_share(expected_token_in_before_fee, swap_fee, liquidity) | ||
|
||
print(F"given sqrt_price_next: {sqrt_price_next}") | ||
print(F"price_next: {price_next}") | ||
print(F"expected_token_in: {expected_token_in}") | ||
print(F"token_out: {token_out}") | ||
print(F"fee_amount_per_share: {fee_amount_per_share}") | ||
|
||
return expected_token_in, token_out, fee_amount_per_share |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: For scripts, I suggest reviewing this file in-detail and comparing it against Go test cases. However, I don't think there is value in reviewing other internal script calculations so feel free to skip