Consider a scenario where their is a PartyA and account1 is created in PartyA. Now we have to initiate a transaction between account1 and PartyA. Is it possible to have a transaction flow initiated by an account and receiving party is a host node? If yes, can anyone please suggest what will be required steps to be taken coding wise. If there is a sample example, then please let me know.
A flow is always started by a node (i.e. Party), not by an account.
But, a node can sign a transaction on behalf of an account using the account's PublicKey; and that's what you're looking for.
Your example simplifies this task since the account is hosted on the same node that starts the flow; so you don't need a responder flow.
So things will look this way:
PartyA initiates your flow.
I assume that you have a state where one of the fields is an account; let's assume it's:
MyState(myAccount: PublicKey)
Your flow will have as an input parameter the UUID of myAccount:
class MyFlow(val myAccountId: UUID, ...
You will first query the vault to fetch the account using its UUID:
val myAccountInfo = accountService.accountInfo(myAccountId)
?: throw IllegalStateException("Can't find account with Id $myAccountId")
Request a new key for the account:
val myAccountKey = subFlow(RequestKeyForAccount(myAccountInfo.state.data)).owningKey
Create your state:
val myState = MyState(myAccountKey)
Now the most important part, the command that creates your state will require 2 signatures: PartyA's (which is the node that initiated the flow, i.e. ourIdentity), and the signature of myAccountInfo:
val command = Command(MyState.Commands.Create(),
listOf(ourIdentity.owningKey, myAccountKey))
I'm skipping some steps, but when the time comes to sign the transaction; you will sign it with the key of PartyA (i.e. the initiator of the flow which is ourIdentity) and the key of myAccountInfo:
val fullySignedTx = serviceHub.signInitialTransaction(txBuilder,
listOf(ourIdentity.owningKey, myAccountKey))
You can have a look at the IOU example which is implemented using Accounts Library; again, in your case you don't need a responder flow; they created a responder flow in case the borrower account was hosted on a different node than the initiating node.
See example here.
Related
I'm using Stripe with Standard accounts.
I'm saving Customers and PaymentMethods on the Platform, so, in client side the customer choose a Payment Method and it is sent to the server. So, in the server side I clone the PaymentMethod to the Connected Account that will receive the payment. My server side code looks like this
RequestOptions requestOptions = RequestOptions.builder()
.setStripeAccount("{{CONNECTED_STRIPE_ACCOUNT_ID}}")
.build();
PaymentMethodCreateParams paramsClone = PaymentMethodCreateParams.builder()
.setCustomer("cus_1")//Id of the customer in the platform
.setPaymentMethod("payment_method_id")//One of the payment methods of the cus_1
.build();
PaymentMethod newPaymentMethod = PaymentMethod.create(paramsClone, requestOptions);
At this point I assume that this new newPaymentMethod is in the connected account, right?
Well, then I create a PaymentIntent
PaymentIntentCreateParams params = PaymentIntentCreateParams.builder()
.setAmount(100)
.setPaymentMethod(newPaymentMethod.getId())
.setCurrency("usd")
.setApplicationFeeAmount(10)
.build();
PaymentIntent paymentIntent = PaymentIntent.create(params, requestOptions);
Everything seems good at this point. The Payment Intent is returning the stripe client secret like 'pi_1Ipfl3Bf0KWukpZWQdbAzoz1_secret_RAKsPMLpyhkDJ7q8N1VvSmaoR' and the status is 'requires_confirmation'. So, when I try to confirm in the client side it throws an error saying: No such payment_intent: 'pi_1Ipfl3Bf0KWukpZWQdbAzoz1'.
I think that it is something related to switching things between my platform and the connected account, but I can not figure out what is the exact problem. I'm following this https://stripe.com/docs/connect/cloning-customers-across-accounts and this https://stripe.com/docs/payments/payment-methods/connect#cloning-payment-methods but still I can not figure out how to get it work.
Can someone explain this? Regards!
Your server-side steps are correct, you are creating a PaymentIntent on the Connect account.
What you are missing client-side is, since the PaymentIntent lives on the Connect account, your Stripe.js/mobile SDK also needs to be authenticated as the Connect account.
You basically need to specify this on your client-side:
var stripe = Stripe('{{PLATFORM_PUBLISHABLE_KEY}}', {
stripeAccount: '{{CONNECTED_STRIPE_ACCOUNT_ID}}',
});
https://stripe.com/docs/connect/authentication#adding-the-connected-account-id-to-a-client-side-application
Since I presume you already have Stripe.js authenticated as your Platform publishable key (in order to create the first PaymentMethod on the Platform, to clone), you would have to create a second instance of Stripe.js on your client, one authenticated as the Connect account.
Well, at the end I solved it in the client side. I just had to tell stripe to confirm on behalf of the Connected Account. Using tipsi-stripe in react native is something like this:
stripe.setStripeAccount('acct_XYZ');//Set the connected account
stripe.confirmPaymentIntent({ clientSecret: stripeClientSecret })
.then((cofirmResponse) => {
stripe.setStripeAccount(null);//Reset the connected account
...
}).catch((e) => {
stripe.setStripeAccount(null);//Reset the connected account
...
});
I would like to **allow my users using my app across multiple devices **. Users have to log into my app through firebase auth.
Problem is that payments are assigned to account that is signed on the device (google play), not with account signed into the app.** From firebase auth I can get an email address of the user of my app - this could be used as some unique identifier.
Problem visualized:
I noticed that in Billing flow there is .setAccountId("some id") I think I could use this to fill in a unique identifier of a user. But how can use it querying purchases?
BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
.setAccountId("some id")
.setSku(PREMIUM_YEAR_SUBS).setType(BillingClient.SkuType.SUBS);
TLDR: All I want to do is to retrieve purchases that are connected to my APP user account, not device account (google play currently logged in user).
To implement billing using accountId, try using the getBuyIntentExtraParams() method which provides additional functionality as compared with getBuyIntent() method.
With this method, you may use accountId with the following description:
Optional obfuscated string that is uniquely associated with the user's account in your app. If you pass this value, Google Play can use it to detect irregular activity, such as many devices making purchases on the same account in a short period of time.
Additionally, you may want to also check the typical purchase flow with the In-app Billing API discussed here.
It seems that we can't get the accountId, the accountId just used by google play.
I guess that you use the accountId to instead of the payload, but after my try, I think that it is not successful.
In the Google Billing Library, the develop payload is removed for the same experience between the in-app-purchase and the out-app-purchase. Though we can add payload in the period of consume or acknowledge, but it useless. And the payload should be set on the period of purchase, but google delete it, and will not be add back. The payload issues.
You can check the AccountId attached to each Purchase using
Purchase.getAccountIdentifiers
It'll return AccountIdentifiers object that has
AccountId & ProfileId that were set previously in BillingFlowParams when you launched billing flow
After that you can compare the current user account id with the account id attached to each purchase
to detect the purchases that are connected to the current user account
I am trying to make transaction via bitcoinj (version 0.14.3) and i am expecting to get change back after payment. I am working with testnet, it's not real bitcoins.
I have next code:
Transaction tx = new Transaction(this.networkParameters);
Coin coinToSent = Coin.valueOf(Config.APP_COST);
Coin coinToChange = Coin.valueOf(walletBalance.getValue() - coinToSent.getValue());
tx.addOutput(coinToSent, appAddress);
tx.addOutput(coinToChange, changeAddress);
SendRequest request = SendRequest.forTx(tx);
try {
this.walletAppKit.wallet().completeTx(request);
} catch (InsufficientMoneyException e) {
e.printStackTrace();
return false;
}
this.walletAppKit.wallet().commitTx(request.tx);
this.walletAppKit.peerGroup().broadcastTransaction(request.tx);
So, i am putting two outputs into transaction:
Address to sending money
Address of my wallet for getting change back
To the first address i send some money. And to the second address i send next value: all available money on my wallet minus money received to first address.
But after broadcasting i had an unexpected result. After making a few transactions with this scheme, I've noticed wrong values withdrawing from my wallet. What is surprising, sometimes money is withdrawing but sometimes money coming to wallet.
Here is the link to testnet explorer
Can someone explain what i am doing wrong and how to fix it?
The reason that the transaction is not working as expected is that the Bitcoinj Wallet class is doing a lot of things in the background for you - in this case, it is automatically generating a change address where is would store the change for the transaction. The other factor is that bitcoinj calculates a fee that it will give the miners to process the transaction, which is why you're seeing the change address getting less coin that you requested (on the production network it will throw an exception if you don't have enough funds to cover the fee).
I think the best solution here, for cases which are relatively simple, is to work with the Wallet API and let it do the work of generating change address automatically (It's using a deterministic keychain so all the addresses and keys can be regenerated in case you lose the wallet). For example:
public static Transaction send(Wallet wallet,
String destinationAddress,
long satoshis) throws Exception {
Address dest = Address.fromBase58(params, destinationAddress);
SendRequest request = SendRequest.to(dest, Coin.valueOf(satoshis));
SendResult result = wallet.sendCoins(request);
Transaction endTransaction = result.broadcastComplete.get();
return endTransaction;
}
After sendCoins is completed and the transaction is broadcasted, the wallet will maintain the rest (you can save it to a file after the transactin is complete if you really want to make sure you have the keys for the change addresses), here's a way you can see a list of 10 change addresses and their public/private keys :
NetworkParameters params = new MainNetParams();
List<DeterministicKey> keys = wallet.freshKeys(KeyChain.KeyPurpose.CHANGE, 10);
keys.forEach(key -> {
Address address = new Address(params, key.getPubKeyHash());
System.out.println(address +" : " + key.toStringWithPrivate(params));
});
I am trying to create a webapplication using Spring. The webapplication is a beta/demo site, which is invitation only. So, I need to generate a link to the webapplication url, appending a unique id, which would be valid for 24 hours. User can use that link for 24 hours and make use of the (I kind of also have plans of restricting the user by ip)
To achieve such token generation and expiry, should I just rely on the container with session time out to do it? or does it make sense to create spring backed service layer with token creation and expiry services?
EDIT
Now that I have a bounty on this to draw more attention, I thought I will rephrase the question so that it makes more sense - what would be a good strategy to force users out of a web application after a certain period of time?
Relying on session timeout would not be sufficient solution .
I am not acquaint with Spring . I would put my generic solution as below for any web application having requirement as yours :
Invitation is assumed to include a link to the Web Application .
The link is assumed to include the unique id .
The Beta/Demo user table is assumed to have a beta-expiry ( datetime ) column to hold the expiry date and time .
When your web application is accessed using the link in the invitation , update the beta-expiry column for that unique_id considering 24 hrs from then .
When a Beta/Demo user attempts to sign in , check the beta-expiry column for that particular user and allow access if the expiry is not reached . Display appropriate message in case of expiry .
Whenever a signed in Beta/Demo user performs subsequent accesses to your web application , check the beta-expiry column for that particular user and allow access if the expiry is not reached . Display appropriate message in case of expiry .
If seems useful , display a countdown timer showing the left over time somewhere in the header area .
In case of extension of Beta usage for all or a portion of users , you could update the beta_expiry column appropriately .
Additionally you could also have an invitation-expiry column to hold invitation expiry considering a particular duration for eg. a 48 hrs from when the invitation was sent .
We use a little bit similar solution to sign out ( signed in ) users from our SaaS application after a particular duration of no access .
I think that you should rely more in the back-end rather than a session on a cookie, imagine the case that you set the cookie for 24 hours expiration but the client deletes the cookies from the browser, (depending on your logic) your link will generate a new session or the request will be blocked.
IMHO you can store a session cookie on the client but you need to have a second source of comparison in the server, maybe a database, no-sql document, a collection in cache, something that you can compare and check the latest access to the client.
just to put all together imagine the following use case:
the user get the invitation link and click on it
the system check if the first time they log into the system, and save that date as a "start date" and another one as "last access"
the system sets an authentication cookie with 24 hours expiration
the system track every post back/ ajax call to the server and update "last access" date
if user deletes the cookie the system check the "last access" and make a comparison with the current server date
if valid the system creates a new auth cookie with the remaining hours
if not valid the system sends a message to the user.
for the user the cookie will expire according to the time left (calculation between start date and last access)
I hope this helps.
regards
One strategy is to keep track of expiry date-time of all the users by storing the relevant data in DB and using a cache library (to reduce DB hits while checking for the expiry date). Here is a small example:
Create a DB table with columns to map user id to expiry date: id, unique_user_id, expiry_date_time. You need to create the unique user id in your code and save it in DB before sending the URL to the user with this id. You can keep null as the initial value for expiry_date_time. Create a class to represent this mapping in Java:
class UserIdWithExpiryDate{
private String userId;
private Date expiryDateTime;
...
}
Define a Service with a cacheable method that will return an instance of this for a given userId :
public interface CacheableService {
#Cacheable("expiryDates")
public UserIdWithExpiryDate getUserIdWithExpiryDate(String id);
public void updateUserIdWithExpiryDate(String userId);
}
import org.joda.time.DateTime;
#Service
public class CacheableServiceImpl implements CacheableService {
#Autowired
private YourDao dao;
#Override
public UserIdWithExpiryDate getUserIdWithExpiryDate(String id) {
return dao.getUserIdWithExpiryDate(id);
}
public void updateUserIdWithExpiryDate(String userId){
Date expiryDate = new Date(new DateTime().plusHours(24).getMillis());
dao.update(userId, expiryDate);
}
}
The result of getUserIdWithExpiryDate method is stored into the cache so on subsequent invocations (with the same argument), the value in the cache is returned without having to actually execute the method.
Next step is to check the user's expiry date while accessing the site. This can be done using OncePerRequestFilter:
#Component("timeoutFilter")
public class TimeoutFilter extends OncePerRequestFilter {
#Autowired
CacheableService cacheableService;
// Here you need to decide whether to proceed with the request or not
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
Steps that can be taken inside the doFilterInternal method to check the validity of the user:
Get the user Id from request
Execute: cacheableService.getUserIdWithExpiryDate(userId)
If step 2 returns null, there is no user present with this id. You should not proceed with the request.
If step 2 returns an instance of UserIdWithExpiryDate, check the value of "expiryDateTime"
If the value of "expiryDateTime" is null,it means user is accessing the site for the first time.Update "userExpiryDate":cacheableService.updateUserIdWithExpiryDate(userId) and proceed with the request.
If "expiryDateTime" is not null, compare this with current date_time. If expiryDateTime.isAfter(currentDateTime), proceed with the request.
For caching, you can use Spring Cache Abstraction with EHCACHE.
Tokens
For this marketing purposes we generate tokens upfront, store them in a database alongside all information like restrictions to certain user account, ip ranges (for certain mobile carriers), the date and time ranges of use and so on.
In case of one time codes we just mark it as being used in the database.
To generate those codes we use Random Numbers or encode some information and use (SHA-1 or better). Then we use bigInteger.toString(36) or a different scheme and group the first 16 letters to let it look like a license key.
If we express information with it like useraccount/name or carrier (mobile) or whatever we can even validate the token without a database.
Forcing User Out
Just check for the validity of the token the first time the user starts a session or logs in. Throughout the session you just check if the token has expired (store a value in the session if you have one, append it (encrypted) in the url or whatever or check against a database.
So on every request you just check if the user has permission to access your site otherwise you block the user with an error / info page.
You can also add a java script to each page. The script can determine whether the users permission to use your site has expired by:
Encrypt the relative time that the token is valid in a hidden div and calculate the absolute time using the users local time. Then compare the absolute expire time with the user time every now and than (lets say every 3 seconds) and you can yourself all those polling and pushing (comet, ajax, websockets) behaviour.
Once the java script program notice the token has become expired remove the content sections and replace it (or mark a hidden div as visible) with the info / error page content. This way every time the user revisits pages still stored in the browser history are destroyed also. (if this is a necessity for you).
Summary
Use random tokens and a database or encrypt information (like the day the token can be used) and SHA-1.
Check the tokens validity every time the user requests a page (store the timeframe in a session / url to save roundtrips to the database)
Provide a java script that destroys local pages in the history on revisit.
Here I can think of two use cases that I have seen.
1.) This kind of management is used in applications like online tests or email verifications, where user is provided a link with some token. This link and the token is valid for some fixed period of time and can be used only once. (Ex. online tests or password reset-emails)
2.) Another use case is to provide link with a token which are also valid for a fixed period of time, but in this case the link and the token can be used any number of time within the time period allowed (Ex. Online registration forms for test or some university enrollments).
So, definitely managing this using a session only will not be a good choice as the browsers can be cleared.
So you need to maintain the pair of the link and the token at the server (May be in a DB) with some other information like last accessed time, creation date and time, Valid upto .
To be more flexible validity time for link and the token can be set differently (eg. link can be used for a set of users, but the tokens are unique to a user).
So you can use this info on every user visit to check whether the link or token is still valid and what are their last accessed time. If it turn out to be expired then you can show the relevant error message.
What about "deleting the user's account" (depends on how you are building your logging system) after 24 hours.
Coupling this with checking user's account every time (s)he loads the page, will force him/her out at the first refreshing after the 24 hours threshold passses.
You can store the id with expiration time and when a request comes in with that id check if
it's still valid
and if you are trying to accomplish something like id is valid say 5 hrs after first request then store time when the first request is made and for each subsequent request check if it's still valid
I am new to apex and have built an apex schedule class that runs everyday. If an account has an account review date for commissions is two weeks (14 days) away the scheduler will send an email to our Sales Department. The email contains a link to a flow. The flow starts a process to calculate the new commission. To do that, the flow needs to understand to pull information from the account that triggered the email to be sent, the account that has an account review date in 2weeks.
Currently, the email sends out fine with the link to the flow. The link to the flow works, but once you get to the flow, the flow does not know/understand what account it should be pulling information from. I’m not sure if I need to alter my code in my scheduler and/or the code in my flow.
Here is how the flow is accessing information:
Before the first screen, a record lookup in flow occurs. It pulls the information from the account ID and a variable, vaAccountID. I think that the variable {!vaAccountID} is populated with the AccountID that is linked to the commission.
When I run my scheduler, I have it determine if there is an account with an account review date based upon the account Id. It sends the email template with the flow link to the sales department.
The scheduler sends the email and is “happy”. The criteria it needs to execute the method is complete (there is an account with an account review date 14 days from now and it sends the email).
global class AccountReviewSchedulerEmailAcc implements Schedulable {
global void execute (SchedulableContext ctx)
{
sendEmail();
}
public void sendEmail()
{
for(Account acc : [SELECT Id FROM Account WHERE Next_Account_Review_Date__c = : system.Today().addDays(14)])
{
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
mail.setTemplateId('00XF0000000LfE0');
mail.setTargetObjectId('005J0000000JWYx');
mail.setSaveAsActivity(false);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail });
}
}
}
The flow however, is not “happy”. It does not know what account to pull information from.
In the first screen of the flow, it’s supposed to show the recurring revenue and link to the account page. The recurring revenue field is blank. The link to account page does not work.
If I try to advance past the first screen of the flow, I get a generic error screen from Salesforce and a detailed error message from Salesforce. It says:
Encountered unhandled fault when running process Organic_Commission_Determination_Flow/301J000000001Tx exception by user/organization: 00DJ00000000YTl/{4} Source organization: 00DA0000000KZI8 (null)
interaction.dal.exception.DALExecutionFault: ; nested exception is:
common.exception.ApiQueryException:
Account.Annual_RR__c FROM Account WHERE (Account.Id = '{!Commission__c.AccountId__c}')
^ ERROR at Row:1:Column:89 invalid ID field: {!Commission__c.AccountId__c} (There was a problem executing your command.) > RETRIEVE
caused by element : Data lookup.Lookup_Account
caused by: interaction.dal.exception.DALExecutionFault: ; nested exception is:
common.exception.ApiQueryException:
Account.Annual_RR__c FROM Account WHERE (Account.Id = '{!Commission__c.AccountId__c}')
^ ERROR at Row:1:Column:89 invalid ID field: {!Commission__c.AccountId__c} (There was a problem executing your command.) > RETRIEVE
Salesforce Error ID: 580775287-15539 (1733087783)
What does this error message mean? How can I get more information on Salesforce errors and how to trouble shoot on this matter?
I understand this process is very complex but it relates back to one fundamental question: How do I get the flow to realize that it needs to pull information from the account that had the review date 14 days away in my apex scheduler?
Take a look at the SOQL statement that is being executed in the error message:
Account.Annual_RR__c FROM Account WHERE (Account.Id = '{!Commission__c.AccountId__c}')
This is telling me that the link in your email template is passing the literal value "{!Commission__c.AccountId__c}" into your SOQL, rather than binding the value of that field when sending the email out. So rather than passing an Account Id into the URL, you're passing this string which is most certainly not what the flow is expecting.
This can happen when the API name of the field is entered incorrectly in the email template, or if the record bound to the template isn't of type Commission__c as you were expecting. So this could be one of two things: either the record you're sending out isn't of the correct object type for email template 00XF0000000LfE0, or there is no AccountId__c field on the Commission__c object.