Ngwa nke Waves smart accounts: site na ahịa ahịa ruo na mmemme ego

Ngwa nke Waves smart accounts: site na ahịa ahịa ruo na mmemme ego

A na-ejikọta Blockchain naanị na cryptocurrencies, mana mpaghara ngwa nke teknụzụ DLT ka sara mbara karị. Otu n'ime ebe kachasị mma maka iji blockchain bụ nkwekọrịta smart nke a na-eme na-akpaghị aka na-adịghị achọ ntụkwasị obi n'etiti ndị ọzọ banyere ya.

RIDE – asụsụ maka smart contracts

Waves emepụtala asụsụ pụrụ iche maka nkwekọrịta smart - RIDE. Edere akwụkwọ ya zuru oke ebe a. Na ebe a - isiokwu na isiokwu a na Habr.

Nkwekọrịta RIDE bụ predicate wee weghachi "ezi" ma ọ bụ "ụgha" dịka mmepụta. N'ihi ya, a na-edekọ azụmahịa ahụ na blockchain ma ọ bụ jụ. The smart nkwekọrịta n'ụzọ zuru ezu na-ekwe nkwa mmezu nke kpọmkwem ọnọdụ. Ịmepụta azụmahịa site na nkwekọrịta na RIDE agaghị ekwe omume ugbu a.

Taa enwere ụdị nkwekọrịta smart Waves abụọ: akaụntụ smart na akụ smart. Akaụntụ smart bụ akaụntụ onye ọrụ mgbe niile, mana edobere ya edemede nke na-achịkwa azụmahịa niile. Ederede akaụntụ smart nwere ike ịdị ka nke a, dịka ọmụmaatụ:

match tx {
  case t: TransferTransaction | MassTransferTransaction => false
  case _ => true
}

tx bụ azụmahịa a na-ahazi nke anyị na-ekwe ka iji usoro dabara adaba naanị ma ọ bụrụ na ọ bụghị azụmahịa mbufe. A na-eji ndakọrịta ụkpụrụ na RIDE lelee ụdị azụmahịa. Enwere ike ịhazi akaụntụ niile dị na edemede akaụntụ smart ụdị azụmahịa.

Edemede ahụ nwekwara ike ikwuwapụta mgbanwe dị iche iche, jiri “ma ọ bụrụ-mgbe ahụ-ọzọ” na usoro ndị ọzọ maka ịlele ọnọdụ zuru oke. Iji hụ na nkwekọrịta nwere ike zuru oke na mgbagwoju anya (ọnụahịa) nke dị mfe ịkọ tupu mmezu nkwekọrịta amalite, RIDE enweghị loops ma ọ bụ nkwupụta ụda.

Akụkụ ndị ọzọ nke akaụntụ Waves gụnyere ọnụnọ nke "steeti," ya bụ, ọnọdụ nke akaụntụ ahụ. Ị nwere ike dee ọnụọgụ abụọ nke ụzọ abụọ (igodo, uru) na steeti akaụntụ site na iji azụmahịa data (DataTransaction). Enwere ike ịhazi ozi a ma site na REST API yana ozugbo na nkwekọrịta smart.

Azụmahịa ọ bụla nwere ike ịnwe ọtụtụ ihe akaebe, nke enwere ike ịbanye na mbinye aka nke onye so na ya, ID nke azụmahịa achọrọ, wdg.

Na-arụ ọrụ na RIDE site na HERE na-enye gị ohere ịhụ echiche chịkọtara nke nkwekọrịta ahụ (ọ bụrụ na a chịkọtara ya), mepụta akaụntụ ọhụrụ ma debe ya ederede, yana izipu azụmahịa site na akara iwu.

Maka usoro okirikiri zuru oke, gụnyere ịmepụta akaụntụ, ịwụnye nkwekọrịta smart na ya na izipu azụmahịa, ị nwekwara ike iji ụlọ akwụkwọ maka ịmekọrịta na API REST (dịka ọmụmaatụ, C #, C, Java, JavaScript, Python, Rust, Elixir) . Iji malite ịrụ ọrụ na IDE, dị nnọọ pịa bọtịnụ NEW.

Ohere maka iji nkwekọrịta smart dị obosara: site na igbochi azụmahịa gaa na adreesị ụfọdụ (“ndepụta ojii”) gaa na dApps dị mgbagwoju anya.

Ugbu a, ka anyị leba anya n'ihe atụ ụfọdụ nke iji smart contracts na azụmahịa: mgbe ị na-eduzi auctions, mkpuchi, na ịmepụta mmemme iguzosi ike n'ihe.

Ahịa ahịa

Otu n'ime ọnọdụ maka ịre ahịa na-aga nke ọma bụ nghọta: ndị sonyere ga-enwe obi ike na ọ gaghị ekwe omume ịmegharị atụmatụ. Enwere ike nweta nke a site na blockchain, ebe data enweghị ike ịgbanwe gbasara nzọ niile na oge emere ha ga-adị maka ndị niile sonyere.

Na ebili mmiri blockchain, enwere ike ịdekọ ụgwọ na steeti akaụntụ mgbụsị akwụkwọ site na DataTransaction.

Ị nwekwara ike ịtọ mmalite na njedebe oge nke ọrịre ahụ site na iji nọmba ngọngọ: ugboro nke ọgbọ ngọngọ na Waves blockchain bụ ihe hà nhata. 60 sekọnd.

1. bekee na-arịgo ọnụahịa okushon

Ndị na-eso n'ahịa ịre ahịa bekee na-etinye ọnụ na asọmpi n'etiti ibe ha. Nzọ nzọ ọhụrụ ọ bụla ga-agaferịrị nke gara aga. Ọkụ ahịa ahụ na-akwụsị mgbe enweghị ndị na-ere ahịa ga-agafe ahịa ikpeazụ. N'okwu a, onye na-ere ahịa kachasị elu ga-enye ego a na-ekwu.

Enwekwara nhọrọ ịre ahịa nke onye na-ere ahịa na-ewepụta ọnụahịa kacha nta maka nza, na ọnụahịa ikpeazụ ga-agaferịrị ya. Ma ọ bụghị ya, nza na-anọgide na-ereghị.

N'ọmụmaatụ a, anyị na-arụ ọrụ na akaụntụ emepụtara kpọmkwem maka mgbụsị akwụkwọ. Ogologo oge ịre ahịa bụ ngọngọ 3000, ọnụahịa mmalite nke nza bụ 0,001 WAVES. Onye so na ya nwere ike tinye ntinye aka site na izipu DataTransaction na igodo "ọnụahịa" yana uru nke ntinye ha.

Ọnụahịa nke ntinye ọhụrụ ahụ ga-adị elu karịa ọnụahịa dị ugbu a maka igodo a, onye so na ya ga-enwerịrị opekata mpe [new_bid + Commission] tokens na akaụntụ ya. A ghaghị ịdekọ adreesị onye na-ere ahịa na mpaghara "onye na-ezipụ" na DataTransaction, na ọnụ ahịa nkwụsị nke ugbu a ga-abụrịrị n'ime oge mgbụsị akwụkwọ.

Ọ bụrụ na n'ọgwụgwụ nke ire ere, onye so na ya etinyela ọnụahịa kachasị elu, ọ nwere ike izipu ExchangeTransaction iji kwụọ ụgwọ maka nza kwekọrọ na ọnụahịa a kapịrị ọnụ na ụzọ ego.

let startHeight = 384120
let finishHeight = startHeight + 3000
let startPrice = 100000
 
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
 
match tx {
case d : DataTransaction =>
  #проверяем, задана ли в стейте цена
  let currentPrice = if isDefined(getInteger(this, "price"))
 
                      #извлекаем цену из стейта
                      then extract(getInteger(this, "price"))
                      else startPrice
 
  #извлекаем цену из транзакции
  let newPrice = extract(getInteger(d.data, "price"))
  let priceIsBigger = newPrice > currentPrice
  let fee = 700000
  let hasMoney = wavesBalance(tx.sender) + fee >= newPrice
 
  #убеждаемся, что в текущей транзакции два поля и что отправитель совпадает с указанным в транзакции
  let correctFields = size(d.data) == 2 &&      
      d.sender == addressFromString(extract(getString(d.data,"sender")))
  startHeight <= height && height <= finishHeight && priceIsBigger && hasMoney && correctFields
case e : ExchangeTransaction =>
  let senderIsWinner = e.sender == addressFromString(extract(getString(this, "sender"))) #убеждаемся, что лот обменивает тот, кто его выиграл
  let correctAssetPair = e.sellOrder.assetPair.amountAsset == token && ! isDefined(e.sellOrder.assetPair.priceAsset)
  let correctAmount = e.amount == 1
  let correctPrice = e.price == extract(getInteger(this, "price"))
 
  height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice
case _ => false
}

2. Dutch okushon nke na-ebelata ọnụ ahịa

N'ahịa ahịa Dutch, a na-ebu ụzọ nye ọtụtụ ihe na ọnụahịa dị elu karịa ihe onye zụrụ ya dị njikere ịkwụ. A na-ebelata ọnụahịa ahụ site na nzọụkwụ ruo mgbe otu n'ime ndị sonyere na-ekwenye ịzụta nza na ọnụahịa dị ugbu a.

N'ihe atụ a, anyị na-eji otu nkwụsịtụ dị ka ọ dị na mbụ, yana ọnụahịa ọnụahịa mgbe delta na-ebelata. Edemede akaụntụ ahụ na-enyocha ma onye so na ya bụ onye izizi nzọ nzọ. Ma ọ bụghị ya, blockchain anabataghị DataTransaction.

let startHeight = 384120
let finishHeight = startHeight + 3000
let startPrice = 100000000
let delta = 100
 
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
match tx {
case d : DataTransaction =>
  let currentPrice = startPrice - delta * (height - startHeight)
 
  #извлекаем из поступившей дата-транзакции поле "price"
  let newPrice = extract(getInteger(d.data, "price"))
 
  #убеждаемся, что в стейте текущего аккаунта не содержится поля "sender"
  let noBetsBefore = !isDefined(getInteger(this, "sender"))
  let fee = 700000
  let hasMoney = wavesBalance(tx.sender) + fee >= newPrice
 
  #убеждаемся, что в текущей транзакции только два поля
  let correctFields = size(d.data) == 2 && newPrice == currentPrice && d.sender == addressFromString(extract(getString(d.data, "sender")))
  startHeight <= height && height <= finishHeight && noBetsBefore && hasMoney && correctFields
case e : ExchangeTransaction =>
 
  #убеждаемся, что отправитель текущей транзакции указан в стейте аккаунта по ключу sender
  let senderIsWinner = e.sender == addressFromString(extract(getString(this, "sender")))
 
  #убеждаемся, что аmount ассета указан корректно, и что прайс-ассет - waves
  let correctAssetPair = e.sellOrder.assetPair.amountAsset == token && ! isDefined(e.sellOrder.assetPair.priceAsset)
  let correctAmount = e.amount == 1
  let correctPrice = e.price == extract(getInteger(this, "price"))
  height > finishHeight && senderIsWinner && correctAssetPair && correctAmount && correctPrice
case _ => false
}

3. okushon "niile-akwụ"

"All-akwụ ụgwọ" bụ ọrịre ahịa nke ndị niile sonyere na-akwụ ụgwọ ahụ, n'agbanyeghị onye meriri nza. Onye ọ bụla so na ya na-akwụ ụgwọ, na onye so na ya na-eme ihe kachasị elu na-enweta nza.

N'ọmụmaatụ anyị, onye ọ bụla so na-ere ahịa na-etinye ego site na DataTransaction na (isi, uru)* = ("onye mmeri", adreesị), ("ọnụahịa", ọnụahịa). A kwadoro DataTransaction dị otú ahụ naanị ma ọ bụrụ na onye so na ya enweelarị TransferTransaction na mbinye aka ya na ntinye ya dị elu karịa ndị niile gara aga. Ọkụ ahịa ahụ na-aga n'ihu ruo mgbe a ga-enweta njedebe njedebe.

let startHeight = 1000
let endHeight = 2000
let this = extract(tx.sender)
let token = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
match tx {
 case d: DataTransaction =>
   #извлекаем из поступившей дата-транзакции поле "price"
   let newPrice = extract(getInteger(d.data, "price"))
 
   #извлекаем из пруфов транзакции публичный ключ аккаунта
   let pk = d.proofs[1]
   let address = addressFromPublicKey(pk)
 
   #извлекаем транзакцию доказательство из пруфов поступившей дата транзакции
   let proofTx = extract(transactionById(d.proofs[2]))
   
   height > startHeight && height < endHeight
   && size(d.data) == 2
   #убеждаемся, что адрес победителя, извлеченный из текущей транзакции, совпадает с адресом, извлеченным из пруфов
   && extract(getString(d.data, "winner")) == toBase58String(address.bytes)
   && newPrice > extract(getInteger(this, "price"))
   #проверяем, что транзакция подписана
   && sigVerify(d.bodyBytes, d.proofs[0], d.proofs[1])
   #проверяем корректность транзакции, указанной в пруфах
   && match proofTx {
     case tr : TransferTransaction =>
       tr.sender == address &&
       tr.amount == newPrice
     case _ => false
   }
 case t: TransferTransaction =>
 sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
 || (
   height > endHeight
   && extract(getString(this, "winner")) == toBase58String((addressFromRecipient(t.recipient)).bytes)
   && t.assetId == token
   && t.amount == 1
 )
 case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}

Insurance / Crowdfunding

Ka anyị tụlee ọnọdụ ebe ị chọrọ mkpuchi ndị ọrụ' akụ megide ego mfu. Dịka ọmụmaatụ, onye ọrụ chọrọ nkwa na ọ bụrụ na akara ngosi na-ebelata, ọ ga-enwe ike ị nwetaghachi ego zuru ezu a kwụrụ maka akara ngosi ndị a, ma dị njikere ịkwụ ụgwọ ego mkpuchi kwesịrị ekwesị.

Iji mejuputa nke a, ọ dị mkpa ịnye "ihe mkpuchi mkpuchi". Mgbe ahụ, etinyere edemede na akaụntụ onye nwe iwu, na-enye ohere ka e gbuo naanị ExchangeTransaction ndị na-ezute ọnọdụ ụfọdụ.

Iji gbochie mmefu okpukpu abụọ, ị ga-arịọ onye ọrụ ka o zite DataTransaction na akaụntụ onye nwe iwu tupu oge eruo na ( igodo, uru) = (purchaseTransactionId, sellOrderId) ma machibido izipu DataTransaction na igodo ejirilarị.

Ya mere, ihe akaebe nke onye ọrụ ga-enwerịrị ID azụmahịa nke ịzụrụ ihe mkpuchi mkpuchi. Ụzọ ego abụọ ahụ ga-abụrịrị otu na azụmahịa ịzụrụ. Ọnụ ego ahụ ga-adịkwa nhata nke edoziri n'oge ịzụrụ, wezuga ọnụahịa mkpuchi.

Aghọtara na emesịa akaụntụ mkpuchi ahụ na-azụta akara mkpuchi n'aka onye ọrụ na ọnụ ahịa na-adịghị ala karịa nke ọ zụtara ha: akaụntụ mkpuchi na-emepụta ExchangeTransaction, onye ọrụ bịanyere aka na ya (ọ bụrụ na emechara azụmahịa ahụ nke ọma), akaụntụ mkpuchi bịanyere aka na usoro nke abụọ na azụmahịa niile wee ziga ya na blockchain.

Ọ bụrụ na ọ nweghị ịzụrụ, onye ọrụ nwere ike ịmepụta ExchangeTransaction dịka iwu akọwapụtara na edemede ahụ wee ziga azụmahịa ahụ na blockchain. N'ụzọ dị otú a onye ọrụ nwere ike iweghachi ego e mefuru n'ịzụta mkpuchi mkpuchi.

let insuranceToken = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
 
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let freezePeriod = 150000
let insurancePrice = 10000
match tx {
 
 #убеждаемся, что, если поступила дата-транзакция, то у нее ровно одно поле и в стейте еще нет такого ключа
 case d : DataTransaction => size(d.data) == 1 && !isDefined(getBinary(this, d.data[0].key))
 case e : ExchangeTransaction =>
 
   #если у транзакции нет седьмого пруфа, проверяем корректность подписи
   if !isDefined(e.proofs[7]) then
     sigVerify(e.bodyBytes, e.proofs[0], e.senderPublicKey)
   else
     #если у транзакции есть седьмой пруф, извлекаем из него транзакцию и узнаём её высоту
     let purchaseTx = transactionById(e.proofs[7])
     let purchaseTxHeight = extract(transactionHeightById(e.proofs[7]))
    
     #обрабатываем транзакцию из пруфа
     match purchaseTx {
       case purchase : ExchangeTransaction =>
         let correctSender = purchase.sender == e.sellOrder.sender
         let correctAssetPair = e.sellOrder.assetPair.amountAsset == insuranceToken &&
                                purchase.sellOrder.assetPair.amountAsset == insuranceToken &&
                                e.sellOrder.assetPair.priceAsset == purchase.sellOrder.assetPair.priceAsset
         let correctPrice = e.price == purchase.price - insurancePrice && e.amount == purchase.amount
         let correctHeight = height > purchaseTxHeight + freezePeriod
 
         #убеждаемся, что в транзакции-пруфе указан верный ID текущей транзакции
         let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == e.sellOrder.id
         correctSender && correctAssetPair && correctPrice && correctHeight && correctProof
     case _ => false
   }
 case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}

Enwere ike ịme akara mkpuchi mkpuchi ka ọ bụrụ ihe bara uru, dịka ọmụmaatụ, machibido ịnyefe ya na ndị ọzọ.

Enwere ike itinye atụmatụ a maka ihe nrịbama igwe mmadụ, nke a na-eweghachite ndị nwe ya ma ọ bụrụ na achịkọtabeghị ego achọrọ.

Ụtụ ahịa azụmahịa

Nkwekọrịta smart na-adabara n'ọnọdụ ebe ọ dị mkpa ịnakọta ụtụ isi na azụmahịa ọ bụla na ọtụtụ ụdị akụ. Enwere ike ime nke a site na akụrụngwa ọhụrụ arụnyere nkwado maka azụmahịa nwere smart akụ:

1. Anyị na-enye FeeCoin, nke a ga-ezigara ndị ọrụ na ọnụahịa a kapịrị ọnụ: 0,01 WAVES = 0,001 FeeCoin.

2. Tọọ nkwado maka FeeCoin na ọnụego mgbanwe: 0,001 WAVES = 0,001 FeeCoin.

3. Tọọ script na-esonụ maka smart akụ:

let feeAssetId = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
let taxDivisor = 10
 
match tx {
  case t: TransferTransaction =>
    t.feeAssetId == feeAssetId && t.fee == t.amount / taxDivisor
  case e: ExchangeTransaction | MassTransferTransaction => false
  case _ => true
}

Ugbu a mgbe ọ bụla mmadụ na-ebufe N smart akụ, ha ga-enye gị FeeCoin na ego nke N/taxDivisor (nke a pụrụ ịzụta n'aka gị na 10 *N/taxDivisor WAVES), na ị ga-enye onye na-egwuputa N / taxDivisor WAVES. N'ihi ya, uru gị (ụtụ isi) ga-abụ 9 * N / taxDivisor WAVES.

Ị nwekwara ike rụọ ụtụ isi site na iji edemede bara uru na MassTransferTransaction:

let taxDivisor = 10
 
match tx {
  case t : MassTransferTransaction =>
    let twoTransfers = size(t.transfers) == 2
    let issuerIsRecipient = t.transfers[0].recipient == addressFromString("3MgkTXzD72BTfYpd9UW42wdqTVg8HqnXEfc")
    let taxesPaid = t.transfers[0].amount >= t.transfers[1].amount / taxDivisor
    twoTransfers && issuerIsRecipient && taxesPaid
  case _ => false
}

Cashback na mmemme iguzosi ike n'ihe

Cashback bụ ụdị mmemme iguzosi ike n'ihe nke onye zụrụ ya na-eweghachite akụkụ nke ego ejiri na ngwaahịa ma ọ bụ ọrụ.

Mgbe ị na-emejuputa ikpe a site na iji akaụntụ smart, anyị ga-enyocha ihe akaebe n'otu ụzọ ahụ anyị mere na mkpuchi mkpuchi. Iji gbochie mmefu okpukpu abụọ, onye ọrụ ga-ezite DataTransaction na (igodo, uru) = (purchaseTransactionId, cashbackTransactionId) tupu ịnata cashback.

Anyị ga-eji DataTransaction tọọ mmachibido na igodo ndị dị adị. cashbackDivisor - nkeji kewara site na oke cashback. Ndị ahụ. Ọ bụrụ na òkè cashback bụ 0.1, mgbe ahụ cashbackDivisor 1 / 0.1 = 10.

let cashbackToken = base58'8jfD2JBLe23XtCCSQoTx5eAW5QCU6Mbxi3r78aNQLcNf'
 
#извлекаем из транзакции адрес отправителя
let this = extract(tx.sender)
let cashbackDivisor = 10
match tx {
 
 #убеждаемся, что, если поступила дата-транзакция, то у нее ровно одно поле и в стейте еще нет такого ключа
 case d : DataTransaction => size(d.data) == 1 && !isDefined(getBinary(this, d.data[0].key))
 case e : TransferTransaction =>
 
   #если у транзакции нет седьмого пруфа, проверяем корректность подписи
   if !isDefined(e.proofs[7]) then
     sigVerify(e.bodyBytes, e.proofs[0], e.senderPublicKey)
   else
 
     #если у транзакции есть седьмой пруф, извлекаем из него транзакцию и узнаём её высоту
     let purchaseTx = transactionById(e.proofs[7])
     let purchaseTxHeight = extract(transactionHeightById(e.proofs[7]))
    
     #обрабатываем транзакцию из пруфа
     match purchaseTx {
       case purchase : TransferTransaction =>
         let correctSender = purchase.sender == e.sender
         let correctAsset = e.assetId == cashbackToken
         let correctPrice = e.amount == purchase.amount / cashbackDivisor
 
         #убеждаемся, что в транзакции-пруфе указан верный ID текущей транзакции
         let correctProof = extract(getBinary(this, toBase58String(purchase.id))) == e.id
         correctSender && correctAsset && correctPrice && correctProof
     case _ => false
   }
 case _ => sigVerify(tx.bodyBytes, tx.proofs[0], tx.senderPublicKey)
}

Atọmk agbanwe

Swap atọm na-enye ndị ọrụ ohere ịgbanwe akụ na-enweghị enyemaka nke mgbanwe. Site na ngbanwe atomic, a chọrọ ma ndị sonyere na azụmahịa ahụ ka ha kwenye ya n'ime oge ụfọdụ.

Ọ bụrụ na ọ dịkarịa ala otu n'ime ndị na-eso ya enyeghị nkwenye ziri ezi nke azụmahịa n'ime oge enyere maka azụmahịa ahụ, a na-akagbu azụmahịa ahụ ma mgbanwe ahụ adịghị eme.

N'ọmụmatụ anyị, anyị ga-eji edemede akaụntụ smart a:

let Bob = Address(base58'3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8')
let Alice = Address(base58'3PNX6XwMeEXaaP1rf5MCk8weYeF7z2vJZBg')
 
let beforeHeight = 100000
 
let secret = base58'BN6RTYGWcwektQfSFzH8raYo9awaLgQ7pLyWLQY4S4F5'
match tx {
  case t: TransferTransaction =>
    let txToBob = t.recipient == Bob && sha256(t.proofs[0]) == secret && 20 + beforeHeight >= height
    let backToAliceAfterHeight = height >= 21 + beforeHeight && t.recipient == Alice
    txToBob || backToAliceAfterHeight
  case _ => false
}

N'isiokwu na-esonụ, anyị ga-eleba anya na iji smart akaụntụ na ego ngwá dị ka nhọrọ, ọdịnihu na ụgwọ.

isi: www.habr.com

Tinye a comment