Sending SPL tokens on solana network - reactjs

I am using solana web3.js to send SOL tokens. I am using below code to send SOL tokens to other address:
import * as web3 from '#solana/web3.js';
// ...
// later
const sendToAddress = async(param) => {
const connection = new web3.Connection(web3.clusterApiUrl('devnet'));
let accountFromSecret = web3.Keypair.fromSecretKey(param.privateKey);
let base58ToSend = new web3.PublicKey(param.toAddress);
var transaction = new web3.Transaction().add(
web3.SystemProgram.transfer({
fromPubkey: accountFromSecret.publicKey,
toPubkey: base58ToSend,
lamports: Number(param.amount), // number of SOL to send
}),
);
var signature = await web3.sendAndConfirmTransaction(connection, transaction, [
accountFromSecret,
]);
}
With this I am able to successfully send SOL.
But I also want to send other SPL tokens like Raydium (RAY), Star Atlas (ATLAS), ORBS. How do I send these SPL tokens?

Related

post xlsx file to flask route with React async/await

I have a project where I was originally using fetch for all of my requests, and my excel upload function was working fine. I recently made a lot of changes to my application because I added user login and authentication, so I am now trying to reconfigure my routes using async await in React. I am getting different errors that I don't know how to solve. Sometimes when I try to submit the uploaded file I get a 400 error for a bad request, usually saying ""The browser (or proxy) sent a request that this server could not understand.\nKeyError: 'project'". Or I am getting an error on the back-end that says "ValueError: Excel file format cannot be determined, you must specify an engine manually."
I am really confused about where the error is actually occurring because it seems to be reaching the Flask route and then failing.
This is my current request on the front-end:
const onSubmit = async (ev) => {
ev.preventDefault();
let formData = new FormData();
formData.append("project", selectedFile);
// let status = 0;
const data = await api.post("/projects", {
body: formData,
});
if (!data.ok) {
console.log(data);
console.log("error");
} else {
console.log(data);
console.log("uploaded");
}
};
and the back-end route:
#projects.route('/projects', methods=['POST'])
#authenticate(token_auth)
def request_load_pickle_sim():
fn = save_file(None, "project", "xlsx")
print(fn)
request.files["project"].save(fn)
result = process_raw_util_xl_file(fn)
claims = result['claims']
print(claims)
utilities = result['utilities']
weights = result['weights']
maxdiff_scores = result['maxdiff_scores']
data = jsonify(claims)
print(data)
mdp = MaxDiffProject()
mdp.config = MutableDict({
'claims': claims,
'utilities': utilities,
'weights': weights,
'maxdiff_scores': maxdiff_scores
})
print(mdp.config)
db.session.add(mdp)
db.session.commit()
mdp = MaxDiffProject().query.first()
project_config = mdp.config
claims = project_config['claims']
print(claims)
data = jsonify(claims)
return data
My debugger is printing the instance of the file, so it seems like the backend is receiving the file? But after that nothing is working. The file is passed to the process_raw_util_xl_file function (which is where the ValueError error is coming from). I can't figure out what the core issue is because I'm getting conflicting errors. I guess I'm just confused because it was all working fine when I had fetch requests.
The function on the backend is breaking here:
def process_raw_util_xl_file(xl_fn):
# df = pd.read_csv(xl_fn.read())
df = pd.read_excel(xl_fn) # read the excel file
print(df)
row = df.shape[0] # df.shape[0] = Number of rows, df.shape[1] = number of columns
index_col = [col for col in df if 'id' in col.lower()][0]
print(index_col)
df.set_index(index_col, inplace=True) # Setting the ID as the index
# weights = df['Weights'] if 'Weights' in df else pd.Series([1]*row) # Creating the weights array if there are weights , otherwise an array of 1's with # of rows
if 'Weights' not in df:
df['Weights'] = 1
weights = df['Weights']
df.drop('Weights', axis=1, inplace=True)
sum = weights.values.sum() # Sum of the weights
# if 'Weights' in df: df = df.drop('Weights', axis=1) # removing weights from df if they are there
rlh_cols = [col for col in df if 'rlh' in col.lower()][:1]
df = df.drop(rlh_cols, axis=1) # removing RLH from df if they are there
max_diff_scores = (e ** df) / (1 + e ** df) * 100 # exp the values of the dataframe with
utils = df
return {
"utilities": utils,
"claims": [col for col in utils],
"maxdiff_scores": max_diff_scores,
"weights": weights
}
You are posting an object as a body paramter to the server which has a content type as application/json whereas according the HTTP protocol, to post form-data the content type must be multipart/form-data. Here's how you are doing it,
let formData = new FormData();
formData.append("project", selectedFile);
// let status = 0;
const data = await api.post("/projects", {
body: formData,
});
According to the docs (at page end) you must post form data like this,
let formData = new FormData();
formData.append("project", selectedFile);
// let status = 0;
const data = await api.post("/projects", formData);
Also you cannot post body and form data at a same time within single request.

Solana SplToken web3 : How can i create address/account owned by other address/account?

I would like to create other address/accounts belonging to my initial account, the goal is to have several separate addresses and carry out transactions by paying the fees from my main accounts.
It's like the exchanges create accounts that belong to them and they make transactions between by paying the fees.
This is my example:
// BANK or Exchange
const BankaccountKeypair = web3.Keypair.fromSecretKey([160,15,25, ...]);
const BANK_wallet = splEasy.Wallet.fromKeypair(connection,BankaccountKeypair);
// Customer A (to)
const A_wallet = splEasy.Wallet.fromKeypair(connection,web3.Keypair.fromSecretKey([20,18,125, ...]));
var myToken = new splToken.Token(
connection,
new web3.PublicKey('TRmbtbEW4g.......'),
splToken.TOKEN_PROGRAM_ID,
BANK_wallet
);
// A account (to)
var A_walletAccount = await myToken.getOrCreateAssociatedAccountInfo( A_wallet.publicKey );
// B account(from)
const B_walletAccount = await myToken.createAssociatedTokenAccount( BANK_wallet.publicKey );
// transaction
var transaction = new web3.Transaction()
.add(
splToken.Token.createTransferInstruction(
splToken.TOKEN_PROGRAM_ID,
B_walletAccount.address,
A_walletAccount.address,
BANK_wallet.publicKey,
[],
0
)
);
// signature
var signature = await web3.sendAndConfirmTransaction() ....
But I got an error on:
// B account(from)
const B_walletAccount = await myToken.createAssociatedTokenAccount( BANK_wallet.publicKey );
throw new TypeError('unexpected type, use Uint8Array');
^
TypeError: unexpected type, use Uint8Array
I tried by
const B_walletAccount = await myToken.createAssociatedTokenAccount([160,15,25, ...]);
But I got:
if (!allowOwnerOffCurve && !web3_js.PublicKey.isOnCurve(owner.toBuffer())) {
^
TypeError: owner.toBuffer is not a function
When I use
getOrCreateAssociatedAccountInfo(B_wallet);
it's working but, Transaction is failed :
var transaction = new web3.Transaction()
.add(
splToken.Token.createTransferInstruction(
splToken.TOKEN_PROGRAM_ID,
B_walletAccount1.address,
A_walletAccount.address,
BANK_wallet.publicKey,
[],
2000000
)
);
// error :
Transaction simulation failed: Error processing Instruction 0: custom program error: 0x4
Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [1]
Program log: Instruction: Transfer
Program log: Error: owner does not match
*/
I need to have lot of address without SOL/lamports that I should transfer myToken between those addresses

How to get a reference to a former created Token in Solana (client side, JS)

I'm able to create a token and mint it into an spl account address.
But when I restart my program, how do I get a reference to that Token, so that I mint again?
const web3 = require("#solana/web3.js");
const splToken = require('#solana/spl-token');
const { PublicKey, Keypair, Transaction, SystemProgram, LAMPORTS_PER_SOL, sendAndConfirmTransaction, clusterApiUrl } = require("#solana/web3.js");
let secretKey = Uint8Array.from([233, 65, 11, rest of my secret]);
let fromWindowsWallet = Keypair.fromSecretKey(secretKey);
let connection = new web3.Connection(clusterApiUrl('devnet'));
(async () => {
//create my new token mint
let SWAB = await splToken.Token.createMint(
connection,
fromWindowsWallet,
fromWindowsWallet.publicKey,
fromWindowsWallet.publicKey,
2,
splToken.TOKEN_PROGRAM_ID,
);
console.log(SWAB.publicKey) // -> PublicKey {
_bn: <BN: 2643549b60882496a15407c2f1a6139dd2c4128879480b1d56fdd464550db22b>
}
// ... continue with that Token SWAB
}
So when I restart my program, how can I get a reference to the Token SWAB again? I tried:
let pubKey = new PublicKey("<BN: 6ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9>");
let SWAB = new splToken.Token(
connection,
pubKey,
splToken.TOKEN_PROGRAM_ID,
fromWindowsWallet
)
but that throws: Error: Non-base58 character
After creating the Token I can get the pubKey with:
console.log(SWAB.publicKey.toBase58()) // 3aN3KP6kQdBvTHTeK785Uuykddram97B844RoJc19VNS
Then I can get a reference to the Token like this and continue minting:
let pubKey = new PublicKey('3aN3KP6kQdBvTHTeK785Uuykddram97B844RoJc19VNS');
let SWAB = new splToken.Token(
connection,
pubKey,
splToken.TOKEN_PROGRAM_ID,
fromWindowsWallet
)
(connection and fromWindowsWallet are defined in the code of my question)

Get total amount of tokens received from a specific address using Web3.js

in a scenario, WalletA is receiving TokenB in a regular basis from AddressC.
AddressC only sends TokenB, nothing else.
in etherscan or bscscan it is simple to see how much of TokenB is received in WalletA and "from" field is there so you can do some math to get total.
How can this be done using web3? I couldn't find any relevant api call in web3 documents.
I can get total balance of TokenB in WalletA by web3.js but I need the count of tokens only sent from AddressC.
Thanks.
As per the ERC-20 standard, each token transfer emits a Transfer() event log, containing the sender address, receiver address and token amount.
You can get the past event logs using the web3js general method web3.eth.getPastLogs(), encode the inputs and decode the outputs.
Or you can supply ABI JSON of the contract (it's enough to use just the Transfer() event definition in this case) and use the web3js method web3.eth.Contract.getPastEvents(), which encodes the inputs and decodes the outputs for you based on the provided ABI JSON.
const Web3 = require('web3');
const web3 = new Web3('<provider_url>');
const walletA = '0x3cd751e6b0078be393132286c442345e5dc49699'; // sender
const tokenB = '0xdAC17F958D2ee523a2206206994597C13D831ec7'; // token contract address
const addressC = '0xd5895011F887A842289E47F3b5491954aC7ce0DF'; // receiver
// just the Transfer() event definition is sufficient in this case
const abiJson = [{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}];
const contract = new web3.eth.Contract(abiJson, tokenB);
const fromBlock = 10000000;
const toBlock = 13453500;
const blockCountIteration = 5000;
const run = async () => {
let totalTokensTranferred = 0;
for (let i = fromBlock; i <= (toBlock - blockCountIteration); i += blockCountIteration) {
//console.log("Requesting from block", i, "to block ", i + blockCountIteration - 1);
const pastEvents = await contract.getPastEvents('Transfer', {
'filter': {
'from': walletA,
'to': addressC,
},
'fromBlock': i,
'toBlock': i + blockCountIteration - 1,
});
}
for (let pastEvent of pastEvents) {
totalTokensTranferred += parseInt(pastEvent.returnValues.value);
}
console.log(totalTokensTranferred);
}
run();

Possible to exchange expired Microsoft Graph API access token for a new one?

I am authenticating to the Graph API in my Startup.cs:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = appId,
Authority = "https://login.microsoftonline.com/common/v2.0",
Scope = $"openid email profile offline_access {graphScopes}",
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false // Setting this to true prevents logging in, and is only necessary on a multi-tenant app.
},
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailedAsync,
AuthorizationCodeReceived = async (context) =>
{
// This block executes once an auth code has been sent and received.
Evar idClient = ConfidentialClientApplicationBuilder.Create(appId)
.WithRedirectUri(redirectUri)
.WithClientSecret(appSecret)
.Build();
var signedInUser = new ClaimsPrincipal(context.AuthenticationTicket.Identity);
var tokenStore = new SessionTokenStore(idClient.UserTokenCache, HttpContext.Current, signedInUser);
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(scopes, context.Code).ExecuteAsync();
var userDetails = await GraphUtility.GetUserDetailAsync(result.AccessToken);
After retrieving this access token, I store it into a class variable. The reason why I do this is so that I can retrieve it for use in one of my services (called by an API controller) that interfaces with the Graph API.
public GraphAPIServices(IDbContextFactory dbContextFactory) : base(dbContextFactory)
{
_accessToken = GraphUtility.GetGraphAPIAccessToken();
_graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMessage) =>
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
}));
}
The problem that I am running into is that after some time, this access token eventually expires. I obviously can't run Startup.cs again so there is no opportunity to retrieve a new access token.
What I would like to know is if it's possible to exchange this expired access token for a new one without the need to request that the user logs in again with their credentials?

Resources