Как да определите адреса на интелигентен договор преди внедряване: използване на CREATE2 за крипто обмен

Темата за блокчейна не престава да бъде източник не само на всякакъв хайп, но и на много ценни идеи от технологична гледна точка. Затова не подмина жителите на слънчевия град. Хората се вглеждат внимателно, изучават, опитвайки се да преместят своя опит в традиционната информационна база към блокчейн системи. Дотук по точка: едно от разработките на Rostelecom-Solar е в състояние да провери сигурността на софтуера, базиран на блокчейна. И по пътя възникват някои мисли за решаване на приложни проблеми на блокчейн общността. Един от тези лайфхакове - как да определите адреса на интелигентен договор преди внедряване с помощта на CREATE2 - днес искам да споделя с вас под разреза.

Как да определите адреса на интелигентен договор преди внедряване: използване на CREATE2 за крипто обмен
Операционният код CREATE2 беше добавен в хард форка на Константинопол на 28 февруари тази година. Както е посочено в EIP, този код за операция е въведен предимно за държавни канали. Ние обаче го използвахме за решаване на различен проблем.

Има потребители с баланси на борсата. Трябва да предоставим на всеки потребител адрес в Ethereum, на който всеки може да изпраща токени, като по този начин попълва акаунта си. Нека наречем тези адреси „портфейли“. Когато токените пристигнат в портфейли, трябва да ги изпратим до един портфейл (hotwallet).

В следващите раздели анализирам опциите за решаване на този проблем без CREATE2 и ви казвам защо ги изоставихме. Ако се интересувате само от крайния резултат, можете да го намерите в секцията „Окончателно решение“.

Ethereum адреси

Най-простото решение е да генерирате нови Ethereum адреси за нови потребители. Тези адреси ще бъдат портфейлите. За да прехвърлите токени от портфейл към hotwallet, трябва да подпишете транзакцията, като извикате функцията трансфер () с частния ключ на портфейла от бекенда.

Този подход има следните предимства:

  • просто е
  • цената за прехвърляне на токени от портфейл към hotwallet е равна на цената за извикване на функцията трансфер ()

Ние обаче изоставихме този подход, защото има един съществен недостатък: трябва да съхранявате частни ключове някъде. И не само, че те могат да бъдат загубени, но и че трябва внимателно да управлявате достъпа до тези ключове. Ако поне един от тях е компрометиран, тогава токените на определен потребител няма да достигнат горещия портфейл.

Как да определите адреса на интелигентен договор преди внедряване: използване на CREATE2 за крипто обмен

Създайте отделен интелигентен договор за всеки потребител

Разполагането на отделен интелигентен договор за всеки потребител ви позволява да избегнете съхраняването на частни ключове за портфейли на сървъра. Борсата ще извика този интелигентен договор, за да прехвърли токените към hotwallet.

Също така изоставихме това решение, тъй като потребителят не може да покаже адреса на портфейла си без внедряване на интелигентен договор (това всъщност е възможно, но по доста сложен начин с други недостатъци, които няма да обсъждаме тук). На борсата потребителят може да създаде толкова акаунти, колкото му трябва, и всеки има нужда от собствен портфейл. Това означава, че трябва да харчим пари за внедряване на договор, без дори да сме сигурни, че потребителят ще използва този акаунт.

Операционен код CREATE2

За да коригираме проблема на предишния метод, решихме да използваме кода за операция CREATE2. CREATE2 ви позволява да определите предварително адреса, на който ще бъде внедрен интелигентният договор. Адресът се изчислява по следната формула:

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


, където:

  • адрес — адрес на интелигентния договор, който ще извика CREATE2
  • сол - произволна стойност
  • init_code — байт код на интелигентен договор за внедряване

Това гарантира, че адресът, който предоставяме на потребителя, действително ще съдържа желания байт код. Освен това този интелигентен договор може да бъде разгърнат, когато имаме нужда. Например, когато потребител реши да използва портфейла си за първи път.
Как да определите адреса на интелигентен договор преди внедряване: използване на CREATE2 за крипто обмен
Освен това можете да изчислявате адреса на интелигентния договор всеки път, вместо да го съхранявате, защото:

  • адрес във формулата е константа, тъй като е адресът на нашата фабрика за портфейли
  • сол — хеш на user_id
  • init_code е постоянно, тъй като използваме един и същ портфейл

Още подобрения

Предишното решение все още има един недостатък: трябва да платите за внедряване на интелигентен договор. Въпреки това можете да се отървете от него. За това можете да извикате функцията трансфер (), и тогава самоунищожаване() в конструктора на портфейла. И тогава газът за внедряване на интелигентния договор ще бъде върнат.

Противно на общоприетото схващане, можете да внедрите интелигентен договор на един и същ адрес няколко пъти с кода за операция CREATE2. Това е така, защото CREATE2 проверява дали nonce на целевия адрес е нула (присвоява му се стойността "1" в началото на конструктора). В същото време функцията самоунищожаване() нулира nonce адресите всеки път. Така че, ако извикате CREATE2 отново със същите аргументи, проверката nonce ще премине.

Моля, обърнете внимание, че това решение е подобно на опцията за адрес на Ethereum, но без необходимост от съхраняване на лични ключове. Цената за прехвърляне на пари от портфейл към hotwallet е приблизително равна на цената за извикване на функция трансфер (), тъй като ние не плащаме за внедряване на интелигентен договор.

Окончателно решение

Как да определите адреса на интелигентен договор преди внедряване: използване на 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:]


Когато потребител прехвърли токени към съответния адрес на портфейла, нашият бекенд вижда събитие за прехвърляне с параметъра _да се, равен на адреса на портфейла. На този етап вече е възможно да увеличите баланса на потребителя на борсата, преди да разгърнете портфейла.

Когато адресът на портфейла натрупа достатъчен брой токени, можем да ги прехвърлим наведнъж към hotwallet. За да направи това, бекендът извиква фабриката за интелигентни договори, която изпълнява следните действия:

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


По този начин се извиква конструкторът на интелигентни договори на портфейла, който прехвърля всичките си токени към адреса на hotwallet и след това се самоунищожава.

Пълният код може да бъде намерен тук. Моля, обърнете внимание, че това не е нашият производствен код, тъй като решихме да оптимизираме байт кода на портфейла и го написахме в кодове за операции.

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

Източник: www.habr.com

Добавяне на нов коментар