Skip to content

Commit

Permalink
create ATA fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
kev1n-peters committed Mar 19, 2024
1 parent 5e88a94 commit ee1a23c
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 47 deletions.
67 changes: 39 additions & 28 deletions wormhole-connect/src/routes/cctpManual/chains/evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ import {
import { BigNumber, ethers, providers, utils } from 'ethers';
import { getNativeVersionOfToken } from 'store/transferInput';
import { getTokenById, getTokenDecimals } from 'utils';
import { PayloadType, isEvmChain, solanaContext, wh } from 'utils/sdk';
import {
PayloadType,
isEvmChain,
solanaContext,
toChainId,
toChainName,
} from 'utils/sdk';
import {
ManualCCTPMessage,
SignedMessage,
Expand All @@ -23,6 +29,7 @@ import {
getNonce,
} from '../utils';
import ManualCCTP from './abstract';
import config from 'config';

export default class ManualCCTPEvmImpl
implements ManualCCTP<providers.TransactionReceipt>
Expand All @@ -35,23 +42,24 @@ export default class ManualCCTPEvmImpl
recipientChain: ChainName | ChainId,
recipientAddress: string,
): Promise<providers.TransactionReceipt> {
const fromChainId = wh.toChainId(sendingChain);
const fromChainName = wh.toChainName(sendingChain);
const fromChainId = toChainId(sendingChain);
const fromChainName = toChainName(sendingChain);
const decimals = getTokenDecimals(fromChainId, token);
const parsedAmt = utils.parseUnits(amount, decimals);

// only works on EVM
if (!isEvmChain(sendingChain)) {
throw new Error('No support for non EVM cctp currently');
}
const chainContext = wh.getContext(
const chainContext = config.wh.getContext(
sendingChain,
) as EthContext<WormholeContext>;
const tokenMessenger =
wh.mustGetContracts(sendingChain).cctpContracts?.cctpTokenMessenger;
config.wh.mustGetContracts(sendingChain).cctpContracts
?.cctpTokenMessenger;
const circleTokenMessenger = await TokenMessenger__factory.connect(
tokenMessenger!,
wh.getSigner(fromChainId)!,
config.wh.getSigner(fromChainId)!,
);
const tokenAddr = (token as TokenId).address;
// approve
Expand All @@ -61,8 +69,8 @@ export default class ManualCCTPEvmImpl
tokenAddr,
parsedAmt,
);
const recipientChainName = wh.toChainName(recipientChain);
const destinationDomain = wh.conf.chains[recipientChainName]?.cctpDomain;
const recipientChainName = toChainName(recipientChain);
const destinationDomain = config.chains[recipientChainName]?.cctpDomain;
if (destinationDomain === undefined)
throw new Error(`No CCTP on ${recipientChainName}`);
const tx = await circleTokenMessenger.populateTransaction.depositForBurn(
Expand All @@ -72,7 +80,9 @@ export default class ManualCCTPEvmImpl
chainContext.context.parseAddress(tokenAddr, sendingChain),
);

const sentTx = await wh.getSigner(fromChainName)?.sendTransaction(tx);
const sentTx = await config.wh
.getSigner(fromChainName)
?.sendTransaction(tx);
const rx = await sentTx?.wait();
if (!rx) throw new Error("Transaction didn't go through");
return rx;
Expand All @@ -85,11 +95,11 @@ export default class ManualCCTPEvmImpl
): Promise<providers.TransactionReceipt> {
if (!isSignedCCTPMessage(message))
throw new Error('Signed message is not for CCTP');
const context: any = wh.getContext(destChain);
const context: any = config.wh.getContext(destChain);
const circleMessageTransmitter =
context.contracts.mustGetContracts(destChain).cctpContracts
?.cctpMessageTransmitter;
const connection = wh.mustGetSigner(destChain);
const connection = config.wh.mustGetSigner(destChain);
const contract = MessageTransmitter__factory.connect(
circleMessageTransmitter,
connection,
Expand All @@ -110,40 +120,40 @@ export default class ManualCCTPEvmImpl
): Promise<ManualCCTPMessage> {
// use this as reference
// https://goerli.etherscan.io/tx/0xe4984775c76b8fe7c2b09cd56fb26830f6e5c5c6b540eb97d37d41f47f33faca#eventlog
const provider = wh.mustGetProvider(chain);
const provider = config.wh.mustGetProvider(chain);

const receipt = await provider.getTransactionReceipt(tx);
if (!receipt) throw new Error(`No receipt for ${tx} on ${chain}`);

// Get the CCTP log
const cctpLog = receipt.logs.filter(
(log) => log.topics[0] === CCTP_LOG_TokenMessenger_DepositForBurn,
(log: any) => log.topics[0] === CCTP_LOG_TokenMessenger_DepositForBurn,
)[0];

const parsedCCTPLog =
TokenMessenger__factory.createInterface().parseLog(cctpLog);

const messageLog = receipt.logs.filter(
(log) => log.topics[0] === CCTP_LOG_MessageSent,
(log: any) => log.topics[0] === CCTP_LOG_MessageSent,
)[0];

const message =
MessageTransmitter__factory.createInterface().parseLog(messageLog).args
.message;

const toChain = getChainNameCCTP(parsedCCTPLog.args.destinationDomain);
const destContext = wh.getContext(toChain);
const destContext = config.wh.getContext(toChain);
let recipient = destContext.parseAddress(parsedCCTPLog.args.mintRecipient);
if (toChain === 'solana') {
recipient = await solanaContext().getTokenAccountOwner(recipient);
}
const fromChain = wh.toChainName(chain);
const fromChain = toChainName(chain);
const tokenId: TokenId = {
chain: fromChain,
address: parsedCCTPLog.args.burnToken,
};
const token = getTokenById(tokenId);
const decimals = await wh.fetchTokenDecimals(tokenId, fromChain);
const decimals = await config.wh.fetchTokenDecimals(tokenId, fromChain);
return {
sendTx: receipt.transactionHash,
sender: receipt.from,
Expand Down Expand Up @@ -177,7 +187,7 @@ export default class ManualCCTPEvmImpl
recipientAddress: string,
routeOptions?: any,
): Promise<BigNumber> {
const provider = wh.mustGetProvider(sendingChain);
const provider = config.wh.mustGetProvider(sendingChain);
const { gasPrice } = await provider.getFeeData();
if (!gasPrice)
throw new Error('gas price not available, cannot estimate fees');
Expand All @@ -186,22 +196,23 @@ export default class ManualCCTPEvmImpl
if (!isEvmChain(sendingChain)) {
throw new Error('No support for non EVM cctp currently');
}
const chainContext = wh.getContext(
const chainContext = config.wh.getContext(
sendingChain,
) as EthContext<WormholeContext>;
const tokenMessenger =
wh.mustGetContracts(sendingChain).cctpContracts?.cctpTokenMessenger;
config.wh.mustGetContracts(sendingChain).cctpContracts
?.cctpTokenMessenger;
const circleSender = TokenMessenger__factory.connect(
tokenMessenger!,
wh.getSigner(sendingChain)!,
config.wh.getSigner(sendingChain)!,
);
const tokenAddr = (token as TokenId).address;
const toChainName = wh.toChainName(recipientChain)!;
const decimals = getTokenDecimals(wh.toChainId(sendingChain), token);
const toChain = toChainName(recipientChain)!;
const decimals = getTokenDecimals(toChainId(sendingChain), token);
const parsedAmt = utils.parseUnits(`${amount}`, decimals);
const destinationDomain = wh.conf.chains[toChainName]?.cctpDomain;
const destinationDomain = config.chains[toChain]?.cctpDomain;
if (destinationDomain === undefined)
throw new Error(`CCTP not supported on ${toChainName}`);
throw new Error(`CCTP not supported on ${toChain}`);
const tx = await circleSender.populateTransaction.depositForBurn(
parsedAmt,
destinationDomain,
Expand All @@ -221,11 +232,11 @@ export default class ManualCCTPEvmImpl
if (!isSignedCCTPMessage(messageInfo))
throw new Error('Signed message is not for CCTP');
const nonce = getNonce(messageInfo.message);
const context: any = wh.getContext(destChain);
const context: any = config.wh.getContext(destChain);
const circleMessageTransmitter =
context.contracts.mustGetContracts(destChain).cctpContracts
?.cctpMessageTransmitter;
const connection = wh.mustGetProvider(destChain);
const connection = config.wh.mustGetProvider(destChain);
const iface = new utils.Interface([
'function usedNonces(bytes32 domainNonceHash) view returns (uint256)',
]);
Expand All @@ -235,7 +246,7 @@ export default class ManualCCTPEvmImpl
connection,
);

const cctpDomain = wh.conf.chains[messageInfo.fromChain]?.cctpDomain;
const cctpDomain = config.chains[messageInfo.fromChain]?.cctpDomain;
if (cctpDomain === undefined)
throw new Error(`CCTP not supported on ${messageInfo.fromChain}`);

Expand Down
27 changes: 13 additions & 14 deletions wormhole-connect/src/routes/cctpManual/chains/solana.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {
WormholeContext,
} from '@wormhole-foundation/wormhole-connect-sdk';
import { BigNumber, utils as ethUtils } from 'ethers';
import { PayloadType, solanaContext, wh } from 'utils/sdk';
import { TOKENS } from '../../../config';
import { PayloadType, solanaContext, toChainId, toChainName } from 'utils/sdk';
import { getNativeVersionOfToken } from '../../../store/transferInput';
import { getTokenById, getTokenDecimals } from '../../../utils';
import {
Expand All @@ -34,6 +33,7 @@ import ManualCCTP from './abstract';
import { getChainNameCCTP, getDomainCCTP } from '../utils/chains';
import { CircleBridge } from '@wormhole-foundation/sdk-definitions';
import { hexlify } from 'ethers/lib/utils';
import config from 'config';

const CCTP_NONCE_OFFSET = 12;
const MAX_NONCES_PER_ACCOUNT = 6400n;
Expand Down Expand Up @@ -67,7 +67,7 @@ const findProgramAddress = (
};

function getMessageTransmitter(): Program<MessageTransmitter> {
const context = wh.getContext(
const context = config.wh.getContext(
CHAIN_ID_SOLANA,
) as SolanaContext<WormholeContext>;
const connection = context.connection;
Expand All @@ -84,7 +84,7 @@ function getMessageTransmitter(): Program<MessageTransmitter> {
}

function getTokenMessenger(): Program<TokenMessenger> {
const context = wh.getContext(
const context = config.wh.getContext(
CHAIN_ID_SOLANA,
) as SolanaContext<WormholeContext>;
const connection = context.connection;
Expand All @@ -109,15 +109,15 @@ export class ManualCCTPSolanaImpl implements ManualCCTP<Transaction> {
recipientChain: ChainName | ChainId,
recipientAddress: string,
): Promise<Transaction> {
const fromChainId = wh.toChainId(sendingChain);
const fromChainId = toChainId(sendingChain);
const decimals = getTokenDecimals(fromChainId, token);
const parsedAmt = ethUtils.parseUnits(amount, decimals);

if (token === 'native')
throw new Error('Native not supported by cctp routes');

const recipientChainName = wh.toChainName(recipientChain);
const destinationDomain = wh.conf.chains[recipientChainName]?.cctpDomain;
const recipientChainName = toChainName(recipientChain);
const destinationDomain = config.chains[recipientChainName]?.cctpDomain;
if (destinationDomain === undefined)
throw new Error(`No CCTP on ${recipientChainName}`);

Expand Down Expand Up @@ -163,7 +163,7 @@ export class ManualCCTPSolanaImpl implements ManualCCTP<Transaction> {
new PublicKey(senderAddress),
);

const destContext = wh.getContext(recipientChain);
const destContext = config.wh.getContext(recipientChain);
const recipient = destContext.formatAddress(recipientAddress);
const messageSentKeypair = Keypair.generate();

Expand Down Expand Up @@ -213,7 +213,7 @@ export class ManualCCTPSolanaImpl implements ManualCCTP<Transaction> {
const messageTransmitterProgram = getMessageTransmitter();
const tokenMessengerMinterProgram = getTokenMessenger();

const fromContext = wh.getContext(message.fromChain);
const fromContext = config.wh.getContext(message.fromChain);

const messageBytes = Buffer.from(message.message.replace('0x', ''), 'hex');
const attestationBytes = Buffer.from(
Expand All @@ -224,7 +224,7 @@ export class ManualCCTPSolanaImpl implements ManualCCTP<Transaction> {

const remoteDomain = getDomainCCTP(message.fromChain);
const tokenKey = getNativeVersionOfToken('USDC', 'solana');
const tokenConfig = TOKENS[tokenKey];
const tokenConfig = config.tokens[tokenKey];
if (!tokenConfig || !tokenConfig.tokenId)
throw new Error('Invalid USDC token');
const solanaUsdcAddress = new PublicKey(tokenConfig.tokenId.address);
Expand Down Expand Up @@ -390,16 +390,15 @@ export class ManualCCTPSolanaImpl implements ManualCCTP<Transaction> {
if (!data) throw new Error('No message sent data');
// TODO: why 44?
const circleMsgArray = new Uint8Array(data.data.slice(44));
const [circleMsg, hash] = CircleBridge.deserialize(circleMsgArray);
console.log(circleMsg, hash);
const [circleMsg] = CircleBridge.deserialize(circleMsgArray);
const tokenAddress = await context.parseAssetAddress(
circleMsg.payload.burnToken.toString(),
);
const tokenId: TokenId = { address: tokenAddress, chain: 'solana' };
const token = getTokenById(tokenId);
const decimals = await wh.fetchTokenDecimals(tokenId, 'solana');
const decimals = await config.wh.fetchTokenDecimals(tokenId, 'solana');
const toChain = getChainNameCCTP(circleMsg.destinationDomain);
const destContext = wh.getContext(toChain);
const destContext = config.wh.getContext(toChain);
const recipient = destContext.parseAddress(
circleMsg.payload.mintRecipient.toString(),
);
Expand Down
2 changes: 2 additions & 0 deletions wormhole-connect/src/routes/cctpManual/utils/chains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const CCTPDomains: Partial<Record<ChainName, number>> = {
arbitrumgoerli: 3,
basegoerli: 6,
solana: 5,
polygon: 7,
mumbai: 7,
};

export function getChainNameCCTP(domain: number): ChainName {
Expand Down
2 changes: 1 addition & 1 deletion wormhole-connect/src/routes/operator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class Operator {
}

if (chain === 'solana') {
const { connection, contracts } = wh.getContext(
const { connection, contracts } = config.wh.getContext(
chain,
) as SolanaContext<WormholeContext>;
if (!connection) throw new Error('No connection for Solana');
Expand Down
10 changes: 7 additions & 3 deletions wormhole-connect/src/views/Bridge/Inputs/TokenWarnings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
setForeignAsset,
} from 'store/transferInput';
import config from 'config';
import { getWrappedTokenId } from 'utils';
import { getTokenById, getWrappedTokenId } from 'utils';
import { TransferWallet, signAndSendTransaction } from 'utils/wallet';
import { joinClass } from 'utils/style';
import { solanaContext } from 'utils/sdk';
Expand Down Expand Up @@ -157,7 +157,9 @@ function TokenWarnings() {
setShowErrors(false);
return false;
}
const tokenId = getWrappedTokenId(tokenConfig);
const tokenId =
getTokenById({ chain: 'solana', address: foreignAsset })?.tokenId ||
getWrappedTokenId(tokenConfig);
const account = await solanaContext().getAssociatedTokenAccount(
tokenId,
receiving.address,
Expand All @@ -183,7 +185,9 @@ function TokenWarnings() {
throw new Error(
'The token must be registered on Solana before an associated token account can be created',
);
const tokenId = getWrappedTokenId(tokenConfig);
const tokenId =
getTokenById({ chain: 'solana', address: foreignAsset })?.tokenId ||
getWrappedTokenId(tokenConfig);
const tx = await solanaContext().createAssociatedTokenAccount(
tokenId,
receiving.address,
Expand Down
6 changes: 5 additions & 1 deletion wormhole-connect/src/views/Redeem/SendTo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ function AssociatedTokenAlert() {
const wallet = useSelector((state: RootState) => state.wallet.receiving);

const createAssociatedTokenAccount = useCallback(async () => {
const token = getTokenById(txData.tokenId);
const receivedToken = config.tokens[txData.receivedTokenKey];
const token =
receivedToken?.nativeChain === 'solana'
? receivedToken
: getTokenById(txData.tokenId);
if (!token) return;
const tokenId = getWrappedTokenId(token);
const tx = await solanaContext().createAssociatedTokenAccount(
Expand Down

0 comments on commit ee1a23c

Please sign in to comment.