Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile DEX (with partial filling) contracts #17

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ trait Compilation extends Parsing with Liftables {

private def findContractDefDef(select: Select): String = {
import scala.meta._
// c.warn(s"getting file path for $select")
val path = select.symbol.pos.source.file.file.toPath
val source = new String(java.nio.file.Files.readAllBytes(path), "UTF-8")
val input = Input.VirtualFile(path.toString, source)
Expand Down Expand Up @@ -148,12 +149,15 @@ trait Compilation extends Parsing with Liftables {
case BlockValue(IndexedSeq(), body) => body
case v => v
}
c.info(s"unwrapped BlockValue: $unwrappedBlockValue")
// c.untypecheck {
q"""
ErgoContract(
$assembledContractBodyScalaTree,
$unwrappedBlockValue
)
"""
// }
}

def compileVerified[A, B](func: Expr[A => B]) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import sigmastate.utxo.{
}

import scala.reflect.macros.whitebox
import sigmastate.ArithOp

trait Liftables extends Types {
val c: whitebox.Context
Expand Down Expand Up @@ -102,10 +103,11 @@ trait Liftables extends Types {
case IntConstant(v) => q"$svpack.IntConstant($v)"
case ast: SigmaTransformer[_, _] => sigmaTransLiftable(ast)
case ast: Transformer[_, _] => transLiftable(ast)
case ast: ArithOp[_] => arithOpLiftable(ast)
// case ast: Relation[_, _] => relationLiftable(ast.asInstanceOf[Relation[SType, SType]])
case BlockValue(stats, res) =>
// TODO: WTF with list?
q"$svpack.BlockValue(${stats.toList}.toIndexedSeq, $res)"
q"$svpack.BlockValue(${stats.toList}.toIndexedSeq, $res).asInstanceOf[$svpack.Value[${res.tpe}]]"
case ast: Value[_] if ast.tpe == SSigmaProp => sigmaPropLiftable(ast.asSigmaProp)
// case ast: NotReadyValue[_] if ast.tpe == SBoolean =>
// notReadyBoolValueLiftable(ast.asInstanceOf[NotReadyValueBoolean])
Expand Down Expand Up @@ -170,6 +172,12 @@ trait Liftables extends Types {
// case v @ _ => c.fail(s"no Liftable for Coll: $v")
// }

implicit def arithOpLiftable[T <: SType]: Liftable[ArithOp[T]] = Liftable[ArithOp[T]] {
case ArithOp(l, r, opCode) =>
q"$spack.ArithOp($l, $r, $opCode.asInstanceOf[sigmastate.serialization.OpCodes.OpCode])"
case v @ _ => c.fail(s"no Liftable for ArithOp: $v")
}

implicit def transLiftable[IV <: SType, OV <: SType]: Liftable[Transformer[IV, OV]] =
Liftable[Transformer[IV, OV]] {
case SizeOf(v) => q"$supack.SizeOf($v)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ import special.sigma.SigmaContract

import scala.collection.mutable
import scala.reflect.api.Trees
import sigmastate.serialization.OpCodes
import sigmastate.ArithOp
import sigmastate.Values.LongConstant

trait Parsing {
this: Compilation =>
Expand Down Expand Up @@ -81,10 +84,12 @@ trait Parsing {

val astParser: Parser[SValue] = Parser[SValue] {
case q"$i: $typ" => astParser(i)
case `constParser`(v) => v
case `contextApiParser`(v) => v
case `contractApiParser`(v) => v
case `sigmaTransParser`(v) => v
case `relationParser`(v) => v
case `twoArgOpParser`(v) => v
case `collApiParser`(v) => v
case `boxApiParser`(v) => v
case `sigmaPropApiParser`(v) => v
Expand All @@ -98,7 +103,7 @@ trait Parsing {
// case t: Tree => ScalaTree(t)
}

// TODO: wtf?
// TODO: remove?
var callArgToIdentMap: Map[String, String] = Map[String, String]()
var valDefsMap: mutable.Map[String, (Int, SType)] = mutable.Map[String, (Int, SType)]()

Expand Down Expand Up @@ -137,14 +142,16 @@ trait Parsing {
val capturedValParser: Parser[ScalaTree] = Parser[ScalaTree] {
// case t: Select if is[SigmaContractDsl](t.qualifier) => c.fail(s"add parsing of: $t")
// case t: Select if is[SigmaContextDsl](t.qualifier) => c.fail(s"add parsing of: $t")
case i @ Ident(TermName(name)) if callArgToIdentMap.get(cname(name)).nonEmpty =>
val newName = callArgToIdentMap(cname(name))
val v = Ident(TermName(newName))
case i @ Ident(TermName(name)) =>
val newName =
if (callArgToIdentMap.get(cname(name)).nonEmpty) callArgToIdentMap(cname(name))
else name
val v = Ident(TermName(newName))
c.info(s"Capturing converted($name -> $newName}): ${showRaw(v)}")
ScalaTree(v, tpeToSType(i.tpe))
case t: Tree =>
c.info(s"Capturing: ${showRaw(t)}")
ScalaTree(t, tpeToSType(t.tpe))
c.fail(s"Capturing non-Ident node: ${showRaw(t)}")
// ScalaTree(t, tpeToSType(t.tpe))
}

val sigmaTransParser: Parser[SigmaTransformer[_, _]] = Parser[SigmaTransformer[_, _]] {
Expand Down Expand Up @@ -189,11 +196,27 @@ trait Parsing {
case Apply(Select(astParser(l), TermName("$less")), Seq(astParser(r))) => LT(l, r)
}

val twoArgOpParser: Parser[SValue] = Parser[SValue] {
case Apply(Select(astParser(l), TermName("$times")), Seq(astParser(r))) =>
ArithOp(l, r, OpCodes.MultiplyCode)
case Apply(Select(astParser(l), TermName("$plus")), Seq(astParser(r))) =>
ArithOp(l, r, OpCodes.PlusCode)
case Apply(Select(astParser(l), TermName("$minus")), Seq(astParser(r))) =>
ArithOp(l, r, OpCodes.MinusCode)
}

val tupleParser: Parser[SValue] = Parser[SValue] {
case q"$s._1" if isTypeTuple(s.tpe) => SelectField(astParser(s).asTuple, 1)
case q"$s._2" if isTypeTuple(s.tpe) => SelectField(astParser(s).asTuple, 2)
}

val constParser: Parser[SValue] = Parser[SValue] {
case Literal(ct @ c.universe.Constant(i)) if ct.tpe == IntTpe =>
IntConstant(i.asInstanceOf[Int])
case Literal(ct @ c.universe.Constant(i)) if ct.tpe == LongTpe =>
LongConstant(i.asInstanceOf[Long])
}

val intValueParser: Parser[IntValue] = Parser[IntValue] {
case Literal(ct @ c.universe.Constant(i)) if ct.tpe == IntTpe =>
IntConstant(i.asInstanceOf[Int])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ trait ErgoScriptCompilationDsl {
implicit private var IR: CompiletimeIRContext = new CompiletimeIRContext()

private def compile(env: ScriptEnv, ergoScript: String): ErgoContract = {
IR.resetContext()
val liftedEnv = env.mapValues { v =>
val tV = Evaluation.rtypeOf(v).get
val elemTpe = Evaluation.rtypeToSType(tV)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.ergoplatform.compiler.test.contracts.dex

import org.ergoplatform.compiler.{ErgoContract, ErgoScalaCompiler}
import special.collection.Coll
import special.sigma.{Context, SigmaContract, SigmaDslBuilder, SigmaProp}

sealed abstract class DexPartialFilling extends SigmaContract {

override def builder: SigmaDslBuilder = ???

def buyer(
ctx: Context,
buyerPk: SigmaProp,
tokenId: Coll[Byte],
tokenPrice: Long,
dexFeePerToken: Long
): SigmaProp = {
import ctx._
buyerPk || {

val returnBox = OUTPUTS(0)
// val returnBox = OUTPUTS.filter { b =>
// b.R4[Coll[Byte]].isDefined && b
// .R4[Coll[Byte]]
// .get == SELF.id && b.propositionBytes == buyerPk.propBytes
// }(0)

val returnTokenData = returnBox.tokens(0)
val returnTokenId = returnTokenData._1
val returnTokenAmount = returnTokenData._2
val maxReturnTokenErgValue = returnTokenAmount * tokenPrice
val totalReturnErgValue = maxReturnTokenErgValue + returnBox.value
val expectedDexFee = dexFeePerToken * returnTokenAmount

val foundNewOrderBoxes = OUTPUTS
// val foundNewOrderBoxes = OUTPUTS.filter { b =>
// b.R4[Coll[Byte]].isDefined && b
// .R4[Coll[Byte]]
// .get == SELF.id && b.propositionBytes == SELF.propositionBytes
// }

val coinsSecured = (SELF.value - expectedDexFee) == maxReturnTokenErgValue || {
foundNewOrderBoxes.size == 1 && foundNewOrderBoxes(0).value >= (SELF.value - totalReturnErgValue - expectedDexFee)
}

val tokenIdIsCorrect = returnTokenId == tokenId

tokenIdIsCorrect && returnTokenAmount >= 1 && coinsSecured
}
}

// def seller(ctx: Context, ergAmount: Long, pkB: SigmaProp): SigmaProp = {
// import ctx._
// pkB || (
// OUTPUTS.size > 1 &&
// OUTPUTS(1).R4[Coll[Byte]].isDefined
// ) && {
// val knownBoxId = OUTPUTS(1).R4[Coll[Byte]].get == SELF.id
// OUTPUTS(1).value >= ergAmount &&
// knownBoxId &&
// OUTPUTS(1).propositionBytes == pkB.propBytes
// }
// }
}

object DexPartialFillingCompilation extends DexPartialFilling {

def buyerContractInstance(
buyerPk: SigmaProp,
tokenId: Coll[Byte],
tokenPrice: Long,
dexFeePerToken: Long
): ErgoContract =
ErgoScalaCompiler.contract { context: Context =>
buyer(context, buyerPk, tokenId, tokenPrice, dexFeePerToken)
}

// def sellerContractInstance(ergAmount: Long, pkB: SigmaProp): ErgoContract =
// ErgoScalaCompiler.contract { context: Context =>
// seller(context, ergAmount, pkB)
// }

}