feat: add associated token account

This commit is contained in:
bartosz-lipinski 2021-03-08 21:16:08 -06:00
parent 2820b3f22e
commit c0f8f94108
6 changed files with 147 additions and 35 deletions

View File

@ -0,0 +1,5 @@
import { ASSET_CHAIN } from "../../models/bridge/constants";
export const TokenDisplay = ({ asset, chain }: { asset: string, chain: ASSET_CHAIN }) => {
return '';
}

View File

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useState } from 'react';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { Card, notification, Spin, Button } from 'antd';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import { LABELS } from '../../constants';

View File

@ -56,7 +56,7 @@ export const EthereumProvider: FunctionComponent = ({children}) => {
logoURI: val.logoURI ? val.logoURI?.replace('ipfs://', 'https://cloudflare-ipfs.com/ipfs/') : ` https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/${val.address}/logo.png `,
tags: val.tags ? [...val.tags, extraTag] : [extraTag]
};
acc.set(val.address, item);
acc.set(val.address.toLowerCase(), item);
return acc;
}, map));

View File

@ -8,6 +8,9 @@ import {
cache,
TokenAccountParser,
ParsedAccount,
formatNumber,
formatAmount,
createAssociatedTokenAccountInstruction,
} from '@oyster/common';
import { ethers } from 'ethers';
@ -23,7 +26,6 @@ import {
PublicKey,
TransactionInstruction,
} from '@solana/web3.js';
import { createTokenAccount } from '@oyster/common/dist/lib/actions';
import { AccountInfo, AccountLayout } from '@solana/spl-token';
export interface ProgressUpdate {
@ -92,11 +94,10 @@ export const transfer = async (
return;
}
const multiplier = ethers.utils
.bigNumberify(10)
.pow(ethers.utils.bigNumberify(request.info.decimals));
let amountBN = ethers.utils.bigNumberify(request.amount).mul(multiplier);
request.amountBN = amountBN;
request.amountBN = ethers.utils.parseUnits(
formatAmount(request.amount, 9),
request.info.decimals,
);
return steps.prepare(request);
},
@ -142,6 +143,8 @@ export const transfer = async (
programIds().associatedToken,
)
)[0];
console.log('Recipient: ', recipient.toBase58());
request.recipient = recipient.toBuffer();
const accounts = await getMultipleAccounts(
@ -149,6 +152,7 @@ export const transfer = async (
[mintKey.toBase58(), recipient.toBase58()],
'single',
);
debugger;
const instructions: TransactionInstruction[] = [];
const signers: Account[] = [];
@ -166,15 +170,12 @@ export const transfer = async (
}
if (!accounts.array[1]) {
createTokenAccount(
createAssociatedTokenAccountInstruction(
instructions,
recipient,
wallet.publicKey,
wallet.publicKey,
await connection.getMinimumBalanceForRentExemption(
AccountLayout.span,
),
mintKey,
wallet.publicKey,
signers,
);
}

View File

@ -1,6 +1,16 @@
import { AccountLayout, MintLayout, Token } from '@solana/spl-token';
import { Account, PublicKey, SystemProgram, TransactionInstruction } from '@solana/web3.js';
import { TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT } from '../utils/ids';
import {
Account,
PublicKey,
SystemProgram,
SYSVAR_RENT_PUBKEY,
TransactionInstruction,
} from '@solana/web3.js';
import {
SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
TOKEN_PROGRAM_ID,
WRAPPED_SOL_MINT,
} from '../utils/ids';
import { TokenAccount } from '../models/account';
import { cache, TokenAccountParser } from '../contexts/accounts';
@ -10,17 +20,37 @@ export function ensureSplAccount(
toCheck: TokenAccount,
payer: PublicKey,
amount: number,
signers: Account[]
signers: Account[],
) {
if (!toCheck.info.isNative) {
return toCheck.pubkey;
}
const account = createUninitializedAccount(instructions, payer, amount, signers);
const account = createUninitializedAccount(
instructions,
payer,
amount,
signers,
);
instructions.push(Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, WRAPPED_SOL_MINT, account, payer));
instructions.push(
Token.createInitAccountInstruction(
TOKEN_PROGRAM_ID,
WRAPPED_SOL_MINT,
account,
payer,
),
);
cleanupInstructions.push(Token.createCloseAccountInstruction(TOKEN_PROGRAM_ID, account, payer, payer, []));
cleanupInstructions.push(
Token.createCloseAccountInstruction(
TOKEN_PROGRAM_ID,
account,
payer,
payer,
[],
),
);
return account;
}
@ -32,7 +62,7 @@ export function createTempMemoryAccount(
payer: PublicKey,
signers: Account[],
owner: PublicKey,
space = DEFAULT_TEMP_MEM_SPACE
space = DEFAULT_TEMP_MEM_SPACE,
) {
const account = new Account();
instructions.push(
@ -43,7 +73,7 @@ export function createTempMemoryAccount(
lamports: 0,
space: space,
programId: owner,
})
}),
);
signers.push(account);
@ -55,7 +85,7 @@ export function createUninitializedMint(
instructions: TransactionInstruction[],
payer: PublicKey,
amount: number,
signers: Account[]
signers: Account[],
) {
const account = new Account();
instructions.push(
@ -65,7 +95,7 @@ export function createUninitializedMint(
lamports: amount,
space: MintLayout.span,
programId: TOKEN_PROGRAM_ID,
})
}),
);
signers.push(account);
@ -77,7 +107,7 @@ export function createUninitializedAccount(
instructions: TransactionInstruction[],
payer: PublicKey,
amount: number,
signers: Account[]
signers: Account[],
) {
const account = new Account();
instructions.push(
@ -87,7 +117,7 @@ export function createUninitializedAccount(
lamports: amount,
space: AccountLayout.span,
programId: TOKEN_PROGRAM_ID,
})
}),
);
signers.push(account);
@ -95,17 +125,77 @@ export function createUninitializedAccount(
return account.publicKey;
}
export function createAssociatedTokenAccountInstruction(
instructions: TransactionInstruction[],
associatedTokenAddress: PublicKey,
payer: PublicKey,
walletAddress: PublicKey,
splTokenMintAddress: PublicKey,
) {
const keys = [
{
pubkey: payer,
isSigner: true,
isWritable: true,
},
{
pubkey: associatedTokenAddress,
isSigner: false,
isWritable: true,
},
{
pubkey: walletAddress,
isSigner: false,
isWritable: false,
},
{
pubkey: splTokenMintAddress,
isSigner: false,
isWritable: false,
},
{
pubkey: SystemProgram.programId,
isSigner: false,
isWritable: false,
},
{
pubkey: TOKEN_PROGRAM_ID,
isSigner: false,
isWritable: false,
},
{
pubkey: SYSVAR_RENT_PUBKEY,
isSigner: false,
isWritable: false,
},
];
instructions.push(
new TransactionInstruction({
keys,
programId: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
data: Buffer.from([]),
}),
);
}
export function createTokenAccount(
instructions: TransactionInstruction[],
payer: PublicKey,
accountRentExempt: number,
mint: PublicKey,
owner: PublicKey,
signers: Account[]
signers: Account[],
) {
const account = createUninitializedAccount(instructions, payer, accountRentExempt, signers);
const account = createUninitializedAccount(
instructions,
payer,
accountRentExempt,
signers,
);
instructions.push(Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, account, owner));
instructions.push(
Token.createInitAccountInstruction(TOKEN_PROGRAM_ID, mint, account, owner),
);
return account;
}
@ -119,18 +209,18 @@ export function findOrCreateAccountByMint(
accountRentExempt: number,
mint: PublicKey, // use to identify same type
signers: Account[],
excluded?: Set<string>
excluded?: Set<string>,
): PublicKey {
const accountToFind = mint.toBase58();
const account = cache
.byParser(TokenAccountParser)
.map((id) => cache.get(id))
.map(id => cache.get(id))
.find(
(acc) =>
acc =>
acc !== undefined &&
acc.info.mint.toBase58() === accountToFind &&
acc.info.owner.toBase58() === owner.toBase58() &&
(excluded === undefined || !excluded.has(acc.pubkey.toBase58()))
(excluded === undefined || !excluded.has(acc.pubkey.toBase58())),
);
const isWrappedSol = accountToFind === WRAPPED_SOL_MINT.toBase58();
@ -139,10 +229,25 @@ export function findOrCreateAccountByMint(
toAccount = account.pubkey;
} else {
// creating depositor pool account
toAccount = createTokenAccount(instructions, payer, accountRentExempt, mint, owner, signers);
toAccount = createTokenAccount(
instructions,
payer,
accountRentExempt,
mint,
owner,
signers,
);
if (isWrappedSol) {
cleanupInstructions.push(Token.createCloseAccountInstruction(TOKEN_PROGRAM_ID, toAccount, payer, payer, []));
cleanupInstructions.push(
Token.createCloseAccountInstruction(
TOKEN_PROGRAM_ID,
toAccount,
payer,
payer,
[],
),
);
}
}

View File

@ -1,4 +1,5 @@
export * as actions from './actions';
export * from './actions';
export * as components from './components';
export * from './components'; // Allow direct exports too
export * as constants from './constants';