ubiquity / pay.ubq.fi

Generate and claim spender permits (EIP-2612)
https://pay.ubq.fi
10 stars 41 forks source link

"Faucet" Service #142

Closed 0x4007 closed 11 months ago

0x4007 commented 1 year ago

Perhaps the bot can call the "invoke faucet" API endpoint when generating payment permits instead of pay.ubq.fi UI?

That's exactly what @Keyrxng proposed.

To sum up, as a part of this issue we should implement a server side app (in a cloudflare worker) which exposes a single API endpoint similar to /?faucet?address=0x01 which accepts an address to fund.

The faucet service should have access to the bot's DB in order to fund only when:

We'll use this faucet service in the bot on permit generation.

Original Specification Context

Overview

To onboard normal developers who aren't crypto native, perhaps we can consider virtual wallets, in browser wallets, or for the most simple starting point: automatically transfer the funds if they don't have any gas.

Scenario

Faucet Limitations

Keyrxng commented 1 year ago

/start

ubiquibot[bot] commented 1 year ago

Deadline Thu, 02 Nov 2023 14:49:16 UTC
Registered Wallet 0xAe5D1F192013db889b1e2115A370aB133f359765

Tips:

rndquu commented 1 year ago

So the original issue sounds like "we should allow bounty hunters with 0 XDAI to claim rewards" for a better UX.

There are 4 options:

  1. Meta TXs (for example via Gelato Relay)
  2. Account abstraction (EIP-4337)
  3. Redirect to a ready to use XDAI faucet
  4. Our own server-side solution that transfers XDAI on demand

Option 1: Meta TXs

We're generating permits using the uniswap's permit2 contracts. The thing with permit2 is that rewards can be claimed only by msg.sender for the following reasons. So when a claim transaction is relayed by some 3rd party service (ex: Gelato Network) the msg.sender equals to the relayer address which will revert because msg.sender must be equal to a bounty hunter's address.

Option 2: Account abstraction (EIP-4337)

I haven't checked in depth but this is how it works as far as I understand:

  1. User signs a transaction (UserOperation in terms of EIP-4337)
  2. User sends a transaction (i.e. calls API method) via 3rd party bundler API (example)
  3. Bundler sends the transaction on-chain to the EntryPoint smart contract from bundler's EOA
  4. EntryPoint deploys a smart contract wallet (which is basically a smart contract with executeOp() method).
  5. Smart contract wallet executes the UserOperation (i.e. internal transaction from step 1)

Here is the same situation as with relayers. On-chain transaction is initiated by the bundler so msg.sender will be equal to the bundler's address so as far as I understand we can't use permit2 with any account abstraction SDKs (but I'm not 100% sure, need to check it).

Perhaps we could sign permits for smart contract wallets. Smart contract wallet addresses are deterministic (i.e. can be precomputed because of CREATE2 usage) but even if permit2 works with smart contract wallets it adds a certain overhead on the bot's side. Overall this requires a research.

Option 3: Redirect to a ready to use XDAI faucet

There is a ready to use XDAI faucet so we could simply redirect bounty hunters there.

Option 4: Our own server-side solution that transfers XDAI on demand

We could deploy our our backend service (supabase edge function or cloudflare worker) that would transfer XDAI on demand.

How it would work:

  1. Bounty hunter clicks on a permit URL and opens pay.ubq.fi
  2. In the background some API is called (like pay.ubq.fi/api/faucet?address=0x01)
  3. If address 0x01 is registered in the bot's DB and the address has 0 XDAI then a transaction is sent with some XDAI to a bounty hunter's address
  4. Bounty hunter waits 5 second for a faucet transaction to be mined (but not finalized, we're optimistic here)
  5. Bounty hunter is ready to claim a reward

TXs gas costs:

Given this with 1 USD we can onboard ~2000 new users. Even if the service is abused we would lose only 1 USD.

To sum up

I think the best strategy is to fulfill a research on account abstraction (whether we can use smart contract wallets for permit2). If we can't use account abstraction then we should implement redirect to XDAI faucet (because it's simple and fast) and then implement our own backend faucet solution.

Keyrxng commented 1 year ago

Appreciated rndquu

I was just trialling out using OpenZeppelin's Defender.

As for introducing a fee I was having a hard time with without adding multiple tx steps but as you said with $1 == 2000 users, its not like it's breaking the bank

I'm not uncertain that this or near enough is doable but won't know for sure til POC

Keyrxng commented 1 year ago

Also, the claim portal will this be the only one across all instances of claiming? No partner white-labelled portals or own brand ones? Or is this ubiquity specific?

What I'm getting at is if we setup one relay for gnosis to handle this, will it be responsible for all instances of hunters claiming from partner issues too? Or will each partner have to set things up like this too?

rndquu commented 1 year ago

Also, the claim portal will this be the only one across all instances of claiming? No partner white-labelled portals or own brand ones? Or is this ubiquity specific?

As far as I understand pay.ubq.fi will be a single reward UI for all of our partners.

What I'm getting at is if we setup one relay for gnosis to handle this, will it be responsible for all instances of hunters claiming from partner issues too? Or will each partner have to set things up like this too?

We should make partner UX as simple as possible. So if relaying a transaction requires calling a single API method then it is simpler to be responsible for relaying all partner transactions unless we're subjected to some fees or API rate limits.

0x4007 commented 1 year ago

Yes we should handle this across every partner. Again, if we deduct from the assignee's payout, then it is technically profitable to run this service.

We are incentivized to run this service for everybody for 1. better user experience and 2. small profit

Keyrxng commented 1 year ago

Okay well I'm thinking that we do it like this:

Thoughts on that?

Something like this is probably easiest, as we already have pk access we can handle transfers direct to the user from the bot, can't we? or is there risk to this that I'm not seeing?

rndquu commented 1 year ago

Okay well I'm thinking that we do it like this:

  • Just before the permit is generated we balance check the user, if they have enough gas we don't debit.
  • If they have 0 gas we debit 1xDai from the reward and transfer 0.5 to the user before they even get to the claim page
  • The bot leaves a comment (or is included in the permit comment) something like "As you had no gas to claim, we have debited your award by 1 xDai to allow you to claim, as a deterrent from abuse there is a 0.5 xDai service fee."

Thoughts on that?

Something like this is probably easiest, as we already have pk access we can handle transfers direct to the user from the bot, can't we? or is there risk to this that I'm not seeing?

Debiting the reward is complex. I guess we can simply transfer 0.0003 XDAI to a bounty hunter on permit generation if:

And add some bot comment like "We've funded your wallet address with 0.0003 XDAI (tx url) for you to claim a reward. Thank you for your 1st contribution". So by the time bounty hunters opens a claim URL page the tx should already be mined (keeping in mind gnosis's 5 sec block time).

Keyrxng commented 1 year ago

Just to be clear when I say debit I really meant just reduce their payout by $1 before permit generation, not adding debits to the db.

Glad you see it similarly, this is super onboarding friendly but there's no opt in or out and no way to make it profitable but if making it profitable is a key point then it could be opted into during the pr stage? They could register with the bot something like /subsidise and it'll opt them in for a $1 payout reduction receiving .5 of that while we keep the service fee?

Maybe there is a cleaner way to opt in?

rndquu commented 1 year ago

For me both approaches (a separate /subsidise command or automatically deducting 1$ from a reward for gas fees on 1st permit generation) are fine.

One more point is that it is not clear how to collect a service fee. I mean that payout rewards are signed by partner accounts while a service fee should be somehow collected by ubiquity's faucet account. So we somehow need to transfer a service fee from a partner's account to ubiquity account.

P.S. It seems that the current issue should be moved to the https://github.com/ubiquity/ubiquibot repo.

Keyrxng commented 1 year ago

So a partner signs for the payout but the $0.5 comes from the UBQ account.

I guess we can simply transfer 0.0003 XDAI

I'm assuming that you meant from the UBQ account when you said this ^ and not the partner account

The $1 coming from UBQ means we could generate a $1 permit from the partner to UBQ and then claim it straight to the UBQ account, no?

So we just deduct $1 from the payout amount, generate a permit for say $11.50 for the user and $1 for UBQ upon completion, we have the bot claim that permit and then send the $0.5 to the user?

Factoring in confirmation time I'm unsure what the best thing to do would be as:

P.S I may be misunderstanding the way things work under the hood but as far as I know, the bot has access to both UBQ and Partner accounts when running, so we can send funds directly to the user from UBQ as well as have the permission to generate a permit for UBQ to actually claim from the partner wallet?

rndquu commented 1 year ago

I'm assuming that you meant from the UBQ account when you said this ^ and not the partner account

Yes

The $1 coming from UBQ means we could generate a $1 permit from the partner to UBQ and then claim it straight to the UBQ account, no?

Yes, we could

So we just deduct $1 from the payout amount, generate a permit for say $11.50 for the user and $1 for UBQ upon completion, we have the bot claim that permit and then send the $0.5 to the user?

Yes, it could work this way

Factoring in confirmation time I'm unsure what the best thing to do would be as:

  • Partner has no funds, the permits are still generated, the $1 would fail and we'd still send the .5.
  • Or, if they have no funds we don't send it but then it becomes well how do we facilitate it then, would it be a function of the bot on the pr or issue or a function of the claim portal or would we log the failed $1 claims to the db and they can be manually or semi-manually claimed

Yes, it seems that we should save failed 1$ "faucet" claims to a DB and try to claim later.

P.S I may be misunderstanding the way things work under the hood but as far as I know, the bot has access to both UBQ and Partner accounts when running, so we can send funds directly to the user from UBQ as well as have the permission to generate a permit for UBQ to actually claim from the partner wallet?

Yes, the bot has access to partner accounts (i.e. their wallet private keys). The "UBQ account" you're referring to can be considered as a separate partner (i.e. the whole ubuiquity organization is a separate partner with its own wallet private key regardless that it also maintains the bot). So I think that there should be a separate "ubiquity faucet account" for 1$ faucet transfers.

have the permission to generate a permit for UBQ to actually claim from the partner wallet

Yes, we have this option but this looks fishy from a partner's view. I mean that some 3rd party organization generates permits and transfers funds from partner's wallet. But I can't think of a better approach.

Keyrxng commented 1 year ago

Awesome, well I mean, I can see how that might come across fishy but it's not like that inherent risk wasn't there to begin with, it's just that we are now trying to leverage it for our gain so it does start to stink a lil I guess.

I've been pondering the idea of them somehow restricting us to permits of at max $1 that would supersede any actual permit amount but I do not think that functionality exists.

The only other way that I can think of is custom smart contract or safe module but that would grow arms and legs as a bounty and add additional setup for new partners, although it could be done

0x4007 commented 1 year ago

It might be simplest to start a new codebase/service dedicated to just being a pay.ubq.fi faucet (we can probably fork one.)

We can top it up with some money and pay.ubq.fi can handle the logic of automatically claiming a faucet top-up based on what was discussed above.

This approach is insecure but it is possible that abuse is not an issue for a long, long time.


I also am starting to think more on if we should offer two modes of the bot in the future:

  1. self custody mode (which is what we are doing now for partners.)
  2. centralized mode (which could have native integrations for things like this and perhaps the debit card.)

Ideally we can figure out all the UI/UX to give users a "centralized mode" experience, but with a genuine decentralized backend to stay true to DeFi values.

This may require that users no longer directly register their EOAs, but instead we generate some hosted/smart contract wallet for them. Then we can run transactions on their behalf.

rndquu commented 1 year ago

It might be simplest to start a new codebase/service dedicated to just being a pay.ubq.fi faucet (we can probably fork one.)

As far as I understand you're proposing a dedicated backend service (i.e. cloudflare worker) which will expose a single API like /faucet?address=0x01 for topping up a specified bounty hunter's address if:

So when a bounty hunter opens pay.ubq.fi to claim a reward then:

  1. Frontend calls smth like pay.ubq.fi/faucet?address=0x01 to top-up the balance
  2. We show an info msg like "Your address is being prefunded, pls wait for this transaction to be mined"

Correct?

Keyrxng commented 1 year ago

If the profit-from aspect is removed the simplest way would be to transfer 0.0003 direct to the hunter on pr merge, we use github api to search for merged prs into ubiquity if none then deal if 1 then no deal. It's just a secure as the rest of the bot, and cannot be abused without actually contributing to the project, so ultimately it cannot be abused.


We could write a simple smart contract with a user mapping that allows one subsidy per user, only callable by the bot filled with a couple xDai, we check the mapping on merge if true no subsidy, if false we call it. We could also add WXDAI to xDAI conversion and vice versa (subject to slippage etc ofc).


Didn't see your comment @rndquu, that makes more sense and a better iteration of what I had in mind


I don't yet understand fully how the debit cards will work, excited to see them rolled out though for sure but I'd have thought the cards would be built in as standard either way but yeah it does appease both sides of the fence offering both doesn't it.

As for the centralized mode I think it's what non-natives and web2 folks might opt for and could be approached with AA and Safe, we build safe modules that handle everything at contract level things like fees for centralized usage option either to a profit or to make it a self-sustaining eco-system where fees paid in are used to subsidise tx's etc so at a user level everything just works 'for free' (minus service charge) and they need only sign in with a username & password. Or with 1 signer access to each safe and we can freely debit accounts after rewards are paid in.

A lot of scope for it, I remember a wallet which already exists that allows us to store the PK for repeat transactions but I cannot for the life of me remember it right now.

0x4007 commented 1 year ago

As far as I understand you're proposing a dedicated backend service (i.e. cloudflare worker) which will expose a single API like /faucet?address=0x01 for topping up a specified bounty hunter's address if:

  • bounty hunter's wallet is registered in the bot's DB
  • this is the 1st issue solved by a bounty hunter
  • bounty hunter's wallet has 0 XDAI

So when a bounty hunter opens pay.ubq.fi to claim a reward then:

  1. Frontend calls smth like pay.ubq.fi/faucet?address=0x01 to top-up the balance
  2. We show an info msg like "Your address is being prefunded, pls wait for this transaction to be mined"

Correct?

This sounds like an excellent approach.

I wish there was a way to make the top-up more seamless. I'm unsure about the 5 seconds being fast enough for it to be seamless for new users.

I was thinking it would be nice to prefund the wallet as soon as the permit is generated. That way, when the contributor goes to claim, they should already have the xDAI.

Perhaps the bot can call the "invoke faucet" API endpoint when generating payment permits instead of pay.ubq.fi UI?

Then one day in the future, we can iterate and figure out how to subtract it from their permit (although I feel that this will require some type of SAFE/account abstraction solution.)

rndquu commented 12 months ago

Perhaps the bot can call the "invoke faucet" API endpoint when generating payment permits instead of pay.ubq.fi UI?

That's exactly what @Keyrxng proposed.

To sum up, as a part of this issue we should implement a server side app (in a cloudflare worker) which exposes a single API endpoint similar to /?faucet?address=0x01 which accepts an address to fund.

The faucet service should have access to the bot's DB in order to fund only when:

We'll use this faucet service in the bot on permit generation.

@Keyrxng Sounds good?

Keyrxng commented 12 months ago

It sounds exactly like transfer user .00003 xDai from the bot on permit generation but with extra steps that to me don't serve any really benefit as opposed to just sending directly from the bot, other than it adding another point of failure imo. A lot of additional work for something that would be 20 or so lines of codes for the bot with better error handling in cases when cloudflare fails.

So create a worker that has PK access to an EOA, and call that API on permit generation from the bot so that the EOA sends 0.0003 gas to the user as soon as permit is generated so long as the requirements are met.

The worker will be standalone, will require db access, pk access, and manually be funded with xDai by UBQ?

Am I understanding this right?

rndquu commented 12 months ago

It sounds exactly like transfer user .00003 xDai from the bot on permit generation but with extra steps that to me don't serve any really benefit as opposed to just sending directly from the bot, other than it adding another point of failure imo. A lot of additional work for something that would be 20 or so lines of codes for the bot with better error handling in cases when cloudflare fails.

I guess the idea is to have a generalized solution which could be used in the bot or in pay.ubq.fi or somewhere else like our own facet website should we have such an idea.

The worker will be standalone, will require db access, pk access, and manually be funded with xDai by UBQ?

Yes

rndquu commented 12 months ago

It sounds exactly like transfer user .00003 xDai from the bot on permit generation but with extra steps that to me don't serve any really benefit as opposed to just sending directly from the bot, other than it adding another point of failure imo. A lot of additional work for something that would be 20 or so lines of codes for the bot with better error handling in cases when cloudflare fails.

I guess the idea is to have a generalized solution which could be used in the bot or in pay.ubq.fi or somewhere else like our own facet website should we have such an idea.

The worker will be standalone, will require db access, pk access, and manually be funded with xDai by UBQ?

Yes

P.S. A agree that initiating a transfer from the bot's code is simpler but our requirements are changed frequently so generalized solutions seems to be better.

Keyrxng commented 12 months ago

When you put it like that it does make more sense, I'm too narrow minded 😂

ubiquibot[bot] commented 11 months ago

@Keyrxng - Releasing the bounty back to dev pool because the allocated duration already ended! Last activity time: Thu Nov 09 2023 10:18:10 GMT+0000 (Coordinated Universal Time)

ubiquibot[bot] commented 11 months ago

@Keyrxng The time limit for this bounty is on Sat, 18 Nov 2023 14:35:43 UTC

ubiquibot[bot] commented 11 months ago

@Keyrxng - Releasing the bounty back to dev pool because the allocated duration already ended! Last activity time: Thu Nov 09 2023 10:18:10 GMT+0000 (Coordinated Universal Time)

rndquu commented 11 months ago

@Keyrxng Could you self assign again?

Keyrxng commented 11 months ago

/start

ubiquibot[bot] commented 11 months ago

Deadline Sat, 18 Nov 2023 17:44:44 UTC
Registered Wallet 0xAe5D1F192013db889b1e2115A370aB133f359765

Tips:

ubiquibot[bot] commented 11 months ago

Task Assignee Reward

[ CLAIM 300 WXDAI ]

0xAe5D1F19...33f359765

If you've enjoyed your experience in the DevPool, we'd appreciate your support. Follow Ubiquity on GitHub and star this repo. Your endorsement means the world to us and helps us grow!
We are excited to announce that the DevPool and UbiquiBot are now available to partners! Our ideal collaborators are globally distributed crypto-native organizations, who actively work on open source on GitHub, and excel in research & development. If you can introduce us to the repository maintainers in these types of companies, we have a special bonus in store for you!

ubiquibot[bot] commented 11 months ago

Task Creator Reward

pavlovcik: [ CLAIM 109.2 WXDAI ]