Hoe u het adres van een slim contract kunt bepalen vóór implementatie: CREATE2 gebruiken voor een crypto-uitwisseling

Het onderwerp blockchain blijft niet alleen een bron van allerlei hypes, maar ook van zeer waardevolle ideeën vanuit technologisch oogpunt. Daarom omzeilde ze de inwoners van de zonnige stad niet. Mensen kijken nauwlettend, studeren en proberen hun expertise in de traditionele infobase te verschuiven naar blockchain-systemen. Tot nu toe puntsgewijs: een van de ontwikkelingen van Rostelecom-Solar is in staat om de veiligheid van software te controleren op basis van de blockchain. En gaandeweg ontstaan ​​er enkele gedachten over het oplossen van toegepaste problemen van de blockchain-gemeenschap. Een van deze lifehacks – hoe je het adres van een slim contract kunt bepalen voordat je het gebruikt met CREATE2 – wil ik vandaag met je delen onder de bezuiniging.

Hoe u het adres van een slim contract kunt bepalen vóór implementatie: CREATE2 gebruiken voor een crypto-uitwisseling
De CREATE2-opcode werd op 28 februari van dit jaar toegevoegd aan de hard fork van Constantinopel. Zoals vermeld in het EIP, werd deze opcode voornamelijk geïntroduceerd voor staatskanalen. We hebben het echter gebruikt om een ​​ander probleem op te lossen.

Er zijn gebruikers met saldi op de beurs. We moeten elke gebruiker een Ethereum-adres geven waarnaar iedereen tokens kan sturen, waardoor zijn account wordt aangevuld. Laten we deze adressen "portefeuilles" noemen. Wanneer tokens in portemonnees aankomen, moeten we ze naar een enkele portemonnee (hotwallet) sturen.

In de volgende secties analyseer ik opties om dit probleem op te lossen zonder CREATE2 en leg ik uit waarom we deze hebben verlaten. Als u alleen geïnteresseerd bent in het eindresultaat, kunt u dit vinden in de sectie Eindoplossing.

Ethereum-adressen

De eenvoudigste oplossing is het genereren van nieuwe Ethereum-adressen voor nieuwe gebruikers. Deze adressen zullen de portemonnees zijn. Om tokens van een portemonnee naar hotwallet over te zetten, moet u de transactie ondertekenen door de functie aan te roepen overdracht() met de privésleutel van de portemonnee uit de backend.

Deze aanpak heeft de volgende voordelen:

  • het is gewoon
  • de kosten voor het overbrengen van tokens van een portemonnee naar hotwallet zijn gelijk aan de kosten van een functieaanroep overdracht()

We hebben deze aanpak echter verlaten omdat deze één belangrijk nadeel heeft: je moet privésleutels ergens opslaan. En het is niet alleen dat ze verloren kunnen gaan, maar ook dat u de toegang tot deze sleutels zorgvuldig moet beheren. Als ten minste één ervan gecompromitteerd is, zullen de tokens van een bepaalde gebruiker de hot wallet niet bereiken.

Hoe u het adres van een slim contract kunt bepalen vóór implementatie: CREATE2 gebruiken voor een crypto-uitwisseling

Maak voor elke gebruiker een afzonderlijk slim contract

Door voor elke gebruiker een afzonderlijk slim contract te implementeren, kunt u geen privésleutels van portemonnees op de server opslaan. De beurs zal dit slimme contract aanroepen om de tokens naar de hotwallet over te dragen.

We hebben ook van deze oplossing afgezien, omdat de gebruiker zijn portemonnee-adres niet kan zien zonder een slim contract in te zetten (dit is eigenlijk mogelijk, maar op een nogal gecompliceerde manier met andere nadelen die we hier niet zullen bespreken). Op de beurs kan de gebruiker zoveel accounts aanmaken als hij nodig heeft, en iedereen heeft zijn eigen portemonnee nodig. Dit betekent dat we geld moeten uitgeven aan het implementeren van een contract zonder er zelfs maar zeker van te zijn dat de gebruiker dit account zal gebruiken.

Opcode CREATE2

Om het probleem van de vorige methode op te lossen, hebben we besloten de CREATE2-opcode te gebruiken. Met CREATE2 kunt u vooraf het adres bepalen waar het slimme contract zal worden ingezet. Het adres wordt berekend met behulp van de volgende formule:

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


, Waar:

  • adres — adres van het slimme contract dat CREATE2 zal aanroepen
  • zout - willekeurige waarde
  • init_code — slimme contractbytecode voor implementatie

Dit zorgt ervoor dat het adres dat wij aan de gebruiker verstrekken ook daadwerkelijk de gewenste bytecode bevat. Bovendien kan dit slimme contract worden ingezet wanneer we maar willen. Bijvoorbeeld wanneer een gebruiker besluit zijn portemonnee voor de eerste keer te gebruiken.
Hoe u het adres van een slim contract kunt bepalen vóór implementatie: CREATE2 gebruiken voor een crypto-uitwisseling
Bovendien kunt u het slimme contractadres elke keer berekenen in plaats van het op te slaan, omdat:

  • adres in de formule is constant omdat dit het adres is van onze portefeuillefabriek
  • zout — user_id-hash
  • init_code is permanent omdat we dezelfde portemonnee gebruiken

Meer verbeteringen

De vorige oplossing heeft nog steeds één nadeel: je moet betalen voor de implementatie van slimme contracten. Je kunt er echter vanaf komen. Hiervoor kun je de functie aanroepen overdracht()en dan zelfvernietiging() in de portemonnee-constructor. En dan wordt het gas voor de inzet van het slimme contract teruggegeven.

In tegenstelling tot wat vaak wordt gedacht, kunt u een slim contract meerdere keren op hetzelfde adres implementeren met de CREATE2-opcode. Dit komt omdat CREATE2 controleert of de nonce van het doeladres nul is (aan het begin van de constructor wordt de waarde "1" toegewezen). Tegelijkertijd is de functie zelfvernietiging() reset elke keer nonce-adressen. Dus als je CREATE2 opnieuw aanroept met dezelfde argumenten, zal de nonce-controle slagen.

Houd er rekening mee dat deze oplossing vergelijkbaar is met de Ethereum-adresoptie, maar zonder de noodzaak om privésleutels op te slaan. De kosten voor het overboeken van geld van een portemonnee naar hotwallet zijn ongeveer gelijk aan de kosten voor het aanroepen van een functie overdracht(), aangezien we niet betalen voor de inzet van het slimme contract.

Laatste beslissing

Hoe u het adres van een slim contract kunt bepalen vóór implementatie: CREATE2 gebruiken voor een crypto-uitwisseling

Oorspronkelijk opgesteld door:

  • functie om zout binnen te krijgen user_id
  • slim contract dat de CREATE2-opcode aanroept met het juiste zout (dat wil zeggen portemonneefabriek)
  • portemonnee bytecode die overeenkomt met het contract met de volgende constructor:

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


Voor elke nieuwe gebruiker tonen wij door middel van een berekening zijn/haar portemonnee-adres

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


Wanneer de gebruiker tokens overdraagt ​​naar het corresponderende portemonnee-adres, ziet onze backend de Transfer-gebeurtenis met de parameter _tot, gelijk aan het portemonneeadres. Op dit moment is het al mogelijk om het saldo van de gebruiker op de beurs te verhogen voordat de portemonnee wordt ingezet.

Wanneer er voldoende tokens zijn verzameld in het portemonnee-adres, kunnen we ze allemaal in één keer overbrengen naar de hotwallet. Om dit te doen, roept de backend de smart contract factory-functie aan, die de volgende acties uitvoert:

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


Zo wordt de slimme contractconstructor van de portemonnee gebeld, die al zijn tokens naar het hotwallet-adres overbrengt en vervolgens zichzelf vernietigt.

De volledige code is te vinden hier. Houd er rekening mee dat dit niet onze productiecode is, omdat we besloten hebben de bytecode van de portemonnee te optimaliseren en deze in opcodes te schrijven.

Auteur Pavel Kondratenkov, Ethereum-specialist

Bron: www.habr.com

Voeg een reactie