Skip to content

Commit

Permalink
feat: view methods for bond contract
Browse files Browse the repository at this point in the history
Refs: #99
  • Loading branch information
bucurdavid committed Feb 22, 2024
1 parent 5f23ce5 commit d7eb098
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 27 deletions.
22 changes: 16 additions & 6 deletions src/abis/core-mx-life-bonding-sc.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
},
{
"name": "lock_period",
"type": "u16"
"type": "u64"
}
],
"outputs": []
Expand Down Expand Up @@ -83,7 +83,7 @@
},
{
"name": "new_lock_period",
"type": "optional<u16>",
"type": "optional<u64>",
"multi_arg": true
}
],
Expand Down Expand Up @@ -116,7 +116,7 @@
"inputs": [],
"outputs": [
{
"type": "variadic<u16>",
"type": "variadic<u64>",
"multi_result": true
}
]
Expand All @@ -127,7 +127,7 @@
"inputs": [
{
"name": "lock_period",
"type": "u16"
"type": "u64"
}
],
"outputs": [
Expand Down Expand Up @@ -276,6 +276,16 @@
}
]
},
{
"name": "getLockPeriodsBonds",
"mutability": "readonly",
"inputs": [],
"outputs": [
{
"type": "tuple<List<u64>,List<BigUint>>"
}
]
},
{
"name": "sanction",
"mutability": "mutable",
Expand Down Expand Up @@ -356,7 +366,7 @@
"inputs": [
{
"name": "args",
"type": "variadic<multi<u16,BigUint>>",
"type": "variadic<multi<u64,BigUint>>",
"multi_arg": true
}
],
Expand Down Expand Up @@ -452,7 +462,7 @@
},
{
"name": "lock_period",
"type": "u16"
"type": "u64"
},
{
"name": "bond_timestamp",
Expand Down
151 changes: 134 additions & 17 deletions src/bond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ import {
} from './config';

import bondContractAbi from './abis/core-mx-life-bonding-sc.abi.json';
import { Bond, Compensation } from './interfaces';
import { parseBond, parseCompensation } from './common/utils';
import { Bond, Compensation, State } from './interfaces';
import {
parseBond,
parseCompensation,
parseTokenIdentifier
} from './common/utils';
import BigNumber from 'bignumber.js';

export class BondContract {
readonly contract: SmartContract;
Expand Down Expand Up @@ -62,13 +67,72 @@ export class BondContract {
}

/**
* Returns a `Bond` object for the given bondId
* @param bondId bond id to query
* Returns the contract state as a `State` enum
*/
async viewBond(bondId: number): Promise<Bond> {
const interaction = this.contract.methodsExplicit.getBond([
new U64Value(bondId)
]);
async viewContractState(): Promise<State> {
const interaction = this.contract.methodsExplicit.getContractState([]);
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 stateValue = firstValue?.valueOf();
return stateValue.name as State;
} else {
throw new ErrContractQuery('viewContractState', returnCode.toString());
}
}

/**
* Returns the contract owner address
*/
async viewAdministrator(): Promise<string> {
const interaction = this.contract.methodsExplicit.getAdministrator([]);
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()) {
return firstValue?.valueOf();
} else {
throw new ErrContractQuery('viewAdministrator', returnCode.toString());
}
}

/**
* Returns the accepted callers that can bond
*/
async viewAcceptedCallers(): Promise<string[]> {
const interaction = this.contract.methodsExplicit.getAcceptedCallers();
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()) {
return firstValue
?.valueOf()
.map((address: any) => new Address(address).bech32());
} else {
throw new ErrContractQuery('viewAcceptedCallers', returnCode.toString());
}
}

/**
* Returns the contract lock periods and bond amounts
*/
async viewLockPeriodsWithBonds(): Promise<
{ lockPeriod: string; amount: string }[]
> {
const interaction = this.contract.methodsExplicit.getLockPeriodsBonds([]);
const query = interaction.buildQuery();
const queryResponse = await this.networkProvider.queryContract(query);
const endpointDefinition = interaction.getEndpoint();
Expand All @@ -77,10 +141,42 @@ export class BondContract {
endpointDefinition
);
if (returnCode.isSuccess()) {
const bond = parseBond(firstValue);
return bond;
const lockPeriods: BigNumber[] = firstValue?.valueOf().field0;
const bondAmounts: BigNumber[] = firstValue?.valueOf().field1;

// Construct array of objects containing lock period and bond amount
const result: { lockPeriod: string; amount: string }[] = [];
for (let i = 0; i < lockPeriods.length; i++) {
const lockPeriod = lockPeriods[i].toString();
const bondAmount = bondAmounts[i].toString();
result.push({ lockPeriod: lockPeriod, amount: bondAmount });
}

return result;
} else {
throw new ErrContractQuery('viewBond', returnCode.toString());
throw new ErrContractQuery(
'viewLockPeriodsWithBonds',
returnCode.toString()
);
}
}

/**
* Returns the contract bond payment token
*/
async viewBondPaymentToken(): Promise<string> {
const interaction = this.contract.methodsExplicit.getBondPaymentToken([]);
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()) {
return firstValue?.valueOf();
} else {
throw new ErrContractQuery('viewBondPaymentToken', returnCode.toString());
}
}

Expand Down Expand Up @@ -134,14 +230,23 @@ export class BondContract {
* @param bondIds Bond ids to query.
*/
async viewBonds(bondIds: number[]): Promise<Bond[]>;
/**
* Returns a `Bond` object array for the given full tokenIdentifier.
* @param fullTokenIdentifier Full tokenIdentifier to query.
*/
async viewBonds(fullTokenIdentifiers: string[]): Promise<Bond[]>;
/**
* Returns a `Bond` object array for the given tokenIdentifiers and nonces.
* @param tokenIdentifier Token identifiers array to query.
* @param nonce Nonce array to query.
*/
async viewBonds(tokenIdentifier: string[], nonce: number[]): Promise<Bond[]>;
async viewBonds(
tokenIdentifiers: string[],
nonces: number[]
): Promise<Bond[]>;
async viewBonds(arg1: number[] | string[], arg2?: number[]): Promise<Bond[]> {
let interaction;

if (Array.isArray(arg1) && typeof arg1[0] === 'number') {
// Implementation for bondIds
const bondIdsAsU64 = arg1.map((id) => new U64Value(id));
Expand All @@ -159,7 +264,20 @@ export class BondContract {
combinedArray.push(new U64Value(arg2[i]));
}
interaction =
this.contract.methodsExplicit.getBondsByTokenIdentifierAndNonce(
this.contract.methodsExplicit.getBondsByTokenIdentifierNonce(
combinedArray
);
} else if (Array.isArray(arg1) && typeof arg1[0] === 'string' && !arg2) {
// Implementation for fullTokenIdentifier
const combinedArray = [];
for (let i = 0; i < arg1.length; i++) {
const { collection, nonce } = parseTokenIdentifier(arg1[i].toString());
combinedArray.push(new TokenIdentifierValue(collection));
combinedArray.push(new U64Value(nonce));
}

interaction =
this.contract.methodsExplicit.getBondsByTokenIdentifierNonce(
combinedArray
);
} else {
Expand All @@ -175,19 +293,18 @@ export class BondContract {
);
if (returnCode.isSuccess()) {
const returnValue = firstValue?.valueOf();
const bonds: Bond[] = returnValue.map((offer: any) => parseBond(offer));
const bonds: Bond[] = returnValue.map((bond: any) => parseBond(bond));
return bonds;
} else {
throw new ErrContractQuery('viewBonds', returnCode.toString());
}
}

/**
* Returns a `Compensation` object for the given tokenIdentifier and nonce
* @param tokenIdentifier token identifier to query
* @param nonce nonce to query
*/
async getCompensation(
async viewCompensation(
tokenIdentifier: string,
nonce: number
): Promise<Compensation> {
Expand All @@ -203,7 +320,7 @@ export class BondContract {
endpointDefinition
);
if (returnCode.isSuccess()) {
const compensation = parseCompensation(firstValue);
const compensation = parseCompensation(firstValue?.valueOf());
return compensation;
} else {
throw new ErrContractQuery('getCompensation', returnCode.toString());
Expand Down
4 changes: 2 additions & 2 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function parseBond(value: any): Bond {
nonce: value.nonce.toNumber(),
lockPeriod: value.lock_period.toNumber(),
bond_timestamp: value.bond_timestamp.toNumber(),
unbound_timestmap: value.unbound_timestmap.toNumber(),
unbound_timestamp: value.unbound_timestamp.toNumber(),
bond_amount: value.bond_amount.toFixed(0)
};
}
Expand All @@ -91,7 +91,7 @@ export function parseCompensation(value: any): Compensation {
return {
tokenIdentifier: value.token_identifier.toString(),
nonce: value.nonce.toNumber(),
totalCompensationAmount: value.total_compensation_amount.toFixed(0)
totalCompensationAmount: value.total_compenstation_amount.toFixed(0)
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const minterContractAddress: { [key in EnvironmentsEnum]: string } = {
};

export const bondContractAddress: { [key in EnvironmentsEnum]: string } = {
devnet: 'erd1qqqqqqqqqqqqqpgq5j9uzn3sede83tqc32jkurxzle4hntzgw3wqjvcj9q',
devnet: 'erd1qqqqqqqqqqqqqpgqwufw9acp0lnl4ljugq0zttu0jw2hx4zcw3wqm0ghg0',
mainnet: '',
testnet: ''
};
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export * from './marketplace';
export * from './minter';
export * from './nft-minter';
export * from './sft-minter';
export * from './bond';
export { parseTokenIdentifier, createTokenIdentifier } from './common/utils';
7 changes: 6 additions & 1 deletion src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,15 @@ export interface Bond {
nonce: number;
lockPeriod: number; // days
bond_timestamp: number;
unbound_timestmap: number;
unbound_timestamp: number;
bond_amount: string;
}

export enum State {
Inactive = 0,
Active = 1
}

export interface Compensation {
tokenIdentifier: string;
nonce: number;
Expand Down
47 changes: 47 additions & 0 deletions tests/bond.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { BondContract, Compensation, State } from '../src';
import { Bond } from '../src';

describe('Bond test', () => {
test('#test view methods', async () => {
const bondContract = new BondContract('devnet');

const bondPaymentToken = await bondContract.viewBondPaymentToken();

expect(typeof bondPaymentToken).toBe('string');

const lockPeriodsWithBonds = await bondContract.viewLockPeriodsWithBonds();

expect(typeof lockPeriodsWithBonds).toBe('object');

const contractState = await bondContract.viewContractState();

expect(Object.values(State).includes(contractState)).toBe(true);

const acceptedCallers = await bondContract.viewAcceptedCallers();

expect(typeof acceptedCallers).toBe('object');

const bond: Bond[] = await bondContract.viewBonds([1]);

expect(bond).toMatchObject<Bond>;

const sameBond: Bond[] = await bondContract.viewBonds(
['NEWDNFT-3a8caa'],
[8]
);

expect(sameBond).toMatchObject<Bond[]>;

const sameBond2: Bond[] = await bondContract.viewBonds([
'NEWDNFT-3a8caa-08'
]);
expect(sameBond2).toMatchObject<Bond[]>;

const compensation: Compensation = await bondContract.viewCompensation(
'NEWDNFT-3a8caa',
8
);

expect(compensation).toMatchObject<Compensation>;
});
});

0 comments on commit d7eb098

Please sign in to comment.