FukiPay is a trustless messaging bot which allows users to easily interact with the Ethereum blockchain. The messaging bot generates a unique smart-wallet for each user which can be used to receive and spend Ethereum and ERC-20 tokens but to also interact with the Ethereum DeFi.
FukiPay is a trustless messaging bot which allows users to easliy interact with the Ethereum blockchain Each user starting a conversation with the FukiPay software will get a smart-wallet created and deployed on the Ethereum blockchain. The smart-wallet generated by FukiPay allows the users to do the following operations:
For this hackathon, we built the FukiPay bot on Telegram, due to its openness and flexibility on bot development. Furthermore, many crypto communities use Telegram daily, thus allowing this target demographic to use our software.
When interacting with the FukiPay bot on Telegram, a main menu workflow will be displayed to the user with message button he can press to directly send commands without having to tap anything. User inputs are required only for specifying an amount to send or receive.
Languages: Typescript, Solidity
Prod environment: Firebase
CI: Github Actions
API: Blocknative
We chose to use TypeScript whereas the team was not familiar with it.
At this time, written code is surely not conventional, but choosing it from the beginning, it left us open for some improvement and may bring more interest for potential contributors.
We used Solidity for smart contracts because the vast majority of the ecosystem uses it.
For the development of smart-contract, we started from the starter kit communicated at the beginning of the hackathon. So Buidler is used, it has been a great experience, and we definitely will continue to use it for future projects.
We also used ethers.js in the bot code, to keep the same stack as in the smart contract, and also because it is a good lib and works nicely with TypeScript.
For the production environment, Firebase was chosen for its convenience as a serverless solution and zero cost for a humble app. Still, we had to upgrade to the Blaze plan because the free (Spark) plan doesn't allow external queries (outside of Google) and we had to make some for notifications. Services used are Cloud Functions and Cloud Firestore.
For the Telegram bot, we used Telegraf because it currently seems to be the most active and documented JS library for this purpose.
In the beginning, we wanted to create a non-custodial smart wallet (still with some owner related stuff for safety), with encrypted message handling, but our first disappointment was that there is not yet a standard that defines an URI scheme to call smart contract methods, and the ease of use was a priority (we needed to be able to accept the deposit of funds via a QR code). So we decided to create a contract for each onboarding account, the manager being a sort of router, as a result unfortunately, it makes the solution less non-custodial.
On the backend side, there are 2 functions:
- one for the Telegram webhook
- one for the Blocknative webhook
We needed to be notified of transactions happening on the blockchain, so we searched for webhook solutions, but many projects didn't seem to be active anymore, then we found Blocknative, it seems to be a young project, and it worked well for us so far. It is a webhook solution that allows to listen to an address and notifications of all the transactions happening.
We store some data in the chose persistence solution (Cloud Firestore).
We need to persist data for 2 reasons:
- having a sort of mini-indexer to keep track of the transactions and display a history
- mapping the users with their wallet
As we may expand the solution to other bots in the future, the user is identified with a UID, which is stored in the smart wallet manager.
A sample record of a user data looks like this:
{
"wallet_address": {
"stringValue": "0x0A17cd45f84D8cF2672cD934ED2625dd3B25e62f"
},
"wallet_status": {
"stringValue": "active"
},
"uid": {
"stringValue": "537082d3-245d-4597-8b95-6d1e3ff7902f"
},
"is_2fa_active": {
"booleanValue": true
},
"id": {
"integerValue": "257696245"
},
"secret_2fa": {
"stringValue": "DNTFEYCSJRBUWOZR"
},
"username": {
"stringValue": "VitalikButerin"
}
},
"createTime": "2020-05-24T11:30:00.437369Z",
"updateTime": "2020-05-24T11:31:17.359071Z"
A transaction record like this:
{
{
"type": {
"stringValue": "wallet_creation"
},
"uid": {
"stringValue": "537082d3-245d-4597-8b95-6d1e3ff7902f"
},
"hash": {
"stringValue": "0x58c825ece0fe257794af0ec4d8a9e33897e44e3a4ddfea3185a1e662e3624d0d"
},
"status": {
"stringValue": "confirmed"
}
},
"createTime": "2020-05-24T11:30:54.525885Z",
"updateTime": "2020-05-24T11:31:17.444171Z"
},
The 2 main points of failure are the non-blockchain parts, aka the serverless functions, and the database.
As anyone can query our webhook, we must make sure nobody is faking requests, a first step is to hide our webhook behind a secret path, and change it regularly, we should also verify the origin of each request.
The Cloud Firestore database setting must be configured with care, as it is easy to accidentally publicly expose data.
The project uses a SmartWalletManager
smart-contract, which is managed by the Ethereum private key of the Telegram bot, and serves as the smart-wallet factory. Every time a new user is onboarded on the application, the bot will call the createWallet(UID)
function on the SmartWalletManager
, which will then deploy a new smart-contract UserSmartWallet
, containing all the smart-wallet and DeFi logic and registered with the UID of the newly joined user.
The SmartWalletManager stores a mapping of all the UID with their corresponding smart-wallet addresses (if they exist).
To simplify the listening of events on the Ethereum blockchain and to avoid having the bot to subscribe to every single user smart-wallets, we decided to use the smart-wallet Manager as the central event emitter. Any time an action is processed on a smart-wallet, the latter will send this information back to the smart-wallet manager in order to have only one smart-contract to listen.
Thus, Blocknative will call back the serverless project with a webhook once an event is detected from the Manager contract, and will allow the bot to send a notification message back to the user.
The UserSmartWallet
smart-contract integrates multiple interfaces from other smart-contracts, more specifically:
ERC-20 interface to allow the receiving and spending of ERC-20 tokens.
Aave's aToken
, LendingPool
and LendingPoolAddressesProvider
interfaces to allow the deposit and redemption of lent tokens on the Aave protocol.
pTokens interface for the redeem()
method access to swap pBTC on the Ethereum chain into BTC.
The User smart-wallet contract also manages a list of owners that can interact with it.
mapping (address => bool) public hasOwnerAccess;
By default, the Telegram bot FukiPay will be granted owner access to all user smart-wallets. However, the users can add Ethereum addresses to their smart-wallet in order to interact with their smart-wallet from outside the bot (by using a web app connected to the smart-wallet abi). Users can also remove the FukiPay bot owner access, if they want to keep the smart-wallet for themselves, granting complete control of the funds to them.