new NonNegativeNumber in { contract NonNegativeNumber(@init, return) = { new this, valueStore in { contract this(@"add", @x, success) = { if (x >= 0) { for(@v <- valueStore){ if (v + x > v) { valueStore!(v + x) | success!(true) } else { //overflow valueStore!(v) | success!(false) } } } else { success!(false) } } | contract this(@"sub", @x, success) = { if (x >= 0) { for(@v <- valueStore) { if (x <= v) { valueStore!(v - x) | success!(true) } else { valueStore!(v) | success!(false) } } } else { success!(false) } } | contract this(@"value", return) = { for(@v <- valueStore) { valueStore!(v) | return!(v) } } | return!(bundle+{*this}) | if (init >= 0) { valueStore!(init) } else { valueStore!(0) } //Initial balance is zero if given is negative} } } | new MakeMint in { contract MakeMint(return) = { new thisMint, internalMakePurse, decr in { contract thisMint(@"makePurse", @init, return) = { new balanceCh in { // initialize NonNegativeNumber, living on the name balance. NonNegativeNumber!(init, *balanceCh) | for(@balance <- balanceCh) { internalMakePurse!(balance, *return) } } } | // since balance is a NonNegativeNumber, it exposes all the methods of NN contract internalMakePurse(balance, return) = { //balance must be a name that NonNegativeNumber contract is listening on new thisPurse in { contract thisPurse(@=*decr, @amount, success) = { balance!("sub", amount, *success) } | contract thisPurse(@"getBalance", return) = { balance!("value", *return) } | contract thisPurse(@"sprout", return) = { thisMint!("makePurse", 0, *return) } | contract thisPurse(@"split", @amount, return) = { new destPurseCh, successCh in { thisPurse!("sprout", *destPurseCh) | for(@destPurse <- destPurseCh) { @destPurse!("deposit", amount, *thisPurse, *successCh) | for(@success <- successCh) { if (success) { return!([destPurse]) } else { return!([]) } } } } } | contract thisPurse(@"deposit", @amount, @src, success) = { new result in { @src!(*decr, amount, *result) | //call src decr function. for(@decrSuccess <- result) { if (decrSuccess) { balance!("add", amount, *success) // add transferred amount to this purse } else { success!(false) } } } } | return!(bundle+{*thisPurse}) } } | return!(bundle+{*thisMint}) } } | // Integer overflow bug new retCh, stdout(`rho:io:stdout`) in { MakeMint!(*retCh) | for(myMint <- retCh) { // we initialize our purses with the maximum amount of tokens myMint!("makePurse", 9223372036854775807, *retCh) | for(myInitialPurse <- retCh) { myMint!("makePurse", 9223372036854775807, *retCh) | for(mySecondPurse <- retCh) { myInitialPurse!("deposit", 9223372036854775807, *mySecondPurse, *retCh) | for(myRet <- retCh) { stdout!(["Return from the method add - Expected false (meaning overflow), got: ", *myRet]) | myInitialPurse!("getBalance", *retCh) | for(balance <- retCh) { stdout!(["Balance from first purse - Expected 9223372036854775807 (initial balance), got: ", *balance]) | mySecondPurse!("getBalance", *retCh) | for(balance <- retCh) { stdout!(["Balance from second purse - expected 0 (9223372036854775807 tokens destroyed), got: ",*balance]) } } } } } } } } }