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));
});
Related
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.
Customer1 is paying to Customer2 after the deduction of (platform fees + stripe Fees). To run such scenario. I did the following steps in Stripe-Connect:
Created a Customer1 object and added the card Info.
Created an account for a Customer2 using endpoint: https://stripe.com/docs/api#create_account
I can see the created account in Connected account section.
Verified the account after entering test Legal entity from the browser itself.
Creating a Charge object (Customer1 is paying) which also has an application_fee. The destination account mentioned in the request is newly generated Customer2 account.
I am using the Java API and it throwing me an error:
Can only apply an application_fee when the request is made on behalf of another account (using an OAuth key, the Stripe-Account header, or the destination parameter).
I tried to follow up here on StackOverflow and it seems like I need to create a platform account to initiate such charges. If so, How can I create a Platform account?
How will it help me to charge the Customer1 and transfer the money to Customer2 connect account after the deduction of application_fee?
It sounds a bit confusing to me. Any help or hint would be appreciable.
You already have a platform account here. This is simply the word used to describe the main account (yours) that has connected accounts.
The issue here seems to be with the way you create the Charge. You can only take an application fee if you explicitly make that request on behalf of a connected account. There are currently 2 ways to do this:
Destination charges go through the platform and the funds are automatically sent to the connected account
Direct charges are created directly on the connected account and the application fee is sent back to you.
Since you are using Custom accounts where you create and own the accounts for your sellers you should use the first approach. In that case, you don't even have to take an application fee. Instead, you simply decide how much to send to the connected account when you create the charge. The idea is that you charge $100 and you only send $90 to the connected account so that you keep $10 for yourself (minus Stripe's fees).
The code would look like this:
// Create the list of parameters for the charge
Map<String, Object> params = new HashMap<String, Object>();
params.put("amount", 10000); // amount to charge in cents
params.put("currency", "usd");
params.put("source", "tok_visa");
// Decide how what to send to the connected account
Map<String, Object> destinationParams = new HashMap<String, Object>();
destinationParams.put("account", "acct_XXXXX"); // connected account id
destinationParams.put("amount", 9000); // amount to send to the connected account
params.put("destination", destinationParams);
Charge charge = Charge.create(params);
I have a webapp running on my server, which does some balance update. Once the balance is updated, I need to check if the balance is below 5000. In case, the balance goes below 5000, I should send an email alert. The point to note here is that, I need to send the alert only once in a day, alert should not keep going every time the balance is below 5000.
I believe, I should use singleton pattern for sending the mail, but I am not sure how to use this.
The program when sees the balance going below 5000, should call the singleton class which will have the function to send email alert, but how do you ensure that program will not call this function again when the balance goes down?
Can anyone guide me on this?
There is two separate things you need think about:
Email sending service.
Several ways to implement it. Yes, it could be Singleton, but it also could be a plain Java service. If you use Spring, then they have very simple and useful predefined implementations. Here is an example.
Your checking balance logic.
Depends on what you really need. If you need to check every balance update but send alerts not more that once per day, then it will be something like:
private Date lastAlertDate;
private static final BALANCE_LIMIT = 5000;
private void handleBalanceUpdated(long balance) {
if (balance < 5000) {
log.info("Balance has gone below {}", BALANCE_LIMIT);
int daysDifference = getDifferenceInDays(lastAlertDate, new Date());
if (daysDifference >= 1) {
log.info("Last alert was {} days ago, going to send email alert", daysDifference);
alertService.sendSimpleAlert("Balance has gone below " + BALANCE_LIMIT + "!");
lastAlertDate = new Date();
}
}
}
Singleton is a design pattern that makes sure only one instance of an object is created.
Doesn't sound like it has anything to do with what you need, you could add a flag in your DB like alert_sent=true/false and update it accordingly.
User Timer Task to send mail only once a day
Singleton Pattern
You do not need any "special" design patterns here. For instance you can store the date when the last email notification was sent, like:
Date lastEmail = ... // last email date
And when trying to send email chekc the condition:
If( ... ) // lastEmail is before current day
{ //send emal and update lastEmail }
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.
I'm working with PayPal Adaptive Payments' IPN. I was able to get the IPN to work, but when I decided to get payment details of a COMPLETED transaction back from PayPal, the PaymentDetails class' getReceiverList method returned null.
PaymentDetailsRequest paymentDetailsRequest = new PaymentDetailsRequest("en_US", ServiceEnvironment.SANDBOX);
paymentDetailsRequest.setPayKey(payKey);
PaymentDetailsResponse paymentDetailsResponse = paymentDetailsRequest.execute(credentialObj);
PaymentDetails paymentDetails = paymentDetailsResponse.getPaymentDetails();
List<Receiver> receiverList = paymentDetails.getReceiverList();
// receiverList returns null
That shouldn't be happening because the transaction has completed and there obviously is a receiver.
If I pull other data from the same paymentDetails object such as the payment status, i get the proper result.
String paymentStatus = paymentDetails.getStatus();
// paymentStatus returns COMPLETED
Has anyone come across this and could tell me why this is happening?
Just in case someone comes across this problem, I have found out that the PayPal Adaptive Payments' IPN still has many glitches, this being one of them. Basically the method getReceiverList() does not get anything. This will be the case for every method that returns null when it should be returning something.