EIP-2612 è l'estensione ERC-20 Permit che consente a un possessore di token di concedere un'autorizzazione di spesa a un contratto intelligente o a un altro account tramite una firma off-chain anziché una transazione approve onchain. Incorporando i dati firmati in un'unica chiamata permit(), gli utenti risparmiano gas e gli integratori possono raggruppare approvazione + azione in un'unica transazione atomica.
Caratteristiche principali
- Gasless, single-call approvals: Un possessore firma un messaggio EIP-712 off-chain e un'unica chiamata permit() imposta istantaneamente l'autorizzazione verificando al contempo la firma, eliminando la necessità di un approve onchain separato e semplificando l'esperienza utente.
- Security & backward compatibility: Each permit consumes a unique, ever-increasing nonce and the signature is bound to the token's EIP-712 domain (name, chain ID, contract address). The extension adds < 200 bytes to a standard ERC-20, leaving balances and transfers untouched.
- Seamless DeFi & wallet integration: DEXs, lending protocols, routers, and meta-TX relayers can batch permit -> action in one atomic transaction, while wallets like MetaMask and Ledger present it as a familiar Sign Message flow instead of a gas-priced approval.
Perché non è necessario su Solana
Il modello di account di Solana elimina questa necessità
Modello di approvazione token
Come funzionano le approvazioni su Solana
Modello fee payer
Chi paga le commissioni di transazione
Come implementare
Guida all'implementazione
Esempio 1
Implementazione base
JavaScript
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
import {
createApproveInstruction,
createTransferInstruction,
getAssociatedTokenAddressSync
} from "@solana/spl-token";
const connection = new Connection("https://api.devnet.solana.com");
const owner = Keypair.generate();
const delegate = owner.publicKey;
const recipient = new PublicKey("DESTINATION_WALLET");
const mint = new PublicKey("TOKEN_MINT");
const amount = 1_000_000;
const ownerATA = getAssociatedTokenAddressSync(mint, owner.publicKey);
const recipientATA = getAssociatedTokenAddressSync(mint, recipient);
const ixApprove = createApproveInstruction(ownerATA, delegate, owner.publicKey, amount);
const ixTransfer = createTransferInstruction(ownerATA, recipientATA, owner.publicKey, amount);
const tx = new Transaction().add(ixApprove, ixTransfer);
tx.feePayer = owner.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.sign(owner);
const sig = await connection.sendRawTransaction(tx.serialize());
console.log("Sent (self-sponsored):", sig);Esempio 2
Implementazione avanzata
JavaScript
import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
import { createTransferInstruction, getAssociatedTokenAddressSync } from "@solana/spl-token";
const connection = new Connection("https://api.devnet.solana.com");
const owner = Keypair.generate(); // replace with real keypair
const feePayer = Keypair.generate(); // replace with real keypair
const recipient = new PublicKey("DESTINATION_WALLET");
const mint = new PublicKey("TOKEN_MINT");
const amount = 500_000;
const ownerATA = getAssociatedTokenAddressSync(mint, owner.publicKey);
const recipientATA = getAssociatedTokenAddressSync(mint, recipient);
const ix = createTransferInstruction(ownerATA, recipientATA, owner.publicKey, amount);
const tx = new Transaction().add(ix);
tx.feePayer = feePayer.publicKey;
tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
tx.partialSign(owner);
tx.sign(feePayer);
const sig = await connection.sendRawTransaction(tx.serialize());
console.log("Sent (relayer-sponsored):", sig);
Confronto tra nodi