Skip to content

Commit

Permalink
add chain context to constructor args so we always use the same chain…
Browse files Browse the repository at this point in the history
… context obj
  • Loading branch information
barnjamin committed Jan 9, 2024
1 parent dfb32e3 commit 33269ba
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 79 deletions.
55 changes: 39 additions & 16 deletions connect/src/protocols/cctpTransfer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ export class CircleTransfer<N extends Network = Network>
{
private readonly wh: Wormhole<N>;

fromChain: ChainContext<N, Platform, Chain>;
toChain: ChainContext<N, Platform, Chain>;

// state machine tracker
private _state: TransferState;

Expand All @@ -62,10 +65,18 @@ export class CircleTransfer<N extends Network = Network>

attestations?: AttestationReceipt<CircleTransferProtocol>[];

private constructor(wh: Wormhole<N>, transfer: CircleTransferDetails) {
private constructor(
wh: Wormhole<N>,
transfer: CircleTransferDetails,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
) {
this._state = TransferState.Created;
this.wh = wh;
this.transfer = transfer;

this.fromChain = fromChain ?? wh.getChain(transfer.from.chain);
this.toChain = toChain ?? wh.getChain(transfer.to.chain);
}

getTransferState(): TransferState {
Expand All @@ -76,43 +87,58 @@ export class CircleTransfer<N extends Network = Network>
static async from<N extends Network>(
wh: Wormhole<N>,
from: CircleTransferDetails,
timeout?: number,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>>;
static async from<N extends Network>(
wh: Wormhole<N>,
from: WormholeMessageId,
timeout?: number,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>>;
static async from<N extends Network>(
wh: Wormhole<N>,
from: string, // CircleMessage hex encoded
timeout?: number,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>>;
static async from<N extends Network>(
wh: Wormhole<N>,
from: TransactionId,
timeout?: number,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>>;
static async from<N extends Network>(
wh: Wormhole<N>,
from: CircleTransferDetails | WormholeMessageId | string | TransactionId,
timeout: number = DEFAULT_TASK_TIMEOUT,
fromChain?: ChainContext<N, Platform, Chain>,
toChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>> {
// This is a new transfer, just return the object
if (isCircleTransferDetails(from)) {
return new CircleTransfer(wh, from);
return new CircleTransfer(wh, from, fromChain, toChain);
}

// This is an existing transfer, fetch the details
let tt: CircleTransfer<N> | undefined;
if (isWormholeMessageId(from)) {
tt = await CircleTransfer.fromWormholeMessageId(wh, from, timeout);
} else if (isTransactionIdentifier(from)) {
tt = await CircleTransfer.fromTransaction(wh, from, timeout);
tt = await CircleTransfer.fromTransaction(wh, from, timeout, fromChain);
} else if (isCircleMessageId(from)) {
tt = await CircleTransfer.fromCircleMessage(wh, from, timeout);
tt = await CircleTransfer.fromCircleMessage(wh, from);
} else {
throw new Error("Invalid `from` parameter for CircleTransfer");
}

tt.fromChain = fromChain ?? wh.getChain(tt.transfer.from.chain);
tt.toChain = toChain ?? wh.getChain(tt.transfer.to.chain);

await tt.fetchAttestation(timeout);

return tt;
Expand Down Expand Up @@ -158,7 +184,6 @@ export class CircleTransfer<N extends Network = Network>
private static async fromCircleMessage<N extends Network>(
wh: Wormhole<N>,
message: string,
timeout: number,
): Promise<CircleTransfer<N>> {
const [msg, hash] = CircleBridge.deserialize(encoding.hex.decode(message));

Expand Down Expand Up @@ -188,22 +213,23 @@ export class CircleTransfer<N extends Network = Network>
wh: Wormhole<N>,
from: TransactionId,
timeout: number,
fromChain?: ChainContext<N, Platform, Chain>,
): Promise<CircleTransfer<N>> {
const { chain, txid } = from;
const originChain = wh.getChain(chain);
fromChain = fromChain ?? wh.getChain(chain);

// First try to parse out a WormholeMessage
// If we get one or more, we assume its a Wormhole attested
// transfer
const msgIds: WormholeMessageId[] = await originChain.parseTransaction(txid);
const msgIds: WormholeMessageId[] = await fromChain.parseTransaction(txid);

// If we found a VAA message, use it
let ct: CircleTransfer<N>;
if (msgIds.length > 0) {
ct = await CircleTransfer.fromWormholeMessageId(wh, msgIds[0]!, timeout);
} else {
// Otherwise try to parse out a circle message
const cb = await originChain.getCircleBridge();
const cb = await fromChain.getCircleBridge();
const circleMessage = await cb.parseTransactionDetails(txid);
const details: CircleTransferDetails = {
...circleMessage,
Expand Down Expand Up @@ -234,27 +260,25 @@ export class CircleTransfer<N extends Network = Network>
if (this._state !== TransferState.Created)
throw new Error("Invalid state transition in `start`");

const fromChain = this.wh.getChain(this.transfer.from.chain);

let xfer: AsyncGenerator<UnsignedTransaction<N>>;
if (this.transfer.automatic) {
const cr = await fromChain.getAutomaticCircleBridge();
const cr = await this.fromChain.getAutomaticCircleBridge();
xfer = cr.transfer(
this.transfer.from.address,
{ chain: this.transfer.to.chain, address: this.transfer.to.address },
this.transfer.amount,
this.transfer.nativeGas,
);
} else {
const cb = await fromChain.getCircleBridge();
const cb = await this.fromChain.getCircleBridge();
xfer = cb.transfer(
this.transfer.from.address,
{ chain: this.transfer.to.chain, address: this.transfer.to.address },
this.transfer.amount,
);
}

this.txids = await signSendWait<N, typeof fromChain.chain>(fromChain, xfer, signer);
this.txids = await signSendWait<N, Chain>(this.fromChain, xfer, signer);
this._state = TransferState.SourceInitiated;

return this.txids.map(({ txid }) => txid);
Expand Down Expand Up @@ -371,12 +395,11 @@ export class CircleTransfer<N extends Network = Network>
const { message, attestation: signatures } = attestation;
if (!signatures) throw new Error(`No Circle Attestation for ${id.hash}`);

const toChain = this.wh.getChain(this.transfer.to.chain);
const tb = await toChain.getCircleBridge();
const tb = await this.toChain.getCircleBridge();

const xfer = tb.redeem(this.transfer.to.address, message, signatures!);

const txids = await signSendWait<N, typeof toChain.chain>(toChain, xfer, signer);
const txids = await signSendWait<N, Chain>(this.toChain, xfer, signer);
this.txids?.push(...txids);
return txids.map(({ txid }) => txid);
}
Expand Down
Loading

0 comments on commit 33269ba

Please sign in to comment.