USD Finans

Magasinet der gør dig klogere på penge

EIP-2612: Gasfri token-godkendelser med Permit

EIP-2612: Gasfri token-godkendelser med Permit

Hvorfor betale for en godkendelse, der i bund og grund blot er et digitalt nik? Hvis du nogensinde har siddet og ventet på, at din wallet først skulle “Approve” og derefter “Swap”, mens gasmåleren tikkede derudad, ved du præcis, hvor frustrerende det kan føles. De ekstra klik koster tid, penge – og for mange nye brugere: modet til overhovedet at prøve DeFi.

Den gode nyhed er, at EIP-2612 vender hele det billede på hovedet. Med ét enkelt pennestrøg – eller rettere: én digital signatur – kan du nu give dApps tilladelse til at flytte dine tokens helt uden at skulle fyre en separat on-chain-transaktion af. Resultatet? Gasfri godkendelser, færre trin i brugerrejsen og en mere strømlinet oplevelse, fra første klik til færdig handel.

I denne artikel dykker vi ned i, hvordan Permit-funktionen virker, hvorfor den er sikker, og hvad udviklere såvel som investorer bør vide, inden de hopper ombord. Vi ser også på konkrete use cases – fra én-klik swaps til meta-transaktioner – og kigger frem mod næste bølge af innovation med Uniswaps Permit2.

Er du klar til at spare på både nerver og gas? Læs videre, og opdag, hvordan EIP-2612 kan blive de smarte penge på din næste DeFi-rejse.

Baggrund: Traditionelle ERC-20-godkendelser og deres begrænsninger

ERC-20-standarden blev udformet med en simpel approve/allowance-model, der har tjent økosystemet godt siden 2017. Modellen fungerer i to trin:

  1. approve: Brugeren kalder approve(spender, amount) på selve token-kontrakten og giver dermed spender (typisk en DEX eller DeFi-protokol) ret til at trække op til amount tokens fra brugerens konto.
  2. transferFrom: Når handlingen (swap, deposit, låntagning osv.) skal udføres, kalder kontrakten transferFrom(owner, spender, amount) og flytter tokens inden for det godkendte loft.

Hvorfor modellen giver friktion

Udfordring Praktisk konsekvens
Ekstra transaktion Brugeren skal først sende approve og derefter selve handlingen – to on-chain hændelser i stedet for én.
Gasomkostninger Approve koster typisk 40-60k gas oven i den efterfølgende handling. På høje gas-dage kan det være flere dollars pr. token.
Tidsforsinkelse Brugeren må vente på, at godkendelsen bliver mined, før selve swap/deposit kan eksekveres.
Brugerforvirring Nye brugere undrer sig over, hvorfor de skal “betale to gange” og signere to gange for én handling.

Specifikt i dex- og defi-flows

  • Hver ny token der handles, kræver separat approval. Mange brugere får derfor en hel “godkendelses-kø” første gang de prøver DeFi.
  • Onboarding-flows, hvor man typisk vil bytte eller deponere tokens med det samme, ender i et stop-go-stop-go mønster, der koster konverteringer.
  • Meta- og batch-transaktioner, som ellers kunne pakkes i ét klik, må opgive at inkludere token-overførsler, fordi godkendelsen skal ligge forud.

Sikkerheds-trade-offs

For at reducere friktionen vælger mange wallets og dApps at bede om uint256.max (“uendelig”) allowance, så brugeren kun behøver godkende én gang. Det skaber dog et permanent angrebsflade: bliver DEX-kontrakten opdateret med en bug, eller kompromitteres den, kan hele brugerens saldo drænes.

Opsummering

Approve/allowance-modellen er solid, men den koster både gas, tid og brugeroplevelse. For især førstegangs-brugere og mobile wallets er ekstra klik og ventetid en reel barriere. Dette sætter scenen for EIP-2612 Permit, der samler godkendelse og handling i én gasfri signatur.

Sådan virker Permit: Signaturer, nonces og EIP-712

Nøglen til EIP-2612 er, at godkendelsen flyttes fra en on-chain approve-transaktion til en off-chain signatur, som efterfølgende kan indløses af enhver på kæden. Det gøres via den nye funktion

function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;

Funktionen accepterer tre grupper af data:

  1. Autorisering: owner, spender og value.
  2. Replay-beskyttelse: deadline og en nonce, der ligger gemt i kontrakten.
  3. Signaturen: de klassiske v, r, s-felter fra Elliptic Curve Digital Signature Algorithm (ECDSA).

Eip-712: Maskinlæsbar signering

Signaturen dækker over en typed data-struktur defineret i EIP-712. For et ERC-20-token ser det typisk sådan ud:

Permit( address owner, address spender, uint256 value, uint256 nonce, uint256 deadline)

Walleten viser brugeren præcist de felter, der indgår, og danner signaturen over

keccak256( abi.encode( PERMIT_TYPEHASH, owner, spender, value, nonce, deadline ))

Den hash bliver dernæst kombineret med domæneseparatoren for at undgå identiske signaturer på tværs af kontrakter eller kæder:

Felt Formål
name Token-navn (f.eks. “USD Coin”)
version Kontraktversion (ofte “1”)
chainId Undgår cross-chain misbrug efter en hardfork
verifyingContract Selve token-adresssen

Nonces & deadlines = ingen genspil

  • Nonce: Et heltal, der kun kan bruges én gang pr. owner. Kontrakten ++nonce[owner] ved hver succesfuld permit.
  • Deadline: UNIX-tid, hvorefter signaturen bliver ugyldig. Udviklere bør tillade 5-10 minutter som standard, ikke “uint(-1)”.

Denne kombination gør det umuligt for angribere at gensende en gammel signatur eller genbruge den på et andet netværk.

Hvem gør hvad?

  1. Bruger: Underskriver EIP-712-prompten i sin wallet – ingen gas betales her.
  2. dApp: Samler signaturen og kalder permit on-chain, ofte i samme transaktion som den efterfølgende handling (swap, deposit …).
  3. Relayer (valgfri): Kan betale gas for brugeren og videresende permit + handling, hvilket gør hele flowet fuldstændigt gasfrit for slutbrugeren.

Resultatet er, at dApp’en kan gå direkte videre til den egentlige forretning uden den sædvanlige “Approve token”-flaskehals – alt sammen sikret af kryptografisk verificerbare signaturer og robuste replay-værn.

Sikkerhed og risici: Bedste praksis for udviklere og brugere

Når godkendelser flyttes fra kæden til signaturer, skifter angrebsfladen karakter. Følg derfor disse grundregler, uanset om du er token-udvikler, dApp-bygger eller slutbruger:

  1. Begræns tidshorisonten
    Sæt deadline til minutter – ikke dage. En kort udløbstid reducerer værdien af en kompromitteret signatur.
  2. Undgå ubegrænsede allowances
    Udfyld value med det præcise beløb, der skal bruges, i stedet for type(uint256).max. Det begrænser skaden, hvis spender-adressen kompromitteres.
  3. Gennemsigtig UI
    Wallets og dApps bør altid vise de fem nøglefelter – owner, spender, value, deadline og nonce – så brugeren forstår, hvad der signeres.

Tekniske faldgruber og hvordan de afværges

Trussel Beskrivelse Afværgning
Signatur-malleabilitet Ændring af s-værdien kan skabe en anden men gyldig signatur. Brug OpenZeppelin v4+ implementationer, som afviser ikke-kanoniske ECDSA-signaturer.
chainId-skift Efter hard fork får kæden nyt ID; ældre signaturer kan blive ugyldige. Inkludér altid aktuel chainId i domæneseparatoren og kræv ny signatur efter fork.
Phishing via off-chain prompts Brugere lokkes til at “signere for at logge ind”, men afgiver reel permit. UI skal fremhæve spender-adressen (ofte en DEX-router). Educér brugere om aldrig at underskrive tilladelser, de ikke forventer.
Forældede allowances Spender har fortsat ret efter brug, hvis allowance ikke nulstilles. dApps bør kalde permit(..., value=0) efter handlingen, eller benytte transferFrom til at forbruge hele beløbet.

Validér og log korrekt

dApp-side:

  • Brug _signTypedData/eth_signTypedData_v4 til at indhente signaturen.
  • Verificér lokalt med ethers.utils.verifyTypedData før du sender den on-chain. Så slipper brugeren for en mislykket transaktion, hvis signaturen er ugyldig.
  • Gem rå v, r, s i backend eller analytics-lag for revision og fejlsporing.

Wallet-side:

  • List aktive permit-allowances i UI, ligesom det allerede gøres for on-chain approve.
  • Tilbyd “Revoke”-knap, der udfører en ny permit med value = 0 eller kalder tokenets approve(0).
  • Marker signaturer, der nærmer sig udløb, så brugeren hurtigt kan forlænge eller slette dem.

Ekstra tip til udviklere

  1. Implementér nonces() som public view returns (uint256) så front-ender kan hente den aktuelle nonce uden at parse events.
  2. Supportér permit selv på L2’s, hvor gasprisen er lav – det fjerner ét klikhop for brugeren.
  3. Udgiv en EIP-165 interface-ID, så tredjeparts-dApps kan autodetektere, at din kontrakt understøtter EIP-2612.

Ved at kombinere korte deadlines, tydelig brugerflade og robust signatur-validering kan EIP-2612 nedsætte friktionen i DeFi uden at øge risikoen – men kun hvis både udviklere og brugere følger ovenstående retningslinjer.

Implementering og kompatibilitet i praksis

Den hurtigste vej til en kompatibel token er at nedarve fra ERC20Permit i OpenZeppelins kontrakt-bibliotek (v4.9+). Ét enkelt import-statement tilføjer hele EIP-2612-flowet – inkl. nonces(), DOMAIN_SEPARATOR() og selve permit().

// SPDX-License-Identifier: MITpragma solidity ^0.8.20;import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Permit.sol";contract USDK is ERC20Permit { constructor() ERC20("USD Københavner", "USDK") ERC20Permit("USD Københavner") // name field i domain separator { _mint(msg.sender, 1_000_000 ether); }}

Vigtige grænseflader (skal eksponeres, hvis du skriver kontrakten fra bunden):

  • function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s)
  • function nonces(address owner) returns (uint256)
  • function DOMAIN_SEPARATOR() returns (bytes32)

Bemærk, at OpenZeppelin automatisk håndterer EIP-712 domain separator, opdaterer nonces og validerer signaturernes v/r/s. Udvikleren skal primært beslutte chainId locking (standard i OZ), og hvorvidt deadline skal tjekkes mod block.timestamp (det gør OZ også).

2. Dapp-siden: Signér, send permit, udfør handling

  1. Hent nonce & byg typed data
    const nonce = await token.nonces(userAddress);
    Typed-data strukturen skal følge præcis skemaet i EIP-2612 (se tabel nedenfor).
  2. Lad wallet signere
    I ethers.js v6:
    // EIP-712 signaturconst sig = await signer.signTypedData( { name: "USD Københavner", version: "1", chainId: 1, verifyingContract: token.address, }, { Permit: [ { name:"owner", type:"address" }, { name:"spender", type:"address" }, { name:"value", type:"uint256" }, { name:"nonce", type:"uint256" }, { name:"deadline",type:"uint256" } ]}, { owner, spender, value, nonce, deadline });

    Underliggende RPC-metode er eth_signTypedData_v4, som alle større wallets efterhånden understøtter.

  3. Send on-chain permit
    De fleste dApp-flows lægger permit først i en multicall / batch:
    const tx = await router.swapExactTokensForETHSupportingFeeOnTransferTokens( value, 0, path, user, deadline, { permits: [{ ...sig, owner, spender: router.address, value, deadline }] });

    Fælles gas deles med den efterfølgende swap eller deposit, så brugeren stadig kun signer én gang.

Field Type Formål
owner address Token-ejer, der signerer
spender address dApp / kontrakt, der får allowance
value uint256 Beløb (evt. type(uint256).max)
nonce uint256 Replay-beskyttelse
deadline uint256 Tidsgrænse for signaturen

3. Wallet- og netværksstøtte

  • Metamask, Rabby, Coinbase Wallet – fuld støtte til eth_signTypedData_v4.
  • Hardware wallets – Ledger Live og Trezor Suite kan nu vise typed-data felter direkte; ældre firmware kræver blind signing.
  • Layer 2 – Domain-separatoren indeholder chainId; samme signatur kan ikke genbruges cross-chain, hvilket er en fordel på rollups.

4. Fallback-strategier, når et token ikke har eip-2612

dApp’en bør detektere permit() ved runtime:

const hasPermit = !!token.interface.getFunction("permit");
  • Ingen permit
    Vis standard Approve-skærm og forvent to transaktioner. Husk at estimere korrekt gas for traditionelle godkendelser.
  • Meta-transaktions fallback
    Relayers kan betale gas og kalde approve på vegne af brugeren, mod et lille gebyr i token’en selv (Gelato, Biconomy). Ikke helt gasfrit, men ét klik.
  • Uniswap Permit2
    Hvis token ikke understøtter EIP-2612, men brugeren allerede har givet global Permit2-tilladelse, kan dApp’en udnytte det i stedet. Kræver dog support i routeren.

5. Test & verifikation

Unit-tests bør inkludere:

  • Valid signatur = korrekt nonce stiger og allowance sættes.
  • Forkert v/r/s eller udløbet deadline = revert.
  • Nonce-genbrug = revert (replay-angreb).

På dApp-siden kan man lave dry-run simulation via Anvil eller Tenderly for at sikre, at permit + den næste handling eksekveres i samme blok.

Med disse byggesten kan både token-udstedere og dApp-udviklere indføre brugeroplevelser, hvor “godkend” ikke længere er en flaskehals, men blot en usynlig del af flowet.

Use cases, måling af effekt og fremtiden (Permit2 m.m.)

Når udviklere først begynder at indarbejde permit-flowet, opdager de hurtigt, at værdien rækker langt ud over den umiddelbare gasbesparelse. Her er de mest udbredte anvendelser – og hvordan man kan måle, at de faktisk gør en forskel.

Praktiske use cases

  1. Én-klik swaps på DEX’er
    Uden EIP-2612 skal brugeren:
    1) sende en approve, vente på mined-status og
    2) sende selve swap-kaldet.

    Med permit signerer brugeren blot off-chain, og dApp’en kalder permit → swap i samme transaktion. Resultat: ét klik, én transaktion, lavere frafald.

  2. Gasfri onboarding til wallets & DeFi-protokoller
    Mange nye brugere har ingen native ETH/MATIC osv. at betale gas med. En relayer eller sponsoreret transaktion kan nøjes med at sende brugerens signatur on-chain og dække gasregningen. Dermed er første interaktion helt friktionsfri.
  3. Batch- og meta-transaktioner
    Wallets som Safe (tidl. Gnosis Safe) eller transaktionsbundlere (f.eks. Gelato, Biconomy) kan pakke permit sammen med flere efterfølgende handlinger – f.eks. permit → deposit → stake – i én executeret transaktion. Det reducerer både block-tid og kompleksitet for brugeren.

Måling af effekt

Metric Før (approve+call) Efter (permit) Forbedring
Antal on-chain tx pr. handling 2 1 −50 %
Bruger-klik i UI 2-3 1 −60 – 70 %
Gasforbrug* (swap-eksempel) ≈ 90 k ≈ 60 k −35 %
Konverteringsrate** 67 % 82 % +15 pp

*Gas afhænger af token-implementering og swap-router. **Konverteringsrate måles som fuldførte swaps i forhold til signerede intents.

Fremtiden: Uniswap permit2 m.m.

I november 2022 introducerede Uniswap Labs Permit2 – et udvidet godkendelseskoncept, der løser flere begrænsninger i EIP-2612:

Funktion EIP-2612 Permit2
Understøttede tokens Kræver ændring af hver ERC-20-kontrakt Én fælles kontrakt, token-agnostisk
Godkendelses-scope Kun owner→spender Batch-godkendelser & sweeps
Revokering approve(0) on-chain Central invalidate-funktion
Gas-omkostning Lav til moderat Endnu lavere via delt storage

Permit2 gør det muligt for dApps at:

  • Indhente én signatur, der dækker mange tokens og fremtidige transaktioner.
  • Flytte tokens fra brugeren til flere kontrakter i samme call (sweep).
  • Hurtigt tilbagekalde kompromitterede signaturer globalt.

Adoptionsudsigter

Flere større DEX’er (Uniswap v3/v4, 1inch), wallet-udbydere (Rainbow, Coinbase Wallet) og bundlere har allerede integreret EIP-2612, og flere byggesten som @openzeppelin/contracts gør det trivielt at tilføje til nye tokens. Permit2 er stadig tidlig, men forventes at vinde indpas, fordi den ikke kræver nye token-udrulninger. Kombinationen af EIP-2612 (token-niveau) og Permit2 (dApp-niveau) peger derfor mod en fremtid, hvor godkendelser sker én gang – og brugerne sjældent eller aldrig møder den famøse “Approve X”-popup igen.

Indhold