Come determinare l'indirizzo di uno smart contract prima della distribuzione: utilizzare CREATE2 per uno scambio di criptovalute

Il tema della blockchain non cessa di essere fonte non solo di ogni sorta di clamore pubblicitario, ma anche di idee molto preziose dal punto di vista tecnologico. Pertanto, non ha aggirato gli abitanti della città soleggiata. Le persone guardano da vicino, studiano, cercano di spostare la propria esperienza dall’infobase tradizionale ai sistemi blockchain. Fin qui in modo puntuale: uno degli sviluppi di Rostelecom-Solar è in grado di verificare la sicurezza del software basato sulla blockchain. E lungo il percorso sorgono alcune riflessioni sulla risoluzione dei problemi applicativi della comunità blockchain. Uno di questi trucchetti - come determinare l'indirizzo di un contratto intelligente prima della distribuzione utilizzando CREATE2 - oggi voglio condividerlo con voi sotto il taglio.

Come determinare l'indirizzo di uno smart contract prima della distribuzione: utilizzare CREATE2 per uno scambio di criptovalute
Il codice operativo CREATE2 è stato aggiunto all'hard fork Constantinople il 28 febbraio di quest'anno. Come indicato nell'EIP, questo codice operativo è stato introdotto principalmente per i canali statali. Tuttavia, lo abbiamo utilizzato per risolvere un problema diverso.

Ci sono utenti con saldi in borsa. Dobbiamo fornire a ciascun utente un indirizzo Ethereum, al quale chiunque può inviare token, ricostituendo così il proprio account. Chiamiamo questi indirizzi "portafogli". Quando i token arrivano nei portafogli, dobbiamo inviarli ad un unico portafoglio (hotwallet).

Nelle sezioni seguenti, analizzo le opzioni per risolvere questo problema senza CREATE2 e spiego perché le abbiamo abbandonate. Se sei interessato solo al risultato finale, puoi trovarlo nella sezione Soluzione Finale.

Indirizzi Ethereum

La soluzione più semplice è generare nuovi indirizzi ethereum per i nuovi utenti. Questi indirizzi saranno i portafogli. Per trasferire i token dal portafoglio all'hotwallet, è necessario firmare la transazione chiamando la funzione trasferimento() con la chiave privata del portafoglio dal backend.

Questo approccio presenta i seguenti vantaggi:

  • è solo
  • il costo del trasferimento dei token dal portafoglio all'hotwallet è pari al costo della chiamata alla funzione trasferimento()

Tuttavia, abbiamo abbandonato questo approccio perché presenta uno svantaggio significativo: è necessario archiviare le chiavi private da qualche parte. E non solo possono andare perse, ma è anche necessario gestire attentamente l'accesso a queste chiavi. Se almeno uno di essi viene compromesso, allora i token di un determinato utente non raggiungeranno l'hot wallet.

Come determinare l'indirizzo di uno smart contract prima della distribuzione: utilizzare CREATE2 per uno scambio di criptovalute

Crea un contratto intelligente separato per ciascun utente

L'implementazione di un contratto intelligente separato per ciascun utente consente di non archiviare chiavi private dai portafogli sul server. L'exchange chiamerà questo contratto intelligente per trasferire i token sull'hotwallet.

Abbiamo abbandonato anche questa soluzione, poiché non è possibile mostrare all'utente l'indirizzo del suo portafoglio senza implementare uno smart contract (questo in realtà è possibile, ma in un modo piuttosto complicato con altri svantaggi di cui non parleremo qui). In borsa, l'utente può creare tutti gli account di cui ha bisogno e ognuno ha bisogno del proprio portafoglio. Ciò significa che dobbiamo spendere soldi per implementare un contratto senza nemmeno essere sicuri che l'utente utilizzerà questo account.

Codice operativo CREATE2

Per risolvere il problema del metodo precedente, abbiamo deciso di utilizzare l'opcode CREATE2. CREATE2 ti consente di predeterminare l'indirizzo in cui verrà distribuito il contratto intelligente. L'indirizzo viene calcolato utilizzando la seguente formula:

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


, dove:

  • indirizzo — indirizzo del contratto intelligente che chiamerà CREATE2
  • sale - valore casuale
  • init_code - bytecode del contratto intelligente per la distribuzione

Ciò garantisce che l'indirizzo che forniamo all'utente conterrà effettivamente il bytecode desiderato. Inoltre, questo contratto intelligente può essere implementato ogni volta che ne abbiamo bisogno. Ad esempio, quando un utente decide di utilizzare il proprio portafoglio per la prima volta.
Come determinare l'indirizzo di uno smart contract prima della distribuzione: utilizzare CREATE2 per uno scambio di criptovalute
Inoltre, puoi calcolare ogni volta l’indirizzo dello smart contract invece di memorizzarlo, perché:

  • indirizzo nella formula è costante in quanto è l'indirizzo della nostra fabbrica di portafogli
  • sale - hash ID_utente
  • init_code è permanente poiché utilizziamo lo stesso portafoglio

Ulteriori miglioramenti

La soluzione precedente presenta ancora uno svantaggio: è necessario pagare per l’implementazione del contratto intelligente. Tuttavia, puoi liberartene. Per questo puoi chiamare la funzione trasferimento()e poi auto distruzione() nel costruttore del portafoglio. E poi verrà restituito il gas per l’implementazione del contratto intelligente.

Contrariamente alla credenza popolare, puoi distribuire uno smart contract allo stesso indirizzo più volte con il codice operativo CREATE2. Questo perché CREATE2 controlla che il nonce dell'indirizzo di destinazione sia zero (gli viene assegnato il valore "1" all'inizio del costruttore). Allo stesso tempo, la funzione auto distruzione() reimposta l'indirizzo nonce ogni volta. Pertanto, se si richiama CREATE2 nuovamente con gli stessi argomenti, il controllo nonce verrà superato.

Tieni presente che questa soluzione è simile alla soluzione dell'indirizzo ethereum, ma senza la necessità di archiviare chiavi private. Il costo del trasferimento di denaro da un portafoglio a un hotwallet è approssimativamente uguale al costo della chiamata di una funzione trasferimento(), poiché non paghiamo per l'implementazione del contratto intelligente.

Decisione finale

Come determinare l'indirizzo di uno smart contract prima della distribuzione: utilizzare CREATE2 per uno scambio di criptovalute

Inizialmente preparato:

  • funzione per ottenere il sale user_id
  • contratto intelligente che chiamerà l'opcode CREATE2 con il sale appropriato (ovvero wallet factory)
  • bytecode del wallet corrispondente al contratto con il seguente costruttore:

constructor () {
    address hotWallet = 0x…;
    address token = 0x…;
    token.transfer (hotWallet, token.balanceOf (address (this)));
    selfdestruct (address (0));
}


Per ogni nuovo utente, mostriamo l'indirizzo del suo portafoglio tramite calcolo

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


Quando l'utente trasferisce i token all'indirizzo del portafoglio corrispondente, il nostro backend vede l'evento Transfer con il parametro _auguale all'indirizzo del portafoglio. A questo punto è già possibile aumentare il saldo dell'utente sull'exchange prima di utilizzare il portafoglio.

Quando nell'indirizzo del portafoglio si accumulano abbastanza token, possiamo trasferirli tutti in una volta sull'hotwallet. Per fare ciò, il backend chiama la funzione smart contract factory, che esegue le seguenti azioni:

function deployWallet (соль uint256) {
    bytes memory walletBytecode =…;
    // invoke CREATE2 with wallet bytecode and salt
}


Pertanto, viene chiamato il costruttore del contratto intelligente del portafoglio, che trasferisce tutti i suoi token all'indirizzo dell'hotwallet e quindi si autodistrugge.

È possibile trovare il codice completo qui. Tieni presente che questo non è il nostro codice di produzione, poiché abbiamo deciso di ottimizzare il bytecode del portafoglio e di scriverlo in codici operativi.

Autore Pavel Kondratenkov, specialista di Ethereum

Fonte: habr.com

Aggiungi un commento