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

feat: wip #218

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
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
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
"lint:module": "lerna exec --scope @meshsdk/core \"yarn eslint --fix\"",
"lint": "yarn lint:module && yarn lint:demo && yarn lint:docs"
},
"dependencies": {
"@meshsdk/common": "1.0.0-alpha.7"
},
"devDependencies": {
"@types/jest": "28.1.6",
"@types/node": "18.6.1",
Expand Down
1 change: 1 addition & 0 deletions packages/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@meshsdk/core": "1.5.16"
},
"dependencies": {
"@harmoniclabs/plu-ts": "0.2.2",
"@meshsdk/mesh-csl": "^0.0.4"
}
}
2 changes: 1 addition & 1 deletion packages/contracts/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
MeshTxBuilder,
IFetcher,
UTxO,
BrowserWallet,
MeshWallet,
} from '@meshsdk/core';
import { UTxO } from '@meshsdk/common';
import { v2ScriptToBech32 } from '@meshsdk/mesh-csl';

export type MeshTxInitiatorInput = {
Expand Down
8 changes: 4 additions & 4 deletions packages/contracts/src/escrow/offchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
mConStr2,
} from '@meshsdk/mesh-csl';
import blueprint from './aiken-workspace/plutus.json';
import { Asset, UTxO, mergeAssets } from '@meshsdk/core';
import { Asset, UTxO, mergeAssets } from '@meshsdk/common';

export type InitiationDatum = ConStr0<[PubKeyAddress, Value]>;
export const initiateEscrowDatum = (
Expand Down Expand Up @@ -71,7 +71,7 @@ export class MeshEscrowContract extends MeshTxInitiator {
await this.mesh
.txOut(scriptAddr, escrowAmount)
.txOutInlineDatumValue(
initiateEscrowDatum(walletAddress, escrowAmount),
initiateEscrowDatum(walletAddress, escrowAmount) as any,
'JSON'
)
.changeAddress(walletAddress)
Expand Down Expand Up @@ -169,7 +169,7 @@ export class MeshEscrowContract extends MeshTxInitiator {
)
.spendingReferenceTxInInlineDatumPresent()
.txInRedeemerValue(
recipientDepositRedeemer(walletAddress, depositAmount),
recipientDepositRedeemer(walletAddress, depositAmount) as any,
{
mem: 7_000_000,
steps: 3_000_000_000,
Expand All @@ -178,7 +178,7 @@ export class MeshEscrowContract extends MeshTxInitiator {
)
.txInScript(this.scriptCbor)
.txOut(scriptAddr, escrowAmount)
.txOutInlineDatumValue(outputDatum, 'JSON')
.txOutInlineDatumValue(outputDatum as any, 'JSON')
.changeAddress(walletAddress)
.txInCollateral(
collateral.input.txHash,
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/src/giftcard/offchain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
mConStr1,
} from '@meshsdk/mesh-csl';
import blueprint from './aiken-workspace/plutus.json';
import { Asset, UTxO } from '@meshsdk/core';
import { Asset, UTxO } from '@meshsdk/common';

export class MeshGiftCardContract extends MeshTxInitiator {
tokenNameHex: string = '';
Expand Down
266 changes: 266 additions & 0 deletions packages/contracts/src/marketplace/basic.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
import {
IFetcher,
IInitiator,
ISigner,
ISubmitter,
parseAssetUnit,
resolveDataHash,
resolveEpochNo,
resolvePaymentKeyHash,
resolvePlutusScriptAddress,
Transaction,
} from '@meshsdk/core';
import type { Network, PlutusScript, UTxO } from '@meshsdk/common';
import { buildPlutusScript, OwnerAddress } from './contract';

export class BasicMarketplace {
private _fetcher: IFetcher;
private _initiator: IInitiator;
private _network: Network;
private _owner: string;
private _percentage: number;
private _script: PlutusScript;
private _signer: ISigner;
private _submitter: ISubmitter;

constructor(options = {} as CreateMarketplaceOptions) {
this._fetcher = options.fetcher;
this._initiator = options.initiator;
this._network = options.network;
this._owner = options.owner;
this._percentage = options.percentage;
this._script = buildPlutusScript(options.owner, options.percentage);
this._signer = options.signer;
this._submitter = options.submitter;
}

async delistAsset(address: string, asset: string, price: number) {
const { policyId, assetName } = parseAssetUnit(asset);
const tx = await this.buildTx();

const datum = {
alternative: 0,
fields: [resolvePaymentKeyHash(address), price, policyId, assetName],
};

const redeemer = {
data: {
alternative: 1,
fields: [],
},
};

const assetUTxO = await this.findUTxO(
resolvePlutusScriptAddress(
this._script,
this._network === 'mainnet' ? 1 : 0
),
asset,
resolveDataHash(datum)
);

tx.redeemValue({
value: assetUTxO,
script: this._script,
datum,
redeemer,
})
.sendValue(address, assetUTxO)
.setRequiredSigners([address]);

const unsignedTx = await tx.build();
const signedTx = await this._signer.signTx(unsignedTx, true);
return this._submitter.submitTx(signedTx);
}

async listAsset(address: string, asset: string, price: number) {
const { policyId, assetName } = parseAssetUnit(asset);
const tx = await this.buildTx();

const datum = {
alternative: 0,
fields: [resolvePaymentKeyHash(address), price, policyId, assetName],
};

tx.sendAssets(
{
address: resolvePlutusScriptAddress(
this._script,
this._network === 'mainnet' ? 1 : 0
),
datum: { value: datum },
},
[
{
unit: asset,
quantity: '1',
},
]
);

const unsignedTx = await tx.build();
const signedTx = await this._signer.signTx(unsignedTx, false);
return this._submitter.submitTx(signedTx);
}

async purchaseAsset(address: string, asset: string, price: number) {
const { policyId, assetName } = parseAssetUnit(asset);
const tx = await this.buildTx();

const datum = {
alternative: 0,
fields: [resolvePaymentKeyHash(address), price, policyId, assetName],
};

const redeemer = {
data: {
alternative: 0,
fields: [],
},
};

const assetUTxO = await this.findUTxO(
resolvePlutusScriptAddress(
this._script,
this._network === 'mainnet' ? 1 : 0
),
asset,
resolveDataHash(datum)
);

const buyerAddress = await this._initiator.getUsedAddress();

const { marketFees } = this.splitAmount(price);

tx.redeemValue({
value: assetUTxO,
script: this._script,
datum,
redeemer,
})
.sendValue(buyerAddress.to_bech32(), assetUTxO)
.sendLovelace(address, price.toString())
.sendLovelace(this._owner, marketFees.toString());

const unsignedTx = await tx.build();
const signedTx = await this._signer.signTx(unsignedTx, true);
return this._submitter.submitTx(signedTx);
}

async relistAsset(
address: string,
asset: string,
oldPrice: number,
newPrice: number
) {
const { policyId, assetName } = parseAssetUnit(asset);
const tx = await this.buildTx();

const datum = {
alternative: 0,
fields: [resolvePaymentKeyHash(address), oldPrice, policyId, assetName],
};

const redeemer = {
data: {
alternative: 1,
fields: [],
},
};

const assetUTxO = await this.findUTxO(
resolvePlutusScriptAddress(
this._script,
this._network === 'mainnet' ? 1 : 0
),
asset,
resolveDataHash(datum)
);

tx.redeemValue({
value: assetUTxO,
script: this._script,
datum,
redeemer,
})
.sendAssets(
{
address: resolvePlutusScriptAddress(
this._script,
this._network === 'mainnet' ? 1 : 0
),
datum: {
value: {
alternative: 0,
fields: [
resolvePaymentKeyHash(address),
newPrice,
policyId,
assetName,
],
},
},
},
[
{
unit: asset,
quantity: '1',
},
]
)
.setRequiredSigners([address]);

const unsignedTx = await tx.build();
const signedTx = await this._signer.signTx(unsignedTx, true);
return this._submitter.submitTx(signedTx);
}

private async buildTx() {
const epoch = resolveEpochNo(this._network);
const parameters = await this._fetcher.fetchProtocolParameters(epoch);

return new Transaction({
initiator: this._initiator,
parameters,
});
}

private async findUTxO(address: string, assetId: string, dataHash: string) {
const utxos = await this._fetcher.fetchAddressUTxOs(address, assetId);

if (utxos.length === 0) {
throw new Error(`No listing found for asset with Id: ${assetId}`);
}

const utxo: UTxO | undefined = utxos.find(
(utxo) => utxo.output.dataHash === dataHash
);

if (utxo === undefined) {
throw new Error(`No listing found for asset with Hash: ${dataHash}`);
}

return utxo;
}

private splitAmount(price: number) {
const minFees = 1_000_000;
const marketFees = Math.max(
(this._percentage / 1_000_000) * price,
minFees
);
const netPrice = price - marketFees;

return { marketFees, netPrice };
}
}

type CreateMarketplaceOptions = {
percentage: number;
initiator: IInitiator;
submitter: ISubmitter;
owner: OwnerAddress;
fetcher: IFetcher;
network: Network;
signer: ISigner;
};
Loading