Adding LP provisioning to token faucet: Seeking guidance

So I wrote a faucet that gives out X tokens once per address, with a time limit. Probably going to add a "NoContracts" modifier in there. The idea was to just set it to return 1.9x the gas cost so it's not profitable to abuse.

But it occurred to me that, for people who want to support the project, a faucet that gives out a value of tokens equal to the amount of (whatever stablecoin where LP provisions exist) the users inputs, and then auto-provisions the liquidity and timelocks it would be a great way for the community to both support our project and provide "unruggable" grass-roots-based liquidity. That is, even with timelocks, provisioning liquidity for a year via a mass crowdsale doesn't really safegaurd the individual users beyond the timelock period.

This way, the liquidity pool would be built with thousands of "micro LP" individuals.

Timelocks are pretty easy, but any experience or guidance on how to work with PCS V2 or UniswapV2 auto-provisioning would be great. Just started here:

I'd like to fully understand how this works Vs. just copying in "reflection" code (although that's a good way to just get it done).

Cheers in advance to anyone offering advice, and have a great day!


// SPDX-License-Identifier: MIT

pragma solidity ^0.8.6;

// import "./Context.sol"; // pulled in by Ownable.sol and Pausable.sol
import "./Ownable.sol";
import "./Pausable.sol";

interface ERC20 {
    function transfer(address to, uint256 value) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);

contract Faucet is Ownable, Pausable {
   // uint256 constant public tokenAmount = 100000000000000000000; // @dev if you want fixed distribution
    uint256 public tokenAmount = 200000000000000000000;
    uint256 public waitTime = 1 minutes;

    ERC20 public tokenInstance;

    mapping(address => uint256) lastAccessTime;

    event tokenAmountUpdated(address indexed _owner, uint256 previousRate, uint256 newRate);
    event waitTimeUpdated(address indexed _owner, uint256 previouswaitTime, uint256 newwaitTime);
    event WithdrawTokensSentHere(address token, address _operator, uint256 amount);

    constructor(address _tokenInstance) {
       // emit TokenAddressTransferred(address(0), tokenInstance);
        require(_tokenInstance != address(0));
        tokenInstance = ERC20(_tokenInstance);
        // initialize the number of participants as zero
        numParticipants = 0;

    struct Participant {
        bool registered;  // if true, that person already registered

    mapping(address => Participant) public participants;
    uint public numParticipants;

    modifier onlyOnce() {
        if (participants[msg.sender].registered) {
            revert("Declined::Only once per address");

     * @dev Update the charity rate.
     * Can only be called by the current operator.
    function updateTokenAmount(uint16 _tokenAmount) public onlyOwner whenNotPaused {
        require(_tokenAmount >= 1000000000000000000,"updateTokenAmount::Too Low");
        emit tokenAmountUpdated(msg.sender, tokenAmount, _tokenAmount);
        tokenAmount = _tokenAmount;

    function updatewaitTime(uint256 _waitTime) public onlyOwner whenNotPaused {
        require(_waitTime >= 1 minutes,"updatewaitTime::Too Short");
        emit waitTimeUpdated(msg.sender, waitTime, _waitTime);
        waitTime = _waitTime;

    // @dev -- public views of state variables
    function Participants() public view returns (uint256) {
        return numParticipants;

    function TokenAmounts() public view returns (uint256) {
        return tokenAmount;

    function waitTimes() public view returns (uint256) {
        return waitTime;
    // @dev -- ends public views of state variables

    function requestTokens() public onlyOnce() whenNotPaused {
        tokenInstance.transfer(msg.sender, tokenAmount);
        lastAccessTime[msg.sender] = block.timestamp + waitTime;
        Participant storage p = participants[msg.sender];
        p.registered = true;

    function allowedToWithdraw(address _address) public view returns (bool) {
        if(lastAccessTime[_address] == 0) {
            return true;
        } else if(block.timestamp >= lastAccessTime[_address]) {
            return true;
        return false;

        // @dev owner can drain tokens that are sent here by mistake
    function withdrawTokensSentHere(ERC20 token, uint256 amount)
        emit WithdrawTokensSentHere(address(token), owner(), amount);
        token.transfer(owner(), amount);