Ergo'da Dağıtık Borsa Sözleşmeleri

This page is machine-translated.
Denys Zadorozhnyi

31 Temmuz 2020

Ergo, alıcılar ve satıcılar tarafından bağımsız olarak blok zincirine konulabilen imzalı alım ve satım emirlerinin uygulamasına olanak tanıyan, ifade gücü yüksek akıllı sözleşmelere ve işlem modeline sahiptir. Bir off-chain eşleştirme servisi, Ergo blok zincirini gözlemleyebilir, eşleşen emirleri bulabilir ve herhangi bir sır bilmeden takas işlemini gönderebilir. Eşleştirme, bir takas işleminin parçası olarak ödenen DEX ödülü ile teşvik edilebilir. İki emrin eşleşmesini ilk keşfeden herkes, takas işlemini oluşturabilir ve ERG cinsinden bir ödül alabilir. Kısmi eşleştirme desteklenmektedir, bu da hedef (alım/satım) emrinin kısmen yerine getirilebileceği anlamına gelir; bu durumda aynı takas işleminde yeni bir "artık" emir (kutu) oluşturulması gerekir. Herhangi bir emir, "sahibi" tarafından herhangi bir zamanda iptal edilebilir.

Satış emri sözleşmesi kaynak.

Alım emri sözleşmesi kaynak.

Kısmi eşleştirme

Her iki sözleşmede de derleme sırasında kodlanmış token fiyatı ve DEX ücreti parametreleri bulunmaktadır. Bu, "artık" emir varlıklarını, alım emri için ERG'leri ve satış emri için token'ları kontrol etmemizi sağlar.

Alım emri sözleşmesinde, doğru parametreler ve varlıklar içerip içermediğini kontrol ederek bir artık kutu arıyoruz.

// kısmi eşleştirme durumunda, bu tx'de eşleşmeyen fonlarla yeni bir alım emri kutusu oluşturulmalıdır
val foundResidualOrderBoxes = OUTPUTS.filter { (b: Box) => 
  val tokenIdParamIsCorrect = b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == tokenId 
  val tokenPriceParamIsCorrect = b.R5[Long].isDefined && b.R5[Long].get == tokenPrice
  val dexFeePerTokenParamIsCorrect = b.R6[Long].isDefined && b.R6[Long].get == dexFeePerToken
  val contractParamsAreCorrect = tokenIdParamIsCorrect && 
    tokenPriceParamIsCorrect && dexFeePerTokenParamIsCorrect
  val referenceMe = b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id 
  val guardedByTheSameContract = b.propositionBytes == SELF.propositionBytes
  contractParamsAreCorrect && referenceMe && guardedByTheSameContract
}

source

Sonra, aşağıdaki özelliklerin geçerli olduğunu kontrol ediyoruz:

  • "Artık" emir kutusunun değeri, mevcut kutunun (emir) değeri ile bu takas işleminde aldığımız token'ların ERG değeri ve bu takas işlemi için DEX ücreti çıkarıldığında elde edilen değerdir.
  • Bu takas işleminde yalnızca bir "artık" emir kutusu oluşturulmuştur.
// satın alınan token'lar için ödenen ERG'ler
val returnTokenValue = returnTokenAmount * tokenPrice
// toplam eşleştirme durumu (tüm ERG'ler harcanır ve doğru miktarda token satın alınır)
val totalMatching = (SELF.value - expectedDexFee) == returnTokenValue && 
  returnBox.value >= fullSpread
// kısmi eşleştirme durumu, örneğin satın alınan token'ların yanı sıra, bu emrin eşleşmeyen kısmı için ERG'ler ile yeni bir alım emri talep ediyoruz
val partialMatching = {
  val correctResidualOrderBoxValue = (SELF.value - returnTokenValue - expectedDexFee)
  foundResidualOrderBoxes.size == 1 && 
    foundResidualOrderBoxes(0).value == correctResidualOrderBoxValue && 
    returnBox.value >= fullSpread
}

source

Satış emri sözleşmesinde, doğru parametreler ve varlıklar içerip içermediğini kontrol ederek bir artık kutu arıyoruz.

// kısmi eşleştirme durumunda, bu tx'de eşleşmeyen token'larla yeni bir satış emri kutusu oluşturulmalıdır
// kodun ilerleyen kısımlarında yalnızca bir tane böyle kutu oluşturulduğunu kontrol edin
val foundResidualOrderBoxes = OUTPUTS.filter { (b: Box) => 
  val tokenIdParamIsCorrect = b.R4[Coll[Byte]].isDefined && b.R4[Coll[Byte]].get == tokenId 
  val tokenPriceParamIsCorrect = b.R5[Long].isDefined && b.R5[Long].get == tokenPrice
  val dexFeePerTokenParamIsCorrect = b.R6[Long].isDefined && b.R6[Long].get == dexFeePerToken
  val contractParamsAreCorrect = tokenIdParamIsCorrect && 
    tokenPriceParamIsCorrect && 
    dexFeePerTokenParamIsCorrect
  val referenceMe = b.R7[Coll[Byte]].isDefined && b.R7[Coll[Byte]].get == SELF.id 
  val guardedByTheSameContract = b.propositionBytes == SELF.propositionBytes
  contractParamsAreCorrect && referenceMe && guardedByTheSameContract
}

source

Sonra, aşağıdaki özelliklerin geçerli olduğunu kontrol ediyoruz:

  • Mevcut kutudaki (emir) token miktarı ile "artık" emir kutusu arasındaki fark, satıcının bu takas işleminde "satılan" token'lar için aldığı ERG miktarını belirler (soldTokenAmount * tokenPrice).
  • "Artık" emir kutusunun değeri, mevcut kutunun (emir) değeri ile bu takas işlemi için DEX ücreti çıkarıldığında elde edilen değerdir.
  • Bu takas işleminde yalnızca bir "artık" emir kutusu oluşturulmuştur.
// kısmi eşleştirme durumu, örneğin alınan ERG'lerin yanı sıra, bu emrin eşleşmeyen kısmı için token'larla yeni bir satış emri talep ediyoruz
val partialMatching = {
  foundResidualOrderBoxes.size == 1 && {
    val residualOrderBox = foundResidualOrderBoxes(0)
    val residualOrderTokenData = residualOrderBox.tokens(0)
    val residualOrderTokenAmount = residualOrderTokenData._2
    val soldTokenAmount = selfTokenAmount - residualOrderTokenAmount
    val soldTokenErgValue = soldTokenAmount * tokenPrice
    val expectedDexFee = dexFeePerToken * soldTokenAmount

    val residualOrderTokenId = residualOrderTokenData._1
    val tokenIdIsCorrect = residualOrderTokenId == tokenId

    val residualOrderValueIsCorrect = residualOrderBox.value == (SELF.value - expectedDexFee)
    val returnBoxValueIsCorrect = returnBox.value == soldTokenErgValue + fullSpread(soldTokenAmount)
    tokenIdIsCorrect && 
      soldTokenAmount >= 1 && 
      residualOrderValueIsCorrect && 
      returnBoxValueIsCorrect
  }
}

source

Toplam eşleştirme

Hem satış hem de alım emirleri, takas işleminde tamamen yerine getirilebilir. Bu durumda, "artık" emir kutusu için bir gereklilik yoktur.
Bu yol için, aşağıdaki özelliklerin geçerli olduğunu kontrol ediyoruz.
Satış emri için:

  • Bu takas işleminde satıcının aldığı ERG miktarı, mevcut emirdeki token miktarı ile token fiyatının çarpımına eşit olmalıdır.
    val totalMatching = (returnBox.value == selfTokenAmount * tokenPrice + fullSpread(selfTokenAmount))
    source

Alım emri için:

  • Bu takas işleminde alıcının aldığı token değeri (token miktarı * token fiyatı, ERG cinsinden), mevcut kutunun (emir) değeri ile DEX ücreti çıkarıldığında elde edilen değere eşit olmalıdır.
    val totalMatching = (SELF.value - expectedDexFee) == (returnTokenAmount * tokenPrice) && returnBox.value >= fullSpread
    source

Teklif-Satış farkı

Karşı emirlerin sıralama kontrolü

Fark, alım (teklif) emri fiyatı ile satış (satış) emri fiyatı arasındaki farktır. Eğer bir fark varsa, "daha eski" emrin bunu almasını sağlamak istiyoruz.
Bu sözleşme, karşı emirlerin (harcama emirleri) fark miktarına göre sıralanmasını gerektirir. Böylece daha büyük fark olanlar "ilk" olarak "tüketilecektir".
Alım emri sözleşmesinde:

// bu emrin belirli bir karşı emir (yükseklik) için farkı alıp almayacağını kontrol et
val spreadIsMine = { (counterOrderBoxHeight: Int) => 
// yalnızca sıkı bir şekilde daha büyük olduğu için, eşitlik yalnızca satış emri sözleşmesinde kazanır
// Denys: yükseklik eşit olduğunda kimin farkı alacağına karar vermemiz gerekiyor, herhangi bir neden olmaksızın alım emrini seçtim
counterOrderBoxHeight >= SELF.creationInfo._1 
}

// INPUTS'te karşı (satış) emirlerin farklara göre sıralandığını kontrol et
// böylece daha büyük (üst) fark "ilk" olarak "tüketilecektir"
val sellOrderBoxesAreSortedBySpread = { (boxes: Coll[Box]) => 
boxes.size > 0 && {
  val alledgedlyTopSpread = if (spreadIsMine(boxes(0).creationInfo._1)) { 
    tokenPrice - boxes(0).R5[Long].getOrElse(0L)
  } else { 0L }
  boxes.fold((alledgedlyTopSpread, true), { (t: (Long, Boolean), box: Box) => 
    val prevSpread = t._1
    val isSorted = t._2
    val boxTokenPrice = box.R5[Long].getOrElse(0L)
    val boxTokenPriceIsCorrect = boxTokenPrice > 0 && boxTokenPrice <= tokenPrice
    val spread = if (spreadIsMine(box.creationInfo._1)) { 
      tokenPrice - boxTokenPrice 
    } else { 0L }
    (spread, isSorted && boxTokenPriceIsCorrect && spread <= prevSpread)
  })._2 
}
}

source

Ayrıca, karşı satış emirlerinin R5 kaydında belirtilen token fiyatının doğru aralıkta olduğunu kontrol ediyoruz, böylece aritmetik taşma ve diğer benzer saldırıların istismarını önleyebiliriz.

Satış emri sözleşmesinde:

// bu emrin belirli bir karşı emir (yükseklik) için farkı alıp almayacağını kontrol et
val spreadIsMine = { (counterOrderBoxHeight: Int) => 
// eşitlik yalnızca alım emri sözleşmesinde kazanır
// Denys: yükseklik eşit olduğunda kimin farkı alacağına karar vermemiz gerekiyor, herhangi bir neden olmaksızın alım emrini seçtim
counterOrderBoxHeight > SELF.creationInfo._1 
}

// INPUTS'te karşı (alım) emirlerin farklara göre sıralandığını kontrol et
// böylece daha büyük (üst) fark "ilk" olarak "tüketilecektir"
val buyOrderBoxesAreSortedBySpread = { (boxes: Coll[Box]) => 
boxes.size > 0 && {
  val alledgedlyTopSpread = if (spreadIsMine(boxes(0).creationInfo._1)) { 
    boxes(0).R5[Long].getOrElse(0L) - tokenPrice 
  } else { 0L }
  boxes.fold((alledgedlyTopSpread, true), { (t: (Long, Boolean), box: Box) => 
    val prevSpread = t._1
    val isSorted = t._2
    val boxTokenPrice = box.R5[Long].getOrElse(0L)
    // alım emrinin DEX ücreti burada kullanılmasa da, pozitif olup olmadığını kontrol ediyoruz
    val boxDexFeePerToken = box.R6[Long].getOrElse(0L)
    val spread = if (spreadIsMine(box.creationInfo._1)) { boxTokenPrice - tokenPrice } else { 0L }
    (spread, isSorted && boxTokenPrice >= tokenPrice && boxDexFeePerToken > 0L && spread <= prevSpread)
  })._2 
}
}

source

Ayrıca, karşı alım emirlerinin R5 kaydında belirtilen token fiyatının ve R6 kaydındaki DEX ücretinin doğru aralıkta olduğunu kontrol ediyoruz.

Fark hesaplama

Mevcut emrin farkını alıp almadığını kontrol etmek için, önce onu hesaplamamız gerekiyor. Karşı emirler fark miktarına göre sıralandığında, onları bu sırayla "tüketmeye" başlıyoruz ve bu eşleşmede kalan token sayısını azaltıyoruz.
Alım emri sözleşmesinde:

// tüm karşı (satış) emirlerden aldığımız toplam fark
val fullSpread = {
  spendingSellOrders.fold((returnTokenAmount, 0L), { (t: (Long, Long), sellOrder: Box) => 
    val returnTokensLeft = t._1
    val accumulatedFullSpread = t._2
    val sellOrderTokenPrice = sellOrder.R5[Long].get
    val sellOrderTokenAmount = sellOrder.tokens(0)._2
    val tokenAmountFromThisOrder = min(returnTokensLeft, sellOrderTokenAmount)
    if (spreadIsMine(sellOrder.creationInfo._1)) {
      // fark bizim
      val spreadPerToken = tokenPrice - sellOrderTokenPrice
      val sellOrderSpread = spreadPerToken * tokenAmountFromThisOrder
      (returnTokensLeft - tokenAmountFromThisOrder, accumulatedFullSpread + sellOrderSpread)
    }
    else {
      // fark bizim değil
      (returnTokensLeft - tokenAmountFromThisOrder, accumulatedFullSpread)
    }
  })._2
}

source

Satış emri sözleşmesinde, o alım emrinde kaç token olduğunu hesaplamak için hem token fiyatına hem de DEX ücreti miktarına güvenmemiz gerekiyor. Bunun yanı sıra, bu takas işleminde "satılan" token miktarını geri kutu değerinden çıkaramadığımız için, fark hesaplamasını ileride kodda bileceğimiz belirli bir token miktarı ile parametreli hale getiriyoruz:

// tüm karşı (alım) emirlerden aldığımız toplam fark
val fullSpread = { (tokenAmount: Long) =>
  spendingBuyOrders.fold((tokenAmount, 0L), { (t: (Long, Long), buyOrder: Box) => 
    val returnTokensLeft = t._1
    val accumulatedFullSpread = t._2
    val buyOrderTokenPrice = buyOrder.R5[Long].get
    val buyOrderDexFeePerToken = buyOrder.R6[Long].get
    val buyOrderTokenAmountCapacity = buyOrder.value / (buyOrderTokenPrice + buyOrderDexFeePerToken)
    val tokenAmountInThisOrder = min(returnTokensLeft, buyOrderTokenAmountCapacity)
    if (spreadIsMine(buyOrder.creationInfo._1)) {
      // fark bizim
      val spreadPerToken = buyOrderTokenPrice - tokenPrice
      val buyOrderSpread = spreadPerToken * tokenAmountInThisOrder
      (returnTokensLeft - tokenAmountInThisOrder, accumulatedFullSpread + buyOrderSpread)
    }
    else {
      // fark bizim değil
      (returnTokensLeft - tokenAmountInThisOrder, accumulatedFullSpread)
    }
  })._2
}

source

Alınan farkı kontrol et

Fark miktarı belirlendikten sonra, mevcut emrin gerçekten farkı alıp almadığını kontrol etmemiz gerekiyor.
Alım emri sözleşmesinde, bunun geri kutu değerine dahil olduğunu kontrol ediyoruz:

// toplam eşleştirme durumu (tüm ERG'ler harcanır ve doğru miktarda token satın alınır)
val totalMatching = (SELF.value - expectedDexFee) == returnTokenValue && 
  returnBox.value >= fullSpread
// kısmi eşleştirme durumu, örneğin satın alınan token'ların yanı sıra, bu emrin eşleşmeyen kısmı için ERG'ler ile yeni bir alım emri talep ediyoruz
val partialMatching = {
  val correctResidualOrderBoxValue = (SELF.value - returnTokenValue - expectedDexFee)
  foundResidualOrderBoxes.size == 1 && 
    foundResidualOrderBoxes(0).value == correctResidualOrderBoxValue && 
    returnBox.value >= fullSpread
}

source

Satış emri sözleşmesinde, bu takas işleminde "satılan" token miktarını bildiğimizde, geri kutu değerinin farka dahil olduğunu kontrol ediyoruz.
Toplam eşleştirme durumunda mevcut emirdeki toplam token miktarını kullanıyoruz:

// toplam eşleştirme durumu (tüm token'lar satılır ve tam miktarda ERG alınır)
val totalMatching = (returnBox.value == selfTokenAmount * tokenPrice + fullSpread(selfTokenAmount))

source

Kısmi eşleştirme durumunda, "satılan" token miktarını artık emrinden biliyoruz (val soldTokenAmount = selfTokenAmount - residualOrderTokenAmount) ve farkın geri kutu değerine dahil olduğunu kontrol ediyoruz:

val returnBoxValueIsCorrect = returnBox.value == soldTokenErgValue + fullSpread(soldTokenAmount)

source

Share post

Ergo Altyapı DAO: Ergo Ekosisteminin Omurgasını Merkeziyetsizleştirmek

Ergo Altyapı DAO: Ergo Ekosisteminin Omurgasını Merkeziyetsizleştirmek

Ergo’nun misyonu her zaman merkeziyetsizlikte kök salmıştır, sadece konsensüs katmanında değil, tüm yığın boyunca.

Ergo Platform

13 Ağustos 2025

Mew Finance: Ergo Ekosistemi için Eğlenceli Bir DeFi Araç Seti

Mew Finance: Ergo Ekosistemi için Eğlenceli Bir DeFi Araç Seti

Mew Finance, Ergo Blockchain üzerinde merkeziyetsiz bir uygulama setidir.

Ergo Platform

12 Ağustos 2025

Lithos: Madenciliği On-Chain Havuzlarla Merkeziyetsizleştirmek

Lithos: Madenciliği On-Chain Havuzlarla Merkeziyetsizleştirmek

Lithos, madencilik havuzlarının nasıl çalıştığını köklü bir şekilde değiştirmek için tasarlanmış yeni bir protokoldür; havuzları o.

Ergo Platform

24 Temmuz 2025

Sigma 6.0: Daha Akıllı, Daha Esnek Ergo

Sigma 6.0: Daha Akıllı, Daha Esnek Ergo

Sigma 6.0 Ergo blockchain için önerilen büyük bir güncellemedir.

Ergo Platform

23 Temmuz 2025

Rosen'ın Geleceğini Şekillendirmek: Beş Ana Hazine Teklifi Üzerine Topluluk Çağrısı

Rosen'ın Geleceğini Şekillendirmek: Beş Ana Hazine Teklifi Üzerine Topluluk Çağrısı

Rosen kurucu ortağı Armeanio, Rosen Hazine'sine beş yeni teklif sunmuştur.

Ergo Platform

9 Temmuz 2025

Ergo'nun Genişletilmiş UTXO'su ve Yapay Ekonomik Zekanın Yükselişi

Ergo'nun Genişletilmiş UTXO'su ve Yapay Ekonomik Zekanın Yükselişi

Otonom Ekonomik Ajanlar için Pratik Bir Vizyon Otonom ekonomik ajanlar, Ergo blok zincirinde gerçek bir dijital ekonomide faydalı.

Ergo Platform

12 Mayıs 2025

ErgoHACK X: Ergo Blok Zincirinde Yapay Zeka

ErgoHACK X: Ergo Blok Zincirinde Yapay Zeka

Dağıtık İnovasyonun Onuncu Yılı yıl dönümü ErgoHACK'e katılın ve Ergo blok zincirindeki AI devriminin ön saflarında yer alın! Yara.

Ergo Platform

10 Nisan 2025