ubiquibot / permit-generation

A standalone module to generate permits.
0 stars 6 forks source link

Dollar permits with fees #16

Open rndquu opened 3 weeks ago

rndquu commented 3 weeks ago

User stories:

This issue touches the following repositories / docs:

ubiquibot[bot] commented 3 weeks ago

@rndquu the deadline is at 2024-06-19T06:12:05.277Z

rndquu commented 3 weeks ago

@0x4007 There are 4 options of how to implement permit fees:

  1. Direct transfers. So when permit is generated we simply transfer (since we know partner's private key) the permit fee to the treasury address.
    • Pros: Easy to implement, partner pays for gas
    • Cons: It may seem strange from a partner's point of view that some funds are transferred from time to time
  2. Batch permits. SignatureTransfer supports setting 2 destination addresses in a permit. So when permit is generated we can set that 95% of the permit reward would go to the contributor and 5% to the treasury. The issue with this approach is that contributor will be able to set his own address instead of the treasury address and get the fee since SignatureTransferDetails object is not signed by the partner's private key.
    • Pros: Easy to implement, contributors pay for gas
    • Cons: Malicious contributor is able to collect treasury fees
  3. Custom permit2 contract. We can modify SignatureTransfer and set SignatureTransferDetails to be part of the permit signature.
    • Pros: Solid solution, contributors pay for gas
    • Cons: Complex solution, requires an audit (?)
  4. On permit generation create 2 permits: one for contributor and one for the treasury EOA. Save permits to DB and claim treasury permits using CRON job.
    • Pros: Easy to implement
    • Cons: Treasury EOA pays for gas

@gentlementlegen @web4er @molecula451 @gitcoindev @whilefoo @Keyrxng Other options are appreciated

gitcoindev commented 3 weeks ago

Good proposals. Number 1 seems strange for me, at least from the partner's perspective. I would reject number 2 immediately. Between number 3 and 4, 3 seems the 'proper' but more complex, if requires audit also costly. For number 4, even if treasury pays for gas, I guess the cost would be negligible for L2 permits (or simply treasury would earn 5% - gas fee). Therefore I vote for option '4', and 2nd choice is option '3'.

Keyrxng commented 3 weeks ago

The only other thing I can think of is just a more complex alternative of 4. Automate treasury permits through OZ Defender but it's a long way for a shortcut.

I'd opt for 4, as it's the easiest to implement and like @gitcoindev says the fee is negligible. 3 seems like overkill despite it being my 2nd choice as well.

EresDev commented 3 weeks ago

very well thought out.

If I am not mistaken, there is a solution in permit2 that combines the pros of your option 2 & 3 and mostly removes the cons of both. It appears permitWitnessTransferFrom allows you to lock the SignatureTransferDetails and the bounty hunter can't change the "transfer to" address. I could be wrong because I haven't been able to fully understand and try it, probably will need some time to play with it to confirm. It also has a batch variation to combine multiple transfers batch-permitWitnessTransferFrom

Personally, even if I am right, I would still not go with this option or the option 2 or 3. The ability to change SignatureTransferDetails offers flexibility as it did in offering fiat visa/mastercard as a payment option. It will also help with upcoming Gnosis Pay Integration. And it keeps the door open for other opportunities.

Option 1 & 4 are the simpler solutions and the change will not leak into other repositories. The option-4 will require a cron job setup but 1 will be easier to implement and something similar is already being considered in Automatic Transfer The cons of option-1 are not serious as the partner would be already aware of the fee. And by the time fee is deducted, partner would have received the value in return.

molecula451 commented 3 weeks ago
  1. Direct transfers seems an option to me, we save time and cost in implementation and maybe implement some logs stuff to the DB to handle records etc, why no? seems to be the simplest, partners should be aware of which payment receiving from which whitelist address and lastly the ideal would be

a combination of the 2-3 with some combination added from the 4

0x4007 commented 3 weeks ago

It will also help with upcoming Gnosis Pay Integration. And it keeps the door open for other opportunities.

It is appealing to me if we can build infrastructure that helps with more objectives.

To be honest, many of these permit2 method details are beyond me.

A suggestion is that we can do the "lower security" options, and then enforce that they do not tamper with the code by cutting off their service (kernel ignores their installation ID/organization) if they have an outstanding balance.


Direct transfers always seemed the most straightforward to me though. Perhaps we can dynamically calculate the gas fee and withdraw the amount due, minus the gas cost. However, especially on mainnet, I am unsure what we would do if gas fees exceed our profit within a transaction. In these cases my mind jumps to "roll up" balances, leveraging something like the ERC20 allowance method; but that might be an off topic conversation for another time.

rndquu commented 3 weeks ago

Thanks everyone.

So we can't use custom permit2 contract with signed transfer details since it breaks (at least) https://github.com/ubiquity/pay.ubq.fi/pull/226.

If we think of fees in terms of monetization for plugin developers then direct transfers from partner wallet is not ideal since: 1) This way partner pays for gas both for fees and plugin developers rewards 2) We have a headache of calculating gas costs so solvency won't be 100% 3) We have a headache of implementing a retry payout mechanic since transactions will fail from time to time

Overall it seems that right now the best option is to generate 2 permits: contributor reward and fee for the treasury.

Consider this example with 5% reward fee and 3 plugins in the chain (each eligible for 25% of the fee) that should be monetized: a) Contributor solves an issue worth 100 USD b) There are 5 permits generated in a DB: 1) Our standard permit reward for 95 USD 2) Fee permit for the treasury worth 1.25 USD 3) Plugin developer 1 permit reward worth 1.25 USD 4) Plugin developer 2 permit reward worth 1.25 USD 5) Plugin developer 3 permit reward worth 1.25 USD

So both treasury EOA and plugin developers are responsible for claiming only their own permits + both of them pay for gas themselves.

In the next "fee feature" iteration, as 0x4007 said, we could consolidate those permits and create a handy UI to claim everything in a single transaction.

0x4007 commented 3 weeks ago

In the next "fee feature" iteration, as 0x4007 said, we could consolidate those permits and create a handy UI to claim everything in a single transaction.

This seems tricky because we need to securely prove to the partner signer that we are "trading" previously generated permits to create a new permit D that is the sum value of fee permits A, B, and C.

I wonder if there is an opportunity here for NFTs to represent the debts. Then we can easily record from which signer (partner) owes the debt, and how much the debt is worth. Then we can have a smart contract that allows a user to deposit all the NFT debts, and withdraw the sum total all at once?


    struct Debt {
        address partner;
        uint256 amount;
        address beneficiary;
    }

Minting the NFTs would likely only be viable on a network like Gnosis Chain, but it could remove the database dependency, which is nice.


One other-slightly off topic-monetization method that should be kept in mind, and supported in the future: monthly recurring. For example, ideally, if we can enforce on chain that in order to add the bot to your organization at all, you need to pay $25 a month etc.

I'm unsure if there is open source tech for this, but being able to manage this billing method entirely on-chain will be great for our bottom line.

rndquu commented 1 week ago

monthly recurring. For example, ideally, if we can enforce on chain that in order to add the bot to your organization at all, you need to pay $25 a month etc

Since we already enforce partners to have an encrypted private key for permits we could use the address derived from that private key to check (on-chain) that the monthly fee is paid.

So for a partner the flow could be:

  1. Partner sends 25 DAI and github organization id to our smart contract
  2. Partner installs the bot
  3. On github event the kernel checks that: a) address derived from evmPrivateEncrypted bot config param has a paid subscription b) github event source organization id matches the one in the smart contract (to prevent the case when a malicious partner tries to use an encrypted PK from another partner/organization)
  4. If the fee is paid the kernel processes the request otherwise throws an error