I'm using NodeJs to write the Hyperledger Fabric chaincode v2.x and using const { Contract } = require('fabric-contract-api')
I have 2 sets of chaincode, one to maintain the user and its wallet amount, and 2nd contract has the information about the asset e.g. quantity, price, name, etc.
I wanted to transfer the asset some quantity from user1 to user2 and wanted to deduct money from user1's account and transfer it to user2's account.
How can I call the function of transfer from the user contract inside the asset contract?
Yes, you can call one chain code function in another chain code .
You can find a few more information in the below link:
https://hyperledger.github.io/fabric-chaincode-node/release-2.2/api/fabric-shim.ChaincodeStub.html#invokeChaincode__anchor
As there is nothing like a piece of code to explain how the SDK works, I would like to offer the following which may help. The exchangeAsset is a method signature on the current contract. It receives as parameters, the AssetId and the buyerId.
async exchangeAsset(ctx, assetId, buyerId) {
Further down in this contract method, there is a need to make a cross contract call to the client contract, which contains information on buyers and sellers. First create an array containing the name of the function to call and the number of parameters required e.g.
let values = new Array("readKeyValue", buyerId);
Then make the call using the following
let buyer = await this.crossChannelRead(
ctx,
"client",
[...values],
"channelname"
);
The "client" string is the name of the other contract to call.
The values array is spread and will read as readKeyValue, buyerId, which means use the readKeyValue function and use buyerId as the parameter.
The "channelname" as shown above will actually be the name of the channel where the contract can be found.
Related
I'm using ethers.rs & want to call a function of a deployed smart contract. I don't to use the ABI of smart contract for this.
Based on my research so far I've found a way of using the function selector. This has to be encoded along with the function arguments in the data field of the transaction.
How can I do so using ethers.rs if I just know the contract address & the function that I want to call?
First you need to parse your contract abi with abigen:
abigen!(ERC20Token, "./erc20.json",);
more information here
next you create your contract object:
let contract = ERC20Token::new(address, client);
and finally you call it:
contract.total_supply().call().await
contract.transfer(to, amount).call().await
you can check the full example here
I have a trouble when I want to get query result in my fabric. I have 2 channels, channel 1 stored account data, channel 2 stored some content and their cost. I am in channel 1,I want to query a content's cost in channel2,then "buy" it in channel 1. For example,channel1 have an account A and he has $20,channel2 have a movie cost $9, A wants to query the cost of the movie, then "buy" it, so A only have $11 now. But now I don't know how to get the "$9" from channel2. How can I do it?
Fabric uses channels as a form of isolation.
How ever you can invoke another chaincode using 'InvokeChaincode' API.
// InvokeChaincode locally calls the specified chaincode `Invoke` using the
// same transaction context; that is, chaincode calling chaincode doesn't
// create a new transaction message.
// If the called chaincode is on the same channel, it simply adds the called
// chaincode read set and write set to the calling transaction.
// If the called chaincode is on a different channel,
// only the Response is returned to the calling chaincode; any PutState calls
// from the called chaincode will not have any effect on the ledger; that is,
// the called chaincode on a different channel will not have its read set
// and write set applied to the transaction. Only the calling chaincode's
// read set and write set will be applied to the transaction. Effectively
// the called chaincode on a different channel is a `Query`, which does not
// participate in state validation checks in subsequent commit phase.
// If `channel` is empty, the caller's channel is assumed.
InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response
Source
As you know there is chance to have multiple transaction in one block , depend on the batch size and orderer configuration.
I need to make only one call to return all transaction inside the block not one by one.
I could retrieve one transaction with queryTransaction by using fabric SDK.
like
let response_payload = await channel.queryTransaction(trxnID, peer);
First Approach: implement a chanincode function and pass the block number which comes from eventHub along the method then inside the chaincode retrieve all transaction Ids and then make a query to find all transaction then stitch all together as result.
Second Approach:
retrieve the block inside with fabric sdk then parse all signed proposal in the payload of the block content.
Third Approach:
retrieve the block inside with fabric sdk then retrieve the transaction ids or keys in the payload and then make a couch db query to retrieve all content .
Which approach do you think is more reasonable if not what is your suggestion?
If you have a your client set up correctly, there should be a
LedgerClient which has a function like
QueryBlock(blockNumber uint64, options ...ledger.RequestOption) (*common.Block, error)
Once you have the block, you can pull the data out of it
block, _ := QueryBlock(37)
data := block.GetData().GetData()
data is a [][]byte, and each entry is one transaction.
I have upgraded the Stripe.net to the latest version which is 20.3.0 and now I don't seem to find the .Last4 for the credit card. I had the following method:
public void CreateLocalCustomer(Stripe.Customer stipeCustomer)
{
var newCustomer = new Data.Models.Customer
{
Email = stipeCustomer.Email,
StripeCustomerId = stipeCustomer.Id,
CardLast4 = stipeCustomer.Sources.Data[0].Card.Last4
};
_dbService.Add(newCustomer);
_dbService.Save();
}
But now the stipeCustomer.Sources.Data[0].Card.Last4 says 'IPaymentSource' does not contain a definition for 'Card'. Does anyone know how I can get the card details now? The flow is that I create the customer by passing the Stripe token to Stripe, then I get the above stripeCustomer. So I expect it to be somewhere in that object. But I can't find it. The release notes can be found here.
Thank you.
In the old world of Stripe, there only used to be one type of payment method you could attach to a Customer; specifically, Card-objects. You would create a Card-object by using Stripe.js/v2 or the Create Token API Endpoint to first create a Token-object and then attach that token to a Customer-object with the Create Card API Endpoint.
Once Stripe expanded to support a number of other payment methods though, Stripe built support for a new object type that encapsulated a number of payment methods (including credit cards) called Source-objects. A Source-object is created either by using Stripe.js/v3 or the Create Source API Endpoint. It can also be attached to a Customer-object in much the same way as the Card-objects mentioned above, except they retain their object type. They're still a Source. You use the Attach Source API Endpoint to do this (that is notably identical to the Create Card API Endpoint mentioned above).
What I'm getting at here, is there are now two different object types (or more) that you can expect to see returned in the sources-array (or Sources in .NET). All of these methods though inherit from the IPaymentSource-interface. So if you know you have a Card-object getting returned, you can simply cast the returned object to the Card-class.
Something like this should get you going:
CardLast4 = ((Card) stipeCustomer.Sources.Data[0]).Last4
You can see what I mean by inheritance by looking at this line in the Card-class file:
https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Cards/Card.cs#L7
Good luck!
As of Stripe.net.21.4.1, this is what works:
var chargeService = new ChargeService();
var charge = chargeService.Get(id);
CardLast4 = ((Card)charge.Source).Last4;
It's getting hard not to panic when code breaks because of all the micro-changes Stripe makes.
So after debugging, it looks like the Data[0] needs to be cast as Card to get the card.
So it will be CardLast4 = ((Card)stipeCustomer.Sources.Data[0]).Last4.
I've got a question regarding outside-aggregate validation.
In our domain partner can place orders that contain certain products (1).
Once order is placed (2) he can mark it as paid (3) in our system.
Once order is marked as paid (4) we assign licences to products in external library service (5).
Once we know licences are assigned (6) we close entire saga.
Here's a small drawing illustrating the process:
At this moment besides commands, command handlers and events there are two domain classes that are involved in entire process:
Order aggregate containing business logic
Order saga coordinating entire process and assigning licences
Now, there is one invariant that is not modelled in this process yet - before we mark order as paid we have to check if user does not already have particular licence assigned. We get this from library service as well.
Where would you put this validation? Command handler? Wrap Order in some domain service? Pass some validator to Order constructor?
class Order
{
public function __construct(OrderValidator $validator)
{
if (!$validator->isValid($this)) {
throw new \DomainException();
}
// else proceed
}
}
class OrderValidator
{
private $libraryServiceClient;
public function isValid(Order $order)
{
// check licence using $libraryServiceClient
}
}
As far as I understood the problem is in step 3 (Mark order as payed). In this step we need a user (let's call it payer) that marks the order as payed. So when creating this payer object (using factory maybe) we need to know if he is allowed to mark an order as payed. In order to get this information a call should be made to the external library.
What I suggest is to have an application service that have ->markOrderAsPayed($orderId, $payerUserId)
This method will make a call to 2 domain services. One for getting the payer and one for marking the order as payed.
$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);
In the getPayer() function you should make a call to the external library to know how many licences the payer have.
I hope this will be helpful, it is just based on what I understood from the questions and comments.