Ensure oracle fees are paid independently#3899
Open
flopez7 wants to merge 8 commits into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
2 Skipped Deployments
|
…omplete/Cancel in the same transaction
portuu3
requested changes
May 13, 2026
| chainId: number, | ||
| escrowAddress: string, | ||
| ): Promise<bigint> { | ||
| const fundAmount = await escrowClient.getFundAmount(escrowAddress); |
Collaborator
There was a problem hiding this comment.
I think you can use totalFundAmount from escrow data obtained in the next line.
…anceler address and event amount
portuu3
requested changes
May 14, 2026
Comment on lines
+481
to
+484
| require(_recipients.length == _amounts.length, 'Length mismatch'); | ||
| require(_amounts.length > 0, 'Empty amounts'); | ||
| require(_recipients.length <= BULK_MAX_COUNT, 'Too many recipients'); | ||
| uint256 length = _amounts.length; | ||
| require(length > 0, 'Empty amounts'); | ||
| require(length <= BULK_MAX_COUNT, 'Too many recipients'); |
Collaborator
There was a problem hiding this comment.
Suggested change
| require(_recipients.length == _amounts.length, 'Length mismatch'); | |
| require(_amounts.length > 0, 'Empty amounts'); | |
| require(_recipients.length <= BULK_MAX_COUNT, 'Too many recipients'); | |
| uint256 length = _amounts.length; | |
| require(length > 0, 'Empty amounts'); | |
| require(length <= BULK_MAX_COUNT, 'Too many recipients'); | |
| uint256 length = _amounts.length; | |
| require(_recipients.length == length, 'Length mismatch'); | |
| require(length > 0, 'Empty amounts'); | |
| require(length <= BULK_MAX_COUNT, 'Too many recipients'); |
Comment on lines
325
to
373
| EscrowStatuses _status = status; | ||
| uint256 _remaining = remainingFunds; | ||
| uint256 _remainingFunds = remainingFunds; | ||
|
|
||
| uint256 _reputationOracleFee = (fundAmount * | ||
| reputationOracleFeePercentage) / 100; | ||
| uint256 _recordingOracleFee = (fundAmount * | ||
| recordingOracleFeePercentage) / 100; | ||
| uint256 _exchangeOracleFee = (fundAmount * | ||
| exchangeOracleFeePercentage) / 100; | ||
|
|
||
| IERC20 tokenContract = IERC20(token); | ||
|
|
||
| if (_remaining > 0) { | ||
| IERC20 tokenContract = IERC20(token); | ||
| tokenContract.safeTransfer(launcher, _remaining); | ||
| fundAmount = 0; | ||
| remainingFunds = 0; | ||
| reservedFunds = 0; | ||
|
|
||
| if (_reputationOracleFee > 0) { | ||
| tokenContract.safeTransfer(reputationOracle, _reputationOracleFee); | ||
| } | ||
| if (_recordingOracleFee > 0) { | ||
| tokenContract.safeTransfer(recordingOracle, _recordingOracleFee); | ||
| } | ||
| if (_exchangeOracleFee > 0) { | ||
| tokenContract.safeTransfer(exchangeOracle, _exchangeOracleFee); | ||
| } | ||
| if ( | ||
| _reputationOracleFee > 0 || | ||
| _recordingOracleFee > 0 || | ||
| _exchangeOracleFee > 0 | ||
| ) { | ||
| address[] memory oracles = new address[](3); | ||
| uint256[] memory amounts = new uint256[](3); | ||
|
|
||
| oracles[0] = reputationOracle; | ||
| oracles[1] = recordingOracle; | ||
| oracles[2] = exchangeOracle; | ||
|
|
||
| amounts[0] = _reputationOracleFee; | ||
| amounts[1] = _recordingOracleFee; | ||
| amounts[2] = _exchangeOracleFee; | ||
|
|
||
| emit OracleFeeTransfer(oracles, amounts); | ||
| } | ||
| if (_remainingFunds > 0) { | ||
| tokenContract.safeTransfer(launcher, _remainingFunds); | ||
| if (_status == EscrowStatuses.ToCancel) { | ||
| emit CancellationRefund(_remaining); | ||
| emit CancellationRefund(_remainingFunds); | ||
| } | ||
| remainingFunds = 0; | ||
| reservedFunds = 0; | ||
| } |
Collaborator
There was a problem hiding this comment.
Suggested change
| EscrowStatuses _status = status; | |
| uint256 _remaining = remainingFunds; | |
| uint256 _remainingFunds = remainingFunds; | |
| uint256 _reputationOracleFee = (fundAmount * | |
| reputationOracleFeePercentage) / 100; | |
| uint256 _recordingOracleFee = (fundAmount * | |
| recordingOracleFeePercentage) / 100; | |
| uint256 _exchangeOracleFee = (fundAmount * | |
| exchangeOracleFeePercentage) / 100; | |
| IERC20 tokenContract = IERC20(token); | |
| if (_remaining > 0) { | |
| IERC20 tokenContract = IERC20(token); | |
| tokenContract.safeTransfer(launcher, _remaining); | |
| fundAmount = 0; | |
| remainingFunds = 0; | |
| reservedFunds = 0; | |
| if (_reputationOracleFee > 0) { | |
| tokenContract.safeTransfer(reputationOracle, _reputationOracleFee); | |
| } | |
| if (_recordingOracleFee > 0) { | |
| tokenContract.safeTransfer(recordingOracle, _recordingOracleFee); | |
| } | |
| if (_exchangeOracleFee > 0) { | |
| tokenContract.safeTransfer(exchangeOracle, _exchangeOracleFee); | |
| } | |
| if ( | |
| _reputationOracleFee > 0 || | |
| _recordingOracleFee > 0 || | |
| _exchangeOracleFee > 0 | |
| ) { | |
| address[] memory oracles = new address[](3); | |
| uint256[] memory amounts = new uint256[](3); | |
| oracles[0] = reputationOracle; | |
| oracles[1] = recordingOracle; | |
| oracles[2] = exchangeOracle; | |
| amounts[0] = _reputationOracleFee; | |
| amounts[1] = _recordingOracleFee; | |
| amounts[2] = _exchangeOracleFee; | |
| emit OracleFeeTransfer(oracles, amounts); | |
| } | |
| if (_remainingFunds > 0) { | |
| tokenContract.safeTransfer(launcher, _remainingFunds); | |
| if (_status == EscrowStatuses.ToCancel) { | |
| emit CancellationRefund(_remaining); | |
| emit CancellationRefund(_remainingFunds); | |
| } | |
| remainingFunds = 0; | |
| reservedFunds = 0; | |
| } | |
| EscrowStatuses _status = status; | |
| uint256 _remainingFunds = remainingFunds; | |
| uint256 _reputationOracleFee = (fundAmount * | |
| reputationOracleFeePercentage) / 100; | |
| uint256 _recordingOracleFee = (fundAmount * | |
| recordingOracleFeePercentage) / 100; | |
| uint256 _exchangeOracleFee = (fundAmount * | |
| exchangeOracleFeePercentage) / 100; | |
| IERC20 tokenContract = IERC20(token); | |
| fundAmount = 0; | |
| remainingFunds = 0; | |
| reservedFunds = 0; | |
| address[] memory oracles = new address[](3); | |
| uint256[] memory amounts = new uint256[](3); | |
| oracles[0] = reputationOracle; | |
| oracles[1] = recordingOracle; | |
| oracles[2] = exchangeOracle; | |
| amounts[0] = _reputationOracleFee; | |
| amounts[1] = _recordingOracleFee; | |
| amounts[2] = _exchangeOracleFee; | |
| if (_reputationOracleFee > 0) { | |
| tokenContract.safeTransfer(reputationOracle, _reputationOracleFee); | |
| } | |
| if (_recordingOracleFee > 0) { | |
| tokenContract.safeTransfer(recordingOracle, _recordingOracleFee); | |
| } | |
| if (_exchangeOracleFee > 0) { | |
| tokenContract.safeTransfer(exchangeOracle, _exchangeOracleFee); | |
| } | |
| emit OracleFeeTransfer(oracles, amounts); | |
| if (_remainingFunds > 0) { | |
| tokenContract.safeTransfer(launcher, _remainingFunds); | |
| if (_status == EscrowStatuses.ToCancel) { | |
| emit CancellationRefund(_remainingFunds); | |
| } | |
| } |
| reservedFunds = 0; | ||
| } | ||
|
|
||
| if (_status == EscrowStatuses.ToCancel) { |
Collaborator
There was a problem hiding this comment.
if no payout happened the oracles should not get any fee
…cle fee calculations in Escrow contract
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Issue tracking
#3880
Context behind the change
Oracle fees were previously affected when worker submissions were rejected and no worker payout was made. This change separates oracle compensation from worker payouts so oracle fees are reserved from the funded amount and paid when the escrow is completed or canceled, while rejected submissions still receive no worker payout. The SDK, oracles, and subgraph were updated to use and track the corrected fund amounts and oracle fee transfers.
How has this been tested?
Deployed locally
Release plan
Deploy new contract version, SDKs and subgraph
Potential risks; What to monitor; Rollback plan
Check bulkpayout balance and fees.