How to integrate contract (program) with web3 in Solana? - solana
I am using #solana/web3.js library and have tested to create new account and get balance.
Now I am going to integrate the contract (Raydium Liqudity PoolV4) with web3.
I have googled and can not find good material to learn.
Can you help me how to integrate the contract in solana using web3?
Thanks.
If you want to integrate with a smart contract, you have to know the source of the smart contract. The program will give you information on how to create the instructions for your transactions.
Let's look at Raydium. They're closed source program-side, but from their client-side code.
We can see that the dataLayout is:
const dataLayout = struct([u8('instruction'), nu64('amountIn'), nu64('minAmountOut')])
That tells us the the swap instruction takes in a u64 amountIn and u64 minAmountOut. nu64 is u64 on the program-side.
Likely a lot like the spl-swap swap instruction
pub struct Swap {
/// SOURCE amount to transfer, output to DESTINATION is based on the exchange rate
pub amount_in: u64,
/// Minimum amount of DESTINATION token to output, prevents excessive slippage
pub minimum_amount_out: u64,
}
We can then see that the data is encoded with instruction: 9, meaning the swap instruction is the 9th instruction on the program.
const data = Buffer.alloc(dataLayout.span)
dataLayout.encode(
{
instruction: 9,
amountIn,
minAmountOut
},
data
)
What the above does is allocates the data buffer and encodes it with your parameters so that the transaction executes the right transaction.
So the Rust program would look something like this:
pub enum RaydiumInstructions {
/** 0 **/Instruction0 (/**/),
/** 1 **/Instruction1 (/**/),
/** 2 **/Instruction2 (/**/),
/** 3 **/Instruction3 (/**/),
/** 4 **/Instruction4 (/**/),
/** 5 **/Instruction5 (/**/),
/** 6 **/Instruction6 (/**/),
/** 7 **/Instruction7 (/**/),
/** 8 **/Instruction8 (/**/),
/** 9 **/Swap (/**/)
}
We need to know the accounts required by this instruction to send with the transaction. If you check spl-swap, it lays out exactly what accounts, order, and whether they're a signer or writable. 11 accounts.
/// 0. `[]` Token-swap
/// 1. `[]` swap authority
/// 2. `[]` user transfer authority
/// 3. `[writable]` token_(A|B) SOURCE Account, amount is transferable by user transfer authority,
/// 4. `[writable]` token_(A|B) Base Account to swap INTO. Must be the SOURCE token.
/// 5. `[writable]` token_(A|B) Base Account to swap FROM. Must be the DESTINATION token.
/// 6. `[writable]` token_(A|B) DESTINATION Account assigned to USER as the owner.
/// 7. `[writable]` Pool token mint, to generate trading fees
/// 8. `[writable]` Fee account, to receive trading fees
/// 9. `[]` Token program id
/// 10. `[optional, writable]` Host fee account to receive additional trading fees
Swap(Swap),
You can see in Raydium's front end they list all the accounts for the transaction:
const keys = [
// spl token
{ pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
// amm
{ pubkey: ammId, isSigner: false, isWritable: true },
{ pubkey: ammAuthority, isSigner: false, isWritable: false },
{ pubkey: ammOpenOrders, isSigner: false, isWritable: true },
{ pubkey: ammTargetOrders, isSigner: false, isWritable: true },
{ pubkey: poolCoinTokenAccount, isSigner: false, isWritable: true },
{ pubkey: poolPcTokenAccount, isSigner: false, isWritable: true },
// serum
{ pubkey: serumProgramId, isSigner: false, isWritable: false },
{ pubkey: serumMarket, isSigner: false, isWritable: true },
{ pubkey: serumBids, isSigner: false, isWritable: true },
{ pubkey: serumAsks, isSigner: false, isWritable: true },
{ pubkey: serumEventQueue, isSigner: false, isWritable: true },
{ pubkey: serumCoinVaultAccount, isSigner: false, isWritable: true },
{ pubkey: serumPcVaultAccount, isSigner: false, isWritable: true },
{ pubkey: serumVaultSigner, isSigner: false, isWritable: false },
{ pubkey: userSourceTokenAccount, isSigner: false, isWritable: true },
{ pubkey: userDestTokenAccount, isSigner: false, isWritable: true },
{ pubkey: userOwner, isSigner: true, isWritable: false }
]
So the next step is to track down all these accounts to send via the transaction.
Finally we add these to a transaction object and broadcast!
let transaction = new Transaction().add(new TransactionInstruction({
keys,
programId,
data
})
await sendTransaction(connection, wallet, transaction)
Related
Access Spock data provider variable from inside where: block
I'm trying to access a where block variable from within the where block and it is not working. I'm thinking Spock doesn't allow this, but thought I'd give it a shot and see if anyone knows how to do it. where: testNumber << Stream.iterate(1, n -> n).iterator() test << Stream.generate(() -> { testNumber > 15 }).iterator() Result: No such property: testNumber for class If this isn't possible and someone has an alternative way to accomplish something similar I'm open to that. Basically I'm trying to make this test easier to manage, because keeping track of multiple arrays of 15-20 booleans is a bit of a pain: testNumber << [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] post << [false, false, false, false, true, true, true, true, true, true, true, true, true, true, true, true] postWeekend << [true, true, true, true, true, true, false, false, false, false, false, false, false, false, false] dividendReinvested << [true, false, true, false, true, true, false, true, true, true, true, true, true, true, true] createCCB << [false, false, false, false, false, false, false, false, false, false, false, false, false, false, true] ntd << [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false] But many of them I can set up based on the test number instead, if I can access it (and having the test number available also makes it easy to determine which test failed).
It looks like you want to calculate something based on testNumber. You can use data variables for that. Another problem is that you are using an infinite stream, which will not terminate before the jvm will run out of memory. So you need to either use .limit(20) or just use a groovy range to define it more succinctly. import spock.lang.* class ASpec extends Specification { def "hello world"() { expect: testNumber > 15 == test where: testNumber << (1..20) test = testNumber > 15 } } Try it in the Groovy Web Console. If that isn't what you wanted then you should update your question as #kriegaex suggested to tell us what you actually want to achieve.
Please do not accept this answer, Leonard's one solved the original problem. I am just presenting some more details. The Spock manual explains how to access other data variables inside a where block. Additionally, if in another situation you only need the iteration index in the unrolled method name, but not inside the feature method itself, you can use #iterationIndex. The count starts at index 0. Here is an example showing you both: package de.scrum_master.stackoverflow.q70661506 import spock.lang.Shared import spock.lang.Specification class ReferringToDataTableVariablesTest extends Specification { #Shared final n = 8 def "feature [#iterationIndex]: #testNumber, #testRange"() { println "$testNumber, $testRange, ${testClosure()}" expect: true where: testNumber << (1..n) testRange = testNumber + 3..2 * testNumber testClosure = { -> testNumber / 2 > 2 } } } Try it in the Groovy Web Console. In my IDE, running the test looks like this:
The accounts must be put with some sequence or can be random when initiate a TransactionInstruction?
Here it is, we have a account list when create TransactionInstruction. So the list could have a random order? or it must follow some specific order? const keys = [ { pubkey: key1, isSigner: true, isWritable: true, }, { pubkey: key2, isSigner: false, isWritable: true, }, ... ]; new TransactionInstruction({ keys, programId: PROGRAM_ID, data: txnData, }),
The list of accounts must be in the order expected by the program. For example, during a CreateAccount instruction, you have the from account and the new account, defined in that order: https://github.com/solana-labs/solana/blob/c8f76b8bd05c9557123dd5695b3b809e01fe9ccd/web3.js/src/system-program.ts#L655 When processing the instruction, the runtime will take the first account as the from account, and the second account as the new account: https://github.com/solana-labs/solana/blob/c8f76b8bd05c9557123dd5695b3b809e01fe9ccd/runtime/src/system_instruction_processor.rs#L284
Angular 8 multiple targets in proxy.conf.json with context set
so my current configuration is as follows: I'm using a context array in order to group multiple paths to the same target const TARGET_URL1 = 'https://target-url-1.xyz'; const PROXY_CONFIG = [ { context: [ '/api/link1', '/api/link2', ], target: TARGET_URL1, secure: false, changeOrigin: true, ws: true, }, ]; But right now, I need a new target for a new context path and I can't find any example on how to implement while keeping the context.
The correct way of implementation is to duplicate the whole object and change your context and targets: const TARGET_URL1 = 'https://target-url-1.xyz'; const TARGET_URL2 = 'https://target-url-2.xyz'; const PROXY_CONFIG = [ { context: [ '/api/link1', '/api/link2', ], target: TARGET_URL1, secure: false, changeOrigin: true, ws: true, }, { context: [ '/api/new-different-link', ], target: TARGET_URL2, secure: false, changeOrigin: true, }, ];
Property 'app' does not exist on type 'cy & EventEmitter'
Source code from Cypress on Rails // spec/cypress/support/on-rails.ts Cypress.Commands.add('app', function (name, command_options) { return cy .appCommands({ name: name, options: command_options }) .then((body) => { return body[0]; }); }); spec/cypress/tsconfig.json { "compilerOptions": { "strict": true, "target": "es5", "lib": ["es6", "dom"], "module": "es6", "moduleResolution": "node", "sourceMap": false, "types": ["cypress"], "downlevelIteration": true, "allowSyntheticDefaultImports": true, "esModuleInterop": true }, "include": ["**/*.ts"] } Results in Property 'app' does not exist on type 'cy & EventEmitter'.
Rather old, but I recently ran across this issue. The documents show a way to deal with Commands. Here is a link to their document: https://docs.cypress.io/guides/tooling/typescript-support#Adding-child-or-dual-commands cypress/support/index.ts // load type definitions that come with Cypress module /// <reference types="cypress" /> declare global { namespace Cypress { interface Chainable { /** * Custom command to type a few random words into input elements * #param count=3 * #example cy.get('input').typeRandomWords() */ typeRandomWords( count?: number, options?: Partial<TypeOptions> ): Chainable<Element> } } } cypress/support/index.ts Cypress.Commands.add('typeRandomWords', { prevSubject: 'element' }, ( subject /* :JQuery<HTMLElement> */, count = 3, options? ) => { return cy.wrap(subject).type(generateRandomWords(count), options) })
Using variables from Struts2 with ReactJS
So here`s the deal. At my workplace, we are trying to introduce ReactJS components in our web app (JSP/Struts2 etc). So far I've built a component that is supposed to display a tree based on an object, here's a sample: export default { name: 'Global', nodeid: 99, toggled: true, children: [ { name: 'Mid Node', nodeid: 0, chosen: false, pushed: false, toggled: false, children: [ { name: 'Lower Node', nodeid: 1, chosen: false, pushed: false, toggled: false, children: [{ name : "Low Child 1", pushed: false, toggled: false, chosen:false }] } ] } ] }; What I want to do is receive this from a struts action response, rather than having it hard coded to a file which is what I did in my example. import React from 'react'; import TreeComponent from 'proj-1/TreeComponent'; import HierarchyJson from './internal/Data'; export default function ExampleTreeComponent() { return <TreeComponent hierarchyJson={HierarchyJson} functionMode={2} htmlId="tree1"/> } I've seen a ton of posts where spring is used, but I don't know what are my options in this case. I don't want to have to write an AJAX call to get the data after my JSP page has already rendered.