ERights Home smart-contracts / ertp 
No Previous Sibling No Next Sibling

Money in ERTP


Adapted from this message, in turn based on erights.updoc, which was analyzed in a long and informative thread on e-lang starting here.

# E sample
def Issuer := <type:net.ertp.Issuer>
def Purse := <type:net.ertp.Purse>
def Assay := <type:net.ertp.Assay>
 
def SealedBox := <type:org.erights.e.elib.sealing.SealedBox>
def makeBrand := <elib:sealing.Brand>

def makeMint(name :String, timer, makeSturdyRef) :near {
    def [assaySealer, assayUnsealer] := makeBrand(`$name assay`)
    def [purseSealer, purseUnsealer] := makeBrand(`$name purse`)
    def [incrSealer, incrUnsealer] := makeBrand(`$name incr`)
    def sturdyRefDuration := 1000 * 60 * 60 * 24 * 7
 
    def issuer implements Issuer {
        to __printOn(oo :TextWriter) :void { oo.print(`<$name bucks>`) }
 
        /** ERTP method */
        to vouchForAssay(item :Assay) :Assay {
            ^assayUnsealer.unseal(item.getSealed())
        }
 
        /** ERTP method */
        to vouchForPurse(item :Purse) :Purse {
            ^purseUnsealer.unseal(item.getSealed())
        }
 
        /** ERTP method */
        to sturdyVouchForAssay(item :Assay) :SturdyRef {
            ^makeSturdyRef(issuer.vouchForAssay(item), timer.now() + sturdyRefDuration)
        }
 
        /** ERTP method */
        to sturdyVouchForPurse(item :Purse) :SturdyRef {
            ^makeSturdyRef(issuer.vouchForPurse(item), timer.now() + sturdyRefDuration)
        }
 
        /** ERTP method */
        to makeEmptyPurse() :Purse {
            var balance :(int >= 0) := 0
            def incr(delta :(int >= -balance)) :void {
                balance += delta
            }
 
            ^def purse implements Purse {
                to __printOn(oo :TextWriter) :void { 
                    oo.print(`<holds $balance $name bucks>`)
                }
 
                /** ERTP method */
                to getIssuer()    :Issuer { ^issuer }
 
                /** implementation detail */
                to getSealed() :SealedBox { ^purseSealer.seal(purse) }
 
                /** implementation detail */
                to getIncr()   :SealedBox { ^incrSealer.seal(incr) }
 
                /** ERTP method */
                to getAssay()      :Assay { ^issuer.makeAssay(balance) }
 
                to getBalance()      :int { ^balance }
 
                /** ERTP method */
                to depositAll(src :Purse) :Assay {
                    def assay := issuer.vouchForAssay(src.getAssay())
                    assay.transfer(src, purse)
                    ^assay
        }   }   }
 
        to makeAssay(amount :(int >= 0)) :Assay {
            ^def assay implements Assay {
                to __printOn(oo :TextWriter) :void {
                    oo.print(`<assays $amount $name bucks>`)
                }
 
                /** ERTP method */
                to getIssuer() :Issuer { ^issuer }
 
                /** implementation detail */
                to getSealed() :SealedBox { ^assaySealer.seal(assay) }
 
                /** ERTP method */
                to transfer(src :Purse, dest :Purse) :void {
                    def srcIncr := incrUnsealer.unseal(src.getIncr())
                    def destIncr := incrUnsealer.unseal(dest.getIncr())
                    srcIncr(-amount)
                    destIncr(amount)
                }
 
                /** ERTP method */
                to compareTo(otherAssay :Assay) :near {
                    def vouchedOtherAssay := issuer.vouchForAssay(otherAssay)
                    ^amount.compareTo(vouchedOtherAssay.getAmount())
                }
 
                to getAmount() :int { ^amount }
    }   }   }
 
    ^def mint {
        to __printOn(oo :TextWriter) :void { oo.print(`<$name's Mint>`) }
 
        to getIssuer() :Issuer { ^issuer }
 
        to inflate(dest :Purse, amount :int) :void {
            def destIncr := incrUnsealer.unseal(dest.getIncr())
            destIncr(amount)
}   }   }

Here's an alternate style, using trademarking instead of sealing for vouching. Sealing is still used for rights amplification, as trademarking doesn't provide that. If we adopt this style for ERTP in general, then Issuers should provide the obvious getPurseGuard/0 and getAssayGuard/0 methods instead of the vouchForPurse/1 and vouchForAssay/1 methods shown below. Note that remote clients still cannot use these simply as guards, as, to them, they will be far references, accepting only eventual sends. However, perhaps if the rcvr guard template were clever enough, a remote client could successfully say :rcvr[FooPurse]. In any case, a remote client could always say

def vouchedPurse := FooPurse <- coerce(candidatePurse, null)

which isn't really less convenient than using the current vouch methods.

Altogether, I think the trademarking style is more natural and less accident prone.

# E sample
def Issuer := <type:net.ertp.Issuer>
def Purse := <type:net.ertp.Purse>
def Assay := <type:net.ertp.Assay>
 
def SealedBox := <type:org.erights.e.elib.sealing.SealedBox>
def makeBrand := <elib:sealing.Brand>

def makeMint(name :String, timer, makeSturdyRef) :near {
    interface MyAssay guards MyAssayStamp extends Assay {}
    interface MyPurse guards MyPurseStamp extends Purse {}
    def [incrSealer, incrUnsealer] := makeBrand(`$name incr`)
    def sturdyRefDuration := 1000 * 60 * 60 * 24 * 7
 
    def issuer implements Issuer {
        to __printOn(oo :TextWriter) :void { oo.print(`<$name bucks>`) }
 
        /** ERTP method */
        to vouchForAssay(item :MyAssay) :MyAssay {
            ^item
        }
 
        /** ERTP method */
        to vouchForPurse(item :MyPurse) :MyPurse {
            ^item
        }
 
        /** ERTP method */
        to sturdyVouchForAssay(item :MyAssay) :SturdyRef {
            ^makeSturdyRef(item, timer.now() + sturdyRefDuration)
        }
 
        /** ERTP method */
        to sturdyVouchForPurse(item :MyPurse) :SturdyRef {
            ^makeSturdyRef(item, timer.now() + sturdyRefDuration)
        }
 
        /** ERTP method */
        to makeEmptyPurse() :MyPurse {
            var balance :(int >= 0) := 0
            def incr(delta :(int >= -balance)) :void {
                balance += delta
            }
 
            ^def purse implements MyPurseStamp {
                to __printOn(oo :TextWriter) :void { 
                    oo.print(`<holds $balance $name bucks>`)
                }
 
                /** ERTP method */
                to getIssuer()  :Issuer { ^issuer }
 
                /** implementation detail */
                to getIncr() :SealedBox { ^incrSealer.seal(incr) }
 
                /** ERTP method */
                to getAssay()  :MyAssay { ^issuer.makeAssay(balance) }
 
                to getBalance()    :int { ^balance }
 
                /** ERTP method */
                to depositAll(src :MyPurse) :MyAssay {
                    def assay := src.getAssay()
                    assay.transfer(src, purse)
                    ^assay
        }   }   }
 
        to makeAssay(amount :(int >= 0)) :MyAssay {
            ^def assay implements MyAssayStamp {
                to __printOn(oo :TextWriter) :void {
                    oo.print(`<assays $amount $name bucks>`)
                }
 
                /** ERTP method */
                to getIssuer() :Issuer { ^issuer }
 
                /** ERTP method */
                to transfer(src :MyPurse, dest :MyPurse) :void {
                    def srcIncr := incrUnsealer.unseal(src.getIncr())
                    def destIncr := incrUnsealer.unseal(dest.getIncr())
                    srcIncr(-amount)
                    destIncr(amount)
                }
 
                /** ERTP method */
                to compareTo(otherAssay :MyAssay) :near {
                    ^amount.compareTo(otherAssay.getAmount())
                }
 
                to getAmount() :int { ^amount }
    }   }   }
 
    ^def mint {
        to __printOn(oo :TextWriter) :void { oo.print(`<$name's Mint>`) }
 
        to getIssuer() :Issuer { ^issuer }
 
        to inflate(dest :MyPurse, amount :int) :void {
            def destIncr := incrUnsealer.unseal(dest.getIncr())
            destIncr(amount)
}   }   }

Making money:

? def JoeMint := makeMint("Joe", timer, makeSturdyRef)
# value: <Joe's Mint>
 
? def JoeCurrency := JoeMint.getIssuer()
# value: <Joe bucks>
 
? def ThreeBucks := JoeCurrency.makeAssay(3)
# value: <assays 3 Joe bucks>
 
? def PurseA := JoeCurrency.makeEmptyPurse()
# value: <holds 0 Joe bucks>
 
? def PurseB := JoeCurrency.makeEmptyPurse()
# value: <holds 0 Joe bucks>
 
? ThreeBucks.transfer(PurseA, PurseB)
# problem: not in region
 
? [PurseA, PurseB]
# value: [<holds 0 Joe bucks>, <holds 0 Joe bucks>]
 
? JoeMint.inflate(PurseA, 100)
? JoeMint.inflate(PurseB, 200)
? [PurseA, PurseB]
# value: [<holds 100 Joe bucks>, <holds 200 Joe bucks>]
 
? ThreeBucks.transfer(PurseA, PurseB)
? [PurseA, PurseB]
# value: [<holds 97 Joe bucks>, <holds 203 Joe bucks>]
 
? def TwoBucks := JoeCurrency.makeAssay(2)
# value: <assays 2 Joe bucks>
 
? TwoBucks < ThreeBucks
# value: true
 
? PurseA.depositAll(PurseB)
# value: <assays 203 Joe bucks>
 
? [PurseA, PurseB]
# value: [<holds 300 Joe bucks>, <holds 0 Joe bucks>]

A generic erights changer:

# E sample
def makeCambio(inPurse :Purse, outPurse :Purse, in2out :near) :near {
    ^def cambio {
        to __printOn(oo :TextWriter) :void {
            oo.print(`<turning ${inPurse.getIssuer()} into ${outPurse.getIssuer()}>`)
        }
        to changeMoney(srcPurse :Purse) :Purse {
            def inAssay := inPurse.depositAll(srcPurse)
            def outAssay := in2out(inAssay)
            def destPurse := outPurse.getIssuer().makeEmptyPurse()
            try {
                outAssay.transfer(outPurse, destPurse)
            } catch ex {
                inAssay.transfer(inPurse, srcPurse)
                throw(ex)
            }
            ^destPurse
        }
    }
}

Changing money:

? def BettyMint := makeMint("Betty", timer, makeSturdyRef)
# value: <Betty's Mint>
 
? def BettyBucks := BettyMint.getIssuer()
# value: <Betty bucks>
 
? def BettyPurseA := BettyBucks.makeEmptyPurse()
# value: <holds 0 Betty bucks>
 
? BettyMint.inflate(BettyPurseA, 250)
? BettyPurseA
# value: <holds 250 Betty bucks>
 
? def in2out(inAssay :Assay) :Assay {
>     ^BettyBucks.makeAssay((0.5 * inAssay.getAmount()).round())
> }
# value: <in2out>
 
? def JBCambio := makeCambio(PurseA, BettyPurseA, in2out)
# value: <turning <Joe bucks> into <Betty bucks>>
 
? [PurseA, BettyPurseA]
# value: [<holds 300 Joe bucks>, <holds 250 Betty bucks>]
 
? JoeMint.inflate(PurseB, 23)
? def BettyPurseB := JBCambio.changeMoney(PurseB)
# value: <holds 12 Betty bucks>
 
? [PurseA, BettyPurseA]
# value: [<holds 323 Joe bucks>, <holds 238 Betty bucks>]

For more discussion...

 
Unless stated otherwise, all text on this page which is either unattributed or by Mark S. Miller is hereby placed in the public domain.
ERights Home smart-contracts / ertp 
No Previous Sibling No Next Sibling
Download    FAQ    API    Mail Archive    Donate

report bug (including invalid html)

Golden Key Campaign Blue Ribbon Campaign