Çfarë është e keqja e swapëve atomikë dhe si mund t'i ndihmojnë kanalet; çfarë ndodhi rëndësi në hard fork-un Constantinople dhe çfarë të bëjmë kur nuk kemi për të paguar gazin.
Motivimi kryesor i çdo specialisti të sigurisë është dëshira për të shmangur përgjegjësinë.
Fati ishte bujar, unë u largova nga ICO pa pritur transaksionin e parë të pakthyeshëm, por së shpejti e gjeti veten duke zhvilluar një exchange kriptomalash.
Unë nuk jam aspak Malych Kibalchish, dhe një vështrim i qartë është mjaft për të dorëzuar të gjitha çelësat dhe fjalëkalimet. Prandaj, qëllimi im kryesor si arkitekt ishte të vendosja gjilpërën e nxehtë të kripto-analizës sa më larg elementeve të infrastrukturës që kam më të dashura.
Një çelës, një problem.
Ne po ndërtojmë një sistem shkëmbimi aktivesh dhe duam të përjashtojmë ruajtjen ndërmjetëse të këtyre aktiveve, por duhet të sigurojmë sigurimin e transaksionit.
Mund të funksionoj si gjykatës në një situatë të kontestuar dhe të realizoj transaksione me portofolat që kërkojnë dy nga tre nënshkrimet: blerësi, shitësi dhe escrow.
Megjithatë, nëse një pjesëmarrës sulmon me sukses escrow-n, ai merr dy nënshkrimet e kërkuara.
Swap-i atomik është një skemë shkëmbimi, ku garancia është një smart contract që lejon vetëm sjellje të ndershme.
Si në enigmat e ujkut, delet dhe lakrën, mund të veprosh vetëm sipas skenarit të vetëm të saktë dhe pëson humbje nëse i je larguar nga ai.
Tani, përveç kafshëve lakmuese, rendi sigurohet nga funksioni hash, ku është aq e vështirë të gjesh një kolizion sa nuk ia vlen të fillosh.
Hapi i parë: enigmat.
Supozoni se Aliţa një mëngjes të bukur dëshiron të transferojë Bitcoin te Bobo për një grusht "kripto-juanesh".
- Ajo mendon një sekret të madh.
- Merr një hash nga ai.
- Transferon Bitcoin në smart contract, nga i cili Bobo mund të marrë paratë duke paraqitur sekretin (hash-i duhet të jetë i barabartë me atë të përcaktuar në kontratë).
- Në rast se Bobo nuk erdhi për Bitcoin e tij deri në mbrëmje, Aliţa mund t'i marrë ato përsëri për vete.
Hapi i dytë: lakmimi.
Bobo hyn në lojë dhe transferon "kripto-euro" në kontratën e tij, e cila është e shkruar në një mënyrë që:
- Aliţa mund të marrë "kripto-juanet" duke paraqitur një numër sekret.
- Jo më herët se pasdite, nëse Bobo nuk paraqitet, mund të kthehet depozita.
Hapi i tretë: zgjidhja e lakmimit.
Aliţa vjen për paratë e saj dhe merr paratë nga kontrata e Bobos, duke zbuluar gjithashtu sekretin e saj.
Hapi përfundimtar: enigmat zgjidhur.
Bobo sheh transaksionin dhe me sytë e shqiponjës identifikon sekretin e paraqitur nga Aliţa në kontratë. Ky sekret ai e përdor për të marrë Bitcoin e tij.
Kur diçka nuk shkon siç duhet.
Nëse Aliţa befas vdes, Bobo merr juanet e tij në drekë.
Nga ana tjetër, Aliţa deri në mbrëmje kthen Bitcoin-in, nëse Bobo tradhëtar vendos ta mbajë paratë për ditë më të mira.
Nëse preferoni pamjen për tekstin, në Habr për ju ka një përshkrim më të detajuar dhe vizual të .
Dallimi mes timeout-eve është krijuar për të na mbrojtur nga Alița e keqe, e cila merr paratë e Bobos në momentin e fundit dhe timeout-i ka skaduar, ndersa ai po fut me gishta të dridhura hex-in në transaksion.
Pjesëmarrësit nuk mund të humbasin paratë e tyre, maksimumi do të duhet të presin kthimin.
Mbështetje në blockchain-e.Kjo është një skemë e thjeshtë si një këpucë, e cila kërkon nga blockchain-t që veprojnë vetëm pak gjëra:
- Mbështetje për smart contracts me të paktën një degëzim.
- Të dy blockchain-et duhet të mbështesin të njëjtët algoritma hashimi (mos harroni të kontrolloni gjatësinë e sekretit).
- Kohëe mbylljes.
Më në fund, mund të themi "lamtumirë" bursës, takimi ynë ishte një gabim, por nuk është kështu.
Pavarësisht të gjitha shpërblimeve të saj, zgjidhjet mbi swapet atomikë nuk mbresulojnë me likuiditet. Në shumë aspekte, sepse në çiftin më të njohur BTC-USD, pjesa fiat nuk ishte plotësisht e tokenizuar.
Suksesi i USDT krijoi një valë të tërë monedhash stabile në formatin ERC20 për çdo shije, nga më të besueshmet USDC deri te më algoritmiku DAI.
Prandaj, për thjeshtësi, ne do të flasim më tej për atë se Aliţa shet Bobo bitkoinë për disa ERC20 token-e, dhe shpresojmë në fatin e stabilizatorëve, gjithashtu pasi kemi shumë probleme më teknike.
Shpejtësia
Bitcoin dhe Ethereum dhe secili veçmas nuk janë shumë të shpejtë, dhe këtu na duhet të presim fillimisht një depozitë me të gjitha konfirmimet, pastaj një të dytë.
Kjo është sepse fillimisht paratë i depoziton pjesëmarrësi, i cili di sekretin, dhe ndërshtari pret finalizimin dhe vetëm atëherë transferon pjesën e tij.
Për më tepër, ne jemi duke u marrë me një aktiv shumë të paqëndrueshëm, kështu që gjatë kësaj kohe norma mund të ndryshojë ndjeshëm, dhe të ndryshosh kushtet është tashmë e vështirë.
Konfidencialiteti
Çdo shkëmbim lë pas disa artefakte në të dy blockchainet. Një vëzhgues i kujdesshëm mund të vërë re hashe të njëjta në kontratat smart dhe të nxjerrë përfundime logjike, duke përfshirë ato për kurset dhe taksat.
Kur bursa di për çështjet e tua — kjo është jashtëzakonisht e pakëndshme, kur e di gjithë bota — kjo është dyfish e pakëndshme.
Përdorshmëri
Është forca e blockchain-it, përgjithësisht, dhe e Ethereum-it, në veçanti. Le të shohim se çfarë lëvizjesh duhet të bëjnë shitësi dhe blerësi.
Nga këndvështrimi i shitësit, gjithçka është relativisht e thjeshtë: thjesht duhet të transferojë bitcoin në një adresë p2sh. Por me Ethereum, gjithçka është shumë më e ndërlikuar.
KontrataLe të shqyrtojmë një kontratë të hartuara mesatarisht për shkëmbim në GitHub:
contract iERC20 {
function totalSupply() public view returns (uint256);
function transfer(address receiver, uint numTokens) public returns (bool);
function balanceOf(address tokenOwner) public view returns (uint);
function approve(address delegate, uint numTokens) public returns (bool);
function allowance(address owner, address delegate) public view returns (uint);
function transferFrom(address owner, address buyer, uint numTokens) public returns (bool);
}
contract Swapper {
struct Swap {
iERC20 token;
bytes32 hash;
uint amount;
uint refundTime;
bytes32 secret;
}
mapping (address => mapping(address => Swap)) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, uint refundTime) public {
require(swaps[msg.sender][receiver].amount == 0); // check is swap with given hash already exists
require(token.transferFrom(msg.sender, address(this), amount)); // transfer locked tokens to swap contract
swaps[msg.sender][receiver] = Swap(token, hash, amount, refundTime, 0x00); //create swap
}
function hashOf(bytes32 secret) public pure returns(bytes32) {
return sha256(abi.encodePacked(secret));
}
function withdraw(address owner, bytes32 secret) public {
Swap memory swap = swaps[owner][msg.sender];
require(swap.secret == bytes32(0));
require(swap.hash == sha256(abi.encodePacked(secret))); // swap exists
swaps[owner][msg.sender].secret = secret;
swap.token.transfer(msg.sender, swap.amount);
}
function refund(address receiver) public {
Swap memory swap = swaps[msg.sender][receiver];
require(now > swap.refundTime);
delete swaps[msg.sender][receiver];
swap.token.transfer(msg.sender, swap.amount);
}
}
Kujdes! Mos përdorni këtë dhe kontratat e tjera nga artikulli në prodhim, ato janë shkruar vetëm për demonstrim. Veçanërisht këtë.
- Bobi duhet të thërrasë metodën e kontratës së tokenit
approve, duke i dhënë kontratës së shkëmbimit akses në tokenat e tij - Bobi krijon shkëmbimin dhe kontratën përmes metodës
transferFromduke marrë tokenat e dërguarit në adresën e tij - Alice në
withdrawzbulon sekretin dhe kontrata thërrettransfer
Shumica e portofolëve dhe exchange-ve të kriptove nuk mbështesin approve tokena, dhe nuk është për habi.
Përdoruesit shpesh gabojnë dhe thjesht i dërgojnë tokenat në kontratë, pas së cilës tokenat zhduken. Komentet në Etherscan janë të mbushura me ankthe të pavijuara.
Dhe për të thirrur kontratën, duhet të paguash një tarifë në ETH, kështu që të dy pjesëmarrësit duhet të sigurojnë atë para fillimit të marrëveshjes, një gjë që pak prej tyre duan ta bëjnë.
Gazgolder
Në fillim, duhet të heqim verifikimin e dërguesit kudo që të jetë e mundur, dhe të supozojmë se kemi dikë, që vuaj nga tepërsi gazi dhe thërret kontratat për të gjithë dëshmitarët.
Kontrata e modernizuar
contract Swapper {
struct Swap {
iERC20 token;
address receiver;
uint amount;
address refundAddress;
uint refundTime;
}
mapping (bytes32 => Swap) swaps;
function create(iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public {
require(swaps[hash].amount == 0); // use hash once
require(token.transferFrom(msg.sender, address(this), amount));
swaps[hash] = Swap(token, receiver, amount, refundAddress, refundTime);
}
function withdraw(bytes memory secret) public {
bytes32 hash = sha256(secret);
Swap memory swap = swaps[hash];
require(swap.amount > 0);
delete swaps[hash];
swap.token.transfer(swap.receiver, swap.amount);
}
function refund(bytes32 hash) public {
Swap memory swap = swaps[hash];
require(now > swap.refundTime);
delete swaps[hash];
swap.token.transfer(swap.refundAddress, swap.amount);
}
}
Duale kontrakt-çelës dhe EIP 712
Siç e dimë, adresa në Ether mund të jetë një kontratë, dhe gjithashtu një subjekti, gjithashtu çelësi.
Aktiviteti kryesor i çelësit është të nënshkruajë ndonjë mesazh.
Ne mund të përdorim Bob-kontraktin si dërgues, i cili kryen të gjitha kalimet e nevojshme, pasi të verifikojë nënshkrimin e Bob-çelësit.
Tani, kushdo mund të sponsorizojë tarifën e pjesëmarrësit, por vendos çdoherë vetëm ai që e di çelësin.
Bobi-kontakt
library EIP712ProxyLibrary {
function hashCommand(address sender, iERC20 token, Swapper swapper, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime) public view returns(bytes32);
}
contract ProxyBob {
address owner;
constructor(address _owner) public {
owner = _owner;
}
function createSwap(Swapper swapper, iERC20 token, bytes32 hash, address receiver, uint amount, address refundAddress, uint refundTime, uint8 v, bytes32 r, bytes32 s) public {
require(owner == ecrecover(EIP712ProxyLibrary.hashCommand(address(this), token, swapper, hash, receiver, amount, refundAddress, refundTime), v, r, s));
token.approve(address(swapper), amount);
swapper.create(token, hash, receiver, amount, refundAddress, refundTime);
}
}
Për të punuar me nënshkrime të strukturave të dhënash komplekse në Ethereum ekziston një standard , më shumë rreth tij mund të lexoni në
Përçaj dhe sundo
Shpesh skenari i hackimit të kontratës Ethereum duket kështu:
- Pjesëmarrësi depozit gjendje në kontrat
- Pastaj merr përsëri mjetet
- Diçka nuk shkon siç duhet
- Sulmuesi po merr para përsëri e përsëri
Nëse kthehemi në shembullin tonë të parë, diçka nuk shkon siç duhet nëse misteri është një grup i zbrazët bajtash.
Si të vjedhësh një milionKrijojmë swap me hash-in 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Ky është sha256 nga 0x0000000000000000000000000000000000000000000000000000000000000000
Transferojmë sekretin dhe marrim tokenat tona
Transferojmë edhe një herë dhe marrim të tjerët, gjithçka për shkak se 0 = 0
Duke krijuar një kontratë të veçantë për çdo transaksion, mund të izolojmë kontratat në nivelin EVM.
Por kjo nuk është e gjitha: tani çdo transaksion ka adresën e tij, në të cilën mund të transferohen tokena nga çdo portofol ose bursë.
Kontratat e braktisura dhe create2
Por tani për çdo transaksion na duhet të krijojmë një kontratë dhe të presim që blerësi të transferojë atje “kripto-fenings” e tij. Në skemën “mëngjesi kontratat, mbrëmja paratë” gjithmonë ka rrezik që blerësi të heqë dorë, dhe eteri për krijimin e kontratës është tashmë shpenzuar.
A nuk mund ta bëjmë që mëngjesi të jetë paratë dhe mbrëmja bajtat?
Në hardfork-un Constantinople, zhvilluesit shtuan instrukcionin create2, i cili krijon një kontratë të re në një adresë të përcaktuar
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
Ku
- address — adresa e kontratës fabrikë
- salt — një numër i caktuar, kuptimi i të cilit do ta mësojmë në episodin e ardhshëm
- init_code — kod bajt dhe parametrat e konstruktorit të kontratës.
FabrikaInstruksioni punon vetëm përmes assembly, kështu që fabrika duket disi e frikshme:
contract Factory {
event Deployed(address addr, uint256 salt);
function create2(bytes memory code, uint256 salt) public {
address addr;
assembly {
addr := create2(0, add(code, 0x20), mload(code), salt)
}
emit Deployed(addr, salt);
}
}
Kodi i kontratës suaj mund të merret me ndihmën e web3:
const MyContract = new web3.eth.Contract(ABI, {})
const code = MyContract.deploy({
data: BYTECODE,
arguments: contructorArgs
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(code, salt);
Për shkak të mbështetjes së kufizuar në solidity, gazi për kontratën mund të llogaritet gabim për shkak të disa nuancave të eterit.
Veçanërisht e këndshme është se në rast të mjaftueshmërisë së gazit, kontrata bie me një gabim të brendshëm, pa e treguar se siç duhej është mbaruar gazi.
Tani mund të transferojmë tokena në kontrata pa i krijuar ato paraprakisht dhe derisa t'i publikonim në rrjet, askush nuk do të mund të kuptojë se çfarë bën kontrata.
Korbi nuk i nxjerr sytë korbit
E qartë është se një analist i vërtetë, sidomos ai që ka marrë investime të mira për të luftuar armikun me pastrim parash, këto truke fëmijësh nuk do ta ndalojnë, dhe pas krijimit të kontratës ai do të shohë gjithsesi hash-in.
Si ta bëjmë që hash-i të mos dallohet?
Swap-in e transferojmë në off-chain: pjesëmarrësit e ndajnë nënshkrimet për transferimin në kontratën e swap-it dhe pastaj zbulohen privatisht sekretin.
Hapi pas hapiKrijohen dy "multisig", nga të cilat mund të merren fondet me nënshkrimet e Alicisë dhe Bobit.
Për të siguruar që largimi offline i ndonjërit nga pjesëmarrësit nuk bëhet një tragjedi, do të shtojmë një kohëzgjatje të njohur.
Alicia dhe Bobi depozitojnë paralelisht
- Alicia mendon një sekret dhe i jep Bobit hash-in e sekretit dhe nënshkrimin e transaksionit që transferon bitcoinët në adresën e swap-it
- Bobi i jep Alicisë nënshkrimin për të tërhequr tokenat në kontratën e swap-it me hash-in e menduar.
- Alicia i zbulon Bobit sekretin.
Në këtë moment arrijmë harmoni: dhe Alicia dhe Bobi mund të përfundojnë transaksionin në çdo moment. Në një atmosferë të tillë miqësore ata mund të ndajnë nënshkrimet për të tërhequr paratë në adresat përfundimtare.
Për një vëzhgues të jashtëm, kjo duket sikur paratë kalojnë përmes kontratës me shumë nënshkrime 2 nga 2.
Një tjetër përfitim i kësaj skeme është se të dy palët mund të bëjnë depozitimin njëkohësisht, pasi sekreti mendohesh pas të gjitha konfirmimeve.
Level 2
Duke ditur se mund të tërheqim paratë në një adresë dhe nuk publikojmë transaksionin ndërmjetës, asgjë nuk na pengon të tërheqim paratë në disa adresa dhe të realizojmë një numër të pandërprerë transaksionesh ndërmjetësore. Nuk është se kjo është një nevojë e domosdoshme për një swap, por nëse fillon të mbledhësh swap, e vështirë është të ndalesh.
Tani Alicia dhe Bobi mund të angazhohen plotësisht. Për shembull, llogaritni automatikisht çmimin mesatar duke shkëmbyer sipas satoshit për sekondë, ose thjesht lidhni drejtpërdrejt krijuesin e tregut me marrësin e likuiditetit.
Hapi pas hapi
- Shitësi mendon një sekret dhe i jep blerësit hash-in e sekretit dhe nënshkrimin e transaksionit ku një pjesë e fondeve transferohet në adresën p2sh të swap-it, dhe pjesa tjetër kthehet në adresën e shitësit.
- Blerësi transferon nënshkrimin që lejon tërheqjen e tokenave në swap dhe kthimin në adresën e marrësit.
- Shitësi zbulon sekretin
- Historia përsëritet me një sekret të ri, ndërsa në swap dhe kthim shtohet tërheqja e asaj që ishte blerë më parë në adresën e blerësit dhe tashmë e paguar në adresën e shitësit.
Tani tani, tregtimi me shpejtësi të lartë p2p është tani në dispozicion, e rëndësishme është të monitorosh kohën dhe të mbyllësh marrëveshjen para se të skadojë.
Megjithatë, duke bërë disa ndërrime në kontratat tona, mund t'i ofrojmë kanaleve tona pavdeksinë, gjë që do ta lehtësojë shumë krijimin e rrjetit tonë.
Por për këtë do të flasim në episodin e ardhshëm.
Burimi: habr.com
