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) }