Како да ја одредите адресата на паметниот договор пред распоредувањето: користење CREATE2 за размена на крипто

Темата за блокчејн никогаш не престанува да биде извор не само на секакви возбудувања, туку и на идеи кои се многу вредни од технолошка гледна точка. Затоа, не ги заобиколи жителите на сончевиот град. Луѓето внимателно гледаат, студираат, се обидуваат да ја пренесат својата експертиза во традиционалната безбедност на информациите на блокчејн системи. Досега, тоа е на место: еден од развоите на Rostelecom-Solar може да ја провери безбедноста на софтверот базиран на блокчејн. И на патот, се појавуваат некои размислувања за решавање на применетите проблеми на блокчејн заедницата. Еден од овие животни хакови - како да ја одредите адресата на паметниот договор пред распоредувањето користејќи CREATE2 - денес сакам да споделам со вас под рез.

Како да ја одредите адресата на паметниот договор пред распоредувањето: користење CREATE2 за размена на крипто
Оптичкиот код CREATE2 беше додаден во константинополската хард-форк на 28 февруари оваа година. Како што е наведено во ЕИП, овој оптички код е воведен првенствено за државните канали. Сепак, го искористивме за да решиме друг проблем.

Има корисници со салда на берзата. Мораме на секој корисник да му обезбедиме адреса на Ethereum на која секој може да испраќа токени, а со тоа да ја надополни својата сметка. Ајде да ги наречеме овие адреси „паричници“. Кога токените пристигнуваат во паричници, мора да ги испратиме во еден паричник (топла паричник).

Во следните делови, ги анализирам опциите за решавање на овој проблем без CREATE2 и ви кажувам зошто ги напуштивме. Доколку ве интересира само конечниот резултат, можете да го најдете во делот „Конечно решение“.

Адреси на Ethereum

Наједноставното решение е да се генерираат нови Ethereum адреси за нови корисници. Овие адреси ќе бидат паричниците. За да префрлите токени од паричник во врел паричник, треба да ја потпишете трансакцијата со повикување на функцијата трансфер() со приватниот клуч на паричникот од задниот дел.

Овој пристап ги има следните предности:

  • едноставно е
  • трошокот за пренос на токени од паричник во врел паричник е еднаков на цената на повикот на функцијата трансфер()

Сепак, се решивме против овој пристап бидејќи има еден голем недостаток: треба да ги зачувате приватните клучеви некаде. Не само што може да се изгубат, туку треба и внимателно да управувате со пристапот до овие клучеви. Ако барем еден од нив е компромитиран, тогаш токените на одреден корисник нема да стигнат до врелиот паричник.

Како да ја одредите адресата на паметниот договор пред распоредувањето: користење CREATE2 за размена на крипто

Направете посебен паметен договор за секој корисник

Распоредувањето на посебен паметен договор за секој корисник ви овозможува да избегнете складирање на приватни клучеви за паричници на серверот. Размената ќе го нарече овој паметен договор за пренос на токените во врелиот паричник.

Ние, исто така, го напуштивме ова решение, бидејќи на корисникот не може да му се покаже адресата на неговиот паричник без да се распореди паметен договор (ова е всушност можно, но на прилично сложен начин со други недостатоци за кои нема да разговараме овде). На размена, корисникот може да креира онолку сметки колку што му треба, а на секој му треба свој паричник. Ова значи дека треба да трошиме пари за распоредување на договор без да бидеме сигурни дека корисникот ќе ја користи оваа сметка.

Оптички код CREATE2

За да го решиме проблемот на претходниот метод, решивме да го користиме оптичкиот код CREATE2. CREATE2 ви овозможува однапред да ја одредите адресата каде што ќе биде распореден паметниот договор. Адресата се пресметува со следнава формула:

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


, каде што:

  • адреса — адресата на паметниот договор што ќе го повика CREATE2
  • сол - случајна вредност
  • init_code — бајткод за паметен договор за распоредување

Ова осигурува дека адресата што му ја даваме на корисникот всушност го содржи саканиот бајтекод. Покрај тоа, овој паметен договор може да се користи секогаш кога ни треба. На пример, кога корисникот ќе одлучи да го користи својот паричник за прв пат.
Како да ја одредите адресата на паметниот договор пред распоредувањето: користење CREATE2 за размена на крипто
Покрај тоа, можете да ја пресметате адресата на паметниот договор секој пат наместо да ја складирате затоа што:

  • адреса во формулата е константна, бидејќи ова е адресата на нашата фабрика за паричник
  • сол — хаш на корисник_ид
  • init_code е константна бидејќи го користиме истиот паричник

Повеќе подобрувања

Претходното решение сè уште има еден недостаток: треба да платите за да го распоредите паметниот договор. Сепак, можете да се ослободите од него. За да го направите ова, можете да ја повикате функцијата трансфер(), и потоа самоуништување() во конструкторот на паричникот. И тогаш ќе се врати гасот за распоредување на паметниот договор.

Спротивно на популарното верување, можете да распоредите паметен договор на иста адреса повеќе пати со оптичкиот код CREATE2. Тоа е затоа што CREATE2 проверува дали нонцето на целната адреса е нула (на почетокот на конструкторот и е доделена вредноста „1“). Во овој случај, функцијата самоуништување() секој пат ги ресетира нонс адресите. Значи, ако повторно повикате CREATE2 со истите аргументи, проверката nonce ќе помине.

Имајте предвид дека ова решение е слично на опцијата за адреса на Ethereum, но без потреба од складирање приватни клучеви. Трошоците за префрлање пари од паричник во врел паричник се приближно еднакви на трошоците за повикување функција трансфер(), бидејќи не плаќаме за распоредување на паметни договори.

Конечна одлука

Како да ја одредите адресата на паметниот договор пред распоредувањето: користење CREATE2 за размена на крипто

Првично подготвен од:

  • функција за добивање сол од user_id
  • паметен договор кој ќе го повика CREATE2 оптичкиот код со соодветна сол (т.е. фабрика за паричник)
  • бајтекод на паричникот што одговара на договорот со следниот конструктор:

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


За секој нов корисник ја прикажуваме адресата на неговиот/нејзиниот паричник со пресметка

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


Кога корисникот префрла токени на соодветната адреса на паричникот, нашиот заден дел гледа настан за пренос со параметарот _до, еднаква на адресата на паричникот. Во овој момент, веќе е можно да се зголеми салдото на корисникот на централата пред да се распореди паричникот.

Кога адресата на паричникот ќе акумулира доволен број на токени, можеме да ги пренесеме сите одеднаш во топла паричник. За да го направите ова, задниот дел ја повикува фабричката функција за паметни договори, која ги извршува следните дејства:

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


Така, се повикува конструкторот на паметни договори за паричник, кој ги префрла сите свои токени на адресата на жешкиот паричник и потоа се самоуништува.

Целосниот код може да се најде тука. Ве молиме имајте предвид дека ова не е наш код за производство, бидејќи решивме да го оптимизираме бајтекодот на паричникот и го напишавме во оптички кодови.

Автор Павел Кондратенков, специјалист за Ethereum

Извор: www.habr.com

Додадете коментар