import "util.scrypt"; import "data.scrypt"; /** * A toy token example between two holders */ contract Token { public function addNewMember( PubKey sender, Sig senderSig, bytes txPreimage, int amount, PubKey newUserPk) { // this ensures the preimage is for the current tx require(Tx.checkPreimage(txPreimage)); bytes lockingScript = Util.scriptCode(txPreimage); int scriptLen = length(lockingScript); int qty = unpack(lockingScript[scriptLen - Util.DataLen : ]); int dataBlockLen = Util.DataLen + qty *(Util.PubKeyLen + Util.DataLen); int updatedDataLen = Util.DataLen + (qty + 1) *(Util.PubKeyLen + Util.DataLen); int codeEnd = scriptLen - dataBlockLen - Data.getShift(dataBlockLen); bytes opCode = Data.convertLen(updatedDataLen); bytes preUpdatedScript = lockingScript[ : codeEnd] + opCode; bytes updatedLockingScript = preUpdatedScript + lockingScript[scriptLen - dataBlockLen : scriptLen - Util.DataLen] + newUserPk + num2bin(0, Util.DataLen) + num2bin(qty + 1, Util.DataLen); Sha256 hashOutputs = hash256(num2bin(amount, Util.OutputValueLen) + Util.writeVarint(updatedLockingScript)); require(hashOutputs == Util.hashOutputs(txPreimage)); } public function transfer( // Transaction parameters PubKey sender, Sig senderSig, bytes txPreimage, int amount, // Function parameters int senderIndex, int receiverIndex, int value /* amount to be transferred */ ) { // this ensures the preimage is for the current tx require(Tx.checkPreimage(txPreimage)); // authorize require(checkSig(senderSig, sender)); // read previous locking script bytes lockingScript = Util.scriptCode(txPreimage); int scriptLen = length(lockingScript); int qty = unpack(lockingScript[scriptLen - Util.DataLen : ]); int pkStart = scriptLen - qty *(Util.PubKeyLen + Util.DataLen) - Util.DataLen; // check that index < accoutns qty require(senderIndex < qty); require(receiverIndex < qty); PubKey pkSender = this.getPubKeyByIndex(pkStart, lockingScript, senderIndex); int balanceSender = this.getBalanceByIndex(pkStart, lockingScript, senderIndex); PubKey pkReceiver = this.getPubKeyByIndex(pkStart, lockingScript, receiverIndex); int balanceReceiver = this.getBalanceByIndex(pkStart, lockingScript, receiverIndex); // only between two holders require(sender == pkSender); // transfer require(balanceSender >= value); balanceSender = balanceSender - value; balanceReceiver = balanceReceiver + value; // write new locking script bytes updatedLockingScript = this.updateState(pkStart, lockingScript, senderIndex, balanceSender); updatedLockingScript = this.updateState(pkStart, updatedLockingScript, receiverIndex, balanceReceiver); Sha256 hashOutputs = hash256(num2bin(amount, Util.OutputValueLen) + Util.writeVarint(updatedLockingScript)); require(hashOutputs == Util.hashOutputs(txPreimage)); } function getPubKeyByIndex(int pkStart, bytes lockingScript, int index) returns(PubKey) { int offset = pkStart + index *(Util.PubKeyLen + Util.DataLen); PubKey pkSender = PubKey(lockingScript[offset : offset + Util.PubKeyLen]); return pkSender; } function getBalanceByIndex(int pkStart, bytes lockingScript, int index) returns(int) { int offset = pkStart + index *(Util.PubKeyLen + Util.DataLen) + Util.PubKeyLen; int balance = unpack(lockingScript[offset : offset + Util.DataLen]); return balance; } function updateState(int pkStart, bytes lockingScript, int index, int newBalance) returns(bytes) { int offset = pkStart + index *(Util.PubKeyLen + Util.DataLen) + Util.PubKeyLen; bytes updatedState = lockingScript[ : offset] + num2bin(newBalance, Util.DataLen) + lockingScript[offset + Util.DataLen : ]; return updatedState; } }