Construire un MelonBot – Melon Protocol
Utilisation de MelonJS pour négocier par programme au nom d’un fonds Melon
Le protocole Melon a été conçu pour automatiser et simplifier les parties ennuyeuses de la gestion des actifs. Pour environ 50 $ de gaz Ethereum, vous pouvez créer un fonds qui exécutera toutes ses propres fonctions comptables, gérera les investissements et les rachats et appliquera les mandats de conformité par programme. Et puisque toutes ces actions sont effectuées sur la chaîne, elle est 100% transparente et peut être auditée. En tant que gestionnaire, vous pouvez créer un historique immuable pour montrer vos prouesses, et en tant qu’investisseur, vous pouvez avoir pleinement confiance dans le fonds où vous placez vos actifs.
La partie amusante du travail d’un gestionnaire d’actifs, la gestion des risques, est restée en grande partie manuelle sur Melon à ce jour. À notre connaissance, les échanges ont été exclusivement effectués via le Melon Terminal. Cependant, avec la récente version de MelonJS, il est possible d’automatiser les stratégies de trading qui s’exécutent en arrière-plan, sans avoir à saisir et exécuter manuellement des transactions.
Cette série de billets de blog sera un document évolutif, en commençant par décrire les fonctions les plus élémentaires qu’un bot de trading nécessite avant de passer au déploiement et potentiellement à la stratégie.
Pour commencer, je ferai l’hypothèse que nous construisons un très basique if this then that
bot. En d’autres termes, il surveillera les marchés pour une certaine condition (this
), et lorsque cette condition est remplie, ajustez le portefeuille de l’utilisateur en fonction des règles que le professionnel a mises en place (that
).
le this
la partie de ce bot dépendra de vous. Mon exemple sera simple, à la limite de stupide. Il n’échangera que deux jetons – WETH et MLN – et sera attribué à 100% à l’un ou à l’autre à tout moment. Il décidera quand et quoi échanger en fonction d’une condition pseudo-aléatoire. Il fera probablement mieux que mon Fonds Melon actuel.
Je vais cependant approfondir le that
en abordant en profondeur les sujets suivants:
- Comment vérifier les soldes actuels de votre fonds Melon
- Comment vérifier les prix des actifs sur Uniswap
- Comment trader sur Uniswap
Liens utiles
Tout d’abord, nous allons démarrer un projet et installer les dépendances nécessaires. Pour les trois méthodes ci-dessus, nous aurons besoin de quelques web3
packages et MelonJS
. Utilisez du fil ou npm pour installer @melonproject/melonjs
, web3-core
, web3-eth
, web3-providers
et web3-utils
. De plus, j’utilise bignumber.js
pour gérer tous les nombres et les calculs de jetons, et dotenv-extended
pour accéder aux variables d’environnement. J’écris également ceci en TypeScript, j’ai donc ajouté cela en tant que dépendance de développement. Lorsque vous avez terminé, votre package.json
devrait ressembler à ceci:
Nous aurons également besoin des dernières configurations de déploiement de protocole pour suivre diverses adresses de contrat. Ces fichiers de configuration sont disponibles dans JSON
se former dans divers dépôts Melon. Je les ai pris ici car le Melon Terminal est très activement entretenu et est très probablement la version la plus récente. J’ai ajouté quelques fichiers à l’arborescence pour contenir nos différentes classes, méthodes et utilitaires, donc mon répertoire ressemble maintenant à ceci:
J’ai pris la liberté de m’approprier certaines méthodes utilitaires qui apparaissent dans les bases de code Melon et Avantgarde. Deux fonctionnent avec les mathématiques des jetons et les autres requêtes ethgasstation.io pour nous donner un prix du gaz approprié. J’ai également bloqué la fonction pour créer un environnement (discuté ci-dessous) dans ce dossier.
Notre dernière tâche avant de passer à la partie amusante est de discuter de la gestion des clés privées. Dans la plupart des cas, un utilisateur signe des transactions à l’aide d’une extension de navigateur ou d’un portefeuille matériel. Dans le cas de ce bot, nous automatiserons le processus de signature d’une transaction, nous avons donc besoin d’accéder directement au portefeuille. Ceci peut être réalisé en utilisant la clé privée ou un chiffré JSON
fichier portefeuille et mot de passe.
Par souci de simplicité, je vais stocker le mien en tant que variable d’environnement et utiliser dotenv-extended
pour y accéder. J’ai déjà ajouté .env
fichiers sur mon .gitignore
il n’y a donc aucune chance de pousser accidentellement cela vers un référentiel hébergé avec des clés intactes pour que le monde puisse les voir. Il existe différentes façons de gérer cette interaction, et il vaut la peine de rechercher comment vous souhaitez la gérer. Si vous retirez une chose de ce paragraphe, ce devrait être:
Ne codez pas en dur vos clés privées et ne stockez pas vos clés privées sur Github.
Je sais que c’est deux choses. Mais ils sont tous les deux importants. Couvre ton cul ici.
Par le Documentation, les contrats de protocole Melon ont tous une représentation de classe JavaScript exportée depuis MelonJS. Ces classes nécessitent chacune Environment
La variable est transmise à leur méthode constructeur afin de fournir à la classe un contexte sur le réseau au sein duquel elle fonctionne et le compte Ethereum spécifique qui y accède. Nous allons écrire quelques méthodes pour configurer correctement Environment
variable, ainsi que vos informations de portefeuille Ethereum, afin d’utiliser avec succès les contrats Melon exportés par MelonJS. J’ai coincé ces méthodes dans le util
répertoire, et ils ressemblent à ceci:
La première étape consiste à créer une fonction qui renvoie un provider
, qui est un web3
objet qui représente une connexion à un nœud Ethereum de votre choix. Nous appelons cette fonction et passons le fournisseur retourné au constructeur pour un nouveau Eth
classe que nous appellerons client
. le Eth
la classe est exportée de web3. Nous créons ensuite un compte lié à notre clé privée (qui se souvient que j’ai stocké en tant que variable d’environnement) et l’ajoutons à notre client. Notez que comme je l’ai mentionné ci-dessus, cette clé doit se trouver sur le compte avec lequel vous avez créé le fonds Melon pour lequel ce bot se négociera.
Avec cela, vous avez maintenant prouvé que vous êtes le propriétaire du compte en question. Créer un nouveau environment
en utilisant le client nouvellement instancié et le déploiement JSON
J’ai décrit ci-dessus.
Ensuite, nous allons créer une classe qui contiendra toutes les méthodes que notre bot devra exécuter, ainsi que les variables nécessaires à leur exécution dans l’état. Plus explicitement, en utilisant cet état en combinaison avec ces méthodes, notre bot devrait être capable de:
- Recherchez les soldes symboliques d’un fonds
- Recherchez le prix d’un jeton libellé en WETH ou le prix de WETH libellé en ce jeton sur Uniswap
- Tradez sur Uniswap pour ajuster les soldes du fonds de deux jetons distincts (dans ce cas WETH et MLN)
Il convient de noter que je prends ici l’itinéraire le plus simple possible. Bien que vous puissiez échanger n’importe quel jeton contre un autre sur la version actuelle d’Uniswap, afin de générer un prix de jeton à jeton, vous devez passer par WETH. En d’autres termes, vous devez passer deux appels (Token 1 à WETH, WETH à Token 2) et interpoler ensuite combien de Token 1 vous obtenez un Token 2. Je vais juste échanger WETH contre MLN et vice versa. Cependant, si vous souhaitez voir cette complexité gérée de manière assez transparente, consultez le code du terminal Melon ici.
Tout au long des blocs de code ci-dessous, je ferai référence à des propriétés de classe. Cela étant, je commencerai ma discussion par une section sur les paramètres que nous devons transmettre au constructeur de la classe. Le dépôt contient un exemple de classe entièrement typé.
Toutes les adresses pertinentes des contrats peuvent être référencées via le hub du fonds (dont l’adresse est disponible sur your-fund-name.melon.fund). Nous utiliserons un modèle d’usine et le contrat de concentrateur pour trouver ces adresses et les stocker dans la classe de l’État lorsque vous l’appellerez. Nous allons également instancier les différentes représentations de contrat JavaScript et les stocker dans leur état. Le résultat est que nous devons passer seulement trois variables pour instancier la classe: le hubAddress
et les symboles des deux jetons que vous voulez que le bot échange.
Notez également que nous devons importer et appeler le createEnvironment
lorsque la classe est créée.
Commençons par utiliser le Accounting
contrat exporté par MelonJS pour voir ce que votre fonds détient actuellement.
FundHolding
est un type également exporté depuis MelonJS. Il s’agit d’un objet de la taille de l’exploitation et de l’adresse du jeton.
Nous utiliserons différentes classes de contrats liées à Uniswap pour interroger les prix actuels des avoirs en fonds que nous venons de rentrer, puis éventuellement pour échanger des positions.
Pour vérifier un prix, l’ordre des opérations est le suivant:
- déterminer quel jeton vous échangez contre WETH (la devise de base est celle qui quitte votre inventaire, la devise de cotation est celle que vous achetez)
- trouver l’adresse du contrat d’échange Uniswap pour ce jeton en utilisant le
UniswapFactory
nous avons instancié ci-dessus - créer un objet de contrat pour cet échange en utilisant
UniswapExchange
- appeler une fonction sur ce contrat pour retourner le taux (dans la devise de base) pour trader un montant (de cette devise de base).
Dans notre cas, nous allons également interpoler la taille et le taux de la devise de cotation de l’équation, car la négociation sur Uniswap nécessite un objet paramètres contenant certaines de ces informations. La méthode finit par ressembler à ceci:
MelonJS
les importations dans ce bloc de code incluent UniswapFactory
et UniswapExchange
.
La création d’une transaction commerciale est exécutée de la même manière. Nous prendrons le uniswapTradingAdapter
que nous avons instancié avec la classe et appelons le takeOrder
méthode sur elle. Nous transmettrons cette méthode à l’adresse du responsable et à un argument d’ordre que nous construirons à partir du résultat de la requête de prix.
Il convient de noter ici – J’ai intégré une variable de glissement dans cette méthode, car si vous transmettez un montant supérieur à celui actuellement disponible sur Uniswap, la transaction sera rejetée. Si vous passez un montant inférieur à ce qui est actuellement disponible, Uniswap s’exécutera au meilleur prix disponible. J’ai approximativement 3%; en réalité, mes échanges de tests ont été si petits que j’ai obtenu la quasi-totalité de la taille indiquée sur chaque échange que j’ai effectué. Le glissement dans les pools de liquidité est similaire au glissement dans les échanges traditionnels – plus la taille que vous essayez de trader est grande, plus il y en a probablement. Ce sera quelque chose que vous devrez optimiser par vous-même.
Notre fonction d’échange renvoie ici une promesse de transaction. J’ai laissé à mon script d’exécution le soin de gérer la résolution de cette promesse.
Jusqu’à présent, nous avons une classe qui contient des méthodes pour vérifier le solde de vos jetons de fonds, vérifier les prix de ces jetons sur Uniswap et échanger ces jetons sur Uniswap. Ce qui manque, c’est la sauce secrète que vous fournirez pour injecter de la logique dans le bot. Comment devrait-il négocier et quand? Il est facile d’imaginer une méthode qui vérifie les soldes, puis vérifie les prix, puis exécute ces prix via une sorte d’algorithme d’indicateur, puis effectue des transactions si l’indicateur revient positif. Pour moi, cette fonction magique ressemble à ceci:
Je n’ai pas de sauce secrète pour toi. C’est là que vous pouvez faire preuve de créativité – utilisez vos meilleures mesures d’assistance technique ou sur la chaîne ou tout autre vaudou. Comme je l’ai mentionné ci-dessus, ma stratégie sera de trader au hasard. Cela étant, j’ai écrit un script qui s’appelle récursivement toutes les 15 minutes, génère un nombre aléatoire entre 0 et 1 et échange si ce nombre est supérieur à 0,50. S’il échange, le script gère l’exécution de la transaction. Il existe une multitude de cas de bord et de coin qui feront échouer cette implémentation, dont beaucoup sont liés à la logique de transaction ethereum.
Il vaut la peine de creuser dans le p de web3romievents de réfléchir à la façon dont vous gérerez les erreurs qui se produisent, et il semble que cela pourrait être un bon sujet pour moi à couvrir dans un futur article de blog. D’autres sujets sur ma liste incluent:
- gérer un état plus complexe et le conserver dans une base de données
- mettre en œuvre une stratégie réelle en utilisant cet état complexe et diverses mesures de marché
- vérifier toutes les plates-formes de négociation disponibles et exécuter au meilleur taux possible
- faire le travail des devops pour exécuter ce bot indéfiniment
Dans l’état actuel des choses, mon bot est opérationnel et brûle à travers du gaz, faisant du commerce en mon nom. Lorsque je l’exécute dans mon terminal, cela ressemble à ceci:
➜ yarn devyarn run v1.21.1$ cross-env NODE_ENV=development ts-node --require dotenv-extended/config --transpile-only srcINSTANTIATING ENVIRONMENT ==>FIRING UP THE BOT ==>CONSULTING THE ORACLE ==>NO TRADING BY ORDER OF THE ORACLEGoing to sleep.INSTANTIATING ENVIRONMENT ==>FIRING UP THE BOT ==>CONSULTING THE ORACLE ==>THE ORACLE SAYS TO TRADEBuying 26270323039658927422.53 MLN by selling 430703553862299497 WETHTransaction successful.blockHash: 0xe0a94b99ec8a3ca8d5ba2d7e71a2f4ca0301cd96764d3d5f0afe9db76f71204ftransactionHash: 0xaa0edecb4c741c58b44daf5742305abb5c055949028b913d18f84cdd260bec33gasUsed: 684251Going to sleep.