mirror of https://github.com/certusone/oyster.git
feat: to solana
This commit is contained in:
parent
85d3f8aaf4
commit
3db159667d
|
@ -33,7 +33,7 @@ export const AppLayout = React.memo((props: any) => {
|
|||
<Wormhole
|
||||
onCreated={() => setWormholeReady(true)}
|
||||
show={true}
|
||||
rotate={isRoot}
|
||||
rotate={true}
|
||||
>
|
||||
<Layout title={LABELS.APP_TITLE}>
|
||||
{isRoot && (
|
||||
|
|
|
@ -47,7 +47,7 @@ const WormholeGeometry = ({ rotate }: { rotate?: boolean }) => {
|
|||
if (mesh.current) {
|
||||
// x-Axis defines the "top" we're looking at, try e.g. 30.5
|
||||
mesh.current.rotation.x = 30;
|
||||
if (!rotate) {
|
||||
if (rotate) {
|
||||
mesh.current.rotation.z += 0.0005;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,20 +37,28 @@ export const fromSolana = async (
|
|||
provider: ethers.providers.Web3Provider,
|
||||
setProgress: (update: ProgressUpdate) => void,
|
||||
) => {
|
||||
if (!request.asset) {
|
||||
if (
|
||||
!request.asset ||
|
||||
!request.amount ||
|
||||
!request.recipient ||
|
||||
!request.toChain ||
|
||||
!request.info
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const walletName = 'MetaMask';
|
||||
request.signer = provider?.getSigner();
|
||||
request.recipient = Buffer.from(
|
||||
(await request.signer.getAddress()).slice(2),
|
||||
'hex',
|
||||
);
|
||||
request.nonce = await provider.getTransactionCount(
|
||||
request.signer.getAddress(),
|
||||
const signer = provider?.getSigner();
|
||||
request.recipient = Buffer.from((await signer.getAddress()).slice(2), 'hex');
|
||||
const nonce = await provider.getTransactionCount(
|
||||
signer.getAddress(),
|
||||
'pending',
|
||||
);
|
||||
|
||||
request.amountBN = ethers.utils.parseUnits(
|
||||
request.amount.toString(),
|
||||
request.info.decimals,
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
// check difference between lock/approve (invoke lock if allowance < amount)
|
||||
const steps = {
|
||||
|
@ -63,11 +71,6 @@ export const fromSolana = async (
|
|||
throw new Error('Missing amount');
|
||||
}
|
||||
|
||||
request.amountBN = ethers.utils.parseUnits(
|
||||
request.amount.toString(),
|
||||
request.info.decimals,
|
||||
);
|
||||
|
||||
return steps.lock(request);
|
||||
},
|
||||
|
||||
|
@ -138,75 +141,108 @@ export const fromSolana = async (
|
|||
proposalKey: PublicKey,
|
||||
slot: number,
|
||||
) => {
|
||||
let completed = false;
|
||||
let startSlot = slot;
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
let completed = false;
|
||||
let startSlot = slot;
|
||||
|
||||
let group = 'Lock assets';
|
||||
let group = 'Lock assets';
|
||||
|
||||
let slotUpdateListener = connection.onSlotChange(slot => {
|
||||
if (completed) return;
|
||||
const passedSlots = slot.slot - startSlot;
|
||||
const isLast = passedSlots - 1 === 31;
|
||||
if (passedSlots < 32) {
|
||||
// setLoading({
|
||||
// loading: true,
|
||||
// message: "Awaiting confirmations",
|
||||
// progress: {
|
||||
// completion: (slot.slot - startSlot) / 32 * 100,
|
||||
// content: `${slot.slot - startSlot}/${32}`
|
||||
// }
|
||||
// })
|
||||
// setProgress({
|
||||
// message: ethConfirmationMessage(passedBlocks),
|
||||
// type: isLast ? 'done' : 'wait',
|
||||
// step: counter++,
|
||||
// group,
|
||||
// replace: passedBlocks > 0,
|
||||
// });
|
||||
} else {
|
||||
//setLoading({loading: true, message: "Awaiting guardian confirmation"})
|
||||
}
|
||||
});
|
||||
|
||||
let accountChangeListener = connection.onAccountChange(
|
||||
proposalKey,
|
||||
async a => {
|
||||
let slotUpdateListener = connection.onSlotChange(slot => {
|
||||
if (completed) return;
|
||||
const passedSlots = slot.slot - startSlot;
|
||||
const isLast = passedSlots - 1 === 31;
|
||||
if (passedSlots < 32) {
|
||||
// setLoading({
|
||||
// loading: true,
|
||||
// message: "Awaiting confirmations",
|
||||
// progress: {
|
||||
// completion: (slot.slot - startSlot) / 32 * 100,
|
||||
// content: `${slot.slot - startSlot}/${32}`
|
||||
// }
|
||||
// })
|
||||
// setProgress({
|
||||
// message: ethConfirmationMessage(passedBlocks),
|
||||
// type: isLast ? 'done' : 'wait',
|
||||
// step: counter++,
|
||||
// group,
|
||||
// replace: passedBlocks > 0,
|
||||
// });
|
||||
} else {
|
||||
//setLoading({loading: true, message: "Awaiting guardian confirmation"})
|
||||
}
|
||||
});
|
||||
|
||||
let lockup = TransferOutProposalLayout.decode(a.data);
|
||||
let vaa = lockup.vaa;
|
||||
let accountChangeListener = connection.onAccountChange(
|
||||
proposalKey,
|
||||
async a => {
|
||||
if (completed) return;
|
||||
|
||||
for (let i = vaa.length; i > 0; i--) {
|
||||
if (vaa[i] == 0xff) {
|
||||
vaa = vaa.slice(0, i);
|
||||
break;
|
||||
let lockup = TransferOutProposalLayout.decode(a.data);
|
||||
let vaa = lockup.vaa;
|
||||
|
||||
for (let i = vaa.length; i > 0; i--) {
|
||||
if (vaa[i] == 0xff) {
|
||||
vaa = vaa.slice(0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Probably a poke
|
||||
if (vaa.filter((v: number) => v !== 0).length == 0) {
|
||||
return;
|
||||
}
|
||||
// Probably a poke
|
||||
if (vaa.filter((v: number) => v !== 0).length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
completed = true;
|
||||
connection.removeAccountChangeListener(accountChangeListener);
|
||||
connection.removeSlotChangeListener(slotUpdateListener);
|
||||
completed = true;
|
||||
connection.removeAccountChangeListener(accountChangeListener);
|
||||
connection.removeSlotChangeListener(slotUpdateListener);
|
||||
|
||||
// let signatures = await bridge.fetchSignatureStatus(lockup.signatureAccount);
|
||||
// let sigData = Buffer.of(...signatures.reduce((previousValue, currentValue) => {
|
||||
// previousValue.push(currentValue.index)
|
||||
// previousValue.push(...currentValue.signature)
|
||||
let signatures = await bridge.fetchSignatureStatus(
|
||||
lockup.signatureAccount,
|
||||
);
|
||||
let sigData = Buffer.of(
|
||||
...signatures.reduce((previousValue, currentValue) => {
|
||||
previousValue.push(currentValue.index);
|
||||
previousValue.push(...currentValue.signature);
|
||||
|
||||
// return previousValue
|
||||
// }, new Array<number>()))
|
||||
return previousValue;
|
||||
}, new Array<number>()),
|
||||
);
|
||||
|
||||
// vaa = Buffer.concat([vaa.slice(0, 5), Buffer.of(signatures.length), sigData, vaa.slice(6)])
|
||||
// transferVAA = vaa
|
||||
},
|
||||
'single',
|
||||
);
|
||||
vaa = Buffer.concat([
|
||||
vaa.slice(0, 5),
|
||||
Buffer.of(signatures.length),
|
||||
sigData,
|
||||
vaa.slice(6),
|
||||
]);
|
||||
// transferVAA = vaa
|
||||
try {
|
||||
await steps.postVAA(request);
|
||||
resolve();
|
||||
} catch {
|
||||
reject();
|
||||
}
|
||||
},
|
||||
'single',
|
||||
);
|
||||
});
|
||||
},
|
||||
postVAA: async (request: TransferRequest) => {
|
||||
let wh = WormholeFactory.connect(programIds().wormhole.bridge, signer);
|
||||
|
||||
// setLoading({
|
||||
// ...loading,
|
||||
// loading: true,
|
||||
// message: "Sign the claim...",
|
||||
// })
|
||||
let tx = await wh.submitVAA(vaa);
|
||||
// setLoading({
|
||||
// ...loading,
|
||||
// loading: true,
|
||||
// message: "Waiting for tokens unlock to be mined...",
|
||||
// })
|
||||
await tx.wait(1);
|
||||
// message.success({content: "Execution of VAA succeeded", key: "eth_tx"})
|
||||
},
|
||||
postVAA: async (request: TransferRequest) => {},
|
||||
};
|
||||
|
||||
return steps.transfer(request);
|
||||
|
|
|
@ -24,11 +24,6 @@ export interface TransferRequestInfo {
|
|||
}
|
||||
|
||||
export interface TransferRequest {
|
||||
// ethereum specific fields, TODO: remove
|
||||
nonce?: number;
|
||||
signer?: ethers.Signer;
|
||||
amountBN?: BigNumber;
|
||||
|
||||
amount?: number;
|
||||
|
||||
info?: TransferRequestInfo;
|
||||
|
|
|
@ -30,17 +30,22 @@ export const toSolana = async (
|
|||
provider: ethers.providers.Web3Provider,
|
||||
setProgress: (update: ProgressUpdate) => void,
|
||||
) => {
|
||||
if (!request.asset) {
|
||||
if (!request.asset || !request.amount || !request.info) {
|
||||
return;
|
||||
}
|
||||
const walletName = 'MetaMask';
|
||||
request.signer = provider?.getSigner();
|
||||
const signer = provider?.getSigner();
|
||||
|
||||
request.nonce = await provider.getTransactionCount(
|
||||
request.signer.getAddress(),
|
||||
const nonce = await provider.getTransactionCount(
|
||||
signer.getAddress(),
|
||||
'pending',
|
||||
);
|
||||
|
||||
const amountBN = ethers.utils.parseUnits(
|
||||
request.amount.toString(),
|
||||
request.info.decimals,
|
||||
);
|
||||
|
||||
let counter = 0;
|
||||
// check difference between lock/approve (invoke lock if allowance < amount)
|
||||
const steps = {
|
||||
|
@ -49,11 +54,6 @@ export const toSolana = async (
|
|||
return;
|
||||
}
|
||||
|
||||
request.amountBN = ethers.utils.parseUnits(
|
||||
request.amount.toString(),
|
||||
request.info.decimals,
|
||||
);
|
||||
|
||||
return steps.prepare(request);
|
||||
},
|
||||
|
||||
|
@ -162,24 +162,21 @@ export const toSolana = async (
|
|||
},
|
||||
// approves assets for transfer
|
||||
approve: async (request: TransferRequest) => {
|
||||
if (!request.amountBN || !request.asset || !request.signer) {
|
||||
if (!request.asset) {
|
||||
return;
|
||||
}
|
||||
|
||||
const group = 'Approve assets';
|
||||
try {
|
||||
if (request.info?.allowance.lt(request.amountBN)) {
|
||||
let e = Erc20Factory.connect(request.asset, request.signer);
|
||||
if (request.info?.allowance.lt(amountBN)) {
|
||||
let e = Erc20Factory.connect(request.asset, signer);
|
||||
setProgress({
|
||||
message: `Waiting for ${walletName} approval`,
|
||||
type: 'user',
|
||||
group,
|
||||
step: counter++,
|
||||
});
|
||||
let res = await e.approve(
|
||||
programIds().wormhole.bridge,
|
||||
request.amountBN,
|
||||
);
|
||||
let res = await e.approve(programIds().wormhole.bridge, amountBN);
|
||||
setProgress({
|
||||
message: 'Waiting for ETH transaction to be mined...',
|
||||
type: 'wait',
|
||||
|
@ -216,13 +213,11 @@ export const toSolana = async (
|
|||
// locks assets in the bridge
|
||||
lock: async (request: TransferRequest) => {
|
||||
if (
|
||||
!request.amountBN ||
|
||||
!amountBN ||
|
||||
!request.asset ||
|
||||
!request.signer ||
|
||||
!request.recipient ||
|
||||
!request.toChain ||
|
||||
!request.info ||
|
||||
!request.nonce
|
||||
!request.info
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -230,10 +225,7 @@ export const toSolana = async (
|
|||
let group = 'Lock assets';
|
||||
|
||||
try {
|
||||
let wh = WormholeFactory.connect(
|
||||
programIds().wormhole.bridge,
|
||||
request.signer,
|
||||
);
|
||||
let wh = WormholeFactory.connect(programIds().wormhole.bridge, signer);
|
||||
setProgress({
|
||||
message: `Waiting for ${walletName} transfer approval`,
|
||||
type: 'user',
|
||||
|
@ -242,10 +234,10 @@ export const toSolana = async (
|
|||
});
|
||||
let res = await wh.lockAssets(
|
||||
request.asset,
|
||||
request.amountBN,
|
||||
amountBN,
|
||||
request.recipient,
|
||||
request.toChain,
|
||||
request.nonce,
|
||||
nonce,
|
||||
false,
|
||||
);
|
||||
setProgress({
|
||||
|
|
|
@ -3,6 +3,7 @@ import {
|
|||
getVerboseTokenName,
|
||||
KnownTokenMap,
|
||||
} from '@oyster/common';
|
||||
import { TokenInfo } from '@solana/spl-token-registry';
|
||||
|
||||
export const getAssetName = (
|
||||
parsedAssetAddress: string,
|
||||
|
@ -48,6 +49,6 @@ export const chainToName = (chain?: ASSET_CHAIN) => {
|
|||
return CHAIN_NAME[chain || ASSET_CHAIN.Ethereum];
|
||||
};
|
||||
|
||||
export const filterModalSolTokens = (tokens: any[]) => {
|
||||
export const filterModalSolTokens = (tokens: TokenInfo[]) => {
|
||||
return tokens;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue