Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions contracts/v1/ergonames_v1_collection.es
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
// ===== Compile Time Constants ($) ===== //
// $revealErgoTreeBytesHash: Coll[Byte]
// $revealProxyErgoTreeBytesHash: Coll[Byte]
// $ergonameCollectionSingletonTokenId: Coll[Byte]
// $ergonameCollectionTokenId: Coll[Byte]

// ===== Context Variables (_) ===== //
// None
Expand All @@ -37,8 +39,9 @@

// ===== Relevant Variables ===== //
val minerFeeErgoTreeHash: Coll[Byte] = fromBase16("e540cceffd3b8dd0f401193576cc413467039695969427df94454193dddfb375")
val ergonameCollectionTokenId: Coll[Byte] = SELF.tokens(1)._1
val ergonameCollectionTokenAmount: Long = SELF.tokens(1)._2
val ergonameCollectionTokenAmount = SELF.tokens.fold(0L, { (sum: Long, t: (Coll[Byte], Long)) =>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could just use filter?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or is it possible for same token to be in different sections of the tokens collection?

if (t._1 == $ergonameCollectionTokenId) sum + t._2 else sum
})
val isRefund: Boolean = (OUTPUTS.size == 3)

if (!isRefund) {
Expand All @@ -56,11 +59,27 @@

val validSelfRecreation: Boolean = {

val validSingletonTransfer: Boolean = {

ergonameCollectionBoxOut.tokens.exists({ (t: (Coll[Byte], Long)) =>
t._1 == $ergonameCollectionSingletonTokenId
})

}

val validCollectionTokensTransfer: Boolean = {

ergonameCollectionBoxOut.tokens.exists({ (t: (Coll[Byte], Long)) =>
t == ($ergonameCollectionTokenId, ergonameCollectionTokenAmount - 1L)
})

}

allOf(Coll(
(ergonameCollectionBoxOut.value == SELF.value),
(ergonameCollectionBoxOut.propositionBytes == SELF.propositionBytes),
(ergonameCollectionBoxOut.tokens(0) == SELF.tokens(0)),
(ergonameCollectionBoxOut.tokens(1) == (ergonameCollectionTokenId, ergonameCollectionTokenAmount - 1L))
validSingletonTransfer,
validCollectionTokensTransfer
))

}
Expand All @@ -71,8 +90,8 @@

allOf(Coll(
(blake2b256(revealBoxOut.propositionBytes) == $revealErgoTreeBytesHash),
(revealBoxOut.tokens(0) == (ergonameCollectionTokenId, 1L)),
(revealBoxOut.R7[Coll[Byte]].get == ergonameCollectionTokenId), // For artwork standard v2 (EIP-24).
(revealBoxOut.tokens(0) == ($ergonameCollectionTokenId, 1L)),
(revealBoxOut.R7[Coll[Byte]].get == $ergonameCollectionTokenId), // For artwork standard v2 (EIP-24).
))

}
Expand Down Expand Up @@ -105,7 +124,7 @@
(ergonameCollectionBoxOut.value == SELF.value),
(ergonameCollectionBoxOut.propositionBytes == SELF.propositionBytes),
(ergonameCollectionBoxOut.tokens(0) == SELF.tokens(0)),
(ergonameCollectionBoxOut.tokens(1) == (ergonameCollectionTokenId, ergonameCollectionTokenAmount + 1L))
(ergonameCollectionBoxOut.tokens(1) == ($ergonameCollectionTokenId, ergonameCollectionTokenAmount + 1L))
))

}
Expand All @@ -114,7 +133,7 @@

allOf(Coll(
(blake2b256(revealBoxIn.propositionBytes) == $revealErgoTreeBytesHash),
(revealBoxIn.tokens(0) == (ergonameCollectionTokenId, 1L))
(revealBoxIn.tokens(0) == ($ergonameCollectionTokenId, 1L))
))

}
Expand Down
2 changes: 1 addition & 1 deletion contracts/v1/ergonames_v1_commit.es
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@

}

sigmaProp(validRefundTx)
sigmaProp(validRefundTx) && userPKSigmaProp

}

Expand Down
26 changes: 23 additions & 3 deletions contracts/v1/ergonames_v1_registry.es
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@

val validErgoNameInsertion: Boolean = {

val newRegistry: AvlTree = previousRegistry.insert(Coll((_ergoNameHash, ergoNameTokenId)), _insertionProof).get
val newRegistry: AvlTree = previousRegistry.insert(Coll((_ergoNameHash, ergoNameTokenId)), _insertionProof).get

allOf(Coll(
(registryBoxOut.R4[AvlTree].get.digest == newRegistry.digest),
Expand All @@ -174,7 +174,9 @@
allOf(Coll(
(registryBoxOut.value == SELF.value),
(registryBoxOut.propositionBytes == SELF.propositionBytes),
(registryBoxOut.tokens(0) == SELF.tokens(0))
(registryBoxOut.tokens(0) == SELF.tokens(0)),
(registryBoxOut.R6[(Int, Int)].get == ageThreshold),
(registryBoxOut.R7[Coll[BigInt]].get == priceMap)
))

}
Expand Down Expand Up @@ -213,7 +215,25 @@

if (isDefaultPaymentMode) {

val validFeePayment: Boolean = (ergoNameFeeBoxOut.value.toBigInt >= equivalentNanoErg)
val validFeePayment: Boolean = {

val amount: BigInt = revealBoxIn.value.toBigInt // Reveal box contains target price when reveal was created + 5% slippage.
val target: BigInt = (amount * 100.toBigInt) / 105.toBigInt // 5% slippage
val slippage: BigInt = (amount - target)
val difference: BigInt = (equivalentNanoErg - target)
val isWithin: Boolean = (difference >= 0 && difference < slippage) || (difference <= 0 && difference > -1.toBigInt * slippage)

val validFee: Boolean = (ergoNameFeeBoxOut.value.toBigInt >= equivalentNanoErg)
val validChange: Boolean = (ergoNameIssuanceBoxOut.value.toBigInt >= (amount - equivalentNanoErg))

allOf(Coll(
isWithin,
validFee,
validChange
))

}

val validFeeAddress: Boolean = (blake2b256(ergoNameFeeBoxOut.propositionBytes) == $ergoNameFeeContractBytesHash)

allOf(Coll(
Expand Down
11 changes: 8 additions & 3 deletions contracts/v1/ergonames_v1_reveal.es
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@

val validRevealBoxInValue: Boolean = {

val validErgValue: Boolean = (SELF.value == subNameRegistryAmount + ergoNameIssuanceAmount + ergoNameFeeErgAmount + minerFeeAmount + txOperatorFeeAmount)
val validErgValue: Boolean = (SELF.value == subNameRegistryAmount + ergoNameIssuanceAmount + ergoNameFeeErgAmount + minerFeeAmount)
val validTokenValue: Boolean = {

if (isPayingWithToken) {
Expand Down Expand Up @@ -202,6 +202,8 @@
validCommitBoxIn,
validSubNameRegistryAmount,
validErgonameIssuanceAmount,
validErgoNameMint,
validCollectionTokenBurn,
validMinerFeeBoxOut,
validTxOperatorFeeBoxOut,
(OUTPUTS.size == 6)
Expand Down Expand Up @@ -229,10 +231,12 @@
val validUser: Boolean = {

val propAndBox: (SigmaProp, Box) = (userPKSigmaProp, userPKBoxOut)
val validPaymentTokenTransfer: Boolean = if isPayingWithToken (userPKBoxOut.tokens(0) == SELF.tokens(1)) else (userPKBoxOut.tokens.size == 0)

allOf(Coll(
(userPKBoxOut.value == SELF.value - minerFee),
isSigmaPropEqualToBoxProp(propAndBox)
isSigmaPropEqualToBoxProp(propAndBox),
validPaymentTokenTransfer
))

}
Expand All @@ -241,7 +245,8 @@

allOf(Coll(
(minerFeeBoxOut.value == minerFee),
(blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash)
(blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash),
(minerFeeBoxOut.tokens.size == 0)
))

}
Expand Down
147 changes: 113 additions & 34 deletions contracts/v1/ergonames_v1_reveal_proxy.es
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@
// R4: Coll[Byte] RevealBoxHash
// R5: Long MinerFee
// R6: Long TxOperatorFee
// R7: GroupElement UserPKGroupElement

// ===== Relevant Transactions ===== //
// 1. Reveal
// Inputs: ErgoNameCollection, RevealProxy
// Data Inputs: None
// Outputs: ErgoNameCollection, Reveal, MinerFee, TxOperatorFee
// Context Variables: None
// 2. Refund Reveal Proxy
// Inputs: RevealProxy
// DataInputs: None
// Outputs: UserPKBoxOut, MinerFee
// Context Variables: None

// ===== Compile Time Constants ($) ===== //
// $ergoNameCollectionSingletonTokenId: Coll[Byte]
Expand All @@ -28,62 +34,135 @@
// None

// ===== User Defined Functions ===== //
// None
// def isSigmaPropEqualToBoxProp: ((SigmaProp, Box) => Boolean)

def isSigmaPropEqualToBoxProp(propAndBox: (SigmaProp, Box)): Boolean = {

val prop: SigmaProp = propAndBox._1
val box: Box = propAndBox._2

val propBytes: Coll[Byte] = prop.propBytes
val treeBytes: Coll[Byte] = box.propositionBytes

if (treeBytes(0) == 0) {

(treeBytes == propBytes)

} else {

// offset = 1 + <number of VLQ encoded bytes to store propositionBytes.size>
val offset = if (treeBytes.size > 127) 3 else 2
(propBytes.slice(1, propBytes.size) == treeBytes.slice(offset, treeBytes.size))

}

}

// ===== Relevant Variables ===== //
val minerFeeErgoTreeHash: Coll[Byte] = fromBase16("e540cceffd3b8dd0f401193576cc413467039695969427df94454193dddfb375")
val revealBoxHash: Coll[Byte] = SELF.R4[Coll[Byte]].get
val minerFee: Long = SELF.R5[Long].get
val txOperatorFee: Long = SELF.R6[Long].get
val userPKGroupElement: GroupElement = SELF.R7[GroupElement].get
val userPKSigmaProp: SigmaProp = proveDlog(userPKGroupElement)
val isPayingWithToken: Boolean = (SELF.tokens.size == 1)
val isRefund: Boolean = (OUTPUTS.size == 2)

val validRevealTx: Boolean = {
if (!isRefund) {

// Inputs
val ergonameCollectionBoxIn: Box = INPUTS(0)
val validRevealTx: Boolean = {

// Outputs
val ergonameCollectionBoxOut: Box = OUTPUTS(0)
val revealBoxOut: Box = OUTPUTS(1)
val minerFeeBoxOut: Box = OUTPUTS(2)
val txOperatorFeeBoxOut: Box = OUTPUTS(3)
// Inputs
val ergonameCollectionBoxIn: Box = INPUTS(0)

val validCollection: Boolean = (ergonameCollectionBoxIn.tokens(0)._1 == $ergoNameCollectionSingletonTokenId)
// Outputs
val ergonameCollectionBoxOut: Box = OUTPUTS(0)
val revealBoxOut: Box = OUTPUTS(1)
val minerFeeBoxOut: Box = OUTPUTS(2)
val txOperatorFeeBoxOut: Box = OUTPUTS(3)

val validReveal: Boolean = {
val validCollection: Boolean = {

val revealHash: Coll[Byte] = blake2b256(revealBoxOut.bytesWithoutRef) // Bytes of box contents without transaction id and output index.
val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(0) == SELF.tokens(0)) else true
ergonameCollectionBoxIn.tokens.exists({ (t: (Coll[Byte], Long)) =>
t._1 == $ergoNameCollectionSingletonTokenId
})

allOf(Coll(
(revealBoxOut.value == SELF.value - minerFee - txOperatorFee),
validPaymentToken,
(revealHash == revealBoxHash)
))
}

}
val validReveal: Boolean = {

val revealHash: Coll[Byte] = blake2b256(revealBoxOut.bytesWithoutRef) // Bytes of box contents without transaction id and output index.
val validPaymentToken: Boolean = if (isPayingWithToken) (revealBoxOut.tokens(1) == SELF.tokens(0)) else true

allOf(Coll(
(revealBoxOut.value == SELF.value - minerFee - txOperatorFee),
validPaymentToken,
(revealHash == revealBoxHash)
))

}

val validMinerFee: Boolean = {
val validMinerFee: Boolean = {

allOf(Coll(
(minerFeeBoxOut.value == minerFee),
(blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash)
))

}

val validTxOperatorFee: Boolean = (txOperatorFeeBoxOut.value == txOperatorFee)

allOf(Coll(
validCollection,
validReveal,
validMinerFee,
validTxOperatorFee,
(OUTPUTS.size == 4)
))

}

sigmaProp(validRevealTx)

} else {

val validRefundTx: Boolean = {

// Outputs
val userPKBoxOut: Box = OUTPUTS(0)
val minerFeeBoxOut: Box = OUTPUTS(1)

val validUser: Boolean = {

val propAndBox: (SigmaProp, Box) = (userPKSigmaProp, userPKBoxOut)

allOf(Coll(
(userPKBoxOut.value == SELF.value - minerFee),
isSigmaPropEqualToBoxProp(propAndBox),
(userPKBoxOut.tokens == SELF.tokens)
))

}

val validMinerFee: Boolean = {

allOf(Coll(
(minerFeeBoxOut.value == minerFee),
(blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash)
))

}

allOf(Coll(
(minerFeeBoxOut.value == minerFee),
(blake2b256(minerFeeBoxOut.propositionBytes) == minerFeeErgoTreeHash)
validUser,
validMinerFee
))

}

val validTxOperatorFee: Boolean = (txOperatorFeeBoxOut.value == txOperatorFee)

allOf(Coll(
validCollection,
validReveal,
validMinerFee,
validTxOperatorFee,
(OUTPUTS.size == 4)
))
sigmaProp(validRefundTx) && userPKSigmaProp

}

sigmaProp(validRevealTx)

}