Skip to content

Commit

Permalink
Merge branch 'develop' into jk/functions-scripts-oracle-gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
justinkaseman authored Sep 6, 2023
2 parents c6e3a41 + ad22c6e commit 14a3432
Show file tree
Hide file tree
Showing 105 changed files with 2,167 additions and 1,076 deletions.
16 changes: 15 additions & 1 deletion .github/actions/setup-postgres/wait-for-healthy-postgres.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@
RETRIES=10

until [ $RETRIES -eq 0 ]; do
if docker compose ps postgres --status running --format json | jq >/dev/null -e 'if (.[0].Health == "healthy") then true else false end'; then
DOCKER_OUTPUT=$(docker compose ps postgres --status running --format json)
JSON_TYPE=$(echo "$DOCKER_OUTPUT" | jq -r 'type')

if [ "$JSON_TYPE" == "array" ]; then
HEALTH_STATUS=$(echo "$DOCKER_OUTPUT" | jq -r '.[0].Health')
elif [ "$JSON_TYPE" == "object" ]; then
HEALTH_STATUS=$(echo "$DOCKER_OUTPUT" | jq -r '.Health')
else
HEALTH_STATUS="Unknown JSON type: $JSON_TYPE"
fi

echo "postgres health status: $HEALTH_STATUS"
if [ "$HEALTH_STATUS" == "healthy" ]; then
exit 0
fi

echo "Waiting for postgres server, $((RETRIES--)) remaining attempts..."
sleep 2
done

exit 1
1 change: 1 addition & 0 deletions .github/workflows/solidity-foundry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
FOUNDRY_PROFILE: ${{ matrix.product }}

- name: Run Forge snapshot
if: ${{ !contains(fromJson('["vrf"]'), matrix.product) }}
run: |
forge snapshot --check gas-snapshots/${{ matrix.product }}.gas-snapshot
id: snapshot
Expand Down
2 changes: 1 addition & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ config-docs: ## Generate core node configuration documentation
.PHONY: golangci-lint
golangci-lint: ## Run golangci-lint for all issues.
[ -d "./golangci-lint" ] || mkdir ./golangci-lint && \
docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%s).txt
docker run --rm -v $(shell pwd):/app -w /app golangci/golangci-lint:v1.53.2 golangci-lint run --max-issues-per-linter 0 --max-same-issues 0 > ./golangci-lint/$(shell date +%Y-%m-%d_%H:%M:%S).txt


GORELEASER_CONFIG ?= .goreleaser.yaml
Expand Down
332 changes: 171 additions & 161 deletions contracts/gas-snapshots/llo-feeds.gas-snapshot

Large diffs are not rendered by default.

18 changes: 0 additions & 18 deletions contracts/gas-snapshots/vrf.gas-snapshot

This file was deleted.

15 changes: 12 additions & 3 deletions contracts/src/v0.8/llo-feeds/VerifierProxy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {IVerifier} from "./interfaces/IVerifier.sol";
import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {AccessControllerInterface} from "../shared/interfaces/AccessControllerInterface.sol";
import {IERC165} from "../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC165.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";
import {IVerifierFeeManager} from "./dev/interfaces/IVerifierFeeManager.sol";
import {Common} from "../libraries/Common.sol";

/**
Expand Down Expand Up @@ -65,6 +65,10 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac
/// not conform to the verifier interface
error VerifierInvalid();

/// @notice This error is thrown when the fee manager at an address does
/// not conform to the fee manager interface
error FeeManagerInvalid();

/// @notice This error is thrown whenever a verifier is not found
/// @param configDigest The digest for which a verifier is not found
error VerifierNotFound(bytes32 configDigest);
Expand Down Expand Up @@ -117,7 +121,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac
}

/// @inheritdoc IVerifierProxy
function verify(bytes calldata payload) external payable checkAccess returns (bytes memory verifiedReport) {
function verify(bytes calldata payload) external payable checkAccess returns (bytes memory) {
IVerifierFeeManager feeManager = s_feeManager;

// Bill the verifier
Expand Down Expand Up @@ -192,7 +196,7 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac
}

/// @inheritdoc IVerifierProxy
function getVerifier(bytes32 configDigest) external view override returns (address verifierAddress) {
function getVerifier(bytes32 configDigest) external view override returns (address) {
return s_verifiersByConfig[configDigest];
}

Expand All @@ -207,6 +211,11 @@ contract VerifierProxy is IVerifierProxy, ConfirmedOwner, TypeAndVersionInterfac
function setFeeManager(IVerifierFeeManager feeManager) external onlyOwner {
if (address(feeManager) == address(0)) revert ZeroAddress();

if (
!IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFee.selector) ||
!IERC165(feeManager).supportsInterface(IVerifierFeeManager.processFeeBulk.selector)
) revert FeeManagerInvalid();

address oldFeeManager = address(s_feeManager);
s_feeManager = IVerifierFeeManager(feeManager);
emit FeeManagerSet(oldFeeManager, address(feeManager));
Expand Down
90 changes: 69 additions & 21 deletions contracts/src/v0.8/llo-feeds/dev/FeeManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {IWERC20} from "../../shared/interfaces/IWERC20.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/interfaces/IERC20.sol";
import {Math} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/utils/math/Math.sol";
import {SafeERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/contracts/token/ERC20/utils/SafeERC20.sol";
import {IVerifierFeeManager} from "./interfaces/IVerifierFeeManager.sol";

/**
* @title FeeManager
Expand Down Expand Up @@ -75,6 +76,9 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
// @notice thrown when trying to clear a zero deficit
error ZeroDeficit();

/// @notice thrown when trying to pay an address that cannot except funds
error InvalidReceivingAddress();

/// @notice Emitted whenever a subscriber's discount is updated
/// @param subscriber address of the subscriber to update discounts for
/// @param feedId Feed ID for the discount
Expand All @@ -91,15 +95,31 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
event InsufficientLink(IRewardManager.FeePayment[] rewards);

/// @notice Emitted when funds are withdrawn
/// @param adminAddress Address of the admin
/// @param recipient Address of the recipient
/// @param assetAddress Address of the asset withdrawn
/// @param quantity Amount of the asset withdrawn
event Withdraw(address adminAddress, address assetAddress, uint192 quantity);
event Withdraw(address adminAddress, address recipient, address assetAddress, uint192 quantity);

/// @notice Emits when a deficit has been cleared for a particular config digest
/// @param configDigest Config digest of the deficit cleared
/// @param linkQuantity Amount of LINK required to pay the deficit
event LinkDeficitCleared(bytes32 indexed configDigest, uint256 linkQuantity);

/// @notice Emits when a fee has been processed
/// @param configDigest Config digest of the fee processed
/// @param subscriber Address of the subscriber who paid the fee
/// @param fee Fee paid
/// @param reward Reward paid
/// @param appliedDiscount Discount applied to the fee
event DiscountApplied(
bytes32 indexed configDigest,
address indexed subscriber,
Common.Asset fee,
Common.Asset reward,
uint256 appliedDiscount
);

/**
* @notice Construct the FeeManager contract
* @param _linkAddress The address of the LINK token
Expand Down Expand Up @@ -133,27 +153,32 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
_;
}

modifier onlyProxy() {
if (msg.sender != i_proxyAddress) revert Unauthorized();
_;
}

/// @inheritdoc TypeAndVersionInterface
function typeAndVersion() external pure override returns (string memory) {
return "FeeManager 0.0.1";
return "FeeManager 1.0.0";
}

/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) external pure override returns (bool) {
return interfaceId == this.processFee.selector || interfaceId == this.processFeeBulk.selector;
}

/// @inheritdoc IFeeManager
function processFee(bytes calldata payload, address subscriber) external payable override onlyOwnerOrProxy {
(Common.Asset memory fee, Common.Asset memory reward) = _processFee(payload, subscriber);
/// @inheritdoc IVerifierFeeManager
function processFee(bytes calldata payload, address subscriber) external payable override onlyProxy {
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(payload, subscriber);

if (fee.amount == 0) {
_tryReturnChange(subscriber, msg.value);
return;
}

IFeeManager.FeeAndReward[] memory feeAndReward = new IFeeManager.FeeAndReward[](1);
feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward);
feeAndReward[0] = IFeeManager.FeeAndReward(bytes32(payload), fee, reward, appliedDiscount);

if (fee.assetAddress == i_linkAddress) {
_handleFeesAndRewards(subscriber, feeAndReward, 1, 0);
Expand All @@ -162,8 +187,8 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
}
}

/// @inheritdoc IFeeManager
function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyOwnerOrProxy {
/// @inheritdoc IVerifierFeeManager
function processFeeBulk(bytes[] calldata payloads, address subscriber) external payable override onlyProxy {
FeeAndReward[] memory feesAndRewards = new IFeeManager.FeeAndReward[](payloads.length);

//keep track of the number of fees to prevent over initialising the FeePayment array within _convertToLinkAndNativeFees
Expand All @@ -172,10 +197,18 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {

uint256 feesAndRewardsIndex;
for (uint256 i; i < payloads.length; ++i) {
(Common.Asset memory fee, Common.Asset memory reward) = _processFee(payloads[i], subscriber);
(Common.Asset memory fee, Common.Asset memory reward, uint256 appliedDiscount) = _processFee(
payloads[i],
subscriber
);

if (fee.amount != 0) {
feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(bytes32(payloads[i]), fee, reward);
feesAndRewards[feesAndRewardsIndex++] = IFeeManager.FeeAndReward(
bytes32(payloads[i]),
fee,
reward,
appliedDiscount
);

unchecked {
//keep track of some tallys to make downstream calculations more efficient
Expand All @@ -200,7 +233,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
address subscriber,
bytes memory report,
Quote memory quote
) public view returns (Common.Asset memory, Common.Asset memory) {
) public view returns (Common.Asset memory, Common.Asset memory, uint256) {
Common.Asset memory fee;
Common.Asset memory reward;

Expand All @@ -214,7 +247,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
if (reportVersion == REPORT_V1) {
fee.assetAddress = i_nativeAddress;
reward.assetAddress = i_linkAddress;
return (fee, reward);
return (fee, reward, 0);
}

//verify the quote payload is a supported token
Expand Down Expand Up @@ -255,10 +288,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
}

//return the fee
return (fee, reward);
return (fee, reward, discount);
}

/// @inheritdoc IFeeManager
/// @inheritdoc IVerifierFeeManager
function setFeeRecipients(
bytes32 configDigest,
Common.AddressAndWeight[] calldata rewardRecipientAndWeights
Expand Down Expand Up @@ -293,18 +326,20 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
}

/// @inheritdoc IFeeManager
function withdraw(address assetAddress, uint192 quantity) external onlyOwner {
function withdraw(address assetAddress, address recipient, uint192 quantity) external onlyOwner {
//address 0 is used to withdraw native in the context of withdrawing
if (assetAddress == address(0)) {
payable(owner()).transfer(quantity);
(bool success, ) = payable(recipient).call{value: quantity}("");

if (!success) revert InvalidReceivingAddress();
return;
}

//withdraw the requested asset
IERC20(assetAddress).safeTransfer(owner(), quantity);
IERC20(assetAddress).safeTransfer(recipient, quantity);

//emit event when funds are withdrawn
emit Withdraw(msg.sender, assetAddress, quantity);
emit Withdraw(msg.sender, recipient, assetAddress, uint192(quantity));
}

/// @inheritdoc IFeeManager
Expand All @@ -324,7 +359,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
function _processFee(
bytes calldata payload,
address subscriber
) internal view returns (Common.Asset memory, Common.Asset memory) {
) internal view returns (Common.Asset memory, Common.Asset memory, uint256) {
if (subscriber == address(this)) revert InvalidAddress();

//decode the report from the payload
Expand Down Expand Up @@ -381,6 +416,16 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
totalNativeFee += feesAndRewards[i].fee.amount;
totalNativeFeeLinkValue += feesAndRewards[i].reward.amount;
}

if (feesAndRewards[i].appliedDiscount != 0) {
emit DiscountApplied(
feesAndRewards[i].configDigest,
subscriber,
feesAndRewards[i].fee,
feesAndRewards[i].reward,
feesAndRewards[i].appliedDiscount
);
}
}

//keep track of change in case of any over payment
Expand All @@ -390,7 +435,7 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
//there must be enough to cover the fee
if (totalNativeFee > msg.value) revert InvalidDeposit();

//wrap the amount required to pay the fee & approve as the subscriber paid in unwrapped native
//wrap the amount required to pay the fee & approve as the subscriber paid in wrapped native
IWERC20(i_nativeAddress).deposit{value: totalNativeFee}();

unchecked {
Expand All @@ -413,7 +458,10 @@ contract FeeManager is IFeeManager, ConfirmedOwner, TypeAndVersionInterface {
if (totalNativeFeeLinkValue > IERC20(i_linkAddress).balanceOf(address(this))) {
// If not enough LINK on this contract to forward for rewards, tally the deficit to be paid by out-of-band LINK
for (uint256 i; i < nativeFeeLinkRewards.length; ++i) {
s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount;
unchecked {
//we have previously tallied the fees, any overflows would have already reverted
s_linkDeficit[nativeFeeLinkRewards[i].poolId] += nativeFeeLinkRewards[i].amount;
}
}

emit InsufficientLink(nativeFeeLinkRewards);
Expand Down
Loading

0 comments on commit 14a3432

Please sign in to comment.