Transfer SPL Token using Rust - rust

Is there a way to transfer SPL tokens from on wallet to another.
I have done some research and I found that I have to initialize account first using Create Associated Account and then use Token Transfer?
Is there any code examples where I can transfer tokens or a library which helps with creating account/token transfer. etc

You can directly use the spl-token crate for instructions and types used by the token program: https://docs.rs/spl-token/latest/spl_token/
If you need to create associated token accounts, you can use the spl-associated-token-account crate: https://docs.rs/spl-associated-token-account/latest/spl_associated_token_account/index.html
If you're on-chain, you can create a transfer instruction and pass it in along with the required accounts, ie:
let ix = spl_token::instruction::transfer(
token_program.key,
source.key,
destination.key,
authority.key,
&[],
amount,
)?;
invoke(
&ix,
&[source, destination, authority, token_program],
)
This was adapted from the token-swap transfer code: https://github.com/solana-labs/solana-program-library/blob/b2fad8a0781bddd90c8e9b768184f55306265cef/token-swap/program/src/processor.rs#L138
It's correct that you need to create the source and destination accounts first, and it's preferred for those to be associated token accounts. You can create them on-chain using:
let ix = spl_associated_token_account::instruction::create_associated_token_account(
payer.key,
wallet.key,
token_mint.key,
token_program.key,
);
invoke(
&ix,
&[payer, associated_token_account, wallet, token_mint, system_program, token_program, associated_token_account_program],
)
Note that all of these accounts must be sent to your program in order to perform the cross-program invocations.

Afaik theres no library but token transfer only works from account to account, theres a transfer function inside anchor which you have to invoke and pass the to and from account infos, you can transfer directly to an address beacuse you wud need account info of receiver too which u can get from a publickey but it can be done through escrow, heres a program that i wrote which sends sol to a PDA and the receiver accepts it from PDA
Github link to escrow program

Related

Is there a way from NodeJS to get Tron Blockchain transaction details?

I would need to get, passing the Transaction ID, the from/to address, the value of token transferred, and the type of token passed?
I've found so far the API from Tron Grid, i have already tried the
https://api.trongrid.io/v1/transactions/TRANSACTION_ID/events'
THis call returns the two wallet addresses, and the amount (uint256), but not the type of token passed.
Is there any way?
I also found the tronweb package, but i can't find any documentation about it.
Thank you!
You can keep map of contract addresses and token types. I'm not sure this is relevant to you.
Trongrid API has two POST endpoints for getting details by transaction id (hash).
https://api.trongrid.io/wallet/gettransactioninfobyid
https://api.trongrid.io/wallet/gettransactionbyid
the body is the same for both requests - should contains the transaction hash:
{"value": "440140edbd1e9be5a0a78605018d5803b2388e080227337b435a826b127cd5d8"}
To get the token type for transfer you can use first endpoint - trc20 transfers are in the response.log array and contain 'address' field - the hex address of contract of the token. Then you can get token info by this contract address.
You need API key to use this API. See docs for more details:
https://developers.tron.network/v3.7/reference/transaction-info-by-id
https://developers.tron.network/v3.7/reference/walletgettransactionbyid

Solana Anchor: how can a program check approved token allowance given by an user?

I am trying to port Ethereum's allowance function into Solana program,
token.allowance(msg.sender, address(this))
it seems there is no such allowance function existing in Solana SPL, or Anchor SPL... is there?
Solana SPL: https://spl.solana.com/token#authority-delegation ...
Quote "Authority delegation#
Account owners may delegate authority over some or all of their token balance using the Approve instruction. Delegated authorities may transfer or burn up to the amount they've been delegated. Authority delegation may be revoked by the Account's owner via the Revoke instruction."
...
this does not say clearly how to use such a function
https://github.com/solana-labs/solana-program-library/blob/master/token/program/src/instruction.rs#L919 ... the approve function in is Rust, but it is difficult to be used
Anchor SPL
https://docs.rs/anchor-spl/0.18.2/anchor_spl/token/struct.Approve.html
I see Anchor makes calling Solana's approve function easier. but I could not find the allowance function.
https://docs.rs/anchor-spl/0.19.0/anchor_spl/token/index.html
This is used to check token amounts on certain account. not allowance.
It seems in Solana, we do not need to check the allowance given from an user to another address... because I found this in Anchor's cashiers check test example:
// Transfer funds to the check.
let cpi_accounts = Transfer {
from: ctx.accounts.from.to_account_info().clone(),
to: ctx.accounts.vault.to_account_info().clone(),
authority: ctx.accounts.owner.clone(),
};
let cpi_program = ctx.accounts.token_program.clone();
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
token::transfer(cpi_ctx, amount)?;
That example above does not check for user's given allowance on the program.
Does that mean any Solana program can transfer any user's tokens without their consent?
Why does the approve function exist if we cannot check the allowance?
To answer your questions...
Does that mean any Solana program can transfer any user's tokens without their consent?
That would be quite a security flaw! The concept is that, when you transfer tokens, some account must sign to validate the transfer. That account may be the owner, or some pre-approved delegate. In the exsample that you've shown, authority is given as ctx.accounts.owner.clone(), which means that the owner has likely already signed the transaction. If the owner approves some amount to a delegate, and then signs with that delegate, the token program figures out that the delegate has signed, and allows the transfer.
Why does the approve function exist if we cannot check the allowance?
To check the allowance, you'll have to deserialize the account into a token Account https://docs.rs/anchor-spl/0.19.0/anchor_spl/token/struct.TokenAccount.html. You can use one of the helpers, like try_deserialize, which gives you a type that wraps spl_token::state::Account.
With your spl_token::state::Account, you can check the delegated_amount field to see how much has been approved by the user: https://github.com/solana-labs/solana-program-library/blob/8eb2c3ce60bfe943e277eb172ba8e9ce9b6bdae6/token/program/src/state.rs#L103

No such token: 'btok_1JGm2oKFR93cFUSYN2bui4Yb' when i try to create a Bank Account for Stripe Customer

Whenever i create a Bank account token using plaid/stripe integration and proceed to use this to create a Stripe bank account for my customer it keeps on returning the No Such token error.
Now i have gone through other questions posted here that suggest to check if the environments match i.e if my stripe keys are test keys and if my Plaid is in Sandbox mode.
They are both in test modes but it still fails.
PLAID_ENV = sandbox
const client = new plaid.Client({
clientID: PLAID_CLIENT_ID,
secret: PLAID_DEV_SECRET,
env: plaid.environments[PLAID_ENV],
options: {
version: '2020-09-14', // '2020-09-14' | '2019-05-29' | '2018-05-22' | '2017-03-08'
}
});```
My stripe is using the Stripe Test keys. I confirmed the accounts are linked.
Any help figuring out why it still returns this error would be appreciated
"No such..." errors are usually caused by either a mismatch in API keys (e.g. using a mixture of your test plus live keys) or by trying to access objects that exist on a different account (e.g. trying to perform an operation from your platform account on an object that was created on a connected account).

Stripe connect share card source not working

I am saving customers and their sources on my platform, and trying to create charges for my connected accounts. I am able to successfully create destination charges, but I'm having trouble with creating direct charges.
I've tried creating a token per: https://stripe.com/docs/connect/shared-customers
If I create a token using just the customer the example, the error is:
'You provided a customer without specifying a source. The default source of the customer is a source and cannot be shared from existing customers.'
Even though the documentation says that you need "The card or bank account ID for that customer, if you want to charge a specific card or bank account rather than the default".
I cannot find a parameter that lets me specify a source as well or instead of a customer.
I've tried sharing the customer's chosen source with the connected account per: https://stripe.com/docs/sources/connect#shared-card-sources
which results in the error:
'Sending credit card numbers directly to the Stripe API is generally unsafe. We suggest you use test tokens that map to the test card you are using, see https://stripe.com/docs/testing.'
I tried attaching a test token (tok_visa) to my customer, and creating a charge with that, but that had the same result.
Every time I have some success I end up with the error about sending numbers being unsafe even though I'm only ever sending Stripe's provided token or source ID's.
I've tried this:
const newToken = await stripe.tokens.create({
customer: customerId,
}, {
stripe_account: stripeAccountId,
}).catch((e) => {
console.log(e);
});
and this:
const newToken = await stripe.sources.create({
customer: customerId,
usage: 'single_use',
original_source: sourceId,
}, {
stripe_account: stripeAccountId,
}).catch((e) => {
console.log(e);
});
The only success I've had is creating the direct charge with a test token (tok_visa), completely bypassing the sharing of tokens/sources. No other combination seems to work. But that leaves me at a loss as to how to get a real shared token when I need it.
I found out I should be using sources, not tokens. And it turns out I was accidentally using the whole newToken as the source for the charge. It's working now that I'm passing the newToken.id to the charge.

Authorization in Event Hubs

I am using SAS token authentication along with device-ID (or publisher-Id) in my event Hub publisher code. But i see that it is possible to send an event to any partition ID by using "CreatePartitionedSender" client even though I have authenticated using a device-ID. Whereas I do not want two different device-Ids publishing events in same partition. Is it possible that we can add some custom "authorization" code along with the SAS authentication to allow limited partition access to any device.
The idea behind adding authorization to device and partition-Id combination was to accommodate single event-hub for multiple tenants. Please advise if I am missing anything.
Please see below the code snippet for publisher:
var publisherId = "1d8480fd-d1e7-48f9-9aa3-6e627bd38bae";
string token = SharedAccessSignatureTokenProvider.GetPublisherSharedAccessSignature(
new Uri("sb://anyhub-ns.servicebus.windows.net/"),
eventHubName, publisherId, "send",
sasKey,
new TimeSpan(0, 5, 0));
var factory = MessagingFactory.Create(ServiceBusEnvironment.CreateServiceUri("sb", "anyhub-ns", ""), new MessagingFactorySettings
{
TokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(token),
TransportType = TransportType.Amqp
});
var client = factory.CreateEventHubClient(String.Format("{0}/publishers/{1}", eventHubName, publisherId));
var message = "Event message for publisher: " + publisherId;
Console.WriteLine(message);
var eventData = new EventData(Encoding.UTF8.GetBytes(message));
await client.SendAsync(eventData);
await client.CreatePartitionedSender("5").SendAsync(eventData);
await client.CreatePartitionedSender("6").SendAsync(eventData);
I notice in your example code that you have
var connStr = ServiceBusConnectionStringBuilder.CreateUsingSharedAde...
and then have
CreateFromConnectionString(connectionString
This suggests that you may have used a Connection String containing the send key you used to generate the token rather than the limited access token. In my own tests I did not manage to connect to an EventHub using the EventHubClient, which makes an AMQP connection, with a publisher specific token. This doesn't mean it's not supported just that I got errors that made sense, and the ability to do so doesn't appear to be documented.
What is documented and has an example is making the publisher specific tokens and sending events to the EventHub using the HTTP interface. If you examine the SAS token generated you can see that the token grants access to
[namespace].servicebus.windows.net/[eventhubname]/publishers/[publisherId]
This is consistent with the documentation on the security model, and the general discussion of publisher policies in the overview. I would expect the guarantee on publisherId -> PartitionKey to hold with this interface. Thus each publisherId would have its events end up in a consistent partition.
This may be less than ideal for your multitenant system, but the code to send messages is arguably simpler and is a better match for the intended use case of per device keys. As discussed in this question you would need to do something rather dirty to get each publisher their own partition, and you would be outside the designed use cases.
Cross linking questions can be useful.
For a complete explanation on Event Hubs publisher policy refer this blog.
In short, If you want publisher policy - you will not get partitioned sender. Publisher policy is an extension to SAS security model, designed to support very high number of senders ( to a scale of million senders on event hub ).
With its current authentication model, you can not grant so fine-grained access to publishers. Authentication per partition is not currently supported as per Event Hubs Authentication and Security Model Overview.
You have to either "trust" your publishers, or think on different tenant scheme - i.e. Event Hub per tenant.

Resources