Keycard meta transaction on Point of Sales - help and feedback needed

Hello everyone,
we already posted this in the buidlweek page but I’m posting it here again because I would love some feedback and help to improve it and make it real.

The keycard itself can already be used to sign transactions, but in this project we aim to use it to sign meta transactions, so that the real control can be in a smart contract, where we can have more settings like max tx value, max daily txs etc…



  1. Keycard onbarding without asking users to setup a wallet and manage their keys or mnmemonic.

  2. Selling keycards with some tokens already associated to them without losing the tokens if the keycard is lost or not sold.

  3. Paying on an untrusted point of sale without pairing the keycard. Setting some daily and transaction limits in a smart contract. Signing meta transactions checked and approved by the smart contracts, leaving the gas fee payment to the merchant.


Tap Wallet dApp
Tap Wallet Smart Contract


In the phone on the right I setup a Tap Wallet. The dapp deploys a smart contract similar to a multi sig where the only signer is the keycard, and the owner is the current account used in status.
I can setup multiple Tap Wallets, each one with a different keycard associated to it, for example:

  • One for me with my keycard, and I set a limit of 0.01 value for each tx
  • Another one for me, with a different keycard and different settings
  • One for my kids so that I can top up them with some ETH weekly and manage it in case the keycards are lost.
  • One for a friend of mine that doesn’t have a phone. I’m the owner of the contract and I top it up, but he can use it to pay around.
  • One associated to a keycard I sell to a customer. He can become the owner when he becomes more expert, but he can use it straight away without setting up anything.

After the setup, the phone is no longer needed, I can just use the card to pay.

Paying at a merchant Point Of Sale (POS)

The keycard doesn’t have a display, so the POS can send any transaction and I can’t see what I’m signing. It’s ok when I use my trusted device but not with an untrusted POS.

Normally we can decide to use the keycard to sign full transactions with a pinless key, where we keep a few ETH and it’s separated from the main BIP44 addresses that we use when we pair the card to a trusted device.

In this specific use case instead, the card doesn’t have any ETH, it’s just a signer of a smart contract that has some value.
Here what happens when I tap the card on the POS (phone on the left):

  1. The POS send a random message to the keycard to be signed and get the keycard pinless address.
  2. The POS checks the Tap Wallet Factory and gets the Tap Wallet address associated to the card.
  3. The POS sends a meta transaction to the card, the card signs it and the POS sends it to the Tap Wallet.
  4. The Tap Wallet smart contract checks that the meta transaction has been signed by the right keycard. After that it checks if the value is lower that the maxTransactionValue setting. After that it allows the meta transaction and move the value to a pendingWithdrawal associated to the POS. The meta transaction is sent by the POS, so the user doesn’t pay any gas.
  5. If everything went good, the POS is allowed to withdraw the payment and get the ETH/tokens.

In this example the POS needs to put the password to send the actual transaction, but it can be avoided when we finish the new keys management. After that the tx can be sent with a hot key without asking the password, and the value can be sent automatically to a cold address.

With this use case the keycard doesn’t have any value, so it’s not a problem if we lose it. We can also give it away to a friend, and just remove it from our Tap Wallet.


Thanks Andrea, that’s great and exciting!

Here’s some fuel to the discussion. It’s more than a brain dump than anything else, and hopefully can lead to some discussions to narrow down our cases, and define next steps.

So the elements of the system are

  • On the user side

    • A Keycard with

      • A key pair (pinlesskp) - signs tx when tapped, no pin asked

      • A public address (smartwalletaddress)

    • A deployed smart contract wallet (’smartwallet’)

    • Some ways for the user to set-up, manage, monitor his smart contract wallet activity (smartwallet dapp)

    • Some ways for the user to admin his keycard : change keypair/smartcontract for instance (probably within status app, natively)

  • On the vendor side:

    • An android phone running running a PoS dapp on Status

And some considerations about how the system will be set-up

1/ keycards are handed out to users already set up with pinlesskp and the smart wallet address

From a deployment stand point, let’s consider our #1 priority is to make it simple for a user to get a keycard, get some crypto on it, and pay with it. For this, we could consider that when Keycard is handed out to users the cards are already provisioned with a pinlesskp, a smartwallet address, and the smart wallet is deployed. In this case, it’s status work to set-this all this up before deployment.

The smartwallet might or might not haver any funds on them.

Also, at this stage the user might not have Status downloaded.

In any case what the user will expect here is

  • Know what is his smartwallet adress

  • Top up his smartwallet easily

  • And secondarily how to admin his smartwallet (change max amount authorized per transaction e.g)

To meet this (know amount and top-up)

  • We would have the smartcontract QR code printed on the card. One drawback, is If we do that, we might have prevent the user to change anything to his keycard pinlesskp and smart wallet address. Keycard APi is not designed for this for now.

  • When NFC tapping the card on a phone, it should open the smartwallet dapp html page where he can get the QR code of the public address, copy his public key, see the amount held in the wallet.

Also it would be cool to enable an easy top-up of keycard by dApps too (dApp ruined by the shop owner). Main case being by the Teller network dApp for shops (in a case where shops sells empty cards that they can top up for customers). A dApp should be able to ask for a top-up screen (it’s like our receiving screen but the other way around), when a keycard is tapped to this screen the keycard should communicate the public adress where it want to receive funds. In our current case this is the smartwallet public address.

The smartwallet app page is the one that can admin his wallet settings (e.g max amount per tw, admin rights etc.)

One point is what are the smart wallet admin rules at deployment ? These contracts have been deployed by Status. What can be our strategy here ? Can we give all rights to the pinlesskp, and have the user changes these admin right to a secure keypair held by Status wallet ? Any other ideas ?

2/ implication on Status app side

At this stage the user might not have downloaded Status, he should be able to do it now. He will have to create a new account (a HD tree).

With Status installed he will expect to use it for:

  • Fund his smartwallet - so he should be able to add his smartwallet in his list of accounts (would be a cold one) very easily. Obviously this is relying on having Status manage multiple accounts scenarios.

  • Of course check his smartwallet balance easily

  • Manage his smartwallet through web3 access to his smartwallet dapp page

  • Configure his Keycard -how will he change his pinlesskp or smartwallet address if he wants to ?

Some considerations:

  • some users might want to use keycard only for payment scenarios and not as a hard wallet… meaning they would use a regular non-keycard protected status account, but would have a keycard smartwallet attached to their account still.

  • the pinlesskp will be out of the HD tree - do you see any issues with that apart from status account recovery ?

3/ can we simplify the pre-handout work ?

In case 1, there is significant work to prepare cards with a keypair (this is is pinlesskp) and smart contract address, deploy the smart contract, associate the smart contract with the pinlesskp both on the keycard and smart contract. And optionally to fund the smart contract with some crypto.

This significant work allows a user to just grab the card, and he’s ready to tap it on any phone to see his QR code to provision it, and then tap the card on a PoS to spend it. No need to download status to get im going.

However, can we think of ways where this set-up work is more done by the user or the PoS, to make it easier for Status as an organization to deploy cards ?

One specific case, is for pre-paid cards: let’s say Status wants to produce a batch of 1k keycard with 1eth each pre-paid. We’d be better off not deploy 1k smartcontracts before hand, and let’s say we do, we would be better off keeping ownership of this 1k eth until the user wants to use his keycard for the first time and transfer them at their first use in some way.

Ideas :slightly_smiling_face: ?

… and

4/ implication on the PoS side

for the Point of Sales dapp to receive Keycard payment we need to implement the native ‘receiving screen’ discussed in the past weeks here:

In the case of prepaid cards, you could include something like a burner wallet (GitHub - austintgriffith/burner-wallet: 🔥👛Burner Wallet to move crypto quickly in a web browser. Sweep to cold storage when you get home. 🏠👨🏻‍🚒) and let the user transfer the funds from the burner wallet to the keycard after they set it up.

Another approach might be to create a single contract that holds the ETH and has 1k “slots” where any ethereum address can withdraw 1 ETH by calling redeem(keccak256('secret phrase')) with their supplied secret phrase that would come with the keycard. It’s important to note in this raw version this is subject a front-running attack and would need to be constructed using something like a submarine transaction.

A viable distribution strategy is also the more traditional approach to the above, which is to run a service that sends ETH when I user authenticates. We used this for distributing SNT and ETH in Prague.

Hey Barry, how does this worked ? we’re looking at how we could do that simply for upcoming events with Keycard

Take a look at GitHub - status-im/hackathon-registration-dapp @rramos can provide more color on how it works as he built it.

I also started seeing being distributed at events. It might be work investigating as well.

Looks like this has come full circle :slight_smile: is Nick Johnson’s thing, or at least it used to be and he’s the reason we created Keycard in the first place as he and I thought it would be cool to not have a ‘scratch’n’sniff’ (??) way to do cards :smiley:
There’s certainly alot we can learn from that site in terms of promoting Keycard though.

1 Like

This hack from EthNewYork is relevant too:
Using WalletConnect and ConnextNetwork.

with the new data sync layer we could totally do a decentralized walletconnect

hey @barry these are all great ideas!
My idea is that the keycard can be distributed already with a “burner key”, so that people can take their keycard and go to buy something straight away.
If we get a list of “burner addresses” generated from the factory, we can have the distribution in an easy way where each keycard sign a message to get the funds . Or we can just deploy n “wallets” where each keycard is a signer.
Or we can just put funds on those addresses. or a mix of everything we said.
But I think the main point is using the keycard without the need to pair it to a device.

1 Like

Crossposting here for reference @rramos explanations about how the registration dApp was implemented:

The registration DApps has 3 components:
1 - The smart contract. This keeps records of all registration codes that were used, as well as performs the SNT/ETH transfer when a valid code is scanned. It also performs the validation of the registration codes via a merkle tree.
2 - A backend. This backend offers a REST api that will receive a registration code and wallet address, and will invoke the smart contract, and send proper success / error messages back to the
3 - Frontend. which access the user wallet, and communitcates with the backend.

So basically the flow goes like this:
a. We generate a list of registration codes, and use these registration codes to create a list of URLs that follow status universal link format
b. We load the contract with the merkle root of these codes, as well as sending the ETH + SNT to the contract
c. The backend service is started, (this service has a config file where we specify the account that’s going to be used to interact with the contract), also a webserver (with nginx is started to serve the frontend)

I. Users to be onboarded scan a QR code representation of an URL created in step “a.”
II. The status app will open the url with the registration code, it will open the dapp browser, which will ask the user for permission to access the wallet address
III. The frontend will send the registration code and wallet address to the backend
IV. The backend will receive these values, interact with the contract and send back a response
If the response is valid, the frontend will display a waiting state and periodically ask the backend service for the status of their transaction to know if it has been confirmed or not. if it’s confirmed, it will redirect to the status ens dapp
If the response is invalid, it will display an error message (possible errors are Invalid Code, Code has been used already, Address has been funded already, any other web3 error)