Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions target_chains/ethereum/contracts/contracts/entropy/Entropy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,38 @@ abstract contract Entropy is IEntropy, EntropyState {
// Interaction with an external contract or token transfer
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "withdrawal to msg.sender failed");

emit Withdrawal(msg.sender, msg.sender, amount);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drive-by: we didn't have an event for this action

}

function withdrawAsFeeManager(
address provider,
uint128 amount
) external override {
EntropyStructs.ProviderInfo storage providerInfo = _state.providers[
provider
];

if (providerInfo.sequenceNumber == 0) {
revert EntropyErrors.NoSuchProvider();
}

if (providerInfo.feeManager != msg.sender) {
revert EntropyErrors.Unauthorized();
}

// Use checks-effects-interactions pattern to prevent reentrancy attacks.
require(
providerInfo.accruedFeesInWei >= amount,
"Insufficient balance"
);
providerInfo.accruedFeesInWei -= amount;

// Interaction with an external contract or token transfer
(bool sent, ) = msg.sender.call{value: amount}("");
require(sent, "withdrawal to msg.sender failed");

emit Withdrawal(provider, msg.sender, amount);
}

// requestHelper allocates and returns a new request for the given provider.
Expand Down Expand Up @@ -475,6 +507,28 @@ abstract contract Entropy is IEntropy, EntropyState {
emit ProviderFeeUpdated(msg.sender, oldFeeInWei, newFeeInWei);
}

function setProviderFeeAsFeeManager(
address provider,
uint128 newFeeInWei
) external override {
EntropyStructs.ProviderInfo storage providerInfo = _state.providers[
provider
];

if (providerInfo.sequenceNumber == 0) {
revert EntropyErrors.NoSuchProvider();
}

if (providerInfo.feeManager != msg.sender) {
revert EntropyErrors.Unauthorized();
}

uint128 oldFeeInWei = providerInfo.feeInWei;
providerInfo.feeInWei = newFeeInWei;

emit ProviderFeeUpdated(provider, oldFeeInWei, newFeeInWei);
}

// Set provider uri. It will revert if provider is not registered.
function setProviderUri(bytes calldata newUri) external override {
EntropyStructs.ProviderInfo storage provider = _state.providers[
Expand All @@ -488,6 +542,17 @@ abstract contract Entropy is IEntropy, EntropyState {
emit ProviderUriUpdated(msg.sender, oldUri, newUri);
}

function setFeeManager(address manager) external override {
EntropyStructs.ProviderInfo storage provider = _state.providers[
msg.sender
];
if (provider.sequenceNumber == 0) {
revert EntropyErrors.NoSuchProvider();
}

provider.feeManager = manager;
}

function constructUserCommitment(
bytes32 userRandomness
) public pure override returns (bytes32 userCommitment) {
Expand Down
46 changes: 46 additions & 0 deletions target_chains/ethereum/contracts/forge-test/Entropy.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,52 @@ contract EntropyTest is Test, EntropyTestUtils, EntropyEvents {
provider1Proofs[assignedSequenceNumber]
);
}

function testFeeManager() public {
address manager = address(12);

// Make sure there are some fees for provider1
request(user1, provider1, 42, false);

// Manager isn't authorized, so can't withdraw or set fee.
vm.prank(manager);
vm.expectRevert();
random.withdrawAsFeeManager(provider1, provider1FeeInWei);
vm.prank(manager);
vm.expectRevert();
random.setProviderFeeAsFeeManager(provider1, 1000);

// You can't set a fee manager from an address that isn't a registered provider.
vm.expectRevert();
random.setFeeManager(address(manager));

// Authorizing the fee manager as the provider enables withdrawing and setting fees.
vm.prank(provider1);
random.setFeeManager(address(manager));

// Withdrawing decrements provider's accrued fees and sends balance to the fee manager.
uint startingBalance = manager.balance;
vm.prank(manager);
random.withdrawAsFeeManager(provider1, provider1FeeInWei);
assertEq(random.getProviderInfo(provider1).accruedFeesInWei, 0);
assertEq(manager.balance, startingBalance + provider1FeeInWei);

// Setting provider fee updates the fee in the ProviderInfo.
vm.prank(manager);
random.setProviderFeeAsFeeManager(provider1, 10101);
assertEq(random.getProviderInfo(provider1).feeInWei, 10101);

// Authorizing a different manager depermissions the previous one.
address manager2 = address(13);
vm.prank(provider1);
random.setFeeManager(address(manager2));
vm.prank(manager);
vm.expectRevert();
random.withdrawAsFeeManager(provider1, provider1FeeInWei);
vm.prank(manager);
vm.expectRevert();
random.setProviderFeeAsFeeManager(provider1, 1000);
}
}

contract EntropyConsumer is IEntropyConsumer {
Expand Down
6 changes: 6 additions & 0 deletions target_chains/ethereum/entropy_sdk/solidity/EntropyEvents.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,10 @@ interface EntropyEvents {
event ProviderFeeUpdated(address provider, uint128 oldFee, uint128 newFee);

event ProviderUriUpdated(address provider, bytes oldUri, bytes newUri);

event Withdrawal(
address provider,
address recipient,
uint128 withdrawnAmount
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ contract EntropyStructs {
// are revealed on-chain.
bytes32 currentCommitment;
uint64 currentCommitmentSequenceNumber;
// An address that is authorized to set / withdraw fees on behalf of this provider.
address feeManager;
}

struct Request {
Expand Down
16 changes: 16 additions & 0 deletions target_chains/ethereum/entropy_sdk/solidity/IEntropy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ interface IEntropy is EntropyEvents {
// balance of fees in the contract).
function withdraw(uint128 amount) external;

// Withdraw a portion of the accumulated fees for provider. The msg.sender must be the fee manager for this provider.
// Calling this function will transfer `amount` wei to the caller (provided that they have accrued a sufficient
// balance of fees in the contract).
function withdrawAsFeeManager(address provider, uint128 amount) external;

// As a user, request a random number from `provider`. Prior to calling this method, the user should
// generate a random number x and keep it secret. The user should then compute hash(x) and pass that
// as the userCommitment argument. (You may call the constructUserCommitment method to compute the hash.)
Expand Down Expand Up @@ -102,8 +107,19 @@ interface IEntropy is EntropyEvents {

function setProviderFee(uint128 newFeeInWei) external;

function setProviderFeeAsFeeManager(
address provider,
uint128 newFeeInWei
) external;

function setProviderUri(bytes calldata newUri) external;

// Set manager as the fee manager for the provider msg.sender.
// After calling this function, manager will be able to set the provider's fees and withdraw them.
// Only one address can be the fee manager for a provider at a time -- calling this function again with a new value
// will override the previous value. Call this function with the all-zero address to disable the fee manager role.
function setFeeManager(address manager) external;

function constructUserCommitment(
bytes32 userRandomness
) external pure returns (bytes32 userCommitment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
"internalType": "uint64",
"name": "currentCommitmentSequenceNumber",
"type": "uint64"
},
{
"internalType": "address",
"name": "feeManager",
"type": "address"
}
],
"indexed": false,
Expand Down Expand Up @@ -399,5 +404,30 @@
],
"name": "RevealedWithCallback",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "provider",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint128",
"name": "withdrawnAmount",
"type": "uint128"
}
],
"name": "Withdrawal",
"type": "event"
}
]
84 changes: 84 additions & 0 deletions target_chains/ethereum/entropy_sdk/solidity/abis/IEntropy.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
"internalType": "uint64",
"name": "currentCommitmentSequenceNumber",
"type": "uint64"
},
{
"internalType": "address",
"name": "feeManager",
"type": "address"
}
],
"indexed": false,
Expand Down Expand Up @@ -400,6 +405,31 @@
"name": "RevealedWithCallback",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "provider",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint128",
"name": "withdrawnAmount",
"type": "uint128"
}
],
"name": "Withdrawal",
"type": "event"
},
{
"inputs": [
{
Expand Down Expand Up @@ -554,6 +584,11 @@
"internalType": "uint64",
"name": "currentCommitmentSequenceNumber",
"type": "uint64"
},
{
"internalType": "address",
"name": "feeManager",
"type": "address"
}
],
"internalType": "struct EntropyStructs.ProviderInfo",
Expand Down Expand Up @@ -778,6 +813,19 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "manager",
"type": "address"
}
],
"name": "setFeeManager",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand All @@ -791,6 +839,24 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "provider",
"type": "address"
},
{
"internalType": "uint128",
"name": "newFeeInWei",
"type": "uint128"
}
],
"name": "setProviderFeeAsFeeManager",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand All @@ -816,5 +882,23 @@
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "provider",
"type": "address"
},
{
"internalType": "uint128",
"name": "amount",
"type": "uint128"
}
],
"name": "withdrawAsFeeManager",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]
2 changes: 1 addition & 1 deletion target_chains/ethereum/entropy_sdk/solidity/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pythnetwork/entropy-sdk-solidity",
"version": "1.3.0",
"version": "1.4.0",
"description": "Generate secure random numbers with Pyth Entropy",
"repository": {
"type": "git",
Expand Down