Cara menentukan alamat kontrak cerdas sebelum penyebaran: menggunakan CREATE2 untuk pertukaran crypto

Topik tentang blockchain tidak berhenti menjadi sumber tidak hanya semua jenis sensasi, tetapi juga ide-ide yang sangat berharga dari sudut pandang teknologi. Karena itu, dia tidak melewati penduduk kota yang cerah itu. Orang-orang mengamati, mempelajari, mencoba mengalihkan keahlian mereka dalam analisis informasi tradisional ke sistem blockchain. Sejauh ini, hanya satu poin: salah satu perkembangan Rostelecom-Solar mampu memeriksa keamanan perangkat lunak berdasarkan blockchain. Dan di sepanjang jalan, beberapa pemikiran muncul untuk menyelesaikan masalah yang diterapkan dari komunitas blockchain. Salah satu peretas kehidupan ini - cara menentukan alamat kontrak cerdas sebelum penyebaran menggunakan CREATE2 - hari ini saya ingin berbagi dengan Anda di bawah potongan.

gambar
Opcode CREATE2 ditambahkan ke fork keras Konstantinopel pada 28 Februari tahun ini. Sebagaimana ditunjukkan dalam EIP, opcode ini diperkenalkan terutama untuk saluran negara. Namun, kami menggunakannya untuk memecahkan masalah lain.

Ada pengguna di bursa dengan saldo. Kami harus memberikan setiap pengguna dengan alamat Ethereum tempat siapa pun dapat mengirim token, sehingga mengisi kembali akun mereka. Sebut saja alamat ini "dompet." Ketika token datang ke dompet, kita harus mengirimnya ke satu dompet (hotwallet).

Di bagian berikut, saya menganalisis solusi untuk masalah ini tanpa CREATE2 dan menjelaskan mengapa kami mengabaikannya. Jika Anda hanya tertarik pada hasil akhirnya, Anda dapat menemukannya di bagian "Solusi Akhir".

Alamat Ethereum


Solusi termudah adalah menghasilkan alamat ethereum baru untuk pengguna baru. Alamat-alamat ini akan menjadi dompet. Untuk mentransfer token dari dompet ke hotwallet, Anda harus menandatangani transaksi dengan memanggil fungsi transfer () dengan kunci pribadi dompet dari backend.

Pendekatan ini memiliki keunggulan sebagai berikut:

  • hanya saja
  • biaya transfer token dari dompet ke hotwallet sama dengan harga panggilan fungsi transfer ()

Namun, kami mengabaikan pendekatan ini karena memiliki satu kelemahan signifikan: Anda perlu menyimpan kunci pribadi di suatu tempat. Dan intinya bukan hanya mereka bisa hilang, tetapi juga Anda perlu mengontrol akses ke kunci-kunci ini dengan hati-hati. Jika setidaknya satu dari mereka dikompromikan, maka token pengguna tertentu tidak akan mencapai dompet panas.

gambar

Buat kontrak pintar terpisah untuk setiap pengguna


Menyebarkan kontrak pintar yang terpisah untuk setiap pengguna menghilangkan kebutuhan untuk menyimpan kunci dompet pribadi di server. Pertukaran akan memanggil kontrak pintar ini untuk mentransfer token ke hotwallet.

Kami juga menolak keputusan ini, karena pengguna tidak dapat ditunjukkan alamat dompetnya tanpa menggunakan kontrak pintar (ini sebenarnya mungkin, tetapi dengan cara yang agak rumit dengan kekurangan lainnya, yang tidak akan kami diskusikan di sini). Sebagai gantinya, pengguna dapat membuat akun sebanyak yang dia butuhkan, dan semua orang membutuhkan dompet mereka sendiri. Ini berarti bahwa kita perlu mengeluarkan uang untuk menggunakan kontrak, bahkan tidak yakin bahwa pengguna akan menggunakan akun ini.

Opcode CREATE2


Untuk memperbaiki masalah metode sebelumnya, kami memutuskan untuk menggunakan opcode CREATE2. CREATE2 memungkinkan Anda untuk menentukan sebelumnya alamat di mana kontrak pintar akan digunakan. Alamat dihitung menggunakan rumus berikut:

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

dimana:
  • address - alamat kontrak pintar yang akan memanggil CREATE2
  • garam - nilai acak
  • init_code - bytecode kontrak pintar untuk penyebaran

Ini memastikan bahwa alamat yang kami berikan kepada pengguna memang akan berisi bytecode yang diinginkan. Selain itu, kontrak pintar ini dapat digunakan saat kami membutuhkan. Misalnya, ketika pengguna memutuskan untuk menggunakan dompetnya untuk pertama kalinya.
gambar
Selain itu, Anda dapat menghitung alamat kontrak pintar setiap kali alih-alih menyimpannya, karena:

  • Alamat dalam rumus adalah konstan, karena ini adalah alamat pabrik dompet kami
  • garam - hash dari user_id
  • init_code persisten karena kami menggunakan dompet yang sama

Lebih banyak perbaikan


Solusi sebelumnya masih memiliki satu kelemahan: Anda harus membayar untuk menggunakan kontrak yang cerdas. Namun, Anda dapat menyingkirkan ini. Untuk melakukan ini, Anda dapat memanggil fungsi transfer () , lalu selfdestruct () di konstruktor dompet. Dan kemudian gas untuk penyebaran kontrak pintar akan dikembalikan.

Berlawanan dengan kepercayaan populer, Anda dapat menggunakan kontrak pintar di alamat yang sama beberapa kali dengan kode sandi CREATE2. Ini karena CREATE2 memeriksa bahwa alamat tujuan nol adalah nol (ditetapkan nilai "1" di awal konstruktor). Pada saat yang sama, fungsi selfdestruct () me-reset alamat nonce setiap kali. Dengan demikian, jika Anda memanggil CREATE2 lagi dengan argumen yang sama, pemeriksaan untuk nonce akan berlalu.

Perhatikan bahwa solusi ini mirip dengan opsi alamat ethereum, tetapi tanpa perlu menyimpan kunci pribadi. Biaya mentransfer uang dari dompet ke hotwallet kira-kira sama dengan biaya memanggil fungsi transfer () , karena kami tidak membayar untuk penyebaran kontrak pintar.

Keputusan akhir


gambar

Awalnya disiapkan oleh:

  • berfungsi untuk mendapatkan garam oleh user_id
  • kontrak pintar yang akan memanggil opcode CREATE2 dengan garam yang sesuai (mis. pabrik dompet)
  • kode byte dompet yang sesuai dengan kontrak dengan konstruktor berikut:

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

Untuk setiap pengguna baru, kami menunjukkan alamat dompetnya dengan menghitung

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

Ketika seorang pengguna mentransfer token ke alamat dompet yang sesuai, backend kami melihat acara Transfer dengan parameter _to sama dengan alamat dompet. Pada titik ini, sudah dimungkinkan untuk meningkatkan saldo pengguna di bursa sebelum menyebarkan dompet.

Ketika jumlah token yang cukup menumpuk di alamat dompet, kita dapat mentransfer semuanya sekaligus ke hotwallet. Untuk melakukan ini, backend memanggil fungsi pabrik kontrak pintar, yang melakukan tindakan berikut:

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

Dengan demikian, konstruktor dari kontrak dompet pintar disebut, yang mentransfer semua tokennya ke alamat hotwallet dan kemudian merusak diri sendiri.

Kode lengkap dapat ditemukan di sini . Harap perhatikan bahwa ini bukan kode produksi kami, karena kami memutuskan untuk mengoptimalkan bytecode dompet dan menuliskannya di opcodes.

Diposting oleh Pavel Kondratenkov, Spesialis Ethereum

Source: https://habr.com/ru/post/id475496/


All Articles