-
-
Notifications
You must be signed in to change notification settings - Fork 266
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(connect): solanaComposeTransaction method
- Loading branch information
Showing
10 changed files
with
369 additions
and
3 deletions.
There are no files selected for viewing
96 changes: 96 additions & 0 deletions
96
packages/connect-explorer/src/pages/methods/solana/solanaComposeTransaction.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { SolanaComposeTransaction } from '@trezor/connect/src/types/api/solana'; | ||
|
||
import { ParamsTable } from '../../../components/ParamsTable'; | ||
import { CommonParamsLink } from '../../../components/CommonParamsLink'; | ||
import { ApiPlayground } from '../../../components/ApiPlayground'; | ||
|
||
<ApiPlayground | ||
options={[ | ||
{ | ||
title: 'Advanced schema', | ||
method: 'solanaComposeTransaction', | ||
schema: SolanaComposeTransaction, | ||
}, | ||
]} | ||
/> | ||
|
||
export const paramDescriptions = { | ||
path: 'minimum length is `2`. [read more](/details/path)', | ||
fromAddress: 'Sender address', | ||
toAddress: | ||
'Recipient address. In case of token transfer, this still means the owner address of the token account. The associated token account is created automatically.', | ||
amount: 'Amount to send in decimal string format', | ||
priorityFees: | ||
'Fee configuration. If not set, it defaults to hardcoded values. It is recommended to simulate the transaction using `blockchainEstimateFee`', | ||
token: 'Token details in case of token transfer', | ||
blockHash: 'Recent Block hash', | ||
lastValidBlockHeight: 'Recent Block height', | ||
coin: '"SOL" for mainnet (default), "DSOL" for devnet', | ||
identity: "Blockchain connection identity. It's used to separate multiple connections.", | ||
}; | ||
|
||
## Solana: Compose transaction | ||
|
||
Compose a Solana transfer transaction that can be later signed on device using [solanaSignTransaction](/methods/solana/solanaSignTransaction/). | ||
|
||
The transaction may be a native SOL transfer or a token transfer. | ||
|
||
```javascript | ||
const result = await TrezorConnect.solanaComposeTransaction(params); | ||
``` | ||
|
||
### Params | ||
|
||
<CommonParamsLink /> | ||
|
||
#### SolanaComposeTransaction | ||
|
||
<ParamsTable schema={SolanaComposeTransaction} descriptions={paramDescriptions} /> | ||
|
||
### Examples | ||
|
||
```javascript | ||
TrezorConnect.solanaComposeTransaction({ | ||
fromAddress: '...', | ||
toAddress: '...', | ||
amount: '0.1', | ||
blockHash: '...', | ||
lastValidBlockHeight: 123456, | ||
coin: 'SOL', | ||
}); | ||
``` | ||
|
||
### Result | ||
|
||
[SolanaComposedTransaction type](https://github.com/trezor/trezor-suite/blob/develop/packages/connect/src/types/api/solana/index.ts) | ||
|
||
```javascript | ||
{ | ||
success: true, | ||
payload: { | ||
serializedTx: string, | ||
additionalInfo: { | ||
isCreatingAccount: boolean, | ||
// in case of token transfer: | ||
newTokenAccountProgramName: "spl-token" | "spl-token-2022", | ||
tokenAccountInfo: { | ||
baseAddress: string, | ||
tokenProgram: string, | ||
tokenMint: string, | ||
tokenAccount: string, | ||
}, | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Error | ||
|
||
```javascript | ||
{ | ||
success: false, | ||
payload: { | ||
error: string // error message | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
97 changes: 97 additions & 0 deletions
97
packages/connect/e2e/__fixtures__/solanaComposeTransaction.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
export default { | ||
method: 'solanaComposeTransaction', | ||
setup: { | ||
mnemonic: undefined, // device is not used in this test case | ||
}, | ||
tests: [ | ||
{ | ||
description: 'Basic SOL transfer', | ||
params: { | ||
fromAddress: 'ANctUhC7YZPueiv4T8bkDcHYEAJ7Hwoxhvgnr2QkF8uR', | ||
toAddress: '5Q9c3XoBef8BYA5RzSmogWnRrQas6HPwYuo4AYPafpom', | ||
amount: '0.01', | ||
blockHash: 'BXim2ZLR2UZ4JQxhNGaGngbRaySWej4x8zqaw7TJ4GLo', | ||
lastValidBlockHeight: 290999279, | ||
coin: 'sol', | ||
}, | ||
result: { | ||
serializedTx: | ||
'0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010002048b42f51ed008e27e643818f0503bdfeb6535dc815e3a9fd41a7ce42344f888dc415cd5ca15bbbbcf07713fe3f690ebaab81c9cfa8f8a95f91b17deabb953b83400000000000000000000000000000000000000000000000000000000000000000306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a400000009c7382bc11ef07feb1a080bc78d2f7f6906ae7cb7c389057fd99ae3e97c811e00303000502400d030003000903a086010000000000020200010c020000008096980000000000', | ||
additionalInfo: { | ||
isCreatingAccount: false, | ||
}, | ||
}, | ||
}, | ||
{ | ||
description: 'SOL token transfer', | ||
params: { | ||
fromAddress: 'ANctUhC7YZPueiv4T8bkDcHYEAJ7Hwoxhvgnr2QkF8uR', | ||
toAddress: '5Q9c3XoBef8BYA5RzSmogWnRrQas6HPwYuo4AYPafpom', | ||
amount: '1', | ||
token: { | ||
mint: 'HBoNJ5v8g71s2boRivrHnfSB5MVPLDHHyVjruPfhGkvL', | ||
program: 'spl-token', | ||
decimals: 1, | ||
accounts: [ | ||
{ | ||
publicKey: '6EjZ73R3oEUHQL4zczkx3pRD3acysP3ug7hwMAdzdtNQ', | ||
balance: '30', | ||
}, | ||
], | ||
}, | ||
blockHash: 'HaVyjCbyqQa2sbwXTLKskNretcsRVws6VEBYP6xZMKm', | ||
lastValidBlockHeight: 290999384, | ||
coin: 'sol', | ||
}, | ||
result: { | ||
serializedTx: | ||
'0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010003068b42f51ed008e27e643818f0503bdfeb6535dc815e3a9fd41a7ce42344f888dc4dcf19bed853ae158e8c5ad250530e09f8fb4b82bee35ec1a3c89d30b2b183f559e1abe20307a4f7ed6e586aea367e24b7d9f5c6d4d0969a72d9d0dd3436abe10306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a40000000f07f39f63a83ade085f851ca297f39b6993fd7b0fccba5e3aff7511fad40da3906ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9043f2bcc70fd3420cfbdcdd1da062d993dd46072ab2da56948d6ba1006138da00303000502400d030003000903a0860100000000000504010402000a0c0a0000000000000001', | ||
additionalInfo: { | ||
isCreatingAccount: false, | ||
tokenAccountInfo: { | ||
baseAddress: '5Q9c3XoBef8BYA5RzSmogWnRrQas6HPwYuo4AYPafpom', | ||
tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', | ||
tokenMint: 'HBoNJ5v8g71s2boRivrHnfSB5MVPLDHHyVjruPfhGkvL', | ||
tokenAccount: '73rsTqUoMd34Y3YwXtu4An2LkncLF9SeDY6TGUFfksfe', | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
description: 'SOL token transfer - new account', | ||
params: { | ||
fromAddress: 'ANctUhC7YZPueiv4T8bkDcHYEAJ7Hwoxhvgnr2QkF8uR', | ||
toAddress: 'Aey9o8JXzTcQdjJVrV4Y56xzt5qHkLPWLgAQmaodUojm', | ||
amount: '1', | ||
token: { | ||
mint: 'HBoNJ5v8g71s2boRivrHnfSB5MVPLDHHyVjruPfhGkvL', | ||
program: 'spl-token', | ||
decimals: 1, | ||
accounts: [ | ||
{ | ||
publicKey: '6EjZ73R3oEUHQL4zczkx3pRD3acysP3ug7hwMAdzdtNQ', | ||
balance: '30', | ||
}, | ||
], | ||
}, | ||
blockHash: 'FuVcUvTCAEAefjSb7twrdnM98KFuxPhe9idGNZ3jb4zT', | ||
lastValidBlockHeight: 290999698, | ||
coin: 'sol', | ||
}, | ||
result: { | ||
serializedTx: | ||
'0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010006098b42f51ed008e27e643818f0503bdfeb6535dc815e3a9fd41a7ce42344f888dc297187b6006964cafcb0a71cdf7d16cf80563debd388a20ed2beae6de8f0e23d4dcf19bed853ae158e8c5ad250530e09f8fb4b82bee35ec1a3c89d30b2b183f500000000000000000000000000000000000000000000000000000000000000008f7329c364a8e1d0376058cc672d81ce5ff8585a46c0adcb918ca7e3f0dc82a08c97258f4e2489f1bb3d1029148e0d830b5a1399daff1084048e7bd8dbe9f8590306466fe5211732ffecadba72c39be7bc8ce5bbc5f7126b2c439b3a40000000f07f39f63a83ade085f851ca297f39b6993fd7b0fccba5e3aff7511fad40da3906ddf6e1d765a193d9cbe146ceeb79ac1cb485ed5f5b37913a8cf5857eff00a9dd762ba278d68a101267dbdcd6b7e6e1a84e080acdf553ba8caf0d072fbb6d200406000502400d030006000903a0860100000000000506000104070308000804020701000a0c0a0000000000000001', | ||
additionalInfo: { | ||
isCreatingAccount: true, | ||
newTokenAccountProgramName: 'spl-token', | ||
tokenAccountInfo: { | ||
baseAddress: 'Aey9o8JXzTcQdjJVrV4Y56xzt5qHkLPWLgAQmaodUojm', | ||
tokenProgram: 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', | ||
tokenMint: 'HBoNJ5v8g71s2boRivrHnfSB5MVPLDHHyVjruPfhGkvL', | ||
tokenAccount: '3nn86A71hFhoqYgPqLWSXdoxUwtfJNWoevBQUouAjSEg', | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export { default as solanaComposeTransaction } from './solanaComposeTransaction'; | ||
export { default as solanaGetAddress } from './solanaGetAddress'; | ||
export { default as solanaGetPublicKey } from './solanaGetPublicKey'; | ||
export { default as solanaSignTransaction } from './solanaSignTransaction'; |
117 changes: 117 additions & 0 deletions
117
packages/connect/src/api/solana/api/solanaComposeTransaction.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { Assert } from '@trezor/schema-utils'; | ||
import { SYSTEM_PROGRAM_PUBLIC_KEY } from '@trezor/blockchain-link-utils/src/solana'; | ||
|
||
import { AbstractMethod } from '../../../core/AbstractMethod'; | ||
import { SolanaComposeTransaction as SolanaComposeTransactionSchema } from '../../../types/api/solana'; | ||
import { ERRORS } from '../../../constants'; | ||
import { CoinInfo } from '../../../types'; | ||
import { initBlockchain, isBackendSupported } from '../../../backend/BlockchainLink'; | ||
import { getCoinInfo } from '../../../data/coinInfo'; | ||
import { | ||
buildTokenTransferTransaction, | ||
buildTransferTransaction, | ||
dummyPriorityFeesForFeeEstimation, | ||
fetchAccountOwnerAndTokenInfoForAddress, | ||
} from '../solanaUtils'; | ||
|
||
type SolanaComposeTransactionParams = SolanaComposeTransactionSchema & { | ||
coinInfo: CoinInfo; | ||
}; | ||
|
||
export default class SolanaComposeTransaction extends AbstractMethod< | ||
'solanaComposeTransaction', | ||
SolanaComposeTransactionParams | ||
> { | ||
init() { | ||
this.useDevice = false; | ||
this.useUi = false; | ||
|
||
const { payload } = this; | ||
|
||
// validate bundle type | ||
Assert(SolanaComposeTransactionSchema, payload); | ||
|
||
const coinInfo = getCoinInfo(payload.coin || 'sol'); | ||
if (!coinInfo) { | ||
throw ERRORS.TypedError('Method_UnknownCoin'); | ||
} | ||
// validate backend | ||
isBackendSupported(coinInfo); | ||
|
||
this.params = { | ||
coinInfo, | ||
...payload, | ||
}; | ||
} | ||
|
||
get info() { | ||
return 'Compose Solana transaction'; | ||
} | ||
|
||
async run() { | ||
const backend = await initBlockchain( | ||
this.params.coinInfo, | ||
this.postMessage, | ||
this.params.identity, | ||
); | ||
|
||
const [recipientAccountOwner, recipientTokenAccounts] = this.params.token | ||
? await fetchAccountOwnerAndTokenInfoForAddress( | ||
backend, | ||
this.params.toAddress, | ||
this.params.token.mint, | ||
this.params.token.program, | ||
) | ||
: [undefined, undefined]; | ||
|
||
const tokenTransferTxAndDestinationAddress = | ||
this.params.token && this.params.token.accounts | ||
? await buildTokenTransferTransaction( | ||
this.params.fromAddress, | ||
this.params.toAddress, | ||
recipientAccountOwner || SYSTEM_PROGRAM_PUBLIC_KEY, // toAddressOwner | ||
this.params.token.mint, | ||
this.params.amount || '0', | ||
this.params.token.decimals, | ||
this.params.token.accounts, | ||
recipientTokenAccounts, | ||
this.params.blockHash, | ||
this.params.lastValidBlockHeight, | ||
this.params.priorityFees || dummyPriorityFeesForFeeEstimation, | ||
this.params.token.program, | ||
) | ||
: undefined; | ||
|
||
if (this.params.token && !tokenTransferTxAndDestinationAddress) | ||
throw ERRORS.TypedError('Method_InvalidParameter', 'Token accounts not found'); | ||
|
||
const tx = tokenTransferTxAndDestinationAddress | ||
? tokenTransferTxAndDestinationAddress.transaction | ||
: await buildTransferTransaction( | ||
this.params.fromAddress, | ||
this.params.toAddress, | ||
this.params.amount, | ||
this.params.blockHash, | ||
this.params.lastValidBlockHeight, | ||
this.params.priorityFees || dummyPriorityFeesForFeeEstimation, | ||
); | ||
|
||
const isCreatingAccount = | ||
this.params.token && | ||
recipientTokenAccounts === undefined && | ||
// if the recipient account has no owner, it means it's a new account and needs the token account to be created | ||
(recipientAccountOwner === SYSTEM_PROGRAM_PUBLIC_KEY || recipientAccountOwner == null); | ||
const newTokenAccountProgramName = isCreatingAccount | ||
? this.params.token?.program | ||
: undefined; | ||
|
||
return { | ||
serializedTx: tx.serialize(), | ||
additionalInfo: { | ||
isCreatingAccount: !!isCreatingAccount, | ||
newTokenAccountProgramName, | ||
tokenAccountInfo: tokenTransferTxAndDestinationAddress?.tokenAccountInfo, | ||
}, | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.