Skip to content

Commit

Permalink
[Functions] Add Billing event (#11185)
Browse files Browse the repository at this point in the history
* FUN-974 - Add Billing event

* Add L1 fee share to billing event

* Update gas snapshot
  • Loading branch information
justinkaseman authored Nov 9, 2023
1 parent 5dea552 commit d8dc7ab
Show file tree
Hide file tree
Showing 5 changed files with 237 additions and 27 deletions.
44 changes: 23 additions & 21 deletions contracts/gas-snapshots/functions.gas-snapshot
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14497117)
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14497095)
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14497111)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14508531)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14508508)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14508480)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14508431)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14508420)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14508464)
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumGoerli() (gas: 14534216)
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumMainnet() (gas: 14534194)
ChainSpecificUtil__getCurrentTxL1GasFees_Arbitrum:test__getCurrentTxL1GasFees_SuccessWhenArbitrumSepolia() (gas: 14534210)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseGoerli() (gas: 14545630)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseMainnet() (gas: 14545607)
ChainSpecificUtil__getCurrentTxL1GasFees_Base:test__getCurrentTxL1GasFees_SuccessWhenBaseSepolia() (gas: 14545579)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismGoerli() (gas: 14545530)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismMainnet() (gas: 14545519)
ChainSpecificUtil__getCurrentTxL1GasFees_Optimism:test__getCurrentTxL1GasFees_SuccessWhenOptimismSepolia() (gas: 14545563)
FunctionsBilling_Constructor:test_Constructor_Success() (gas: 14812)
FunctionsBilling_DeleteCommitment:test_DeleteCommitment_RevertIfNotRouter() (gas: 13282)
FunctionsBilling_DeleteCommitment:test_DeleteCommitment_Success() (gas: 15897)
Expand All @@ -26,9 +26,11 @@ FunctionsBilling_OracleWithdrawAll:test_OracleWithdrawAll_SuccessPaysTransmitter
FunctionsBilling_UpdateConfig:test_UpdateConfig_RevertIfNotOwner() (gas: 18974)
FunctionsBilling_UpdateConfig:test_UpdateConfig_Success() (gas: 38251)
FunctionsBilling__DisperseFeePool:test__DisperseFeePool_RevertIfNotSet() (gas: 8801)
FunctionsBilling__FulfillAndBill:test__FulfillAndBill_RevertIfInvalidCommitment() (gas: 13302)
FunctionsBilling__FulfillAndBill:test__FulfillAndBill_Success() (gas: 180763)
FunctionsClient_Constructor:test_Constructor_Success() (gas: 7573)
FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 501740)
FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 202944)
FunctionsClient_FulfillRequest:test_FulfillRequest_MaximumGas() (gas: 504364)
FunctionsClient_FulfillRequest:test_FulfillRequest_MinimumGas() (gas: 205568)
FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_RevertIfNotRouter() (gas: 14623)
FunctionsClient_HandleOracleFulfillment:test_HandleOracleFulfillment_Success() (gas: 22923)
FunctionsClient__SendRequest:test__SendRequest_RevertIfInvalidCallbackGasLimit() (gas: 55059)
Expand All @@ -49,17 +51,17 @@ FunctionsRequest_DEFAULT_BUFFER_SIZE:test_DEFAULT_BUFFER_SIZE() (gas: 246)
FunctionsRequest_EncodeCBOR:test_EncodeCBOR_Success() (gas: 223)
FunctionsRequest_REQUEST_DATA_VERSION:test_REQUEST_DATA_VERSION() (gas: 225)
FunctionsRouter_Constructor:test_Constructor_Success() (gas: 12007)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174021)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164352)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedCostExceedsCommitment() (gas: 174037)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInsufficientGas() (gas: 164368)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidCommitment() (gas: 38115)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedInvalidRequestId() (gas: 35238)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182497)
FunctionsRouter_Fulfill:test_Fulfill_RequestNotProcessedSubscriptionBalanceInvariant() (gas: 182513)
FunctionsRouter_Fulfill:test_Fulfill_RevertIfNotCommittedCoordinator() (gas: 28086)
FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158041)
FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 323262)
FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 336879)
FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2512144)
FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 542628)
FunctionsRouter_Fulfill:test_Fulfill_RevertIfPaused() (gas: 158055)
FunctionsRouter_Fulfill:test_Fulfill_SuccessClientNoLongerExists() (gas: 327615)
FunctionsRouter_Fulfill:test_Fulfill_SuccessFulfilled() (gas: 341236)
FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackReverts() (gas: 2516517)
FunctionsRouter_Fulfill:test_Fulfill_SuccessUserCallbackRunsOutOfGas() (gas: 546996)
FunctionsRouter_GetAdminFee:test_GetAdminFee_Success() (gas: 17983)
FunctionsRouter_GetAllowListId:test_GetAllowListId_Success() (gas: 12904)
FunctionsRouter_GetConfig:test_GetConfig_Success() (gas: 37159)
Expand Down Expand Up @@ -142,8 +144,8 @@ FunctionsSubscriptions_GetTotalBalance:test_GetTotalBalance_Success() (gas: 1501
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoCalldata(uint96) (runs: 256, μ: 43685, ~: 45548)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNoSubscription(uint96) (runs: 256, μ: 46197, ~: 48060)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfCallerIsNotLink(uint96) (runs: 256, μ: 14295, ~: 14295)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51000, ~: 53040)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 85879, ~: 89604)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_RevertIfPaused(uint96) (runs: 256, μ: 51089, ~: 53040)
FunctionsSubscriptions_OnTokenTransfer:test_OnTokenTransfer_Success(uint96) (runs: 256, μ: 86057, ~: 89604)
FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfAmountMoreThanBalance() (gas: 20745)
FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfBalanceInvariant() (gas: 189)
FunctionsSubscriptions_OracleWithdraw:test_OracleWithdraw_RevertIfNoAmount() (gas: 15638)
Expand Down
19 changes: 18 additions & 1 deletion contracts/src/v0.8/functions/dev/v1_X/FunctionsBilling.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling {
using FunctionsResponse for FunctionsResponse.FulfillResult;

uint256 private constant REASONABLE_GAS_PRICE_CEILING = 1_000_000_000_000_000; // 1 million gwei

event RequestBilled(
bytes32 indexed requestId,
uint96 juelsPerGas,
uint256 l1FeeShareWei,
uint96 callbackCostJuels,
uint96 totalCostJuels
);

// ================================================================
// | Request Commitment state |
// ================================================================
Expand Down Expand Up @@ -268,12 +277,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling {
uint256 l1FeeShareWei = ChainSpecificUtil._getCurrentTxL1GasFees(msg.data) / reportBatchSize;
// Gas overhead without callback
uint96 gasOverheadJuels = _getJuelsFromWei(gasOverheadWei + l1FeeShareWei);
uint96 juelsPerGas = _getJuelsFromWei(tx.gasprice);

// The Functions Router will perform the callback to the client contract
(FunctionsResponse.FulfillResult resultCode, uint96 callbackCostJuels) = _getRouter().fulfill(
response,
err,
_getJuelsFromWei(tx.gasprice), // Juels Per Gas conversion rate
juelsPerGas,
gasOverheadJuels + commitment.donFee, // cost without callback or admin fee, those will be added by the Router
msg.sender,
commitment
Expand All @@ -292,6 +302,13 @@ abstract contract FunctionsBilling is Routable, IFunctionsBilling {
// Put donFee into the pool of fees, to be split later
// Saves on storage writes that would otherwise be charged to the user
s_feePool += commitment.donFee;
emit RequestBilled({
requestId: requestId,
juelsPerGas: juelsPerGas,
l1FeeShareWei: l1FeeShareWei,
callbackCostJuels: callbackCostJuels,
totalCostJuels: gasOverheadJuels + callbackCostJuels + commitment.donFee + commitment.adminFee
});
}

return resultCode;
Expand Down
52 changes: 50 additions & 2 deletions contracts/src/v0.8/functions/tests/v1_X/FunctionsBilling.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.19;
import {FunctionsCoordinator} from "../../dev/v1_X/FunctionsCoordinator.sol";
import {FunctionsBilling} from "../../dev/v1_X/FunctionsBilling.sol";
import {FunctionsRequest} from "../../dev/v1_X/libraries/FunctionsRequest.sol";
import {FunctionsResponse} from "../../dev/v1_X/libraries/FunctionsResponse.sol";
import {FunctionsSubscriptions} from "../../dev/v1_X/FunctionsSubscriptions.sol";
import {Routable} from "../../dev/v1_X/Routable.sol";

Expand Down Expand Up @@ -221,8 +222,55 @@ contract FunctionsBilling__StartBilling {
}

/// @notice #_fulfillAndBill
contract FunctionsBilling__FulfillAndBill {
// TODO: make contract internal function helper
contract FunctionsBilling__FulfillAndBill is FunctionsClientRequestSetup {
function test__FulfillAndBill_RevertIfInvalidCommitment() public {
vm.expectRevert();
s_functionsCoordinator.fulfillAndBill_HARNESS(
s_requests[1].requestId,
new bytes(0),
new bytes(0),
new bytes(0), // malformed commitment data
new bytes(0),
1
);
}

event RequestBilled(
bytes32 indexed requestId,
uint96 juelsPerGas,
uint256 l1FeeShareWei,
uint96 callbackCostJuels,
uint96 totalCostJuels
);

function test__FulfillAndBill_Success() public {
uint96 juelsPerGas = uint96((1e18 * TX_GASPRICE_START) / uint256(LINK_ETH_RATE));
uint96 callbackCostGas = 5072; // Taken manually
uint96 callbackCostJuels = juelsPerGas * callbackCostGas;
uint96 gasOverheadJuels = juelsPerGas *
(getCoordinatorConfig().gasOverheadBeforeCallback + getCoordinatorConfig().gasOverheadAfterCallback);

uint96 totalCostJuels = gasOverheadJuels + callbackCostJuels + s_donFee + s_adminFee;

// topic0 (function signature, always checked), check topic1 (true), NOT topic2 (false), NOT topic3 (false), and data (true).
bool checkTopic1 = true;
bool checkTopic2 = false;
bool checkTopic3 = false;
bool checkData = true;
vm.expectEmit(checkTopic1, checkTopic2, checkTopic3, checkData);
emit RequestBilled(s_requests[1].requestId, juelsPerGas, 0, callbackCostJuels, totalCostJuels);

FunctionsResponse.FulfillResult resultCode = s_functionsCoordinator.fulfillAndBill_HARNESS(
s_requests[1].requestId,
new bytes(0),
new bytes(0),
abi.encode(s_requests[1].commitment),
new bytes(0),
1
);

assertEq(uint256(resultCode), uint256(FunctionsResponse.FulfillResult.FULFILLED));
}
}

/// @notice #deleteCommitment
Expand Down
Loading

0 comments on commit d8dc7ab

Please sign in to comment.