Skip to content

Commit

Permalink
Support Script receiver on V2 & V2 transactions (#26)
Browse files Browse the repository at this point in the history
* Support Script receiver on V1 swap transaction

* support V2 custom receiver

* fix format
  • Loading branch information
h2physics authored Sep 13, 2024
1 parent 807cc5b commit 00b270d
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 19 deletions.
104 changes: 96 additions & 8 deletions src/dex-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ import { DexVersion } from "./batcher-fee-reduction/types.internal";
import { FactoryV2 } from "./types/factory";
import { NetworkEnvironment, NetworkId } from "./types/network";
import { lucidToNetworkEnv } from "./utils/network.internal";
import { buildUtxoToStoreDatum } from "./utils/tx.internal";

export type V2CustomReceiver = {
refundReceiver: Address;
refundReceiverDatum?: {
type:
| OrderV2.ExtraDatumType.DATUM_HASH
| OrderV2.ExtraDatumType.INLINE_DATUM;
datum: string;
};
successReceiver: Address;
successReceiverDatum?: {
type:
| OrderV2.ExtraDatumType.DATUM_HASH
| OrderV2.ExtraDatumType.INLINE_DATUM;
datum: string;
};
};

/**
* Options for building Pool V2 Creation transaction
Expand All @@ -50,6 +68,7 @@ export type CreatePoolV2Options = {

export type BulkOrdersOption = {
sender: Address;
customReceiver?: V2CustomReceiver;
orderOptions: OrderOptions[];
expiredOptions?: OrderV2.ExpirySetting;
availableUtxos: UTxO[];
Expand Down Expand Up @@ -733,6 +752,7 @@ export class DexV2 {

async createBulkOrdersTx({
sender,
customReceiver,
orderOptions,
expiredOptions,
availableUtxos,
Expand Down Expand Up @@ -760,6 +780,10 @@ export class DexV2 {
});
const limitOrders: string[] = [];
const lucidTx = this.lucid.newTx();
const necessaryExtraDatums: {
receiver: Address;
datum: string;
}[] = [];
for (let i = 0; i < orderOptions.length; i++) {
const option = orderOptions[i];
const { type, lpAsset } = option;
Expand Down Expand Up @@ -796,16 +820,65 @@ export class DexV2 {
type: OrderV2.AuthorizationMethodType.SIGNATURE,
hash: senderPaymentCred.hash,
};

let successReceiver: Address = sender;
let successReceiverDatum: OrderV2.ExtraDatum = {
type: OrderV2.ExtraDatumType.NO_DATUM,
};
let refundReceiver: Address = sender;
let refundReceiverDatum: OrderV2.ExtraDatum = {
type: OrderV2.ExtraDatumType.NO_DATUM,
};
if (customReceiver) {
const {
successReceiver: customSuccessReceiver,
successReceiverDatum: customSuccessReceiverDatum,
refundReceiver: customRefundReceiver,
refundReceiverDatum: customRefundReceiverDatum,
} = customReceiver;
successReceiver = customSuccessReceiver;
refundReceiver = customRefundReceiver;
if (!customSuccessReceiverDatum) {
successReceiverDatum = {
type: OrderV2.ExtraDatumType.NO_DATUM,
};
} else {
const datumHash = this.lucid.utils.datumToHash(
customSuccessReceiverDatum.datum
);
successReceiverDatum = {
type: customSuccessReceiverDatum.type,
hash: datumHash,
};
necessaryExtraDatums.push({
receiver: successReceiver,
datum: customSuccessReceiverDatum.datum,
});
}
if (!customRefundReceiverDatum) {
refundReceiverDatum = {
type: OrderV2.ExtraDatumType.NO_DATUM,
};
} else {
const datumHash = this.lucid.utils.datumToHash(
customRefundReceiverDatum.datum
);
refundReceiverDatum = {
type: customRefundReceiverDatum.type,
hash: datumHash,
};
necessaryExtraDatums.push({
receiver: refundReceiver,
datum: customRefundReceiverDatum.datum,
});
}
}
const orderDatum: OrderV2.Datum = {
canceller: canceller,
refundReceiver: sender,
refundReceiverDatum: {
type: OrderV2.ExtraDatumType.NO_DATUM,
},
successReceiver: sender,
successReceiverDatum: {
type: OrderV2.ExtraDatumType.NO_DATUM,
},
refundReceiver: refundReceiver,
refundReceiverDatum: refundReceiverDatum,
successReceiver: successReceiver,
successReceiverDatum: successReceiverDatum,
step: orderStep,
lpAsset: lpAsset,
maxBatcherFee: totalBatcherFee,
Expand Down Expand Up @@ -843,6 +916,21 @@ export class DexV2 {
if (composeTx) {
lucidTx.compose(composeTx);
}
for (const necessaryExtraDatum of necessaryExtraDatums) {
const utxoForStoringDatum = buildUtxoToStoreDatum(
this.lucid,
sender,
necessaryExtraDatum.receiver,
necessaryExtraDatum.datum
);
if (utxoForStoringDatum) {
lucidTx.payToAddressWithData(
utxoForStoringDatum.address,
utxoForStoringDatum.outputData,
utxoForStoringDatum.assets
);
}
}
return lucidTx.complete();
}

Expand Down
63 changes: 52 additions & 11 deletions src/dex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ import {
import { NetworkEnvironment, NetworkId } from "./types/network";
import { OrderV1 } from "./types/order";
import { lucidToNetworkEnv } from "./utils/network.internal";
import { buildUtxoToStoreDatum } from "./utils/tx.internal";

export type V1AndStableswapCustomReceiver = {
receiver: Address;
receiverDatum?: {
hash: string;
datum: string;
};
};

/**
* Common options for build Minswap transaction
Expand Down Expand Up @@ -49,7 +58,6 @@ export type BuildCancelOrderOptions = {
* @minimumLPReceived Minimum Received Amount you can accept after order is executed
*/
export type BuildDepositTxOptions = CommonOptions & {
// sender: Address;
assetA: Asset;
assetB: Asset;
amountA: bigint;
Expand Down Expand Up @@ -80,7 +88,6 @@ export type BuildZapInTxOptions = CommonOptions & {
* @minimumAssetBReceived Minimum Received of Asset A in the Pool you can accept after order is executed
*/
export type BuildWithdrawTxOptions = CommonOptions & {
sender: Address;
lpAsset: Asset;
lpAmount: bigint;
minimumAssetAReceived: bigint;
Expand All @@ -95,7 +102,7 @@ export type BuildWithdrawTxOptions = CommonOptions & {
* @expectedAmountOut The expected Amount of Asset Out you want to receive after order is executed
*/
export type BuildSwapExactOutTxOptions = CommonOptions & {
sender: Address;
customReceiver?: V1AndStableswapCustomReceiver;
assetIn: Asset;
assetOut: Asset;
maximumAmountIn: bigint;
Expand All @@ -111,7 +118,7 @@ export type BuildSwapExactOutTxOptions = CommonOptions & {
* @isLimitOrder Define this order is Limit Order or not
*/
export type BuildSwapExactInTxOptions = CommonOptions & {
sender: Address;
customReceiver?: V1AndStableswapCustomReceiver;
assetIn: Asset;
amountIn: bigint;
assetOut: Asset;
Expand All @@ -137,6 +144,7 @@ export class Dex {
): Promise<TxComplete> {
const {
sender,
customReceiver,
assetIn,
amountIn,
assetOut,
Expand All @@ -160,8 +168,8 @@ export class Dex {
}
const datum: OrderV1.Datum = {
sender: sender,
receiver: sender,
receiverDatumHash: undefined,
receiver: customReceiver ? customReceiver.receiver : sender,
receiverDatumHash: customReceiver?.receiverDatum?.hash,
step: {
type: OrderV1.StepType.SWAP_EXACT_IN,
desiredAsset: assetOut,
Expand All @@ -186,6 +194,21 @@ export class Dex {
} else {
tx.attachMetadata(674, { msg: [MetadataMessage.SWAP_EXACT_IN_ORDER] });
}
if (customReceiver && customReceiver.receiverDatum) {
const utxoForStoringDatum = buildUtxoToStoreDatum(
this.lucid,
sender,
customReceiver.receiver,
customReceiver.receiverDatum.datum
);
if (utxoForStoringDatum) {
tx.payToAddressWithData(
utxoForStoringDatum.address,
utxoForStoringDatum.outputData,
utxoForStoringDatum.assets
);
}
}
return await tx.complete();
}

Expand All @@ -194,6 +217,7 @@ export class Dex {
): Promise<TxComplete> {
const {
sender,
customReceiver,
assetIn,
assetOut,
maximumAmountIn,
Expand All @@ -218,8 +242,8 @@ export class Dex {
}
const datum: OrderV1.Datum = {
sender: sender,
receiver: sender,
receiverDatumHash: undefined,
receiver: customReceiver ? customReceiver.receiver : sender,
receiverDatumHash: customReceiver?.receiverDatum?.hash,
step: {
type: OrderV1.StepType.SWAP_EXACT_OUT,
desiredAsset: assetOut,
Expand All @@ -229,7 +253,7 @@ export class Dex {
depositADA: FIXED_DEPOSIT_ADA,
};

return await this.lucid
const tx = this.lucid
.newTx()
.payToContract(
DexV1Constant.ORDER_BASE_ADDRESS[this.networkId],
Expand All @@ -238,8 +262,25 @@ export class Dex {
)
.payToAddress(sender, reductionAssets)
.addSigner(sender)
.attachMetadata(674, { msg: [MetadataMessage.SWAP_EXACT_OUT_ORDER] })
.complete();
.attachMetadata(674, { msg: [MetadataMessage.SWAP_EXACT_OUT_ORDER] });

if (customReceiver && customReceiver.receiverDatum) {
const utxoForStoringDatum = buildUtxoToStoreDatum(
this.lucid,
sender,
customReceiver.receiver,
customReceiver.receiverDatum.datum
);
if (utxoForStoringDatum) {
tx.payToAddressWithData(
utxoForStoringDatum.address,
utxoForStoringDatum.outputData,
utxoForStoringDatum.assets
);
}
}

return await tx.complete();
}

async buildWithdrawTx(options: BuildWithdrawTxOptions): Promise<TxComplete> {
Expand Down
35 changes: 35 additions & 0 deletions src/utils/tx.internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Address, Assets, Lucid, OutputData } from "lucid-cardano";

/**
* Return a Output that pay back to @sender and include @datum
* This function is used for @receiver of an order can be a script
* @param lucid
* @param sender
* @param receiver
* @param datum
*/
export function buildUtxoToStoreDatum(
lucid: Lucid,
sender: Address,
receiver: Address,
datum: string
): {
address: Address;
outputData: OutputData;
assets: Assets;
} | null {
const receivePaymentCred =
lucid.utils.getAddressDetails(receiver).paymentCredential;
// If receiver is not a script address, we no need to store this datum On-chain because it's useless
if (!receivePaymentCred || receivePaymentCred.type === "Key") {
return null;
}

return {
address: sender,
assets: {},
outputData: {
inline: datum,
},
};
}

0 comments on commit 00b270d

Please sign in to comment.