After I create my own token program I am thne minting some supply into another tokenaccount.
I notice the mintTo is a void function, is there any easy way to get the associated transaction signature ?
const token = new splToken.Token(
connection,
new web3.PublicKey(token_type.token_address),
splToken.TOKEN_PROGRAM_ID,
mint_authority_wallet
);
const destinationTokenAccount = await token.getOrCreateAssociatedAccountInfo(
new web3.PublicKey(to_public_address)
);
console.log("destinationTokenAccount>>", destinationTokenAccount);
const test = await token.mintTo(
destinationTokenAccount.address,
mint_authority_wallet.publicKey,
[],
100
);
console.log("test>>",test)
The fix for this is quite simple: you just need to return the result from sendAndConfirmTransaction. Check out the source code at https://github.com/solana-labs/solana-program-library/blob/ab05e4e597c0b538d855c18da3850df84ad6a49a/token/js/client/token.js#L1027
You could always hack your version to return the signature. Better yet, PRs are always welcome!
Related
I have viewed all the articles on here, and haven't done any javascript coding in the past. Hoping someone can help me.
I have a class called rank and of course the parse _User class. I have added a pointer to the _User class to the rank class (the column name is called user_rank, which allows me to give a user a rank - seems simple enough.
What I am trying to achieve, is to use Cloud Code to change a user's rank as the administrator of the app (so it's something I do in my admin app, not the user does in their app).
This is what I have, but all I get is an error 101 'Object not found'. I have no doubt I am doing this all wrong, but I have tried to piece together responses from other posts with no success.
Any help is greatly appreciated.
Updated code with Davi's change below - now throwing error schema mismatch for _User.user_rank; expected Pointer but got String
Parse.Cloud.define("setUserRank", async (request, response) => {
let { userObjectId, rankObjectId } = request.params;
const userQuery = new Parse.Query(Parse.User);
const rankQuery = new Parse.Query('rank');
// Get the user object to change the rank of
try{
let user = await userQuery.get(userObjectId, { useMasterKey: true});
let rank = await rankQuery.get(rankObjectId, { useMasterKey: true});
console.log(user);
console.log("Running");
const rankRelation = user.relation('user_rank');
rankRelation.add(user_rank);
user.save(null, { useMasterKey: true});
return ("User Rank Changed"));
} catch (err) {
throw new Error(err.message)
}
});
I think the problem happens because of this line:
const rankQuery = new Parse.Query(Parse.rank);
In the case of you custom classes, you need to pass the class name as a string:
const rankQuery = new Parse.Query('rank');
How can I get a gasFee estimate for a transaction of my custom contract?
For a normal transaction execution from the SPL library I can do so like this:
import { Transaction } from '#solana/web3.js';
const transaction = new Transaction({
recentBlockhash: recentBlockhash.blockhash,
feePayer: wallet.publicKey
}).add(
// someFunctionCall
);
const estimatedGas = await transaction.getEstimatedFee(connection);
But I do not use new Transaction() to call my custom Program's methods. It's done like:
const tx = await program.methods
.myCustomMethod(...)
.accounts(...)
.rpc();
How can I estimate the gas for the tx w/o actually calling it?
A demo example to print estimated gas cost for transaction created usign Anchor:
const txn = await program.methods
.exchange10(sBump, BNF(exchangeBal1))
.accounts({
feeRecipient: feeRecipient.publicKey,
seller: sellerPDA,
sellerTokenAccount: sellerTknAcc.address,
buyer: wallet2.publicKey,
buyerTokenAccount: buyerTknAcc.address,
tokensForSale: tokensForSalePDA,
tokenProgram: TOKEN_PROGRAM_ID,
})
.signers([wallet2])
.transaction();
txn.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
txn.feePayer = wallet2.publicKey;
console.log(await txn.getEstimatedFee(connection))
I found out you can replace .rpc() with .transaction() which will return an object of type Transaction (from #solana/web3.js).
Then you can exercise the same logic for gas estimation on that object as in the first example.
And, of course, you will need to sendAndConfirm the transaction as an extra step, because otherwise the .rpc() call was taking care of that.
Would appreciate guidance on how to obtain the data back in the variables, which was entered into splToken.createTransferInstruction(), step-by-step, from the buffer variable in the code snippet below:
var transaction = new web3.Transaction();
transaction.add(
splToken.createTransferInstruction(
fromTokenAccount,
toTokenAccount,
senderPublicKey,
amount,
[],
splToken.TOKEN_PROGRAM_ID,
)
);
// Setting the variables for the transaction
transaction.feePayer = provider.publicKey;
let blockhashObj = await connection.getRecentBlockhash();
transaction.recentBlockhash = await blockhashObj.blockhash;
// Transaction constructor initialized successfully
if(transaction) { console.log('Txn created successfully'); }
// Request creator to sign the transaction (allow the transaction)
let signed = await provider.signTransaction(transaction);
let buffer = signed.serialize();
Using web3.Transaction.from(buffer) I obtained a Transaction object - see image from the browser's console:
I need to do something with instructions[0].data, I suppose to break it into byte lengths that will allow me to repopulate from the signed transaction:
fromTokenAccount,
toTokenAccount,
senderPublicKey,
amount,
[], // would this be a variable or zero-byte?
splToken.TOKEN_PROGRAM_ID,
from the splToken.createTransferInstruction() above.
Much appreciated!
From the TransactionInstruction, you can use decodeTransferInstruction to get back the initial parameters. In your case, you can call:
let tx = web3.Transaction.from(buffer);
let decodedIx = decodeTransferInstruction(tx.instructions[0]);
console.log(decodedIx.keys.source);
console.log(decodedIx.keys.destination);
console.log(decodedIx.keys.owner);
console.log(decodedIx.data.amount);
Full source code available at: https://github.com/solana-labs/solana-program-library/blob/24baf875e9e19c26d694d28c557d33848c3a9180/token/js/src/instructions/transfer.ts#L87
I need to force re-authentication of Microsoft Graph within an MVC Core application.
The Graph object is obtained in ConfigureServices using the code segment:
var tokenAcquisition = context.HttpContext.RequestServices
.GetRequiredService<ITokenAcquisition>();
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(async (request) => {
var token = await tokenAcquisition
.GetAccessTokenForUserAsync(_scopes, user: context.Principal);
request.Headers.Authorization =
new AuthenticationHeaderValue("Bearer", token);
})
);
The problem is the token goes stale and a later call to Graph fails. Easy to trap and to put in some reauthentication code except it also fails, with a "MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call" error. Plenty of reference to this scenario online but no definitive response that I can find.
Reauthentication code in the controller is:
if (ex.InnerException.InnerException is MsalUiRequiredException)
{
string[] _scopes = _config.GetValue<string>("AzureAd:GraphScopes")?.Split(' ');
var tokenAcquisition = _http.RequestServices.GetRequiredService<ITokenAcquisition>();
_graph = new GraphServiceClient(
new DelegateAuthenticationProvider(async (request) =>
{
var options = new TokenAcquisitionOptions() { ForceRefresh = true };
var token = await tokenAcquisition.GetAccessTokenForUserAsync(_scopes, user: User, tokenAcquisitionOptions: options);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
})
);
}
Question is how to successfully force reauthentication and obtain a new Graph client?
Answering my own question, turns out it's easily handled in the Controller:
try
{
string token = await _tokenAcquisition
.GetAccessTokenForUserAsync(GraphConstants.Scopes);
return View().WithInfo("Token acquired", token);
}
catch (MicrosoftIdentityWebChallengeUserException)
{
return Challenge();
}
This code segment is from https://learn.microsoft.com/en-us/graph/tutorials/aspnet-core?tutorial-step=3
I assume that your application is forcing the user to log in and you're using that identity to get a Graph token based on the use of context.Principal:
.GetAccessTokenForUserAsync(_scopes, user: context.Principal);
When the token expires I assume the original token that was used to get in has also expired about the same time. That means that there is no user and therefore calls fail with the error that you're describing. It makes me think you need to reauthenticate before you try to get a new graph token.
However, you should monitor the token and get a new one just before it expires - silently -using the refresh token rather than a new authentication.
https://learn.microsoft.com/en-us/advertising/guides/authentication-oauth-get-tokens?view=bingads-13#refresh-accesstoken
How do you delete roles in Parse.com using Cloud Code? I checked: https://parse.com/docs/js/symbols/Parse.Role.html, and it doesn't document any destroy method.
I am creating a role for every group of members, and I'd like to get rid of the role when the group is destroyed. What is the correct way of doing so?
Have you seen:
role.getUsers().remove(user);
This one works for me:
const roles = await new Parse.Query(Parse.Role).find();
await Parse.Object.destroyAll(roles, {useMasterKey: true}};
I played around with this for hours before getting it to work by fluke (no thanks to deficient and incorrect documentation)...
This is architecturally incorrect but the only way I could hack it together was using async function with await + promise... I do not understand Parse's weird mechanics sometimes. It's a love & hate relationship!
// Get user to delete object
let userToDeleteObject = await new Parse.Query(Parse.User)
.equalTo('objectId', userToDelete)
.find({useMasterKey: true});
// Remove user from group role
let roleDeleteQuery = new Parse.Query(Parse.Role);
roleDeleteQuery.contains("name", groupName);
roleDeleteQuery.first({useMasterKey: true})
.then(function(roleObject) {
roleObject.relation("users").remove(userToDeleteObject);
roleObject.save(null, {useMasterKey: true});
});