Skip to content

Commit

Permalink
add: improved superfluid faucet
Browse files Browse the repository at this point in the history
  • Loading branch information
sirpy committed Jan 14, 2025
1 parent 1e8141d commit 340f027
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 26 deletions.
55 changes: 31 additions & 24 deletions contracts/fuseFaucet/SuperfluidFacuet.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ contract SuperfluidFaucet is
using SafeMathUpgradeable for uint256;

bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
uint public constant GAS_TOPPING_AMOUNT = 350000;
uint public constant FIRST_GAS_TOPPING_AMOUNT = 1e6;

uint256 public toppingAmount;
uint256 public maxAmountPerPeriod;
uint256 public _deprecated;
uint256 public maxValuePerPeriod;
uint256 public toppingPeriod;

struct RecipientInfo {
Expand All @@ -30,20 +32,15 @@ contract SuperfluidFaucet is
mapping(address => RecipientInfo) public recipientInfo;

event WalletTopped(address recipient, uint256 amount);
event SettingsUpdated(
uint256 toppingAmount,
uint256 maxAmountPerPeriod,
uint256 toppingPeriod
);
event SettingsUpdated(uint256 maxValuePerPeriod, uint256 toppingPeriod);

/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
_disableInitializers();
}

function initialize(
uint256 _toppingAmount,
uint256 _maxAmountPerPeriod,
uint256 _maxValuePerPeriod,
uint256 _toppingPeriod,
address _admin
) public initializer {
Expand All @@ -53,54 +50,64 @@ contract SuperfluidFaucet is
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, _admin);
toppingAmount = _toppingAmount;
maxAmountPerPeriod = _maxAmountPerPeriod;
maxValuePerPeriod = _maxValuePerPeriod;
toppingPeriod = _toppingPeriod;
}

function updateSettings(
uint256 _toppingAmount,
uint256 _maxAmountPerPeriod,
uint256 _maxValuePerPeriod,
uint256 _toppingPeriod
) external onlyRole(ADMIN_ROLE) {
toppingAmount = _toppingAmount;
maxAmountPerPeriod = _maxAmountPerPeriod;
maxValuePerPeriod = _maxValuePerPeriod;
toppingPeriod = _toppingPeriod;
emit SettingsUpdated(_toppingAmount, _maxAmountPerPeriod, _toppingPeriod);
emit SettingsUpdated(_maxValuePerPeriod, _toppingPeriod);
}

function canTop(address recipient) public view returns (bool) {
function canTop(address recipient, uint amount) public view returns (bool) {
if (recipient == address(0)) return false;
if (recipient.balance >= toppingAmount / 2) return false;
if (recipient.balance >= amount / 2) return false;

uint256 amountToSend = toppingAmount.sub(recipient.balance);
uint256 amountToSend = amount.sub(recipient.balance);
if (address(this).balance < amountToSend) return false;

uint256 currentPeriod = block.timestamp / toppingPeriod;
RecipientInfo storage info = recipientInfo[recipient];
RecipientInfo memory info = recipientInfo[recipient];

if (currentPeriod > info.lastWithdrawalPeriod) {
return true; // New period, reset counters
}

if (info.totalWithdrawnThisPeriod.add(amountToSend) > maxAmountPerPeriod)
if (info.totalWithdrawnThisPeriod.add(amountToSend) > maxValuePerPeriod)
return false;

return true;
}

function getToppingValue(bool firstTime) public view returns (uint) {
//top wallet with current base fee + 10% for priority fee and l1 fees
return
((firstTime ? FIRST_GAS_TOPPING_AMOUNT : GAS_TOPPING_AMOUNT) *
block.basefee *
110) / 100;
}

function topWallet(address payable recipient) external onlyRole(ADMIN_ROLE) {
require(canTop(recipient), "Recipient cannot be topped up");
RecipientInfo storage info = recipientInfo[recipient];
bool firstTime = info.lastWithdrawalPeriod == 0;
uint amount = getToppingValue(firstTime);
//first time we always allow, no canTop check required
if (!firstTime) {
require(canTop(recipient, amount), "Recipient cannot be topped up");
}

uint256 currentPeriod = block.timestamp / toppingPeriod;
RecipientInfo storage info = recipientInfo[recipient];

if (currentPeriod > info.lastWithdrawalPeriod) {
info.totalWithdrawnThisPeriod = 0;
info.lastWithdrawalPeriod = currentPeriod;
}

uint256 amountToSend = toppingAmount.sub(recipient.balance);
uint256 amountToSend = amount.sub(recipient.balance);
require(
address(this).balance >= amountToSend,
"Insufficient contract balance for topping up"
Expand Down
31 changes: 29 additions & 2 deletions scripts/multichain-deploy/7_superfluidfaucet-deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import releaser from "../releaser";
import ProtocolSettings from "../../releases/deploy-settings.json";
import dao from "../../releases/deployment.json";
import { TransactionResponse } from "@ethersproject/providers";
import { SuperfluidFaucet } from "../../types";

const { name } = network;

Expand Down Expand Up @@ -72,7 +73,7 @@ export const deployHelpers = async () => {
: ((await upgrades
.deployProxy(
await ethers.getContractFactory("SuperfluidFaucet"),
[ethers.utils.parseEther("0.000003"), ethers.utils.parseEther("0.000003"), 30, AdminWallet.address],
[ethers.utils.parseEther("0.0000035"), 30, AdminWallet.address],
{ kind: "uups" }
)
.then(printDeploy)) as Contract);
Expand All @@ -89,7 +90,33 @@ export const deployHelpers = async () => {
await verifyContract(impl, "contracts/fuseFaucet/SuperfluidFaucet.sol:SuperfluidFaucet", network.name);
};

const upgrade = async () => {
let [root] = await ethers.getSigners();
const isProduction = network.name.includes("production");

if (isProduction) verifyProductionSigner(root);

//generic call permissions
let schemeMock = root;

console.log("got signers:", {
network,
root: root.address,
schemeMock: schemeMock.address,
balance: await ethers.provider.getBalance(root.address).then(_ => _.toString())
});
let release: { [key: string]: any } = dao[network.name] || {};
const proxy = (await ethers.getContractAt("SuperfluidFaucet", release.SuperfluidFaucet)) as SuperfluidFaucet;
const impl = await ethers.deployContract("SuperfluidFaucet");
console.log("impl:", impl.address);
const callData = proxy.interface.encodeFunctionData("updateSettings", [ethers.utils.parseEther("0.0000035"), 30]);
const tx = await proxy.upgradeToAndCall(impl.address, callData);
console.log(tx.hash);
const res = await tx.wait();
console.log(res.transactionHash);
};
export const main = async () => {
await deployHelpers();
await upgrade();
// await deployHelpers();
};
if (process.argv[1].includes("7_superfluidfaucet")) main();

0 comments on commit 340f027

Please sign in to comment.