Izicelo zama-akhawunti ahlakaniphile we-Waves: kusuka ezindalini kuya ezinhlelweni zebhonasi

Izicelo zama-akhawunti ahlakaniphile we-Waves: kusuka ezindalini kuya ezinhlelweni zebhonasi

I-Blockchain ivame ukuhlotshaniswa kuphela ne-cryptocurrencies, kodwa izindawo zokusetshenziswa kobuchwepheshe be-DLT zibanzi kakhulu. Enye yezindawo ezithembisayo kakhulu zokusetshenziswa kwe-blockchain yinkontileka ehlakaniphile eyenziwa ngokuzenzakalelayo futhi ayidingi ukwethembana phakathi kwezinhlangothi ezingene kuyo.

RIDE – ulimi lwezinkontileka ezihlakaniphile

Amagagasi athuthukise ulimi olukhethekile lwezinkontileka ezihlakaniphile - RIDE. Imibhalo yayo ephelele itholakala lapha. Futhi lapha - isihloko ngalesi sihloko ngoHabr.

Inkontileka ye-RIDE iyisilandiso futhi ibuyisela "iqiniso" noma "amanga" njengokuphumayo. Ngokufanelekile, okwenziwayo kuqoshwa ku-blockchain noma kwenqatshwe. Inkontileka ehlakaniphile iqinisekisa ngokugcwele ukugcwaliseka kwemibandela ethile. Ukukhiqiza ukuthenga ngenkontileka ku-RIDE okwamanje akunakwenzeka.

Namuhla kunezinhlobo ezimbili zezinkontileka ezihlakaniphile ze-Waves: ama-akhawunti ahlakaniphile nezimpahla ezihlakaniphile. I-akhawunti ehlakaniphile i-akhawunti yomsebenzisi evamile, kodwa iskripthi sisethelwe yona esilawula konke okwenziwayo. Iskripthi se-akhawunti ehlakaniphile singabukeka kanje, isibonelo:

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

I-tx iwumsebenzi ocutshungulwayo esiwuvumelayo ukusebenzisa indlela yokufanisa iphethini kuphela uma ingewona umsebenzi wokudlulisa. Ukufaniswa kwephethini ku-RIDE kusetshenziselwa ukuhlola uhlobo lomsebenzi. Wonke ama-akhawunti akhona angacutshungulwa kusikripthi se-akhawunti ehlakaniphile izinhlobo zokuthengiselana.

Umbhalo ungaphinda umemezele okuguquguqukayo, usebenzise "uma-ke-okunye" ukwakha nezinye izindlela zokuhlola izimo ngokugcwele. Ukuqinisekisa ukuthi izinkontileka zinokuphelela nokuyinkimbinkimbi okungafakazeka (izindleko) okulula ukuzibikezela ngaphambi kokuthi kuqale ukusebenza kwenkontileka, i-RIDE ayiqukethe izitatimende eziluphu noma zeqa.

Ezinye izici zama-akhawunti we-Waves zifaka phakathi ukuba khona "kwesimo," okungukuthi, isimo se-akhawunti. Ungabhala inombolo engapheli yamapheya (ukhiye, inani) kusimo se-akhawunti usebenzisa ukuthengiselana kwedatha (DataTransaction). Lolu lwazi lungase lucutshungulwe kokubili nge-REST API futhi ngokuqondile kunkontileka ehlakaniphile.

Okwenziwayo ngakunye kungaqukatha inqwaba yobufakazi, lapho kungafakwa khona isiginesha yombambi qhaza, i-ID yomsebenzi odingekayo, njll..

Ukusebenza nge-RIDE nge LAPHA ikuvumela ukuthi ubone ukubuka okuhlanganisiwe kwenkontileka (uma ihlanganisiwe), dala ama-akhawunti amasha futhi usethe izikripthi zayo, futhi uthumele ukuthengiselana ngomugqa womyalo.

Ngomjikelezo ogcwele, okuhlanganisa ukudala i-akhawunti, ukufaka inkontileka ehlakaniphile kuyo kanye nokuthumela okwenziwayo, ungasebenzisa futhi umtapo wolwazi ukuze uxhumane ne-REST API (isibonelo, C#, C, Java, JavaScript, Python, Rust, Elixir) . Ukuze uqale ukusebenza nge-IDE, vele uchofoze inkinobho OKUSHA.

Amathuba okusebenzisa izinkontileka ezihlakaniphile abanzi: kusukela ekuvimbeleni ukuthengiselana kuya kumakheli athile (“uhlu olumnyama”) kuya kuma-dApp ayinkimbinkimbi.

Manje ake sibheke izibonelo ezithile zokusetshenziswa kwezinkontileka ezihlakaniphile ebhizinisini: lapho uqhuba indali, umshwalense, nokudala izinhlelo zokwethembeka.

Izindali

Omunye wemibandela yendali eyimpumelelo wukwenza izinto obala: ababambiqhaza kufanele baqiniseke ukuthi akunakwenzeka ukukhohlisa amabhidi. Lokhu kungafinyelelwa ngenxa ye-blockchain, lapho idatha engaguquleki mayelana nakho konke ukubheja kanye nesikhathi enziwe ngaso izotholakala kubo bonke ababambiqhaza.

Ku-Waves blockchain, amabhidi angarekhodwa kusimo se-akhawunti yendali nge-DataTransaction.

Ungasetha futhi isikhathi sokuqala nesokugcina sendali usebenzisa izinombolo ze-block: imvamisa yokukhiqizwa kwe-block ku-Waves blockchain icishe ilingane 60 imizuzwana.

1. Indali yentengo yesiNgisi ekhuphukayo

Abahlanganyeli endalini yesiNgisi bafaka amabhidi ngokuncintisana bodwa. Ukubheja okusha ngakunye kufanele kudlule okwangaphambilini. Indali iyaphela uma bengasekho abathengi abazodlula ibhidi yokugcina. Kulokhu, ofaka isicelo esiphezulu kufanele anikeze inani elishiwo.

Kukhona futhi inketho endalini lapho umdayisi ebeka inani elincane lenkatho, futhi inani lokugcina kufanele lidlule. Uma kungenjalo, inkatho ihlala ingathengiswa.

Kulesi sibonelo, sisebenza nge-akhawunti edalelwe ngokukhethekile indali. Isikhathi sendali singamabhulokhi angu-3000, futhi intengo yokuqala yenkatho ingu-0,001 WAVES. Umbambi qhaza angakwazi ukufaka ibhidi ngokuthumela i-DataTransaction ngokhiye "inani" kanye nenani lebhidi yabo.

Intengo yebhidi entsha kufanele ibe phezulu kunentengo yamanje yalo khiye, futhi umhlanganyeli kufanele okungenani abe namathokheni angu-[new_bid + commission] ku-akhawunti yakhe. Ikheli lomabhidi kufanele lirekhodwe endaweni ethi "umthumeli" ku-DataTransaction, futhi ubude bamanje bebhulokhi yebhidi kufanele bube phakathi nesikhathi sendali.

Uma ekupheleni kwendali umhlanganyeli esethe inani eliphakeme kakhulu, angathumela i-ExchangeTransaction ukuze akhokhele inkatho ehambisanayo ngentengo eshiwo kanye nokubhanqwa kohlobo lwemali.

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. Indali yesiDashi yamanani anciphayo

Endalini yase-Dutch, okuningi kunikezwa ekuqaleni ngentengo ephakeme kunaleyo umthengi azimisele ukuyikhokha. Intengo iyancipha isinyathelo ngesinyathelo kuze kube yilapho omunye wabahlanganyeli evuma ukuthenga inkatho ngentengo yamanje.

Kulesi sibonelo sisebenzisa ama-constants afanayo nakwedlule, kanye nesinyathelo sentengo lapho i-delta yehla. Umbhalo we-akhawunti uhlola ukuthi ingabe umhlanganyeli ungowokuqala yini ukubheja. Uma kungenjalo, i-DataTransaction ayamukelwa yi-blockchain.

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. Indali “yokukhokha konke”

“Khokha konke” indali lapho bonke abahlanganyeli bekhokha khona ibhidi, kungakhathaliseki ukuthi ubani owina inkatho. Umhlanganyeli omusha ngamunye ukhokha ibhidi, futhi umhlanganyeli owenza ibhidi ephezulu uwina inkatho.

Esibonelweni sethu, umhlanganyeli wendali ngamunye ubeka ibhidi nge-DataTransaction nge (ukhiye, inani)* = (“owinile”, ikheli),(“inani”, intengo). I-DataTransaction enjalo ivunyelwa kuphela uma lo mbambi qhaza esevele ene-TransferTransaction nesiginesha yakhe futhi ibhidi yakhe iphakeme kunawo wonke angaphambilini. Indali iyaqhubeka kuze kufinyelelwe ku-endHeight.

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)
}

Umshwalense / Crowdfunding

Ake sicabangele isimo lapho udinga ukufaka umshwalense izimpahla zabasebenzisi ngokumelene nokulahlekelwa kwezimali. Isibonelo, umsebenzisi ufuna isiqinisekiso sokuthi uma ithokheni yehla, uzokwazi ukubuyisela inani eliphelele elikhokhelwe lawa mathokheni, futhi uzimisele ukukhokha inani elifanele lomshwalense.

Ukuze wenze lokhu, "amathokheni omshwalense" adinga ukukhishwa. Bese kufakwa umbhalo ku-akhawunti yomnikazi wepholisi, okuvumela kuphela lawo ma-ExchangeTransactions ahlangabezana nemibandela ethile ukuthi asetshenziswe.

Ukuze uvimbele ukusebenzisa imali kabili, udinga ukucela umsebenzisi ukuthi athumele i-DataTransaction ku-akhawunti yomnikazi wepholisi kusenesikhathi (ukhiye, inani) = (purchaseTransactionId, sellOrderId) futhi uvimbele ukuthumela i-DataTransactions ngokhiye osuvele usetshenzisiwe.

Ngakho-ke, ubufakazi bomsebenzisi kufanele buqukathe i-ID yokwenziwe yokuthengwa kwethokheni yomshwalense. Ukubhanqwa kohlobo lwemali kufanele kufane nasekuthengeni. Izindleko kufanele futhi zilingane nalezo ezimisiwe ngesikhathi sokuthenga, kukhishwe inani lomshwalense.

Kuyaqondakala ukuthi kamuva i-akhawunti yomshwalense ithenga amathokheni omshwalense kumsebenzisi ngentengo engephansi kunaleyo ayithenge ngayo: i-akhawunti yomshuwalense idala i-ExchangeTransaction, umsebenzisi asayine i-oda (uma ukuthengiselana kuqediwe ngendlela efanele), I-akhawunti yomshwalense isayina i-oda lesibili kanye nakho konke ukuthengiselana futhi ikuthumele ku-blockchain.

Uma kungekho ukuthenga okwenzekayo, umsebenzisi angakha i-ExchangeTransaction ngokuvumelana nemithetho echazwe kuskripthi futhi athumele ukuthengiselana ku-blockchain. Ngale ndlela umsebenzisi angabuyisela imali esetshenziswe ekuthengeni amathokheni afakwe kumshwalense.

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)
}

Ithokheni yomshwalense ingenziwa ibe yimpahla ehlakaniphile, isibonelo, ukuvimbela ukudluliselwa kwayo kubantu besithathu.

Lolu hlelo lungasetshenziswa futhi kumathokheni e-crowdfunding, abuyiselwa kubanikazi uma inani elidingekayo lingaqoqwanga.

Izintela zomsebenzi

Izinkontileka ezihlakaniphile nazo ziyasebenza ezimeni lapho kudingeka khona ukuqoqa intela ekwenziweni ngakunye ngezinhlobo ezimbalwa zezimpahla. Lokhu kungenziwa ngempahla entsha efakiwe uxhaso ngokwenziwe ngezimpahla ezihlakaniphile:

1. Sikhipha i-FeeCoin, ezothunyelwa kubasebenzisi ngentengo engashintshi: 0,01 WAVES = 0,001 FeeCoin.

2. Setha uxhaso lwe-FeeCoin nezinga lokushintshisana: 0,001 WAVES = 0,001 FeeCoin.

3. Setha umbhalo olandelayo we-smart asset:

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
}

Manje njalo uma othile edlulisela impahla ehlakaniphile engu-N, uzokunikeza i-FeeCoin enanini le-N/taxDivisor (engathengwa kuwe ngo-10 *N/taxDivisor WAVES), futhi uzonikeza umvukuzi N/taxDivisor WAVES. Ngenxa yalokho, inzuzo yakho (intela) izoba ngu-9*N / taxDivisor WAVES.

Ungenza futhi intela usebenzisa iskripthi sempahla ehlakaniphile kanye ne-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
}

Imbuyiselo yemali nezinhlelo zokwethembeka

I-Cashback wuhlobo lohlelo lokwethembeka lapho umthengi ethola khona ingxenye yenani elisetshenziswe kumkhiqizo noma isevisi.

Lapho sisebenzisa leli cala sisebenzisa i-akhawunti ehlakaniphile, kufanele sihlole ubufakazi ngendlela efanayo nesenze ngayo kumshwalense. Ukuze uvimbele ukusetshenziswa kwemali okuphindwe kabili, umsebenzisi kufanele athumele i-DataTransaction (ukhiye, inani) = (purchaseTransactionId, cashbackTransactionId) ngaphambi kokuthola imbuyiselo.

Kufanele futhi simise ukuvinjelwa kokhiye abakhona sisebenzisa i-DataTransaction. i-cashbackDivisor - iyunithi ehlukaniswe ngesabelo se-cashback. Labo. uma i-cashback share ingu-0.1, bese kuba yi-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)
}

Ukushintshwa kwe-athomu

Ukushintshashintsha kwe-athomu kuvumela abasebenzisi ukuthi bashintshisane ngezimpahla ngaphandle kosizo lokushintshisana. Ngokushintshana kwe-athomu, bobabili ababambiqhaza ekwenziweni kudingeka ukuthi bakuqinisekise phakathi nenkathi ethile yesikhathi.

Uma okungenani oyedwa wabahlanganyeli enganikezi isiqinisekiso esifanele sokuthengiselana phakathi nesikhathi esabelwe ukuthengiselana, ukuthengiselana kukhanseliwe futhi ukushintshisana akwenzeki.

Esibonelweni sethu, sizosebenzisa umbhalo we-akhawunti ehlakaniphile olandelayo:

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
}

Esihlokweni esilandelayo sizobheka ukusetshenziswa kwama-akhawunti ahlakaniphile kumathuluzi ezezimali afana nezinketho, ikusasa kanye nezikweletu.

Source: www.habr.com

Engeza amazwana