Rejoignez-Nous sur

Comment coder des jetons sans gaz sur Ethereum

noonification

News

Comment coder des jetons sans gaz sur Ethereum

9nMyFjQNicRJ5HwksmBytJBySMi2 qp8p2wsp
Photo de profil de l'auteur

@albertocuestacanadaAlberto Cuesta Cañada

Bonjour.
Je conçois et construis des solutions blockchain. J'aime rendre le complexe simple.

Débloquer Ethereum pour le grand public

Tout le monde parle de transactions Ethereum «sans gaz» parce que personne n'aime payer pour le gaz. Mais le réseau Ethereum fonctionne précisément parce que les transactions sont payées. Alors, comment pouvez-vous avoir quelque chose «sans gaz»? Quelle est cette sorcellerie?

Dans cet article, je vais vous montrer comment utiliser les schémas des transactions «sans gaz». Vous découvrirez que bien qu'il n'existe pas de déjeuner gratuit à Ethereum, vous pouvez déplacer les coûts de l'essence de manière intéressante.

En appliquant les connaissances de cet article, vos utilisateurs économiseront sur l'essence, profiteront d'une meilleure expérience utilisateur et même créeront de nouveaux modèles de délégation dans vos contrats intelligents.

Mais attendez! Il y a plus! Pour votre commodité, j'ai mis tous les outils nécessaires dans ce référentiel. Alors maintenant, la barrière pour vous de mettre en œuvre des jetons «sans gaz» est soudainement beaucoup plus faible.

Soyons ringards.

Contexte

Je dois avouer que même si je sais comment implémenter des transactions «sans gaz» dans des contrats intelligents, je connais très peu la cryptographie qui les rend possibles. Ce n’était pas un obstacle majeur pour moi, donc cela ne devrait pas non plus être pour vous.

Pour autant que je sache, ma clé privée est utilisée pour signer les transactions que j'envoie à Ethereum, et une certaine magie de cryptographie est utilisée pour m'identifier en tant que msg.sender. Cela sous-tend tout contrôle d'accès dans Ethereum.

La sorcellerie derrière les transactions «sans gaz» est que je peux produire une signature avec ma clé privée et la transaction de contrat intelligent que je veux exécuter.

La signature serait produite hors chaîne, sans rien dépenser en gaz. Ensuite, je pourrais donner cette signature à quelqu'un d'autre pour exécuter la transaction en mon nom, avec son gaz.

La fonction à laquelle la signature est destinée sera généralement une fonction régulière, mais étendue avec des paramètres de signature supplémentaires. Par exemple dans dai.sol nous avons la fonction d'approbation:

function approve(address usr, uint wad) external returns (bool)

Nous avons également le

permit

fonction, qui fait la même chose que

approve

mais prend une signature comme paramètre.

function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external

Ne vous inquiétez pas de tous ces paramètres supplémentaires, nous y arriverons. Vous devez faire attention à ce que les deux fonctions font avec le

allowance

cartographie:

function approve(address usr, uint wad) external returns (bool)
{
  allowance(msg.sender)(usr) = wad;
  …
}
function permit(
  address holder, address spender,
  uint256 nonce, uint256 expiry, bool allowed,
  uint8 v, bytes32 r, bytes32 s
) external {
  …
  allowance(holder)(spender) = wad;
  …
}

Si tu utilises

approve

, tu permets

spender

utiliser jusqu'à

wad

de vos jetons.

Si vous donnez une signature valide à quelqu'un, que quelqu'un peut appeler

permit

autoriser

spender

en utilisant vos jetons.

Donc, fondamentalement, le modèle derrière les transactions «sans gaz» est de créer une signature que vous pouvez donner à quelqu'un, afin qu'il puisse exécuter en toute sécurité une transaction spéciale. C'est comme donner la permission à quelqu'un d'exécuter une fonction.

C'est un modèle de délégation.

Les normes

Si vous êtes comme moi, la première chose à faire est de vous plonger dans le code. J'ai tout de suite remarqué ce commentaire:

// — — EIP712 niceties — -

Avec ça, je est allé dans le terrier du lapin, et s'est perdu désespérément. Maintenant que je le comprends, je peux l'expliquer en termes clairs.

EIP712 décrit comment créer des signatures pour des fonctions, de manière générique. D'autres EIP décrivent comment postuler EIP712 à des cas d'utilisation spécifiques. Par exemple EIP2612 décrit comment utiliser EIP712 signatures pour une fonction appelée

permit

qui devrait avoir la même fonctionnalité que

approve

dans un jeton ERC20.

Si vous souhaitez simplement implémenter une fonction de signature qui a été effectuée auparavant, comme l'ajout de signatures approuvées à votre propre MetaCoin, vous pouvez lire EIP2612 et vous serez bien parti. Vous pouvez même hériter d'un contrat le mettant en œuvre et limiter le stress dans votre vie.

Dans cet article, nous étudierons la mise en œuvre de transactions «sans gaz» dans dai.sol, ce qui rendra les choses claires. le dai.sol la mise en œuvre a eu lieu avant EIP2612 et est légèrement différent. Ce ne sera pas un problème.

Composition signature

Une mise en œuvre précoce de EIP712 les signatures peuvent être trouvées dans dai.sol. Il permet aux détenteurs de dai d'approuver les transactions de transfert en calculant une signature hors chaîne et en la donnant au dépensier, au lieu d'appeler approuver eux-mêmes.

Il comprend quatre éléments:

  1. UNE
    DOMAIN_SEPARATOR

    .

  2. UNE
    PERMIT_TYPEHASH

    .

  3. UNE
    nonces

    variable.

  4. UNE
    permit

    fonction.

C'est le

DOMAIN_SEPARATOR

, avec des variables associées:

string  public constant name     = "Dai Stablecoin";
string  public constant version  = "1";
bytes32 public DOMAIN_SEPARATOR;
constructor(uint256 chainId_) public {
  ...
  DOMAIN_SEPARATOR = keccak256(abi.encode(
    keccak256(
      "EIP712Domain(string name,string version," + 
      "uint256 chainId,address verifyingContract)"
    ),
    keccak256(bytes(name)),
    keccak256(bytes(version)),
    chainId_,
    address(this)
  ));
}

le

DOMAIN_SEPARATOR

n'est rien de plus qu'un hachage qui identifie de manière unique un contrat intelligent. Il est construit à partir d'une chaîne le désignant comme un domaine EIP712, le nom du contrat de jeton, la version, le chainId en cas de changement et l'adresse à laquelle le contrat est déployé.

Toutes ces informations sont hachées sur le constructeur dans le

DOMAIN_SEPARATOR

variable, qui devra être utilisée par le titulaire lors de la création de la signature, et devra correspondre lors de l'exécution du permis. Cela garantit qu'une signature n'est valable que pour un seul contrat.

C'est le

PERMIT_TYPEHASH

:

9nMyFjQNicRJ5HwksmBytJBySMi2 ae3d2w4y

le

PERMIT_TYPEHASH

est le hachage du nom de la fonction (en majuscule) et de tous les paramètres, y compris le type et le nom. Il a pour but d’identifier clairement la fonction pour laquelle la signature.

La signature sera traitée dans la fonction de permis, et si le

PERMIT_TYPEHASH

utilisé n'était pas pour cette fonction spécifique, il reviendra. Cela garantit qu'une signature n'est utilisée que pour la fonction prévue.

Puis il y a le

nonces

cartographie:

mapping (address => uint) public nonces;

Ce mappage enregistre le nombre de signatures utilisées pour un détenteur particulier. Lors de la création de la signature, un

nonces

la valeur doit être incluse. Lors de l'exécution

permit

, le nonce inclus doit correspondre exactement au nombre de signatures qui ont été utilisées jusqu'à présent pour ce titulaire. Cela garantit que chaque signature n'est utilisée qu'une seule fois.

Toutes ces trois conditions réunies, le

PERMIT_TYPEHASH

, les

DOMAIN_SEPARATOR

, et le

nonce

, assurez-vous que chaque signature est utilisée uniquement pour le contrat prévu, la fonction prévue et une seule fois.

Voyons maintenant comment la signature serait traitée dans le contrat intelligent.

La fonction de permis

permit

est le dai.sol fonction qui permet d'utiliser des signatures pour modifier

allowance

de

holder

vers

spender

.

// --- Approve by signature ---
function permit(
  address holder, address spender,
  uint256 nonce, uint256 expiry, bool allowed,
  uint8 v, bytes32 r, bytes32 s
) external;

Comme vous pouvez le voir, il y a beaucoup de paramètres là-bas. Ce sont tous les paramètres nécessaires pour calculer la signature, plus

v

,

r

et

s

qui sont la signature elle-même.

Il semble ridicule que vous ayez besoin des paramètres qui ont été utilisés pour créer la signature, mais vous le faites. La seule chose que vous pouvez récupérer à partir de la signature est l'adresse qui l'a créée, rien de plus. Nous utiliserons tous les paramètres et l'adresse récupérée pour nous assurer que la signature est valide.

Nous calculons d'abord un

digest

en utilisant tous les paramètres dont nous aurons besoin pour assurer la sécurité. le

holder

devra calculer exactement le même condensé hors chaîne, dans le cadre de la création de la signature:

bytes32 digest =
  keccak256(abi.encodePacked(
    "x19x01",
    DOMAIN_SEPARATOR,
    keccak256(abi.encode(
      PERMIT_TYPEHASH,
      holder,
      spender,
      nonce,
      expiry,
      allowed
    ))
  ));

En utilisant

ecrecover

et le

v,r,s

signature nous pouvons récupérer une adresse. Si c'est l'adresse du

holder

, nous savons que tous les paramètres correspondent (

DOMAIN_SEPARATOR

,

PERMIT_TYPEHASH

,

nonce

,

holder

,

spender

,

expiry

, et

allowed

. Si quelque chose est désactivé, la signature est rejetée:

require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");

Un mot d'avertissement ici. Il existe de nombreux paramètres qui entrent dans une signature, certains d'entre eux obscurs comme le

chainId

(partie de la

DOMAIN_SEPARATOR

). N'importe lequel d'entre eux entraînera le rejet de la signature avec le exactement la même erreur, ce qui garantit que le débogage des signatures hors chaîne sera difficile. Tu étais prévenu.

Maintenant nous savons que le

holder

approuvé cet appel de fonction. Ensuite, nous certifierons que la signature n'est pas abusée. Nous vérifions que l'heure actuelle est avant le

expiry

, cela permet de ne détenir les permis que pour une période spécifique.

require(expiry == 0 || now <= expiry, "Dai/permit-expired");

Nous vérifions également qu'une signature avec cela

nonce

n'a pas encore été utilisée, de sorte que chaque signature ne peut être utilisée qu'une seule fois.

require(nonce == nonces(holder)++, "Dai/invalid-nonce");

Et nous avons fini! dai.sol maximise le

allowance

de

holder

vers

spender

, émet un événement, et c’est tout.

uint wad = allowed ? uint(-1) : 0;
allowance(holder)(spender) = wad;
emit Approval(holder, spender, wad);

le dai.sol contrat a une approche binaire envers

allowance

, dans le dépôt à condition de trouver un comportement plus traditionnel.

Création de la signature hors chaîne

Créer la signature n'est pas pour les âmes sensibles, mais avec un peu de pratique et de persévérance, elle peut être maîtrisée. Nous reproduirons ce que fait le contrat intelligent en

permit

en trois étapes:

  1. Générer le
    DOMAIN_SEPARATOR
  2. Générer le
    digest
  3. Créer la signature de transaction

La fonction suivante créera le

DOMAIN_SEPARATOR

. C'est le même code que dans le dai.sol constructeur, mais en JavaScript et en utilisant

keccak256

,

defaultAbiCoder

et

toUtfBytes

de ethers.js. Il a besoin du nom du jeton et de l'adresse de déploiement, ainsi que du

chainId

. Il suppose que la version du jeton est «1».

9nMyFjQNicRJ5HwksmBytJBySMi2 q8802wdw

La fonction suivante créera un

digest

pour un spécifique

permit

appel. Notez que le

holder

,

spender

,

nonce

et

expiry

sont transmis comme arguments. Il passe également un

approve.allowed

argument de clarté, bien que vous puissiez simplement le définir toujours sur

true

, sinon la signature sera rejetée et quel serait l'intérêt? le

PERMIT_TYPEHASH

nous l'avons juste copié de dai.sol.

9nMyFjQNicRJ5HwksmBytJBySMi2 cf852wp4

Une fois que nous avons un

digest

, le signer est relativement facile. Nous utilisons juste

ecsign

de ethereumjs-util après avoir supprimé le préfixe 0x du

digest

. Notez que nous avons besoin de la clé privée de l'utilisateur pour ce faire.

Dans le code, nous appellerions ces fonctions comme suit:

9nMyFjQNicRJ5HwksmBytJBySMi2 ot8g2w69

Notez comment l'appel à

permit

réutilise tous les paramètres qui ont été utilisés pour créer le

digest

, avant sa signature. Seulement dans ce cas, la signature serait valide.

Notez également que les deux seules transactions de cet extrait de code sont appelées par

user2

.

user1

est le

holder

, et est celui qui a créé le

digest

et l'a signé. cependant,

user1

n’a pas dépensé d’essence à le faire.

user1

a donné la signature à

user2

, qui l'a utilisé pour exécuter à la fois le

permit

et le

transferFrom

cette

user1

permis.

Du point de vue de

user1

, c'était une transaction «sans gaz». Il n’a pas dépensé un wei.

Conclusion

Cet article montre comment utiliser les transactions «sans gaz», en précisant que «sans gaz» signifie en fait transmettre le coût du gaz à quelqu'un d'autre. Pour ce faire, nous avons besoin d'une fonction dans un contrat intelligent prêt à gérer les transactions pré-signées, et de nombreuses manipulations de données pour que tout soit sécurisé.

Cependant, il y a des gains importants à utiliser ce modèle, et c'est pourquoi il est largement utilisé. Les signatures permettent de faire passer le coût du gaz de transaction de l'utilisateur au fournisseur de services, éliminant dans de nombreux cas un obstacle considérable. Il permet également la mise en œuvre de modèles de délégation plus avancés, souvent avec des améliorations UX considérables.

UNE dépôt vous a été fourni pour commencer. Veuillez l'utiliser et s'il vous plaît continuer la conversation.

Un merci tout spécial à Georgios Konstantinopoulos, qui m'a appris tout ce que je sais sur ce modèle.

Mots clés

La bannière Noonification

Abonnez-vous pour obtenir votre tour d'horizon quotidien des meilleures histoires technologiques!





Traduction de l’article de Alberto Cuesta Cañada : Article Original

BlockBlog

Le Meilleur de l'Actualité Blockchain Francophone & Internationale | News, Guides, Avis & Tutoriels pour s'informer et démarrer facilement avec Bitcoin, les Crypto-Monnaies et le Blockchain. En Savoir Plus sur L'Équipe BlockBlog

Commenter cet Article

Commenter cet Article

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Plus dans News

Les Plus Populaires

Acheter des Bitcoin

Acheter des Alt-Coins

Sécuriser vos Cryptos

Vêtements et Produits Dérivés

Top