diff --git a/.husky/_/husky.sh b/.husky/_/husky.sh
deleted file mode 100644
index cec959a..0000000
--- a/.husky/_/husky.sh
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env sh
-if [ -z "$husky_skip_init" ]; then
- debug () {
- if [ "$HUSKY_DEBUG" = "1" ]; then
- echo "husky (debug) - $1"
- fi
- }
-
- readonly hook_name="$(basename -- "$0")"
- debug "starting $hook_name..."
-
- if [ "$HUSKY" = "0" ]; then
- debug "HUSKY env variable is set to 0, skipping hook"
- exit 0
- fi
-
- if [ -f ~/.huskyrc ]; then
- debug "sourcing ~/.huskyrc"
- . ~/.huskyrc
- fi
-
- readonly husky_skip_init=1
- export husky_skip_init
- sh -e "$0" "$@"
- exitCode="$?"
-
- if [ $exitCode != 0 ]; then
- echo "husky - $hook_name hook exited with code $exitCode (error)"
- fi
-
- if [ $exitCode = 127 ]; then
- echo "husky - command not found in PATH=$PATH"
- fi
-
- exit $exitCode
-fi
diff --git a/.husky/commit-msg b/.husky/commit-msg
index 0d30cdf..7e2cf34 100644
--- a/.husky/commit-msg
+++ b/.husky/commit-msg
@@ -1,3 +1 @@
-#!/usr/bin/env sh
-. "$(dirname -- "$0")/_/husky.sh"
-npx --no-install commitlint --edit $1
\ No newline at end of file
+npx --no-install commitlint --edit
diff --git a/.husky/pre-commit b/.husky/pre-commit
index 610c2a5..72c4429 100644
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,4 +1 @@
-#!/usr/bin/env sh
-. "$(dirname -- "$0")/_/husky.sh"
-
npm test
diff --git a/package-lock.json b/package-lock.json
index 23f9ab8..b170ac0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@itheum/sdk-mx-data-nft",
- "version": "3.0.0",
+ "version": "2.7.0-beta.11",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@itheum/sdk-mx-data-nft",
- "version": "3.0.0",
+ "version": "2.7.0-beta.11",
"license": "GPL-3.0-only",
"dependencies": {
"@multiversx/sdk-core": "12.18.0",
@@ -24,7 +24,7 @@
"@semantic-release/release-notes-generator": "12.1.0",
"@types/jest": "29.5.11",
"commitlint": "18.4.4",
- "husky": "^8.0.0",
+ "husky": "9.0.11",
"jest": "29.7.0",
"semantic-release": "23.0.2",
"ts-jest": "29.1.2",
@@ -5032,15 +5032,15 @@
}
},
"node_modules/husky": {
- "version": "8.0.3",
- "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
- "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
+ "version": "9.0.11",
+ "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz",
+ "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==",
"dev": true,
"bin": {
- "husky": "lib/bin.js"
+ "husky": "bin.mjs"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/typicode"
diff --git a/package.json b/package.json
index 5818d45..48735b3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@itheum/sdk-mx-data-nft",
- "version": "3.0.0",
+ "version": "2.7.0-beta.11",
"description": "SDK for Itheum's Data NFT Technology on MultiversX Blockchain",
"main": "out/index.js",
"types": "out/index.d.js",
@@ -12,7 +12,7 @@
"lint": "tslint --project .",
"lint:fix": "tslint --project . --fix",
"build": "tsc -p tsconfig.json",
- "prepare": "npm run build"
+ "prepare": "husky"
},
"author": "Itheum Protocol",
"license": "GPL-3.0-only",
@@ -32,7 +32,7 @@
"@semantic-release/release-notes-generator": "12.1.0",
"@types/jest": "29.5.11",
"commitlint": "18.4.4",
- "husky": "^8.0.0",
+ "husky": "9.0.11",
"jest": "29.7.0",
"semantic-release": "23.0.2",
"ts-jest": "29.1.2",
diff --git a/src/abis/core-mx-life-bonding-sc.abi.json b/src/abis/core-mx-life-bonding-sc.abi.json
index d6b224e..3bf9d92 100644
--- a/src/abis/core-mx-life-bonding-sc.abi.json
+++ b/src/abis/core-mx-life-bonding-sc.abi.json
@@ -48,7 +48,7 @@
"type": "u64"
},
{
- "name": "lock_period",
+ "name": "lock_period_seconds",
"type": "u64"
}
],
@@ -108,83 +108,6 @@
],
"outputs": []
},
- {
- "name": "getAcceptedCallers",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "variadic
",
- "multi_result": true
- }
- ]
- },
- {
- "name": "getBondPaymentToken",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "TokenIdentifier"
- }
- ]
- },
- {
- "name": "getLockPeriods",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "variadic",
- "multi_result": true
- }
- ]
- },
- {
- "name": "getLockPeriodBondAmount",
- "mutability": "readonly",
- "inputs": [
- {
- "name": "lock_period",
- "type": "u64"
- }
- ],
- "outputs": [
- {
- "type": "BigUint"
- }
- ]
- },
- {
- "name": "getMinimumPenalty",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "u64"
- }
- ]
- },
- {
- "name": "getMaximumPenalty",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "u64"
- }
- ]
- },
- {
- "name": "getWithdrawPenalty",
- "mutability": "readonly",
- "inputs": [],
- "outputs": [
- {
- "type": "u64"
- }
- ]
- },
{
"name": "getCompensationBlacklist",
"mutability": "readonly",
@@ -395,6 +318,35 @@
}
]
},
+ {
+ "name": "getContractConfiguration",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "ContractConfiguration"
+ }
+ ]
+ },
+ {
+ "name": "initiateBond",
+ "mutability": "mutable",
+ "inputs": [
+ {
+ "name": "address",
+ "type": "Address"
+ },
+ {
+ "name": "token_identifier",
+ "type": "TokenIdentifier"
+ },
+ {
+ "name": "nonce",
+ "type": "u64"
+ }
+ ],
+ "outputs": []
+ },
{
"name": "setBlacklist",
"mutability": "mutable",
@@ -533,7 +485,7 @@
"outputs": []
},
{
- "name": "setPeriodsBonds",
+ "name": "addPeriodsBonds",
"mutability": "mutable",
"inputs": [
{
@@ -620,6 +572,83 @@
"type": "Address"
}
]
+ },
+ {
+ "name": "getAcceptedCallers",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "variadic",
+ "multi_result": true
+ }
+ ]
+ },
+ {
+ "name": "getBondPaymentToken",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "TokenIdentifier"
+ }
+ ]
+ },
+ {
+ "name": "getLockPeriods",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "variadic",
+ "multi_result": true
+ }
+ ]
+ },
+ {
+ "name": "getLockPeriodBondAmount",
+ "mutability": "readonly",
+ "inputs": [
+ {
+ "name": "lock_period",
+ "type": "u64"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "BigUint"
+ }
+ ]
+ },
+ {
+ "name": "getMinimumPenalty",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "u64"
+ }
+ ]
+ },
+ {
+ "name": "getMaximumPenalty",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "u64"
+ }
+ ]
+ },
+ {
+ "name": "getWithdrawPenalty",
+ "mutability": "readonly",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "u64"
+ }
+ ]
}
],
"events": [
@@ -1041,6 +1070,43 @@
}
]
},
+ "ContractConfiguration": {
+ "type": "struct",
+ "fields": [
+ {
+ "name": "contract_state",
+ "type": "State"
+ },
+ {
+ "name": "bond_payment_token_identifier",
+ "type": "TokenIdentifier"
+ },
+ {
+ "name": "lock_periods",
+ "type": "List"
+ },
+ {
+ "name": "bond_amounts",
+ "type": "List"
+ },
+ {
+ "name": "minimum_penalty",
+ "type": "u64"
+ },
+ {
+ "name": "maximum_penalty",
+ "type": "u64"
+ },
+ {
+ "name": "withdraw_penalty",
+ "type": "u64"
+ },
+ {
+ "name": "accepted_callers",
+ "type": "List"
+ }
+ ]
+ },
"EsdtTokenPayment": {
"type": "struct",
"fields": [
diff --git a/src/bond.ts b/src/bond.ts
index f5b0629..5d3f477 100644
--- a/src/bond.ts
+++ b/src/bond.ts
@@ -9,7 +9,8 @@ import {
TokenIdentifierValue,
Transaction,
TypedValue,
- U64Value
+ U64Value,
+ VariadicValue
} from '@multiversx/sdk-core/out';
import {
EnvironmentsEnum,
@@ -22,12 +23,19 @@ import BigNumber from 'bignumber.js';
import bondContractAbi from './abis/core-mx-life-bonding-sc.abi.json';
import {
parseBond,
+ parseBondConfiguration,
parseCompensation,
parseRefund,
parseTokenIdentifier
} from './common/utils';
import { Contract } from './contract';
-import { Bond, Compensation, PenaltyType, State } from './interfaces';
+import {
+ Bond,
+ BondConfiguration,
+ Compensation,
+ PenaltyType,
+ State
+} from './interfaces';
export class BondContract extends Contract {
/**
@@ -71,6 +79,33 @@ export class BondContract extends Contract {
}
}
+ /**
+ * Returns the `bond` contract configuration
+ */
+ async viewContractConfiguration(): Promise {
+ const interaction = this.contract.methodsExplicit.getContractConfiguration(
+ []
+ );
+ const query = interaction.buildQuery();
+ const queryResponse = await this.networkProvider.queryContract(query);
+ const endpointDefinition = interaction.getEndpoint();
+ const { firstValue, returnCode } = new ResultsParser().parseQueryResponse(
+ queryResponse,
+ endpointDefinition
+ );
+ if (returnCode.isSuccess()) {
+ const firstValueAsVariadic = firstValue as VariadicValue;
+ const returnValue = firstValueAsVariadic?.valueOf();
+ const bondConfiguration = parseBondConfiguration(returnValue);
+ return bondConfiguration;
+ } else {
+ throw new ErrContractQuery(
+ 'viewContractConfiguration',
+ returnCode.toString()
+ );
+ }
+ }
+
/**
* Returns the contract owner address
*/
@@ -142,7 +177,7 @@ export class BondContract extends Contract {
* Returns the contract lock periods and bond amounts
*/
async viewLockPeriodsWithBonds(): Promise<
- { lockPeriod: string; amount: string }[]
+ { lockPeriod: number; amount: BigNumber.Value }[]
> {
const interaction = this.contract.methodsExplicit.getLockPeriodsBonds([]);
const query = interaction.buildQuery();
@@ -157,10 +192,10 @@ export class BondContract extends Contract {
const bondAmounts: BigNumber[] = firstValue?.valueOf().field1;
// Construct array of objects containing lock period and bond amount
- const result: { lockPeriod: string; amount: string }[] = [];
+ const result: { lockPeriod: number; amount: BigNumber.Value }[] = [];
for (let i = 0; i < lockPeriods.length; i++) {
- const lockPeriod = lockPeriods[i].toString();
- const bondAmount = bondAmounts[i].toString();
+ const lockPeriod = lockPeriods[i].toNumber();
+ const bondAmount = bondAmounts[i];
result.push({ lockPeriod: lockPeriod, amount: bondAmount });
}
@@ -772,26 +807,57 @@ export class BondContract extends Contract {
}
/**
- * Builds a `setPeriodsBonds` transaction to set the periods and bonds
+ * Builds a `initiateBond` transaction to "whitelist" an address for being able to bond for a specific Data NFT
+ * @param senderAddress the address of the sender
+ * @param address the address to be whitelisted
+ * @param tokenIdentifier the token identifier
+ * @param nonce the token identifier nonce
+ */
+ initiateBond(
+ senderAddress: IAddress,
+ address: IAddress,
+ tokenIdentifier: string,
+ nonce: number
+ ): Transaction {
+ const tx = new Transaction({
+ value: 0,
+ data: new ContractCallPayloadBuilder()
+ .setFunction('initiateBond')
+ .addArg(new AddressValue(address))
+ .addArg(new TokenIdentifierValue(tokenIdentifier))
+ .addArg(new U64Value(nonce))
+ .build(),
+ receiver: this.contract.getAddress(),
+ sender: senderAddress,
+ gasLimit: 20_000_000,
+ chainID: this.chainID
+ });
+ return tx;
+ }
+
+ /**
+ * Builds a `addPeriodsBonds` transaction to set the periods and bonds
* @param senderAddress the address of the sender
* @param periods an array of periods
* @param bonds an array of bond values
*/
- setPeriodsBonds(
+ addPeriodsBonds(
senderAddress: IAddress,
- periods: number[],
- bonds: BigNumber.Value[]
+ lockPeriodsWithBonds: {
+ lockPeriod: number;
+ amount: BigNumber.Value;
+ }[]
) {
let combinedArray: TypedValue[] = [];
- periods.map((period, index) => {
- combinedArray.push(new U64Value(period));
- combinedArray.push(new BigUIntValue(bonds[index]));
+ lockPeriodsWithBonds.map((lockPeriodWithBond) => {
+ combinedArray.push(new U64Value(lockPeriodWithBond.lockPeriod));
+ combinedArray.push(new BigUIntValue(lockPeriodWithBond.amount));
});
const tx = new Transaction({
value: 0,
data: new ContractCallPayloadBuilder()
- .setFunction('setPeriodsBonds')
+ .setFunction('addPeriodsBonds')
.setArgs(combinedArray)
.build(),
receiver: this.contract.getAddress(),
@@ -1078,11 +1144,10 @@ export class BondContract extends Contract {
.setFunction('withdraw')
.addArg(new TokenIdentifierValue(tokenIdentifier))
.addArg(new U64Value(nonce))
- .addArg(new U64Value(nonce))
.build(),
receiver: this.contract.getAddress(),
sender: senderAddress,
- gasLimit: 10_000_000,
+ gasLimit: 50_000_000,
chainID: this.chainID
});
return withdrawTx;
diff --git a/src/common/utils.ts b/src/common/utils.ts
index c6f81db..f9bc199 100644
--- a/src/common/utils.ts
+++ b/src/common/utils.ts
@@ -8,11 +8,14 @@ import {
} from '../errors';
import {
Bond,
+ BondConfiguration,
Compensation,
+ ContractConfiguration,
NftEnumType,
NftType,
Offer,
- Refund
+ Refund,
+ State
} from '../interfaces';
import { EnvironmentsEnum, dataMarshalUrlOverride } from '../config';
@@ -98,6 +101,30 @@ export function parseBond(value: any): Bond {
};
}
+export function parseBondConfiguration(value: any): BondConfiguration {
+ const lockPeriods: BigNumber[] = value.lock_periods;
+ const bondAmounts: BigNumber[] = value.bond_amounts;
+
+ // Construct array of objects containing lock period and bond amount
+ const result: { lockPeriod: number; amount: BigNumber.Value }[] = [];
+ for (let i = 0; i < lockPeriods.length; i++) {
+ const lockPeriod = lockPeriods[i].toNumber();
+ const bondAmount = bondAmounts[i].toFixed(0);
+ result.push({ lockPeriod: lockPeriod, amount: bondAmount });
+ }
+ return {
+ contractState: value.contract_state.name as State,
+ bondPaymentTokenIdentifier: value.bond_payment_token_identifier.toString(),
+ lockPeriodsWithBonds: result,
+ minimumPenalty: value.minimum_penalty.toNumber(),
+ maximumPenalty: value.maximum_penalty.toNumber(),
+ withdrawPenalty: value.withdraw_penalty.toNumber(),
+ acceptedCallers: value.accepted_callers.map((address: any) =>
+ address.toString()
+ )
+ };
+}
+
export function parseCompensation(value: any): Compensation {
return {
compensationId: value.compensation_id.toNumber(),
diff --git a/src/interfaces.ts b/src/interfaces.ts
index 91a9e9b..f960a12 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -137,6 +137,16 @@ export interface Bond {
remainingAmount: BigNumber.Value;
}
+export interface BondConfiguration {
+ contractState: State;
+ bondPaymentTokenIdentifier: string;
+ lockPeriodsWithBonds: { lockPeriod: number; amount: BigNumber.Value }[];
+ minimumPenalty: number;
+ maximumPenalty: number;
+ withdrawPenalty: number;
+ acceptedCallers: string[];
+}
+
export interface Refund {
compensationId: number;
address: string;
diff --git a/src/nft-minter.ts b/src/nft-minter.ts
index bd502a1..3d5af4f 100644
--- a/src/nft-minter.ts
+++ b/src/nft-minter.ts
@@ -187,7 +187,6 @@ export class NftMinter extends Minter {
// deep validate all mandatory URLs
try {
- await checkUrlIsUp(dataStreamUrl, [200, 403]);
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);
} catch (error) {
diff --git a/src/sft-minter.ts b/src/sft-minter.ts
index cc9641b..d12b9d1 100644
--- a/src/sft-minter.ts
+++ b/src/sft-minter.ts
@@ -243,8 +243,8 @@ export class SftMinter extends Minter {
supply: number,
datasetTitle: string,
datasetDescription: string,
- lockPeriod: number,
amountToSend: number,
+ lockPeriod?: number,
options?: {
imageUrl?: string;
traitsUrl?: string;
@@ -292,7 +292,6 @@ export class SftMinter extends Minter {
// deep validate all mandatory URLs
try {
- await checkUrlIsUp(dataStreamUrl, [200, 403]);
await checkUrlIsUp(dataPreviewUrl, [200]);
await checkUrlIsUp(dataMarshalUrl + '/health-check', [200]);
} catch (error) {
@@ -363,12 +362,14 @@ export class SftMinter extends Minter {
.addArg(new U64Value(royalties))
.addArg(new U64Value(supply))
.addArg(new StringValue(datasetTitle))
- .addArg(new StringValue(datasetDescription))
- .addArg(new U64Value(lockPeriod))
- .build();
+ .addArg(new StringValue(datasetDescription));
+
+ if (lockPeriod) {
+ data.addArg(new U64Value(lockPeriod));
+ }
const mintTx = new Transaction({
- data,
+ data: data.build(),
sender: senderAddress,
receiver: this.contract.getAddress(),
gasLimit: 80_000_000,
diff --git a/tests/bond.test.ts b/tests/bond.test.ts
index a6984bb..7587f83 100644
--- a/tests/bond.test.ts
+++ b/tests/bond.test.ts
@@ -1,4 +1,5 @@
import {
+ BondConfiguration,
BondContract,
Compensation,
State,
@@ -16,6 +17,13 @@ describe('Bond test', () => {
expect(e.message).toBe('Contract address is not deployed on testnet');
}
});
+
+ test('#view bond configuration', async () => {
+ const bondContract = new BondContract('devnet');
+ const bondConfiguration = await bondContract.viewContractConfiguration();
+
+ expect(bondConfiguration).toMatchObject;
+ });
test('#test view methods', async () => {
const bondContract = new BondContract('devnet');
diff --git a/tests/datanft.test.ts b/tests/datanft.test.ts
index 8872ada..47496f3 100644
--- a/tests/datanft.test.ts
+++ b/tests/datanft.test.ts
@@ -96,7 +96,7 @@ describe('Data NFT test', () => {
});
const owners = await dataNft.getOwners();
- });
+ }, 200000);
test('#parse token identifier', () => {
const tokenIdentifier = 'DATANFTFT3-d0978a';
@@ -112,7 +112,7 @@ describe('Data NFT test', () => {
expect(parsed).toBeInstanceOf(
Object as unknown as { collection: string; nonce: String }
);
- });
+ }, 20000);
test('#override marhsal url', async () => {
DataNft.setNetworkConfig('mainnet');
@@ -124,7 +124,7 @@ describe('Data NFT test', () => {
);
expect(dataNft.dataMarshal).toBe(marshalUrls[EnvironmentsEnum.devnet]);
expect(dataNft.overrideDataMarshalChainId).toBe('1');
- });
+ }, 20000);
test('#override marshal url should be empty', async () => {
DataNft.setNetworkConfig('mainnet');
@@ -141,5 +141,5 @@ describe('Data NFT test', () => {
expect(dataNft.overrideDataMarshal).toBe('overrideUrl');
expect(dataNft.overrideDataMarshalChainId).toBe('D');
- });
+ }, 20000);
});
diff --git a/tests/nftminter.test.ts b/tests/nftminter.test.ts
index a2041fe..c4d3463 100644
--- a/tests/nftminter.test.ts
+++ b/tests/nftminter.test.ts
@@ -88,7 +88,7 @@ describe('Nft minter test', () => {
}
);
expect(mintTx).toBeInstanceOf(Transaction);
- }, 40000);
+ }, 200000);
test('#mint nft using tax for minting', async () => {
const factoryGeneratedContract = new Address(