cardano-foundation / cardano-wallet

HTTP server & command-line for managing UTxOs and HD wallets in Cardano.
Apache License 2.0
758 stars 211 forks source link

feature to request additional addresses for a wallet #2921

Open benapetr opened 2 years ago

benapetr commented 2 years ago

The problem that you wish to solve

Right now from perspective of someone who implements a "merchandize" system such as e-shop based on cardano - you need to be able to distinguish customers from each other. In ideal situation you assign each customer unique address to which they should send ADA in order to recognize which customer sent ADA (in some cases you may need to have unique address for each order).

cardano-wallet generates only about 20 addresses per wallet. It would be nice if there was some method to generate N additional addresses if current pool is depleted.

Description

Create method (or parameter for addresses call) to generate additional addresses for a wallet

Implementation suggestions

No response

HeinrichApfelmus commented 2 years ago

Thanks for the feedback!

Note that if the wallet detects a payment to or from an address listed in the https://localhost:8090/v2/wallets/{walletId}/addresses endpoint, it will automatically discover new addresses so that ~ 20 unused addresses are available. Unfortunately, that's not quite what you are looking for, in that you probably have many more addresses for which you expect payments.

Unfortunately, increasing this so-called address gap (default 20) makes restoration from a seed mnemonic more difficult -- if you have, say, 1000 consecutive unused addresses (users that did not send funds), the wallet may not be able to discover some payments if it is only looking ahead 20 addresses. This is a technical limitation of the industry standard BIP-44, on which the CIP-1852 standard is based upon.

I'm currently working on making larger address gaps more practical, and I'm looking into alternative standards. It will take a while, though.

In the meantime, possible workarounds include:

benapetr commented 2 years ago

well, the thing is I don't even have these extra addresses, but I would like to have them, basically right now I would be only able to handle first 20 customers, or actually, first 20 orders, for other orders I would have to return error "address pool depleted" or something like that.

Or I would need to create huge amount of wallets, each to get 20 addresses, but that also would be very impractical. I think this is a blocker for everyone who wants to create an online store that uses cardano for payments.

I am also wondering how exchanges overcame this problem, when you want to deposit ADA to exchange, every user gets a unique address to deposit to, so they must have millions of addresses per wallet? So it is probably doable.

benapetr commented 2 years ago

I can't even solve this by knowing senders address, even if I told customers to send to adress addr_XXXXX and fill their address before they start transaction - they will never know from which address is ADA going to be sent, due to this bug - https://github.com/input-output-hk/cardano-wallet/issues/2614 cardano-wallet randomly redistributed ADA across the wallet, and automatically picks which addresses it takes the UTXOs from, and users don't have any way to affect this.

paweljakubas commented 2 years ago

hi @benapetr One way to create addresses (having the same mnemonic, account index=0 - for now only this is supported and arbitrary address index) is to use https://github.com/input-output-hk/cardano-addresses/

  1. So let's assume we have mnemonics:
    $ cat mnemonics.txt 
    whisper control diary solid cattle salmon whale slender spread ice shock solve panel caution upon scatter broken tonight
  2. Create extended root private key:
    $ cardano-address key from-recovery-phrase Shelley < mnemonics.txt > root.xsk
    $ cat root.xsk
    root_xsk1kra0jaflzzgtwu5mxl3qsv0gga05fyd3g0yslf3q0kgsq7ctep2wq9yjg4sgq2rwnpcuk2dw8czw9qde5f9ank5vr080fn4z9vzk8zdkvgj7qt6lmlxyn6hm2ne0ymg2srpxfu6cqxxzz75wh93u6klenqxuet7a
  3. Create stake verification key (this would be needed if you want to stake, so create base address, rather than enterprise address)
    $ cardano-address key child 1852H/1815H/0H/2/0 < root.xsk | cardano-address key public --with-chain-code > stake.xvk
    $ cat stake.xvk 
    stake_xvk14tq9nymn3m76f3q3c99aru5az6dk6az02h6d5flj6g8ghw5qvte79n5w2t5m2ezplw2zgrry8nm86dlw7rdlv46qt8ltp30jpd4malgt7zj8j

    (please notice that 0H account index was used, role=2 and stake index=0 - this should not change)

  4. Now create payment verification key:
    $ cardano-address key child 1852H/1815H/0H/0/0 < root.xsk | cardano-address key public --with-chain-code > addr0.xvk
    $ cat addr0.xvk 
    addr_xvk17sy8yc35xvdc8wg6ssy33yhjr34qtkhdk52p7m2y5qpjxrxhzf53r4scun52lwd0uf6rtke5hy00ejh7sqa9aufa2nlvzxtptycp0lcu4lkx8
    $ cardano-address key child 1852H/1815H/0H/0/1000 < root.xsk | cardano-address key public --with-chain-code > addr1000.xvk
    $ cat addr1000.xvk 
    addr_xvk1u4whatpud5wrkw89vhfx2qcnvw9tjl4q4k246ln42zzht9369aevhxvus9tq4uf6jp8h7vcwhtvsz06lrq06dx70vmln83jaqfekussxsmy50

    (we used here 0H account public key, role=0 and (ix=0 first example, x=1000 second example) ). This is how you can create many payment verification keys! 5a (for enterprise address - not staking) for testnet

    $ cardano-address address payment --network-tag testnet < addr0.xvk > enterprise0.addr
    $ cat enterprise0.addr 
    addr_test1vqjl24fqvgdfsd8x7tc5trwpyafq3qg78dp3w3ugct69eaqdkedcf
    $ cardano-address address payment --network-tag testnet < addr1000.xvk > enterprise1000.addr
    $ cat enterprise1000.addr 
    addr_test1vp5unv4h7f6743hgzqsejhsht3jj9yg6a736w5ljeh2khkcfazhvf

    5b (base addresses staking) for testnet

    $ cardano-address address delegation $(cat stake.xvk) < enterprise0.addr > base0.addr
    $ cat base0.addr 
    addr_test1qqjl24fqvgdfsd8x7tc5trwpyafq3qg78dp3w3ugct69eazqmr34pgfevux4mslq44avqpjxm9hw2ymyquy6zuy0npmq4p4uf6
    $ cardano-address address delegation $(cat stake.xvk) < enterprise1000.addr > base1000.addr
    $ cat base1000.addr 
    addr_test1qp5unv4h7f6743hgzqsejhsht3jj9yg6a736w5ljeh2khk6qmr34pgfevux4mslq44avqpjxm9hw2ymyquy6zuy0npmqelmpxa
piotr-iohk commented 2 years ago

Or I would need to create huge amount of wallets, each to get 20 addresses, but that also would be very impractical. I think this is a blocker for everyone who wants to create an online store that uses cardano for payments.

Actually Shelley wallets API allows creating wallets with larger address pool gap (up to 100k addresses), however it comes with some wallet performance cost (see: https://input-output-hk.github.io/cardano-wallet/api/edge/#operation/postWallet).

Another option at the moment can be Byron wallets (see: https://input-output-hk.github.io/cardano-wallet/api/edge/#operation/postByronWallet). Byron wallets follow random address scheme so it is possible to create new address on the wallet (see: https://input-output-hk.github.io/cardano-wallet/api/edge/#operation/createAddress), or even import some addresses (see: https://input-output-hk.github.io/cardano-wallet/api/edge/#operation/importAddresses) which were created outside (e.g. using cardano-address).

HeinrichApfelmus commented 2 years ago

benapetr :

I am also wondering how exchanges overcame this problem, when you want to deposit ADA to exchange, every user gets a unique address to deposit to, so they must have millions of addresses per wallet? So it is probably doable.

piotr-iohk:

Another option at the moment can be Byron wallets

Some exchanges do use Byron wallets, I suppose for this very reason.

HeinrichApfelmus commented 2 years ago

@benapetr

I can't even solve this by knowing senders address, even if I told customers to send to adress addr_XXXXX and fill their address before they start transaction

Instead of using addresses to disambiguate users, you could also try to use transaction metadata to disambiguate them. This is very similar to the "transfer note" or "intended purpose" for SEPA bank transfers, where retail shops often instruct buyers to include their invoice number. The drawback is that this is extra information which has to be provided by the user.

benapetr commented 2 years ago

@HeinrichApfelmus

@benapetr

I can't even solve this by knowing senders address, even if I told customers to send to adress addr_XXXXX and fill their address before they start transaction

Instead of using addresses to disambiguate users, you could also try to use transaction metadata to disambiguate them. This is very similar to the "transfer note" or "intended purpose" for SEPA bank transfers, where retail shops often instruct buyers to include their invoice number. The drawback is that this is extra information which has to be provided by the user.

this is interesting idea, but is it supported by mainstream wallets? so in theory:

there would 1 central address to which all users would send ADA, each merchant order would be distinct by ID which user would need to provide as transaction metadata. If metadata and amount matches - order is confirmed, otherwise user is asked to correct the amount. For orders that don't match (or missing metadata) user should be refunded back - which is the tricky part - because:

1 - we need to calculate the max_fee and deduct it from returned amount, so that the customer who made the mistake pays the transaction fee and not merchant, otherwise malicious users could abuse this by repeatedly sending invalid transactions 2 - there may not only be ADA as part of this transaction, if someone sends native tokens, they should be also sent back 3 - there could be multiple source addresses, should the ADA be returned to all of them? What if after deduction of max_fee some of the UTXOs would be less than 1ADA and thus impossible to be sent? 4 - what is some part of transaction is made from reward address? where should it be sent back?

To be honest - "refund" or some sort of "rollback" operation seems to me so complex that it should probably be implemented in cardano-wallet as well. If this model that is utilizing transaction metadata is supposed to be widespread, then it would make sense to support this flow in basic tools used by merchants, so that they don't need to keep implementing this same workflow on their own.

HeinrichApfelmus commented 2 years ago

For orders that don't match (or missing metadata) user should be refunded back […]

To be honest - "refund" or some sort of "rollback" operation seems to me so complex that it should probably be implemented in cardano-wallet as well. If this model that is utilizing transaction metadata is supposed to be widespread, then it would make sense to support this flow in basic tools used by merchants, so that they don't need to keep implementing this same workflow on their own.

Thanks for bringing this up, it seems to me that "refunding" is indeed a useful feature. In fact, it seems to be useful even for the original problem of matching customers to addresses: In the worst case, customers may send money to the wrong address and then the funds are gone. When using metadata, at least the shop now owns those funds and can refund them in principle. (Granted, transaction metadata is more likely to go wrong than addresses, because this problem gets much more attention for addresses. But still).

Anyway, it appears that consumer-facing wallets do not support metadata at the time of this writing.

gituser commented 2 years ago

Any update on this?

Why not make an API function of extending the address pool manually?

Sometimes it is needed when you have e.g. 0 incoming transactions and your address pool is exhausted.

HeinrichApfelmus commented 2 years ago

Compliance with the industry standard BIP-44 / CIP-1852 does not allow us to change the address_pool_gap. 😞

Why not make an API function of extending the address pool manually?

The address pool gap cannot be changed dynamically. As a workaround, you can specify a value of address_pool_gap when restoring a wallet, though.

Sometimes it is needed when you have e.g. 0 incoming transactions and your address pool is exhausted.

Could you elaborate? When you make any transaction, the address pool should enlarge automatically.

The "e-shop" scenario was never meant to be supported by BIP-44 / CIP-1852, at least not in this form.

gituser commented 2 years ago

@HeinrichApfelmus

Could you elaborate? When you make any transaction, the address pool should enlarge automatically.

If you accept Cardano (ADA) payments only and do not do any withdrawals the pool might be quickly exhausted.

teddyjfpender commented 2 years ago

@benapetr I'd really like to know a little more about this use case you're describing for cardano-wallet. Can you dive into the scenario a little more, perhaps touch on some things like: comparable existing products/payment services (decentralised/centralised), benefits of one-user-one-address, and extensions of this model (e.g. analytics, what you'd like to achieve if such a feature was created)?

Grateful if you could share any thoughts with us :-)

bogerv commented 2 years ago

@benapetr I'd really like to know a little more about this use case you're describing for cardano-wallet. Can you dive into the scenario a little more, perhaps touch on some things like: comparable existing products/payment services (decentralised/centralised), benefits of one-user-one-address, and extensions of this model (e.g. analytics, what you'd like to achieve if such a feature was created)?

Grateful if you could share any thoughts with us :-)

Example of exchanges like Binance Each user needs to have its own unique address identification, in order to know which user has actually deposit on the chain. However, most exchanges currently do not support additional meta data for withdrawal ADA.

benapetr commented 2 years ago

yes exactly this - imagine you need to create an endpoint where 10 000 different users can deposit some tokens or ADA and you differentiate each of them. Easiest would be to generate 10 000 different addresses, assign one to each user, and track their balance by adding what is sent to these addresses.

of course it's necessary to separately track the balances in separate database, you can't trust on-chain data, because cardano-wallet is randomly reshuffling UTXO between addresses randomly, per https://github.com/input-output-hk/cardano-wallet/issues/2614