Skip to content

Commit

Permalink
support decimals
Browse files Browse the repository at this point in the history
  • Loading branch information
shileiwill committed Apr 17, 2024
1 parent 6b0a7af commit f9d6306
Show file tree
Hide file tree
Showing 14 changed files with 101 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-dancers-flow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

support decimals #added
5 changes: 5 additions & 0 deletions .changeset/loud-peaches-beg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

support decimals #added
5 changes: 5 additions & 0 deletions contracts/.changeset/heavy-horses-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@chainlink/contracts": patch
---

support decimals #added

Large diffs are not rendered by default.

30 changes: 20 additions & 10 deletions contracts/src/v0.8/automation/dev/test/AutomationRegistry2_3.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_000,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 2_000_000_000, // $20
minSpend: 100_000
minSpend: 100_000,
decimals: 18
});

bytes memory onchainConfigBytes = abi.encode(cfg);
Expand Down Expand Up @@ -425,14 +426,16 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_001,
priceFeed: 0x2222222222222222222222222222222222222221,
fallbackPrice: 100,
minSpend: 100
minSpend: 100,
decimals: 18
});
billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: 5_002,
flatFeeMilliCents: 20_002,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 200,
minSpend: 200
minSpend: 200,
decimals: 18
});

bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs);
Expand Down Expand Up @@ -485,7 +488,8 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_001,
priceFeed: 0x2222222222222222222222222222222222222221,
fallbackPrice: 100,
minSpend: 100
minSpend: 100,
decimals: 18
});

bytes memory onchainConfigBytesWithBilling1 = abi.encode(cfg, billingTokens1, billingConfigs1);
Expand All @@ -501,7 +505,8 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_002,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 200,
minSpend: 200
minSpend: 200,
decimals: 18
});

bytes memory onchainConfigBytesWithBilling2 = abi.encode(cfg, billingTokens2, billingConfigs2);
Expand Down Expand Up @@ -559,14 +564,16 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_001,
priceFeed: 0x2222222222222222222222222222222222222221,
fallbackPrice: 100,
minSpend: 100
minSpend: 100,
decimals: 18
});
billingConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: 5_002,
flatFeeMilliCents: 20_002,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 200,
minSpend: 200
minSpend: 200,
decimals: 18
});

bytes memory onchainConfigBytesWithBilling = abi.encode(cfg, billingTokens, billingConfigs);
Expand All @@ -593,7 +600,8 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_000,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 2_000_000_000, // $20
minSpend: 100_000
minSpend: 100_000,
decimals: 18
});

// deploy registry with OFF_CHAIN payout mode
Expand Down Expand Up @@ -628,7 +636,8 @@ contract SetConfig is SetUp {
flatFeeMilliCents: 20_000,
priceFeed: 0x2222222222222222222222222222222222222222,
fallbackPrice: 2_000_000_000, // $20
minSpend: 100_000
minSpend: 100_000,
decimals: 18
});

bytes memory onchainConfigBytes = abi.encode(cfg);
Expand Down Expand Up @@ -1042,7 +1051,8 @@ contract NOPsSettlement is SetUp {
flatFeeMilliCents: 2_000, // 2 cents
priceFeed: address(USDTOKEN_USD_FEED),
fallbackPrice: 100_000_000, // $1
minSpend: 1000000000000000000 // 1 USD
minSpend: 1000000000000000000, // 1 USD
decimals: 18
});

address[] memory registrars = new address[](1);
Expand Down
9 changes: 6 additions & 3 deletions contracts/src/v0.8/automation/dev/test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -173,21 +173,24 @@ contract BaseTest is Test {
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(USDTOKEN_USD_FEED),
fallbackPrice: 100_000_000, // $1
minSpend: 1000000000000000000 // 1 USD
minSpend: 1000000000000000000, // 1 USD
decimals: 18
});
billingTokenConfigs[1] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: DEFAULT_GAS_FEE_PPB, // 15%
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(NATIVE_USD_FEED),
fallbackPrice: 100_000_000, // $1
minSpend: 5000000000000000000 // 5 Native
minSpend: 5000000000000000000, // 5 Native
decimals: 18
});
billingTokenConfigs[2] = AutomationRegistryBase2_3.BillingConfig({
gasFeePPB: DEFAULT_GAS_FEE_PPB, // 10%
flatFeeMilliCents: DEFAULT_FLAT_FEE_MILLI_CENTS, // 2 cents
priceFeed: address(LINK_USD_FEED),
fallbackPrice: 1_000_000_000, // $10
minSpend: 1000000000000000000 // 1 LINK
minSpend: 1000000000000000000, // 1 LINK
decimals: 18
});

if (payoutMode == AutoBase.PayoutMode.OFF_CHAIN) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
uint32 gasFeePPB;
uint24 flatFeeMilliCents; // min fee is $0.00001, max fee is $167
AggregatorV3Interface priceFeed;
uint8 decimals;
// 1st word, read in calculating BillingTokenPaymentParams
uint256 fallbackPrice;
// 2nd word only read if stale
Expand All @@ -395,6 +396,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
* @dev this is a memory-only struct, so struct packing is less important
*/
struct BillingTokenPaymentParams {
uint8 decimals;
uint32 gasFeePPB;
uint24 flatFeeMilliCents;
uint256 priceUSD;
Expand Down Expand Up @@ -426,8 +428,8 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {

/**
* @notice struct containing receipt information about a payment or cost estimation
* @member gasCharge the amount to charge a user for gas spent
* @member premium the premium charged to the user, shared between all nodes
* @member gasCharge the amount to charge a user for gas spent using the billing token's native decimals
* @member premium the premium charged to the user, shared between all nodes, using the billing token's native decimals
* @member gasReimbursementJuels the amount to reimburse a node for gas spent
* @member premiumJuels the premium paid to NOPs, shared between all nodes
*/
Expand Down Expand Up @@ -633,6 +635,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
BillingConfig storage config = s_billingConfigs[billingToken];
paymentParams.flatFeeMilliCents = config.flatFeeMilliCents;
paymentParams.gasFeePPB = config.gasFeePPB;
paymentParams.decimals = config.decimals;
(, int256 feedValue, , uint256 timestamp, ) = config.priceFeed.latestRoundData();
if (
feedValue <= 0 ||
Expand Down Expand Up @@ -660,6 +663,7 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
HotVars memory hotVars,
PaymentParams memory paymentParams
) internal view returns (PaymentReceipt memory receipt) {
uint8 decimals = paymentParams.billingTokenParams.decimals;
uint256 gasWei = paymentParams.fastGasWei * hotVars.gasCeilingMultiplier;
// in case it's actual execution use actual gas price, capped by fastGasWei * gasCeilingMultiplier
if (paymentParams.isTransaction && tx.gasprice < gasWei) {
Expand All @@ -669,13 +673,29 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
uint256 gasPaymentHexaicosaUSD = (gasWei *
(paymentParams.gasLimit + paymentParams.gasOverhead) +
paymentParams.l1CostWei) * paymentParams.nativeUSD; // gasPaymentHexaicosaUSD has an extra 8 zeros because of decimals on nativeUSD feed
receipt.gasCharge = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); // has units of attoBillingToken, or "wei"

uint96 gasCharge18Decimals = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); // has units of attoBillingToken, or "wei"
receipt.gasCharge = gasCharge18Decimals;
if (decimals < 18) {
receipt.gasCharge = SafeCast.toUint96(gasCharge18Decimals / (10 ** (18 - decimals)));
} else if (decimals > 18) {
receipt.gasCharge = SafeCast.toUint96(gasCharge18Decimals * (10 ** (decimals - 18)));
}

receipt.gasReimbursementJuels = SafeCast.toUint96(gasPaymentHexaicosaUSD / paymentParams.linkUSD);
uint256 flatFeeHexaicosaUSD = uint256(paymentParams.billingTokenParams.flatFeeMilliCents) * 1e21; // 1e13 for milliCents to attoUSD and 1e8 for attoUSD to hexaicosaUSD
uint256 premiumHexaicosaUSD = ((((gasWei * paymentParams.gasLimit) + paymentParams.l1CostWei) *
paymentParams.billingTokenParams.gasFeePPB *
paymentParams.nativeUSD) / 1e9) + flatFeeHexaicosaUSD;
receipt.premium = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.billingTokenParams.priceUSD);

uint96 premium18Decimals = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.billingTokenParams.priceUSD); // has units of attoBillingToken, or "wei"
receipt.premium = premium18Decimals;
if (decimals < 18) {
receipt.premium = SafeCast.toUint96(premium18Decimals / (10 ** (18 - decimals)));
} else if (decimals > 18) {
receipt.premium = SafeCast.toUint96(premium18Decimals * (10 ** (decimals - 18)));
}

receipt.premiumJuels = SafeCast.toUint96(premiumHexaicosaUSD / paymentParams.linkUSD);

return receipt;
Expand Down Expand Up @@ -975,7 +995,9 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {

PaymentReceipt memory receipt = _calculatePaymentAmount(hotVars, paymentParams);

// balance is in the token's native decimals
uint96 balance = upkeep.balance;
// payment is in the token's native decimals
uint96 payment = receipt.gasCharge + receipt.premium;

// this shouldn't happen, but in rare edge cases, we charge the full balance in case the user
Expand Down Expand Up @@ -1064,6 +1086,11 @@ abstract contract AutomationRegistryBase2_3 is ConfirmedOwner {
IERC20 token = billingTokens[i];
BillingConfig memory config = billingConfigs[i];

// most ERC20 tokens are 18 decimals, we support tokens with up to 24 decimals
if (config.decimals > 24) {
revert InvalidToken();
}

// if LINK is a billing option, payout mode must be ON_CHAIN
if (address(token) == address(i_link) && mode == PayoutMode.OFF_CHAIN) {
revert InvalidToken();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ describe('AutomationRegistrar2_3', () => {
priceFeed: await registry.getLinkUSDFeedAddress(),
fallbackPrice: 200,
minSpend: minimumRegistrationAmount,
decimals: 18,
},
],
)
Expand Down
8 changes: 8 additions & 0 deletions contracts/test/v0.8/automation/AutomationRegistry2_3.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,6 +667,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: minUpkeepSpend,
decimals: 18,
},
],
)
Expand Down Expand Up @@ -957,6 +958,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: minUpkeepSpend,
decimals: 18,
},
],
]
Expand All @@ -976,6 +978,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: minUpkeepSpend,
decimals: 18,
},
],
]
Expand All @@ -995,6 +998,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: minUpkeepSpend,
decimals: 18,
},
],
]
Expand Down Expand Up @@ -4743,6 +4747,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: newMinUpkeepSpend,
decimals: 18,
},
],
)
Expand Down Expand Up @@ -5258,6 +5263,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: newMinUpkeepSpend,
decimals: 18,
},
],
)
Expand Down Expand Up @@ -5324,6 +5330,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: newMinUpkeepSpend,
decimals: 18,
},
],
)
Expand Down Expand Up @@ -5385,6 +5392,7 @@ describe('AutomationRegistry2_3', () => {
priceFeed: linkUSDFeed.address,
fallbackPrice: fallbackLinkPrice,
minSpend: newMinUpkeepSpend,
decimals: 18,
},
],
)
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ automation_forwarder_logic: ../../contracts/solc/v0.8.16/AutomationForwarderLogi
automation_registrar_wrapper2_1: ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.abi ../../contracts/solc/v0.8.16/AutomationRegistrar2_1/AutomationRegistrar2_1.bin eb06d853aab39d3196c593b03e555851cbe8386e0fe54a74c2479f62d14b3c42
automation_registrar_wrapper2_3: ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistrar2_3/AutomationRegistrar2_3.bin f07ffea17d8d7c2bd5ea91c25a32e2fa64aa6bffbd81a3281ebdb9b542535202
automation_registry_logic_a_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_2/AutomationRegistryLogicA2_2.bin 2f267fb8467a15c587ce4586ac56069f7229344ad3936430d7c7624c0528a171
automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 918082df412d3138c727871545fbcff7d9c9724e56990f8e5e0ab93809f83364
automation_registry_logic_a_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicA2_3/AutomationRegistryLogicA2_3.bin 31e0a1369ecd99652c46669c996ebb67d881defdbe3fdf585f5b3b1a8c01036a
automation_registry_logic_b_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_2/AutomationRegistryLogicB2_2.bin a6d33dfbbfb0ff253eb59a51f4f6d6d4c22ea5ec95aae52d25d49a312b37a22f
automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin b811c11616795e82e416cb8deff85b4d90b9c15f0aea23a5ea35a0d61c37dffc
automation_registry_logic_b_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistryLogicB2_3/AutomationRegistryLogicB2_3.bin b3f422c128842070b08c2d8c9925374644306fa068acd35b2a152072909573ad
automation_registry_wrapper_2_2: ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_2/AutomationRegistry2_2.bin de60f69878e9b32a291a001c91fc8636544c2cfbd9b507c8c1a4873b602bfb62
automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 9aaed50d72437f3882b64f69018606d97f13f9b7c4e4b82ad0da66f2694be433
automation_registry_wrapper_2_3: ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.abi ../../contracts/solc/v0.8.19/AutomationRegistry2_3/AutomationRegistry2_3.bin 862161b6f6d6e1089b3d88c127ecd8d9d0034b855c4f63a820a9ee342b1e32fb
automation_utils_2_1: ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.abi ../../contracts/solc/v0.8.16/AutomationUtils2_1/AutomationUtils2_1.bin 815b17b63f15d26a0274b962eefad98cdee4ec897ead58688bbb8e2470e585f5
automation_utils_2_2: ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.abi ../../contracts/solc/v0.8.19/AutomationUtils2_2/AutomationUtils2_2.bin 8743f6231aaefa3f2a0b2d484258070d506e2d0860690e66890dccc3949edb2e
automation_utils_2_3: ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.abi ../../contracts/solc/v0.8.19/AutomationUtils2_3/AutomationUtils2_3.bin 11e2b481dc9a4d936e3443345d45d2cc571164459d214917b42a8054b295393b
Expand All @@ -31,7 +31,7 @@ dummy_protocol_wrapper: ../../contracts/solc/v0.8.16/DummyProtocol/DummyProtocol
gas_wrapper: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2/KeeperRegistryCheckUpkeepGasUsageWrapper1_2.bin 4a5dcdac486d18fcd58e3488c15c1710ae76b977556a3f3191bd269a4bc75723
gas_wrapper_mock: ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.abi ../../contracts/solc/v0.8.6/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock/KeeperRegistryCheckUpkeepGasUsageWrapper1_2Mock.bin a9b08f18da59125c6fc305855710241f3d35161b8b9f3e3f635a7b1d5c6da9c8
i_automation_registry_master_wrapper_2_2: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster/IAutomationRegistryMaster.bin 9ff7087179f89f9b05964ebc3e71332fce11f1b8e85058f7b16b3bc0dd6fb96b
i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin 16b346a64126554bad0929f49ce020d886cc7203d03ca52c4537daf273b4c369
i_automation_registry_master_wrapper_2_3: ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.abi ../../contracts/solc/v0.8.19/IAutomationRegistryMaster2_3/IAutomationRegistryMaster2_3.bin fbfa3f5d78a357ecb7a1bc597c629ff30d42fedc48ba7f57e1622a6302d36523
i_automation_v21_plus_common: ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.abi ../../contracts/solc/v0.8.19/IAutomationV21PlusCommon/IAutomationV21PlusCommon.bin e8a601ec382c0a2e83c49759de13b0622b5e04e6b95901e96a1e9504329e594c
i_chain_module: ../../contracts/solc/v0.8.19/IChainModule/IChainModule.abi ../../contracts/solc/v0.8.19/IChainModule/IChainModule.bin 383611981c86c70522f41b8750719faacc7d7933a22849d5004799ebef3371fa
i_keeper_registry_master_wrapper_2_1: ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.abi ../../contracts/solc/v0.8.16/IKeeperRegistryMaster/IKeeperRegistryMaster.bin ee0f150b3afbab2df3d24ff3f4c87851efa635da30db04cd1f70cb4e185a1781
Expand Down

0 comments on commit f9d6306

Please sign in to comment.