diff --git a/develop/Asset_&_Method_Definitions.go b/develop/Asset_&_Method_Definitions.go new file mode 100644 index 0000000..1ecbb72 --- /dev/null +++ b/develop/Asset_&_Method_Definitions.go @@ -0,0 +1,186 @@ +package main + +import ( + "fmt" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + + +// ============================================================================================================================ +// Asset Definitions - The ledger will store wallets and owners +// ============================================================================================================================ + +// ----- Wallets ----- // +type Wallet struct { + ObjectType string `json:"docType"` + Id string `json:"id"` + Balance int `json:"balance"` + Owner OwnerRelation `json:"owner"` +} + +// ----- Beneficiaries ----- // +type Beneficiary struct { + ObjectType string `json:"docType"` + Id string `json:"id"` + IdBenef string `json:"idbenef` + NameBenef string `json:"namebenef"` + FirstnameBenef string `json:"firstnamebenef"` + Owner OwnerRelation `json:"owner"` +} + +// ----- Owners ----- // +type Owner struct { + ObjectType string `json:"docType"` + Id string `json:"id"` + Name string `json:"name"` + Firstname string `json:"firstname"` + Mail string `json:"mail"` + Address string `json:"address"` + City string `json:"city"` + Postalcode int `json:"postal"` + Password string `json:"password"` + Association string `json:"association"` + //disabled owners will not be visible to the application + Enabled bool `json:"enabled"` +} + +type OwnerRelation struct { + Id string `json:"id"` + Name string `json:"name"` + Firstname string `json:"firstname"` +} + + +// ============================================================================================================================ +// Main +// ============================================================================================================================ +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode - %s", err) + } +} + + +// ============================================================================================================================ +// Init - initialize the chaincode +// +// Returns - shim.Success or error +// ============================================================================================================================ +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("Wallet Is Starting Up") + funcName, args := stub.GetFunctionAndParameters() + var number int + var err error + txId := stub.GetTxID() + + fmt.Println("Init() is running") + fmt.Println("Transaction ID:", txId) + fmt.Println(" GetFunctionAndParameters() function:", funcName) + fmt.Println(" GetFunctionAndParameters() args count:", len(args)) + fmt.Println(" GetFunctionAndParameters() args found:", args) + + // expecting 1 arg for instantiate or upgrade + if len(args) == 1 { + fmt.Println(" GetFunctionAndParameters() arg[0] length", len(args[0])) + + // expecting arg[0] to be length 0 for upgrade + if len(args[0]) == 0 { + fmt.Println("args[0] is empty...") + } else { + fmt.Println(" Great news everyone, args[0] is not empty") + + // convert numeric string to integer + number, err = strconv.Atoi(args[0]) + if err != nil { + return shim.Error("Expecting a numeric string argument to Init() for instantiate") + } + + // this is a very simple test. let's write to the ledger and error out on any errors + // it's handy to read this right away to verify network is healthy if it wrote the correct value + err = stub.PutState("selftest", []byte(strconv.Itoa(number))) + if err != nil { + return shim.Error(err.Error()) //self-test fail + } + } + } + + // showing the alternative argument shim function + alt := stub.GetStringArgs() + fmt.Println(" GetStringArgs() args count:", len(alt)) + fmt.Println(" GetStringArgs() args found:", alt) + + // store compatible wallet application version + err = stub.PutState("wallets_ui", []byte("4.0.1")) + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("Ready for action") //self-test pass + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Invoke - Our entry point for Invocations +// ============================================================================================================================ +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + function, args := stub.GetFunctionAndParameters() + fmt.Println(" ") + fmt.Println("starting invoke, for - " + function) + + // Handle different functions + if function == "init" { //initialize the chaincode state, used as reset + return t.Init(stub) + } else if function == "read" { //generic read ledger + return read(stub, args) + } else if function == "write" { //generic writes to ledger + return write(stub, args) + } else if function == "delete_wallet" { //deletes a wallet from state + return delete_wallet(stub, args) + } else if function == "delete_owner" { //deletes an owner from state + return delete_owner(stub, args) + } else if function == "delete_beneficiary" { //deletes a beneficiary from state + return delete_beneficiary(stub, args) + } else if function == "init_wallet" { //create a new wallet + return init_wallet(stub, args) + } else if function == "init_owner"{ //create a new wallet owner + return init_owner(stub, args) + } else if function == "init_beneficiary" { //create a new beneficiary + return init_beneficiary(stub, args) + } else if function == "set_owner" { //change owner of a wallet + return set_owner(stub, args) + } else if function == "set_beneficiary" { //change owner of a wallet + return set_beneficiary(stub, args) + } else if function == "disable_owner"{ //disable a wallet owner from appearing on the UI + return disable_owner(stub, args) + } else if function == "transfer"{ //transfer X Units From a User to an other + return transfer(stub, args) + } else if function == "get_wallet"{ //get wallets + return get_wallet(stub, args) + } else if function == "get_owner"{ //get owners + return get_owner(stub, args) + } else if function == "get_beneficiary"{ //get beneficiaries + return get_beneficiary(stub, args) + } else if function == "get_transaction"{ //get transactions + return get_transaction(stub, args) + + // error out + fmt.Println("Received unknown invoke function name - " + function) + return shim.Error("Received unknown invoke function name - '" + function + "'") +} + + +// ============================================================================================================================ +// Query - legacy function +// ============================================================================================================================ +func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) pb.Response { + return shim.Error("Unknown supported call - Query()") +} \ No newline at end of file diff --git a/develop/Get_Class.go b/develop/Get_Class.go new file mode 100644 index 0000000..382c37e --- /dev/null +++ b/develop/Get_Class.go @@ -0,0 +1,132 @@ +package main + +import ( + "encoding/json" + "errors" + "strconv" + + "github.com/hyperledger/fabric/core/chaincode/shim" +) + + +// ============================================================================================================================ +// Get Wallet - get a wallet asset from ledger +// ============================================================================================================================ +func get_wallet(stub shim.ChaincodeStubInterface, id string) (Wallet, error) { + var wallet Wallet + + //getState retreives a key/value from the ledger + walletAsBytes, err := stub.GetState(id) + if err != nil { + return wallet, errors.New("Failed to find wallet - " + id) + } + + //un stringify it aka JSON.parse() + json.Unmarshal(walletAsBytes, &wallet) + + //test if wallet is actually here or just nil + if wallet.Id != id { + return wallet, errors.New("Wallet does not exist - " + id) + } + + return wallet, nil +} + + +// ============================================================================================================================ +// Get Owner - get the owner asset from ledger +// ============================================================================================================================ +func get_owner(stub shim.ChaincodeStubInterface, id string) (Owner, error) { + var owner Owner + + ownerAsBytes, err := stub.GetState(id) + if err != nil { + return owner, errors.New("Failed to get owner - " + id) + } + + json.Unmarshal(ownerAsBytes, &owner) + + //test if owner is actually here or just nil + if len(owner.Username) == 0 { + return owner, errors.New("Owner does not exist - " + id + ", '" + owner.Username "'") + } + + return owner, nil +} + + +// ============================================================================================================================ +// Get Beneficiary - get the beneficiaries asset from ledger +// ============================================================================================================================ +func get_benefeciary(stub shim.ChaincodeStubInterface, id string) (Beneficiary, error) { + var beneficiary Beneficiary + + //getState retreives a key/value from the ledger + beneficiaryAsBytes, err := stub.GetState(id) + if err != nil { + return beneficiary, errors.New("Failed to find beneficiary - " + id) + } + + json.Unmarshal(walletAsBytes, &beneficiary) + + //test if beneficiary is actually here or just nil + if beneficiary.Id != id { + return beneficiary, errors.New("Beneficiary does not exist - " + id) + } + + return beneficiary, nil +} + + +// ============================================================================================================================ +// Get Transactions - get the transactions asset from ledger +// ============================================================================================================================ + + + +// ============================================================================================================================ +// Read - read a generic variable from ledger +// +// Shows Off GetState() - reading a key/value from the ledger +// ============================================================================================================================ +func read(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var key, jsonResp string + var err error + fmt.Println("starting read") + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting key of the var to query") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + key = args[0] + valAsbytes, err := stub.GetState(key) //get the var from ledger + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + key + "\"}" + return shim.Error(jsonResp) + } + + fmt.Println("- end read") + return shim.Success(valAsbytes) //send it onward +} + + +// ======================================================== +// Input Sanitation - dumb input checking, look for empty strings +// ======================================================== +func sanitize_arguments(strs []string) error{ + for i, val:= range strs { + if len(val) <= 0 { + return errors.New("Argument " + strconv.Itoa(i) + " must be a non-empty string") + } + if len(val) > 32 { + return errors.New("Argument " + strconv.Itoa(i) + " must be <= 32 characters") + } + } + return nil +} \ No newline at end of file diff --git a/develop/Ledger_Writer_Class.go b/develop/Ledger_Writer_Class.go new file mode 100644 index 0000000..5bc8ccb --- /dev/null +++ b/develop/Ledger_Writer_Class.go @@ -0,0 +1,614 @@ +package main + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + + +// ============================================================================================================================ +// write() - genric write variable into ledger +// +// Shows Off PutState() - writting a key/value into the ledger +// +// Inputs - Array of strings +// 0 , 1 +// key , value +// "abc" , "test" +// ============================================================================================================================ +func write(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var key, value string + var err error + fmt.Println("starting write") + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2. key of the variable and value to set") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + key = args[0] + value = args[1] + err = stub.PutState(key, []byte(value)) //write the variable into the ledger + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end write") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// delete_wallet() - remove a wallet from state and from wallet index +// +// Shows Off DelState() - "removing" a key/value from the ledger +// +// Inputs - Array of strings +// 0 , 1 +// id , authorized_by_association +// ============================================================================================================================ +func delete_wallet(stub shim.ChaincodeStubInterface, args []string) (pb.Response) { + fmt.Println("starting delete_wallet") + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // input sanitation + err := sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + authorized_by_association := args[1] + + // get the wallet + wallet, err := get_wallet(stub, id) + if err != nil{ + fmt.Println("Failed to find wallet by id " + id) + return shim.Error(err.Error()) + } + + // check authorizing organisation + if wallet.Owner.Association != authorized_by_association{ + return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + wallet.Owner.Association + "'.") + } + + // remove the wallet + err = stub.DelState(id) //remove the key from chaincode state + if err != nil { + return shim.Error("Failed to delete state") + } + + fmt.Println("- end delete_wallet") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// delete_owner() - remove an owner from state and from owner index +// +// ============================================================================================================================ +func delete_owner(stub shim.ChaincodeStubInterface, args []string) (pb.Response) { + fmt.Println("starting delete_owner") + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // input sanitation + err := sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + authorized_by_association := args[1] + + // get the owner + owner, err := get_owner(stub, id) + if err != nil{ + fmt.Println("Failed to find owner by id " + id) + return shim.Error(err.Error()) + } + + // check authorizing organisation + if Owner.Association != authorized_by_association{ + return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + Owner.Association + "'.") + } + + // remove the owner + err = stub.DelState(id) //remove the key from chaincode state + if err != nil { + return shim.Error("Failed to delete state") + } + + fmt.Println("- end delete_owner") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// delete_beneficiary() - remove a beneficiary from state and from beneficiary index +// +// ============================================================================================================================ +func delete_beneficiary(stub shim.ChaincodeStubInterface, args []string) (pb.Response) { + fmt.Println("starting delete_beneficiary") + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // input sanitation + err := sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + authorized_by_association := args[1] + + // get the beneficiary + beneficiary, err := get_beneficiary(stub, id) + if err != nil{ + fmt.Println("Failed to find beneficiary by id " + id) + return shim.Error(err.Error()) + } + + // check authorizing organisation + if beneficiary.Owner.Association != authorized_by_association{ + return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + beneficiary.Owner.Association + "'.") + } + + // remove the beneficiary + err = stub.DelState(id) //remove the key from chaincode state + if err != nil { + return shim.Error("Failed to delete state") + } + + fmt.Println("- end delete_beneficiary") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Init Wallet - create a new wallet, store into chaincode state +// +// Shows off building a key's JSON value manually +// +// Inputs - Array of strings +// 0 , 1 , 2 , 3 +// id , balance , owner id , authorization +// ============================================================================================================================ +func init_wallet(stub shim.ChaincodeStubInterface, args []string) (pb.Response) { + var err error + fmt.Println("starting init_wallet") + + if len(args) != 4 { + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + owner_id := args[2] + authorized_by_association := args[3] + balance, err := strconv.Atoi(args[1]) + if err != nil { + return shim.Error("Second argument must be a numeric string") + } + + //check if new owner exists + owner, err := get_owner(stub, owner_id) + if err != nil { + fmt.Println("Failed to find owner - " + owner_id) + return shim.Error(err.Error()) + } + + //check authorizing organisation + if owner.Association != authorized_by_association{ + return shim.Error("The association '" + authorized_by_association + "' cannot authorize creation for '" + owner.Association + "'.") + } + + //check if wallet id already exists + wallet, err := get_wallet(stub, id) + if err == nil { + fmt.Println("This wallet already exists - " + id) + fmt.Println(wallet) + return shim.Error("This wallet already exists - " + id) + } + + //build the wallet json string manually + str := `{ + "docType":"wallet", + "id": "` + id + `", + "balance": "` + balance + `", + "owner": { + "id": "` + owner_id + `", + "name": "` + owner.Name + `", + "firstname": "` + owner.Firstname + `" + } + }` + err = stub.PutState(id, []byte(str)) //store wallet with id as key + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end init_wallet") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Init Owner - create a new owner, store into chaincode state +// +// Shows off building key's value from GoLang Structure +// +// ============================================================================================================================ +func init_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + fmt.Println("starting init_owner") + + if len(args) != 9 { + return shim.Error("Incorrect number of arguments. Expecting 9") + } + + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + var owner Owner + owner.ObjectType = "wallet_owner" + owner.Id = args[0] + owner.Name = strings.ToLower(args[1]) + owner.Firstname = strings.ToLower(args[2]) + owner.Mail = strings.ToLower(args[3]) + owner.Address = strings.ToLower(args[4]) + owner.City = strings.ToLower(args[5]) + owner.Password = strings.ToLower(args[7]) + owner.Association = args[8] + owner.Enabled = true + Postalcode, err := strconv.Atoi(args[6]) + if err != nil { + return shim.Error("Seventh argument must be a numeric string") + } + + fmt.Println(owner) + + //check if user already exists + _, err = get_owner(stub, owner.Id) + if err == nil { + fmt.Println("This owner already exists - " + owner.Id) + return shim.Error("This owner already exists - " + owner.Id) + } + + //store user + ownerAsBytes, _ := json.Marshal(owner) //convert to array of bytes + err = stub.PutState(owner.Id, ownerAsBytes) //store owner by its Id + if err != nil { + fmt.Println("Could not store user") + return shim.Error(err.Error()) + } + + fmt.Println("- end init_owner wallet") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Init Beneficiary - create a new beneficiary, store into chaincode state +// +// Shows off building a key's JSON value manually +// +// Inputs - Array of strings +// 0 , 1 , 2 , 3 +// id , balance , owner id , authorization +// ============================================================================================================================ +func init_beneficiary(stub shim.ChaincodeStubInterface, args []string) (pb.Response) { + var err error + fmt.Println("starting init_beneficiary") + + if len(args) != 6 { + return shim.Error("Incorrect number of arguments. Expecting 6") + } + + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + idBenef := args[1] + nameBenef := strings.ToLower(args[2]) + firstnameBenef := strings.ToLower(args[3]) + owner_id := args[4] + authorized_by_association := args[5] + + //check if new owner exists + owner, err := get_owner(stub, owner_id) + if err != nil { + fmt.Println("Failed to find owner - " + owner_id) + return shim.Error(err.Error()) + } + + //check authorizing organisation + if owner.Association != authorized_by_association{ + return shim.Error("The association '" + authorized_by_association + "' cannot authorize creation for '" + owner.Association + "'.") + } + + //check if beneficiary id already exists + beneficiary, err := get_beneficiary(stub, id) + if err == nil { + fmt.Println("This beneficiary already exists - " + id) + fmt.Println(beneficiary) + return shim.Error("This beneficiary already exists - " + id) + } + + //build the beneficiary json string manually + str := `{ + "docType":"beneficiary", + "id": "` + id + `", + "idbenef": "` + idbenef + `", + "namebenef": "` + namebenef + `", + "firstnamebenef": "` + firstnamebenef + `", + "owner": { + "id": "` + owner_id + `", + "name": "` + owner.Name + `", + "firstname": "` + owner.Firstname + `" + } + }` + err = stub.PutState(id, []byte(str)) //store beneficiary with id as key + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end init_beneficiary") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Set Owner on Wallet +// +// Shows off GetState() and PutState() +// +// ============================================================================================================================ +func set_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + fmt.Println("starting set_owner") + + // this is quirky + // todo - get the "association that authed the transfer" from the certificate instead of an argument + // should be possible since we can now add attributes to the enrollment cert + // as is.. this is a bit broken (security wise), but it's much much easier to demo! holding off for demos sake + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + var wallet_id = args[0] + var new_owner_id = args[1] + var authorized_by_association = args[2] + fmt.Println(wallet_id + "->" + new_owner_id + " - |" + authorized_by_association) + + // check if user already exists + owner, err := get_owner(stub, new_owner_id) + if err != nil { + return shim.Error("This owner does not exist - " + new_owner_id) + } + + // get wallet's current state + walletAsBytes, err := stub.GetState(wallet_id) + if err != nil { + return shim.Error("Failed to get wallet") + } + res := Wallet{} + json.Unmarshal(walletAsBytes, &res) + + // check authorizing association + if res.Owner.Association != authorized_by_association{ + return shim.Error("The Association '" + authorized_by_association + "' cannot authorize transfers for '" + res.Owner.Association + "'.") + } + + // transfer the wallet + res.Owner.Id = new_owner_id //change the owner + res.Owner.Name = owner.Name + res.Owner.Firstname = owner.Firstname + res.Owner.Association = owner.Association + jsonAsBytes, _ := json.Marshal(res) //convert to array of bytes + err = stub.PutState(args[0], jsonAsBytes) //rewrite the wallet with id as key + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end set owner") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Set Beneficiaries +// +// ============================================================================================================================ +func set_beneficiary(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + fmt.Println("starting set_beneficiary") + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + var beneficiary_id = args[0] + var new_owner_id = args[1] + var authorized_by_association = args[2] + fmt.Println(beneficiary_id + "->" + new_owner_id + " - |" + authorized_by_association) + + // check if user already exists + owner, err := get_owner(stub, new_owner_id) + if err != nil { + return shim.Error("This owner does not exist - " + new_owner_id) + } + + // get beneficiary's current state + beneficiaryAsBytes, err := stub.GetState(beneficiary_id) + if err != nil { + return shim.Error("Failed to get beneficiary") + } + res := Beneficiary{} + json.Unmarshal(beneficiaryAsBytes, &res) + + // check authorizing association + if res.Owner.Association != authorized_by_association{ + return shim.Error("The Association '" + authorized_by_association + "' cannot authorize transfers for '" + res.Owner.Association + "'.") + } + + // transfer the beneficiary + res.Owner.Id = new_owner_id //change the owner + res.Owner.Name = owner.Name + res.Owner.Firstname = owner.Firstname + res.Owner.Association = owner.Association + jsonAsBytes, _ := json.Marshal(res) //convert to array of bytes + err = stub.PutState(args[0], jsonAsBytes) //rewrite the wallet with id as key + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end set owner") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Disable Wallet Owner +// +// Shows off PutState() +// ============================================================================================================================ +func disable_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + fmt.Println("starting disable_owner") + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + var owner_id = args[0] + var authorized_by_association = args[1] + + // get the wallet owner data + owner, err := get_owner(stub, owner_id) + if err != nil { + return shim.Error("This owner does not exist - " + owner_id) + } + + // check authorizing association + if owner.Association != authorized_by_association { + return shim.Error("The association '" + authorized_by_association + "' cannot change another association wallet owner") + } + + // disable the owner + owner.Enabled = false + jsonAsBytes, _ := json.Marshal(owner) //convert to array of bytes + err = stub.PutState(args[0], jsonAsBytes) //rewrite the owner + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end disable_owner") + return shim.Success(nil) +} + + +// ============================================================================================================================ +// Transfer X Money From a User to a Recipient +// +// ============================================================================================================================ +func transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + fmt.Println("starting transfer") + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + // input sanitation + err = sanitize_arguments(args) + if err != nil { + return shim.Error(err.Error()) + } + + id := args[0] + dest_id := args[1] + + // Get the state from the ledger + // TODO: will be nice to have a GetAllState call to ledger + Avalbytes, err := stub.GetState(id) + if err != nil { + return nil, errors.New("Failed to get state") + } + if Avalbytes == nil { + return nil, errors.New("Entity not found") + } + Aval, _ = strconv.Atoi(string(Avalbytes)) + + Bvalbytes, err := stub.GetState(dest_id) + if err != nil { + return nil, errors.New("Failed to get state") + } + if Bvalbytes == nil { + return nil, errors.New("Entity not found") + } + Bval, _ = strconv.Atoi(string(Bvalbytes)) + + // Perform the execution + value, err = strconv.Atoi(args[2]) + Aval = Wallet.Balance - value + Bval = Wallet.Balance + value + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state back to the ledger + err = stub.PutState(id, []byte(strconv.Itoa(Aval))) + if err != nil { + return nil, err + } + + err = stub.PutState(dest_id, []byte(strconv.Itoa(Bval))) + if err != nil { + return nil, err + } + + fmt.Println("- end transfer") + return shim.Success(nil) +} \ No newline at end of file