Ինչո՞ւ են ատոմային սվոփերը վատ և ինչպես կարող են ալիքները օգնել դրանց, ի՞նչ կարևոր իրադարձություններ են տեղի ունեցել Կոստանդնուպոլսի կոշտ ճյուղավորման ժամանակ և ի՞նչ անել, երբ գազի համար վճարելու ոչինչ չունես։
Ցանկացած անվտանգության մասնագետի հիմնական մոտիվացիան պատասխանատվությունից խուսափելու ցանկությունն է։
Նախախնամությունը բարի էր, ես լքեցի ICO-ն առաջին անդառնալի գործարքից առաջ, բայց շուտով հայտնվեցի կրիպտոարժույթների փոխանակման հարթակում։
Ես անկասկած Մալչիշ Կիբալչիշը չեմ, և մեկ խիստ հայացքը բավական է, որ ես հանձնեմ բոլոր բանալիներն ու գաղտնաբառերը։ Հետևաբար, որպես ճարտարապետ՝ իմ գլխավոր նպատակն էր կրիպտանալիզացիայի տաք խայթը որքան հնարավոր է հեռու տեղափոխել ինձ համար թանկ ենթակառուցվածքային տարրերից։
Ոչ թե քո բանալիները, ոչ թե քո խնդիրները
Մենք կառուցում ենք ակտիվների փոխանակման համակարգ և ցանկանում ենք վերացնել այդ ակտիվների միջանկյալ պահեստավորումը, բայց մենք պետք է ապահովենք գործարքի անվտանգությունը։
Դուք կարող եք հանդես գալ որպես դատավոր վիճելի իրավիճակում և գործարքներ կատարել դրամապանակներով, որոնք պահանջում են երեք ստորագրություններից երկուսը՝ գնորդի, վաճառողի և էսքրոուի։
Սակայն, եթե մասնակիցը հաջողությամբ հարձակվում է էսքրոուի վրա, նա ստանում է ցանկալի երկու ստորագրությունները։
Ատոմային սվոփը փոխանակման սխեմա է, որտեղ երաշխավորը խելացի պայմանագիր է, որը թույլ է տալիս միայն ազնիվ վարքագիծ։
Ինչպես գայլի, այծի և կաղամբի մասին հանելուկում, դուք կարող եք գործել միայն մեկ ճիշտ սցենարի համաձայն և կորուստներ կրել, եթե շեղվեք դրանից։
Միայն թե որկրամոլ կենդանիների փոխարեն, կարգը ապահովվում է հեշ ֆունկցիայով, որի դեպքում բախում գտնելն այնքան դժվար է, որ այն նույնիսկ սկսելը չարժե։
Քայլ մեկ՝ հանելուկ
Ենթադրենք, Ալիսը մի գեղեցիկ առավոտ ցանկանում է Բոբին փոխանցել որոշ Bitcoin՝ մի բուռ «կրիպտոյուան»-ի դիմաց։
- Նա մեծ գաղտնիք է բացահայտում։
- Նրանից հաշիշ է ստանում
- Բիթքոյնները փոխանցում է խելացի պայմանագրի, որից Բոբը կարող է գումար հանել՝ ներկայացնելով գաղտնի կոդ (դրա հեշը պետք է հավասար լինի պայմանագրում նշվածին):
- Եթե Բոբը երեկոյան չգա իր բիթքոյնները վերցնելու, Ալիսը կարող է դրանք հետ վերցնել։
Երկրորդ քայլը՝ խայծ
Բոբը մտնում է խաղ և «կրիպտո եվրոն» փոխանցում է իր պայմանագրին, որը գրված է հետևյալ կերպ.
- Ալիսը կարող է պահանջել իր «կրիպտոարժույթները»՝ ներկայացնելով գաղտնի համար
- Ճաշից ոչ շուտ, Բոբը կարող է վերադարձնել կանխավճարը, եթե Ալիսը չներկայանա։
Քայլ երրորդ՝ հուշումը խայծի մեջ է
Ալիսը գալիս է իր փողի համար և վերցնում Բոբի պայմանագրի գումարը՝ այդ ընթացքում բացահայտելով իր գաղտնիքը։
Վերջին քայլը՝ առեղծվածը լուծված է
Բոբը տեսնում է գործարքը և արծվի աչքով դրանից հանում է գաղտնիքը, որը Ալիսը ներկայացրել էր պայմանագրին։ Նա օգտագործում է այս գաղտնիքը՝ իր բիթքոյնները վերցնելու համար։
Երբ բաները սխալ են ընթանում
Եթե Ալիսը հանկարծ պարզվի, որ մահկանացու է, Բոբը իր յուանը ստանում է ճաշի ժամանակ։
Իր հերթին, Ալիսը երեկոյան կվերադարձնի բիթքոյնը, եթե դավաճան Բոբը որոշի պահել գումարը մինչև ավելի լավ ժամանակներ։
Եթե նախընտրում եք նկարներ տեքստին, Habr-ն ունի ավելի մանրամասն և տեսողական տարբերակ ձեզ համար։ .
Թայմ-աութների միջև տարբերությունը նախատեսված է մեզ պաշտպանելու չարամիտ Ալիսից, որը վերջին պահին վերցնում է Բոբի փողերը, և թայմ-աութը լրանում է, երբ նա դողացող մատներով գործարքի մեջ տասնվեցական թվեր է մուտքագրում։
Մասնակիցները չեն կարող կորցնել իրենց գումարը, առավելագույնը նրանք ստիպված կլինեն սպասել վերադարձի։
Բլոկչեյնի աջակցությունՍա պարզ, շրջանաձև սխեմա է, որը շատ քիչ բան է պահանջում փոխազդող բլոկչեյններից.
- Աջակցություն խելացի պայմանագրերի համար առնվազն մեկ մասնաճյուղի հետ
- Երկու բլոկչեյններն էլ պետք է աջակցեն նույն հեշավորման ալգորիթմները (մի մոռացեք ստուգել գաղտնի երկարությունը):
- Ժամանակի կողպեքներ։
Առաջին հայացքից կարելի էր արդեն զրույցին ասել՝ «ցտեսություն, մեր հանդիպումը սխալ էր», բայց դա այդպես չէր։
Իրենց բոլոր առավելություններից անկախ, ատոմային սվոփ լուծումները չեն տպավորում իրացվելիությամբ։ Մեծ մասամբ այն պատճառով, որ ամենատարածված BTC-USD զույգում ֆիատային մասը լիովին տոկենացված չէր։
USDT-ի հաջողությունը առաջացրել է ERC20 կայուն մետաղադրամների ալիք՝ բոլոր ճաշակների համար՝ սկսած պահառության USDC-ից մինչև ալգորիթմական DAI:
Այսպիսով, պարզության համար մենք շարունակում ենք պնդել, որ Ալիսը Բոբին վաճառում է բիթքոյններ որոշ ERC20 տոկենների դիմաց և հույս ունենք կայունացուցիչների հաջողության վրա, բարեբախտաբար, մենք դեռ շատ ավելի տեխնիկական խնդիրներ ունենք։
Բարեմաղթել
Bitcoin-ը և Ethereum-ը առանձին-առանձին շատ արագ չեն գործում, և այստեղ մենք պետք է նախ սպասենք մեկ դեպոզիտի բոլոր հաստատումներով, ապա երկրորդին։
Սա պայմանավորված է նրանով, որ նախ մասնակիցը, ով գիտի գաղտնիքը, գումար է նվիրաբերում, իսկ մրցակիցը սպասում է մինչև եզրափակիչը և միայն դրանից հետո փոխանցում իր բաժինը։
Բացի այդ, մենք գործ ունենք շատ անկայուն ակտիվի հետ, ուստի այս ընթացքում փոխարժեքը կարող է բավականին զգալիորեն փոխվել, և պայմանները փոխելն այլևս հեշտ չէ։
Գաղտնիություն
Ցանկացած փոխանակում թողնում է արտեֆակտներ երկու բլոկչեյնների վրա։ Ուշադիր դիտորդը կարող է նկատել նույնական հեշեր խելացի պայմանագրերում և տրամաբանական եզրակացություն անել, որ այստեղ գործարք է կնքվել, որից կարելի է բազմաթիվ եզրակացություններ անել՝ սկսած փոխարժեքներից մինչև հարկեր։
Երբ ֆոնդային բորսան գիտի ձեր գործերի մասին, դա չափազանց տհաճ է, երբ բոլորը գիտեն դրա մասին, դա կրկնակի տհաճ է։
Usability
Բլոկչեյնի ուժեղ կողմը ընդհանրապես և եթերի՝ մասնավորապես։ Եկեք տեսնենք, թե ինչ քայլեր պետք է անեն վաճառողը և գնորդը։
Վաճառողի տեսանկյունից ամեն ինչ համեմատաբար պարզ է. պարզապես անհրաժեշտ է բիթքոյնը փոխանցել p2sh հասցեի: Եթերի դեպքում ամեն ինչ շատ ավելի բարդ է:
ՊայմանագիրԵկեք դիտարկենք 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);
}
}
Զգուշացում! Մի օգտագործեք այս կամ հոդվածի այլ պայմանագրերը արտադրության մեջ, դրանք գրված են միայն ցուցադրական նպատակներով։ Հատկապես սա.
- Բոբը պետք է կանչի տոկենային պայմանագրի մեթոդը
approve, որը սվոփ պայմանագրին հնարավորություն է տալիս օգտվել իր տոկեններից - Բոբը ստեղծում է փոխանակում և պայմանագիր՝ օգտագործելով մեթոդը
transferFromուղարկողի տոկենները տանում է իր հասցեին - Ալիսը
withdrawբացահայտում է գաղտնիքը, և պայմանագիրը կոչվում էtransfer
Դրամապանակների և կրիպտոարժույթների փոխանակման ծառայությունների մեծ մասը չի աջակցում approve տոկեններ, և լավ պատճառով։
Օգտատերերն իրենք հաճախ սխալներ են թույլ տալիս և պարզապես տոկենները փոխանցում են պայմանագրին, որից հետո տոկենները պարզապես կորչում են: Etherscan-ի վերաբերյալ մեկնաբանությունները լի են դժբախտների մասին ողբերով:
Եվ պայմանագիր կնքելու համար անհրաժեշտ է միջնորդավճար վճարել ETH-ում, ինչը նշանակում է, որ երկու մասնակիցներն էլ պետք է պաշարներ համալրեն գործարքը սկսելուց առաջ, և քչերն են ցանկանում դա անել։
Գազի պահոց
Առաջին քայլը հնարավորության դեպքում հեռացնել ուղարկողի ստուգումը և ենթադրել, որ մենք ունենք մեկը, ով տառապում է ավելորդ բենզինից և բոլորի համար զանգերի պայմանագրերից։
Ժամանակակից պայմանագիր
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);
}
}
Պայմանագրային բանալիի դուալիզմ և EIP 712
Ինչպես գիտենք, օդում գտնվող հասցեն կարող է լինել պայմանագիր, կամ կարող է լինել ենթակա, այսինքն՝ բանալի։
Բանալու հիմնական նպատակը հաղորդագրությունները ստորագրելն է։
Մենք կարող ենք օգտագործել Bob-contract-ը որպես ուղարկող, որը կատարում է բոլոր անհրաժեշտ փոխանցումները՝ նախքան դա անելը ստուգելը Bob-key-ի ստորագրությունը։
Այժմ ցանկացած մեկը կարող է հովանավորել մասնակցի միջնորդավճարը, բայց որոշումը կայացնում է միայն նա, ով գիտի բանալին։
Բոբ-կոնտրակտ
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);
}
}
Ethereum-ում կա բարդ տվյալների կառուցվածքների ստորագրությունների հետ աշխատելու ստանդարտ։ , կարող եք ավելին կարդալ դրա մասին՝
Բաժանել եւ նվաճել
Հաճախ Ethereum-ի պայմանագրի կոտրման սցենարը հետևյալն է թվում.
- Մասնակիցը գումար է ներդնում պայմանագրի մեջ
- Այնուհետև նա վերցնում է միջոցները
- Ինչ-որ բան այն չէ
- Խաբեբան կրկին ու կրկին փող է վերցնում
Եթե վերադառնանք մեր առաջին օրինակին, ինչ-որ բան սխալ է ընթանում, եթե գաղտնիքը բայթերի դատարկ հավաքածու է։
Ինչպես գողանալ միլիոնՍտեղծեք սվոփ հեշով 0x66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
Սա sha256-ն է 0x0000000000000000000000000000000000000000000000000000000000000000
Մենք փոխանցում ենք գաղտնիքը և վերցնում մեր նշանները
Մենք այն կրկին փոխանցում ենք և խլում ենք ուրիշի հաշիվը, որովհետև 0-ն = 0 է։
Յուրաքանչյուր գործարքի համար առանձին պայմանագիր ստեղծելով՝ մենք կարող ենք պայմանագրերը մեկուսացնել EVM մակարդակում։
Բայց սա դեռ ամենը չէ. այժմ յուրաքանչյուր գործարք ունի իր սեփական հասցեն, որին կարող եք փոխանցել տոկեններ ցանկացած դրամապանակից կամ բորսայից։
Լքված պայմանագրեր և create2
Բայց հիմա յուրաքանչյուր գործարքի համար մենք պետք է ստեղծենք պայմանագիր և սպասենք, որ գնորդը «կրիպտոարժույթով» տեղափոխի այնտեղ աշխատուժը։ «Առավոտյան պայմանագրեր, երեկոյան գումար» սխեմայում միշտ կա ռիսկ, որ գնորդը կհեռանա, և պայմանագիրը ստեղծելու համար անհրաժեշտ եթերն արդեն ծախսված է։
Հնարավո՞ր է այնպես անել, որ առավոտյան փող լինի, իսկ երեկոյան՝ բայթեր։
Կոստանդնուպոլսի կոշտ ճյուղավորման մեջ, մշակողները ավելացվել է create2 հրահանգը, որը ստեղծում է նոր պայմանագիր դետերմինիստական հասցեում
keccak256( 0xff ++ address ++ salt ++ keccak256(init_code))[12:]
Որտեղ
- հասցե — գործարանային պայմանագրի հասցե
- աղ - որոշակի թիվ, որի իմաստը մենք կսովորենք հաջորդ դրվագում
- init_code — պայմանագրի բայթկոդը և կոնստրուկտորի պարամետրերը։
ԳործարանՀրահանգը գործում է միայն հավաքման միջոցով, ուստի գործարանը մի փոքր վախեցնող տեսք ունի.
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);
}
}
Ձեր պայմանագրի կոդը կարող եք ստանալ web3-ի միջոցով՝
const MyContract = new web3.eth.Contract(ABI, {})
const сode = MyContract.deploy({
data: BYTECODE,
arguments: contructorArgs
}).encodeABI();
const factory = new web3.eth.Contract(FACTORY_ABI, factoryAddress);
tx = factory.methods.create2(сode, salt);
Հաստության սահմանափակ աջակցության պատճառով, պայմանագրի համար գազի գինը կարող է ճիշտ չհաշվարկվել Ethereum-ի որոշ նրբությունների պատճառով։
Հատկապես հաճելի է, որ գազի պակասի դեպքում պայմանագիրը ձախողվում է ներքին սխալի պատճառով՝ առանց հայտնելու, որ գազը բավարար չէ, ինչպես կարելի էր սպասել։
Հիմա մենք կարող ենք տոկենները փոխանցել պայմանագրերին՝ առանց դրանք նախապես ստեղծելու, և մինչև դրանք չհրապարակենք ցանցում, ոչ ոք չի կռահի, թե կոնկրետ ինչ է անում պայմանագիրը։
Ագռավը ուրիշի ագռավի աչքը չի հանի
Ակնհայտ է, որ իսկական վերլուծաբանը, հատկապես նա, ով լավ ներդրումներ է ստացել ռեժիմի թշնամիների դեմ պայքարում՝ փողերի լվացման միջոցով, չի կանգնի նման մանկական հնարքներով, և պայմանագիրը ստեղծելուց հետո նա դեռ կտեսնի հաշիշը։
Ինչպե՞ս համոզվել, որ հեշը բաց չէ։
Մենք սվոփը դուրս ենք բերում շղթայից. մասնակիցները փոխանակվում են ստորագրություններով՝ սվոփ պայմանագրին անցնելու համար, որից հետո գաղտնիքը գաղտնի բացահայտվում է։
Քայլ առ քայլՍտեղծվում են երկու «բազմաստորագրություններ», որոնցից կարելի է միջոցներ հանել, եթե Ալիսն ու Բոբն ունեն իրենց ստորագրությունները։
Որպեսզի մասնակիցներից մեկի օֆլայն անջատվելը չդառնա ողբերգություն, ավելացնենք հին ու բարի դադար։
Ալիսն ու Բոբը զուգահեռաբար կատարում են ավանդներ
- Ալիսը գաղտնիք է ստեղծում և Բոբին տալիս է գաղտնիքի հեշը և գործարքի ստորագրությունը, որը բիթքոյնները փոխանցում է փոխանակման հասցեին։
- Բոբը Ալիսին ստորագրություն է տալիս՝ տրված հեշով փոխանակման պայմանագրից տոկեններ հանելու համար։
- Ալիսը Բոբին գաղտնիք է պատմում։
Այս պահին ներդաշնակություն է տիրում. Ալիսն ու Բոբը կարող են ցանկացած պահի ավարտել գործարքը։ Նման բարեկամական միջավայրում նրանք կարող են ստորագրություններ փոխանակել՝ իրենց վերջնական հասցեներին գումար հանելու համար։
Արտաքին դիտորդի համար թվում է, թե գումարը կնքվել է 2-ը 2 բազմաստորագրային պայմանագրով:
Այս սխեման նաև թույլ է տալիս երկու կողմերին միաժամանակ կատարել ավանդ, քանի որ գաղտնիքը բացահայտվում է բոլոր հաստատումներից հետո։
Level 2
Քանի որ մենք կարող ենք գումար հանել մեկ հասցեից և չհրապարակել միջանկյալ գործարք, ոչինչ չի խանգարում մեզ գումար հանել մի քանի հասցեներից և կատարել անսահմանափակ թվով միջանկյալ գործարքներ: Ոչ թե սա փոխանակման համար անհրաժեշտ հավաքածու է, բայց երբ սկսում ես սվոփ հավաքել, դժվար է դադարեցնել դա:
Այժմ Ալիսն ու Բոբը կարող են անել իրենց լավագույնը։ Օրինակ՝ ավտոմատ կերպով հաշվարկել միջին գինը՝ փոխանակելով սատոշի վայրկյանում, կամ պարզապես ուղղակիորեն կապել շուկա ստեղծողին և իրացվելիության ստացողին։
Քայլ առ քայլ
- Վաճառողը ստեղծում է գաղտնի կոդ և գնորդին տալիս է գաղտնի կոդի հեշը և գործարքի ստորագրությունը, որտեղ միջոցների մի մասը փոխանցվում է p2sh փոխանակման հասցեին, իսկ մնացած մասը վերադարձվում է վաճառողի հասցեին։
- Գնորդը տրամադրում է ստորագրություն, որը թույլ է տալիս տոկենները և մանրը հանել ստացողի հասցեին՝ փոխանակման համար։
- Վաճառողը բացահայտում է գաղտնիքը
- Պատմությունը կրկնվում է նոր գաղտնիքով, մինչդեռ փոխանակումից և մանրից բացի, կա նաև նախկինում գնվածի և արդեն վճարվածի վերադարձը վաճառողի հասցեին։
Հիմա մենք հասանելիություն ունենք բարձր արագությամբ p2p առևտրին, գլխավորը ժամանակին հետևելն է և գործարքը կնքելը ժամկետի ավարտից առաջ։
Այնուամենայնիվ, մեր պայմանագրերում մի փոքր փոփոխություն կատարելով՝ մենք կարող ենք մեր ալիքներին անմահություն տալ, ինչը մեզ համար շատ ավելի հեշտ կդարձնի ցանց կառուցելը։
Բայց մենք այս մասին կխոսենք հաջորդ թողարկման մեջ։
Source: www.habr.com
