Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Script receiver on V2 & V2 transactions #26

Merged
merged 4 commits into from
Sep 13, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 96 additions & 8 deletions src/dex-v2.ts
Original file line number Diff line number Diff line change
@@ -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
@@ -50,6 +68,7 @@ export type CreatePoolV2Options = {

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

async createBulkOrdersTx({
sender,
customReceiver,
orderOptions,
expiredOptions,
availableUtxos,
@@ -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;
@@ -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,
@@ -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();
}

63 changes: 52 additions & 11 deletions src/dex.ts
Original file line number Diff line number Diff line change
@@ -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
@@ -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;
@@ -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;
@@ -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;
@@ -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;
@@ -137,6 +144,7 @@ export class Dex {
): Promise<TxComplete> {
const {
sender,
customReceiver,
assetIn,
amountIn,
assetOut,
@@ -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,
@@ -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();
}

@@ -194,6 +217,7 @@ export class Dex {
): Promise<TxComplete> {
const {
sender,
customReceiver,
assetIn,
assetOut,
maximumAmountIn,
@@ -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,
@@ -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],
@@ -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> {
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,
},
};
}