@obolnetwork/obol-sdk 2.2.4 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/package.json +2 -2
- package/dist/cjs/src/abi/MerkleDistributorWithDeadline.js +73 -0
- package/dist/cjs/src/incentives.js +92 -0
- package/dist/cjs/src/incentivesHalpers.js +41 -0
- package/dist/cjs/src/index.js +2 -0
- package/dist/cjs/test/incentives.test.js +174 -0
- package/dist/cjs/test/methods.test.js +10 -22
- package/dist/esm/package.json +2 -2
- package/dist/esm/src/abi/MerkleDistributorWithDeadline.js +70 -0
- package/dist/esm/src/incentives.js +88 -0
- package/dist/esm/src/incentivesHalpers.js +36 -0
- package/dist/esm/src/index.js +2 -0
- package/dist/esm/test/incentives.test.js +149 -0
- package/dist/esm/test/methods.test.js +10 -22
- package/dist/types/src/abi/MerkleDistributorWithDeadline.d.ts +91 -0
- package/dist/types/src/incentives.d.ts +49 -0
- package/dist/types/src/incentivesHalpers.d.ts +13 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/types.d.ts +15 -0
- package/dist/types/test/incentives.test.d.ts +1 -0
- package/package.json +2 -2
- package/src/abi/MerkleDistributorWithDeadline.ts +70 -0
- package/src/incentives.ts +116 -0
- package/src/incentivesHalpers.ts +58 -0
- package/src/index.ts +7 -0
- package/src/types.ts +20 -0
package/dist/cjs/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "A package for creating Distributed Validators using the Obol API.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/obolnetwork/obol-sdk/issues"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json",
|
|
16
16
|
"build:clean": "rm -rf ./dist",
|
|
17
17
|
"build": "npm-run-all build:clean compile",
|
|
18
|
-
"test": "jest ./test
|
|
18
|
+
"test": "jest ./test/*.test.ts",
|
|
19
19
|
"generate-typedoc": "typedoc",
|
|
20
20
|
"npm:publish": "npm publish --tag latest",
|
|
21
21
|
"release": "release-it",
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MerkleDistributorABI = void 0;
|
|
4
|
+
exports.MerkleDistributorABI = {
|
|
5
|
+
abi: [
|
|
6
|
+
{
|
|
7
|
+
inputs: [
|
|
8
|
+
{ internalType: 'address', name: 'token_', type: 'address' },
|
|
9
|
+
{ internalType: 'bytes32', name: 'merkleRoot_', type: 'bytes32' },
|
|
10
|
+
],
|
|
11
|
+
stateMutability: 'nonpayable',
|
|
12
|
+
type: 'constructor',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
anonymous: false,
|
|
16
|
+
inputs: [
|
|
17
|
+
{
|
|
18
|
+
indexed: false,
|
|
19
|
+
internalType: 'uint256',
|
|
20
|
+
name: 'index',
|
|
21
|
+
type: 'uint256',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
indexed: false,
|
|
25
|
+
internalType: 'address',
|
|
26
|
+
name: 'account',
|
|
27
|
+
type: 'address',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
indexed: false,
|
|
31
|
+
internalType: 'uint256',
|
|
32
|
+
name: 'amount',
|
|
33
|
+
type: 'uint256',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
name: 'Claimed',
|
|
37
|
+
type: 'event',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
inputs: [
|
|
41
|
+
{ internalType: 'uint256', name: 'index', type: 'uint256' },
|
|
42
|
+
{ internalType: 'address', name: 'account', type: 'address' },
|
|
43
|
+
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
|
|
44
|
+
{ internalType: 'bytes32[]', name: 'merkleProof', type: 'bytes32[]' },
|
|
45
|
+
],
|
|
46
|
+
name: 'claim',
|
|
47
|
+
outputs: [],
|
|
48
|
+
stateMutability: 'nonpayable',
|
|
49
|
+
type: 'function',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
inputs: [{ internalType: 'uint256', name: 'index', type: 'uint256' }],
|
|
53
|
+
name: 'isClaimed',
|
|
54
|
+
outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
|
|
55
|
+
stateMutability: 'view',
|
|
56
|
+
type: 'function',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
inputs: [],
|
|
60
|
+
name: 'merkleRoot',
|
|
61
|
+
outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
|
|
62
|
+
stateMutability: 'view',
|
|
63
|
+
type: 'function',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
inputs: [],
|
|
67
|
+
name: 'token',
|
|
68
|
+
outputs: [{ internalType: 'address', name: '', type: 'address' }],
|
|
69
|
+
stateMutability: 'view',
|
|
70
|
+
type: 'function',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.Incentives = void 0;
|
|
13
|
+
const utils_1 = require("./utils");
|
|
14
|
+
const incentivesHalpers_1 = require("./incentivesHalpers");
|
|
15
|
+
const constants_1 = require("./constants");
|
|
16
|
+
class Incentives {
|
|
17
|
+
constructor(signer, chainId, request) {
|
|
18
|
+
this.signer = signer;
|
|
19
|
+
this.chainId = chainId;
|
|
20
|
+
this.request = request;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Claims obol incentives from a Merkle Distributor contract.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* **⚠️ Important:** If you're storing the private key in an `.env` file, ensure it is securely managed
|
|
27
|
+
* and not pushed to version control.
|
|
28
|
+
*
|
|
29
|
+
* @param {Object} incentivesData - The incentives data needed for claiming.
|
|
30
|
+
* @param {string} incentivesData.contractAddress - The address of the Merkle Distributor contract.
|
|
31
|
+
* @param {number} incentivesData.index - The index in the Merkle tree.
|
|
32
|
+
* @param {string} incentivesData.operatorAddress - The address of the operator.
|
|
33
|
+
* @param {number} incentivesData.amount - The amount to claim.
|
|
34
|
+
* @param {string[]} incentivesData.merkleProof - The Merkle proof.
|
|
35
|
+
* @returns {Promise<{ txHash: string }>} The transaction hash of the claim transaction.
|
|
36
|
+
* @throws Will throw an error if the contract is not available or the claim fails.
|
|
37
|
+
*
|
|
38
|
+
*/
|
|
39
|
+
claimIncentives(incentivesData) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
if (!this.signer) {
|
|
42
|
+
throw new Error('Signer is required in claimIncentives');
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const isContractDeployed = yield (0, utils_1.isContractAvailable)(incentivesData.contractAddress, this.signer.provider);
|
|
46
|
+
if (!isContractDeployed) {
|
|
47
|
+
throw new Error(`Merkle Distributor contract is not available at address ${incentivesData.contractAddress}`);
|
|
48
|
+
}
|
|
49
|
+
const { txHash } = yield (0, incentivesHalpers_1.claimIncentivesFromMerkleDistributor)({
|
|
50
|
+
signer: this.signer,
|
|
51
|
+
contractAddress: incentivesData.contractAddress,
|
|
52
|
+
index: incentivesData.index,
|
|
53
|
+
operatorAddress: incentivesData.operatorAddress,
|
|
54
|
+
amount: incentivesData.amount,
|
|
55
|
+
merkleProof: incentivesData.merkleProof,
|
|
56
|
+
});
|
|
57
|
+
return { txHash };
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
console.log('Error claiming incentives:', error);
|
|
61
|
+
throw new Error(`Failed to claim incentives: ${error.message}`);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Read isClaimed.
|
|
67
|
+
*
|
|
68
|
+
* @param {ETH_ADDRESS} contractAddress - Address of the Merkle Distributor Contract
|
|
69
|
+
* @param {ETH_ADDRESS} index - operator index in merkle tree
|
|
70
|
+
* @returns {Promise<boolean>} true if incentives are already claime
|
|
71
|
+
*
|
|
72
|
+
*/
|
|
73
|
+
isClaimed(contractAddress, index) {
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
return yield (0, incentivesHalpers_1.isClaimedFromMerkleDistributor)(this.chainId, contractAddress, index);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @param address - Operator address
|
|
80
|
+
* @returns {Promise<IncentivesType>} The matched incentives from DB
|
|
81
|
+
* @throws On not found if address not found.
|
|
82
|
+
*/
|
|
83
|
+
getIncentivesByAddress(address) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
const incentives = yield this.request(`/${constants_1.DEFAULT_BASE_VERSION}/address/incentives/${address}`, {
|
|
86
|
+
method: 'GET',
|
|
87
|
+
});
|
|
88
|
+
return incentives;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
exports.Incentives = Incentives;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.isClaimedFromMerkleDistributor = exports.claimIncentivesFromMerkleDistributor = void 0;
|
|
13
|
+
const ethers_1 = require("ethers");
|
|
14
|
+
const MerkleDistributorWithDeadline_1 = require("./abi/MerkleDistributorWithDeadline");
|
|
15
|
+
const utils_1 = require("./utils");
|
|
16
|
+
const claimIncentivesFromMerkleDistributor = (incentivesData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
|
+
try {
|
|
18
|
+
const contract = new ethers_1.Contract(incentivesData.contractAddress, MerkleDistributorWithDeadline_1.MerkleDistributorABI.abi, incentivesData.signer);
|
|
19
|
+
const tx = yield contract.claim(BigInt(incentivesData.index), incentivesData.operatorAddress, BigInt(incentivesData.amount), incentivesData.merkleProof);
|
|
20
|
+
const receipt = yield tx.wait();
|
|
21
|
+
return { txHash: receipt.hash };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.log('Error claiming incentives:', error);
|
|
25
|
+
throw new Error(`Failed to claim incentives: ${error.message}`);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
exports.claimIncentivesFromMerkleDistributor = claimIncentivesFromMerkleDistributor;
|
|
29
|
+
const isClaimedFromMerkleDistributor = (chainId, contractAddress, index) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
try {
|
|
31
|
+
const provider = (0, utils_1.getProvider)(chainId);
|
|
32
|
+
const contract = new ethers_1.Contract(contractAddress, MerkleDistributorWithDeadline_1.MerkleDistributorABI.abi, provider);
|
|
33
|
+
const claimed = yield contract.isClaimed(BigInt(index));
|
|
34
|
+
return claimed;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.log('Error checking claim status:', error);
|
|
38
|
+
throw new Error(`Failed to check claim status: ${error.message}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
exports.isClaimedFromMerkleDistributor = isClaimedFromMerkleDistributor;
|
package/dist/cjs/src/index.js
CHANGED
|
@@ -34,6 +34,7 @@ const ajv_js_1 = require("./ajv.js");
|
|
|
34
34
|
const schema_js_1 = require("./schema.js");
|
|
35
35
|
const splitHelpers_js_1 = require("./splitHelpers.js");
|
|
36
36
|
const utils_js_1 = require("./utils.js");
|
|
37
|
+
const incentives_js_1 = require("./incentives.js");
|
|
37
38
|
__exportStar(require("./types.js"), exports);
|
|
38
39
|
__exportStar(require("./services.js"), exports);
|
|
39
40
|
__exportStar(require("./verification/signature-validator.js"), exports);
|
|
@@ -55,6 +56,7 @@ class Client extends base_js_1.Base {
|
|
|
55
56
|
constructor(config, signer) {
|
|
56
57
|
super(config);
|
|
57
58
|
this.signer = signer;
|
|
59
|
+
this.incentives = new incentives_js_1.Incentives(this.signer, this.chainId, this.request.bind(this));
|
|
58
60
|
}
|
|
59
61
|
/**
|
|
60
62
|
* Accepts Obol terms and conditions to be able to create or update data.
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var _a, _b;
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const ethers_1 = require("ethers");
|
|
37
|
+
const index_1 = require("../src/index");
|
|
38
|
+
const utils = __importStar(require("../src/utils"));
|
|
39
|
+
const incentivesHelpers = __importStar(require("../src/incentivesHalpers"));
|
|
40
|
+
const constants_1 = require("../src/constants");
|
|
41
|
+
const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
|
|
42
|
+
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
43
|
+
const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
|
|
44
|
+
const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
|
|
45
|
+
const mockSigner = wallet.connect(provider);
|
|
46
|
+
const baseUrl = 'https://obol-api-dev.gcp.obol.tech';
|
|
47
|
+
global.fetch = jest.fn();
|
|
48
|
+
describe('Client.incentives', () => {
|
|
49
|
+
let clientInstance;
|
|
50
|
+
const mockIncentivesData = {
|
|
51
|
+
contractAddress: '0x1234567890abcdef1234567890abcdef12345678',
|
|
52
|
+
index: 5,
|
|
53
|
+
operatorAddress: '0xabcdef1234567890abcdef1234567890abcdef12',
|
|
54
|
+
amount: 1000000000000000000,
|
|
55
|
+
merkleProof: [
|
|
56
|
+
'0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef',
|
|
57
|
+
'0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890',
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
jest.clearAllMocks();
|
|
62
|
+
clientInstance = new index_1.Client({ baseUrl, chainId: 17000 }, mockSigner);
|
|
63
|
+
global.fetch.mockReset();
|
|
64
|
+
});
|
|
65
|
+
test('claimIncentives should throw an error without signer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
66
|
+
const clientWithoutSigner = new index_1.Client({
|
|
67
|
+
baseUrl,
|
|
68
|
+
chainId: 17000,
|
|
69
|
+
});
|
|
70
|
+
yield expect(clientWithoutSigner.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Signer is required in claimIncentives');
|
|
71
|
+
}));
|
|
72
|
+
test('claimIncentives should throw an error if contract is not available', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
+
jest
|
|
74
|
+
.spyOn(utils, 'isContractAvailable')
|
|
75
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
|
|
76
|
+
yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow(`Merkle Distributor contract is not available at address ${mockIncentivesData.contractAddress}`);
|
|
77
|
+
}));
|
|
78
|
+
test('claimIncentives should return txHash on successful claim', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
79
|
+
const mockTxHash = '0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef';
|
|
80
|
+
jest
|
|
81
|
+
.spyOn(utils, 'isContractAvailable')
|
|
82
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
83
|
+
jest
|
|
84
|
+
.spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
|
|
85
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve({ txHash: mockTxHash }); }));
|
|
86
|
+
const result = yield clientInstance.incentives.claimIncentives(mockIncentivesData);
|
|
87
|
+
expect(result).toEqual({ txHash: mockTxHash });
|
|
88
|
+
expect(incentivesHelpers.claimIncentivesFromMerkleDistributor).toHaveBeenCalledWith({
|
|
89
|
+
signer: mockSigner,
|
|
90
|
+
contractAddress: mockIncentivesData.contractAddress,
|
|
91
|
+
index: mockIncentivesData.index,
|
|
92
|
+
operatorAddress: mockIncentivesData.operatorAddress,
|
|
93
|
+
amount: mockIncentivesData.amount,
|
|
94
|
+
merkleProof: mockIncentivesData.merkleProof,
|
|
95
|
+
});
|
|
96
|
+
}));
|
|
97
|
+
test('claimIncentives should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
jest
|
|
99
|
+
.spyOn(utils, 'isContractAvailable')
|
|
100
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
101
|
+
jest
|
|
102
|
+
.spyOn(incentivesHelpers, 'claimIncentivesFromMerkleDistributor')
|
|
103
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
104
|
+
throw new Error('Helper function error');
|
|
105
|
+
}));
|
|
106
|
+
yield expect(clientInstance.incentives.claimIncentives(mockIncentivesData)).rejects.toThrow('Failed to claim incentives: Helper function error');
|
|
107
|
+
}));
|
|
108
|
+
test('incentives should be initialized with the same chainId as client', () => {
|
|
109
|
+
const customChainId = 5;
|
|
110
|
+
const clientWithCustomChain = new index_1.Client({ baseUrl, chainId: customChainId }, mockSigner);
|
|
111
|
+
expect(clientWithCustomChain.incentives.chainId).toBe(customChainId);
|
|
112
|
+
});
|
|
113
|
+
test('isClaimed should return true when incentive is claimed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
114
|
+
jest
|
|
115
|
+
.spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
|
|
116
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
117
|
+
const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
|
|
118
|
+
expect(result).toBe(true);
|
|
119
|
+
expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientInstance.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index);
|
|
120
|
+
}));
|
|
121
|
+
test('isClaimed should return false when incentive is not claimed', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
122
|
+
jest
|
|
123
|
+
.spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
|
|
124
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(false); }));
|
|
125
|
+
const result = yield clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
|
|
126
|
+
expect(result).toBe(false);
|
|
127
|
+
}));
|
|
128
|
+
test('isClaimed should throw an error if helper function fails', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
129
|
+
jest
|
|
130
|
+
.spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
|
|
131
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
132
|
+
throw new Error('Helper function error');
|
|
133
|
+
}));
|
|
134
|
+
yield expect(clientInstance.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index)).rejects.toThrow('Helper function error');
|
|
135
|
+
}));
|
|
136
|
+
test('isClaimed should work with a client without signer', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
137
|
+
// Create a client without a signer
|
|
138
|
+
const clientWithoutSigner = new index_1.Client({
|
|
139
|
+
baseUrl,
|
|
140
|
+
chainId: 17000,
|
|
141
|
+
});
|
|
142
|
+
jest
|
|
143
|
+
.spyOn(incentivesHelpers, 'isClaimedFromMerkleDistributor')
|
|
144
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
145
|
+
const result = yield clientWithoutSigner.incentives.isClaimed(mockIncentivesData.contractAddress, mockIncentivesData.index);
|
|
146
|
+
expect(result).toBe(true);
|
|
147
|
+
expect(incentivesHelpers.isClaimedFromMerkleDistributor).toHaveBeenCalledWith(clientWithoutSigner.incentives.chainId, mockIncentivesData.contractAddress, mockIncentivesData.index);
|
|
148
|
+
}));
|
|
149
|
+
test('getIncentivesByAddress should make the correct API request', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
150
|
+
const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
|
|
151
|
+
const mockIncentives = {
|
|
152
|
+
operator_address: '0x8c00157cae72c4ed6a1f8bfb60205601f0252e26',
|
|
153
|
+
amount: '100',
|
|
154
|
+
index: 1,
|
|
155
|
+
merkle_proof: ['hash1', 'hash2'],
|
|
156
|
+
contract_address: '0xContract',
|
|
157
|
+
};
|
|
158
|
+
global.fetch.mockResolvedValueOnce({
|
|
159
|
+
ok: true,
|
|
160
|
+
status: 200,
|
|
161
|
+
json: () => __awaiter(void 0, void 0, void 0, function* () { return mockIncentives; }),
|
|
162
|
+
headers: new Headers(),
|
|
163
|
+
});
|
|
164
|
+
const result = yield clientInstance.incentives.getIncentivesByAddress(mockAddress);
|
|
165
|
+
expect(result).toEqual(mockIncentives);
|
|
166
|
+
expect(global.fetch).toHaveBeenCalledWith(`${baseUrl}/${constants_1.DEFAULT_BASE_VERSION}/address/incentives/${mockAddress}`, expect.objectContaining({ method: 'GET' }));
|
|
167
|
+
}));
|
|
168
|
+
test('getIncentivesByAddress should handle API errors', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
169
|
+
const mockAddress = '0x1234567890abcdef1234567890abcdef12345678';
|
|
170
|
+
global.fetch.mockRejectedValue(new Error('Network error'));
|
|
171
|
+
yield expect(clientInstance.incentives.getIncentivesByAddress(mockAddress)).rejects.toThrow();
|
|
172
|
+
expect(global.fetch).toHaveBeenCalled();
|
|
173
|
+
}));
|
|
174
|
+
});
|
|
@@ -31,6 +31,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
31
31
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
|
+
var _a, _b;
|
|
34
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
36
|
const ethers_1 = require("ethers");
|
|
36
37
|
const index_1 = require("../src/index");
|
|
@@ -44,15 +45,14 @@ const termsAndConditions_1 = require("../src/verification/termsAndConditions");
|
|
|
44
45
|
const utils = __importStar(require("../src/utils"));
|
|
45
46
|
const splitsHelpers = __importStar(require("../src/splitHelpers"));
|
|
46
47
|
jest.setTimeout(20000);
|
|
48
|
+
const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
|
|
49
|
+
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
50
|
+
const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
|
|
51
|
+
const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
|
|
52
|
+
const mockSigner = wallet.connect(provider);
|
|
47
53
|
/* eslint no-new: 0 */
|
|
48
54
|
describe('Cluster Client', () => {
|
|
49
|
-
var _a, _b;
|
|
50
55
|
const mockConfigHash = '0x1f6c94e6c070393a68c1aa6073a21cb1fd57f0e14d2a475a2958990ab728c2fd';
|
|
51
|
-
const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
|
|
52
|
-
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
53
|
-
const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
|
|
54
|
-
const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
|
|
55
|
-
const mockSigner = wallet.connect(provider);
|
|
56
56
|
const clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
|
|
57
57
|
test('createTermsAndConditions should return "successful authorization"', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
58
58
|
clientInstance['request'] = jest
|
|
@@ -117,12 +117,12 @@ describe('Cluster Client', () => {
|
|
|
117
117
|
}
|
|
118
118
|
}));
|
|
119
119
|
test('getClusterdefinition should return cluster definition if config hash exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
120
|
-
var
|
|
120
|
+
var _a;
|
|
121
121
|
clientInstance['request'] = jest
|
|
122
122
|
.fn()
|
|
123
123
|
.mockReturnValue(Promise.resolve(fixtures_js_1.clusterLockV1X8.cluster_definition));
|
|
124
124
|
const clusterDefinition = yield clientInstance.getClusterDefinition(fixtures_js_1.clusterLockV1X8.cluster_definition.config_hash);
|
|
125
|
-
expect((
|
|
125
|
+
expect((_a = clusterDefinition.deposit_amounts) === null || _a === void 0 ? void 0 : _a.length).toEqual(fixtures_js_1.clusterLockV1X8.cluster_definition.deposit_amounts.length);
|
|
126
126
|
expect(clusterDefinition.config_hash).toEqual(fixtures_js_1.clusterLockV1X8.cluster_definition.config_hash);
|
|
127
127
|
}));
|
|
128
128
|
test('getClusterLock should return lockFile if exist', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -233,9 +233,8 @@ describe('Cluster Client without a signer', () => {
|
|
|
233
233
|
}));
|
|
234
234
|
});
|
|
235
235
|
describe('createObolRewardsSplit', () => {
|
|
236
|
-
let clientInstance, clientInstanceWithourSigner, mockSplitRecipients, mockPrincipalRecipient, mockEtherAmount
|
|
236
|
+
let clientInstance, clientInstanceWithourSigner, mockSplitRecipients, mockPrincipalRecipient, mockEtherAmount;
|
|
237
237
|
beforeAll(() => {
|
|
238
|
-
var _a, _b;
|
|
239
238
|
jest
|
|
240
239
|
.spyOn(utils, 'isContractAvailable')
|
|
241
240
|
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
@@ -248,11 +247,6 @@ describe('createObolRewardsSplit', () => {
|
|
|
248
247
|
fee_recipient_address: '0xFeeRecipientAddress',
|
|
249
248
|
});
|
|
250
249
|
}));
|
|
251
|
-
const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
|
|
252
|
-
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
253
|
-
const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
|
|
254
|
-
const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
|
|
255
|
-
mockSigner = wallet.connect(provider);
|
|
256
250
|
clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
|
|
257
251
|
clientInstanceWithourSigner = new index_1.Client({
|
|
258
252
|
baseUrl: 'https://obol-api-dev.gcp.obol.tech',
|
|
@@ -330,9 +324,8 @@ describe('createObolRewardsSplit', () => {
|
|
|
330
324
|
}));
|
|
331
325
|
});
|
|
332
326
|
describe('createObolTotalSplit', () => {
|
|
333
|
-
let clientInstanceWithourSigner, mockSplitRecipients,
|
|
327
|
+
let clientInstanceWithourSigner, mockSplitRecipients, clientInstance;
|
|
334
328
|
beforeAll(() => {
|
|
335
|
-
var _a, _b;
|
|
336
329
|
jest
|
|
337
330
|
.spyOn(utils, 'isContractAvailable')
|
|
338
331
|
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve(true); }));
|
|
@@ -342,11 +335,6 @@ describe('createObolTotalSplit', () => {
|
|
|
342
335
|
jest
|
|
343
336
|
.spyOn(splitsHelpers, 'deploySplitterContract')
|
|
344
337
|
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return yield Promise.resolve('0xSplitterAddress'); }));
|
|
345
|
-
const mnemonic = (_b = (_a = ethers_1.ethers.Wallet.createRandom().mnemonic) === null || _a === void 0 ? void 0 : _a.phrase) !== null && _b !== void 0 ? _b : '';
|
|
346
|
-
const privateKey = ethers_1.ethers.Wallet.fromPhrase(mnemonic).privateKey;
|
|
347
|
-
const provider = new ethers_1.JsonRpcProvider('https://ethereum-holesky.publicnode.com');
|
|
348
|
-
const wallet = new ethers_1.ethers.Wallet(privateKey, provider);
|
|
349
|
-
mockSigner = wallet.connect(provider);
|
|
350
338
|
clientInstance = new index_1.Client({ baseUrl: 'https://obol-api-dev.gcp.obol.tech', chainId: 17000 }, mockSigner);
|
|
351
339
|
clientInstanceWithourSigner = new index_1.Client({
|
|
352
340
|
baseUrl: 'https://obol-api-dev.gcp.obol.tech',
|
package/dist/esm/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@obolnetwork/obol-sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "A package for creating Distributed Validators using the Obol API.",
|
|
5
5
|
"bugs": {
|
|
6
6
|
"url": "https://github.com/obolnetwork/obol-sdk/issues"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"compile": "tsc -b ./tsconfig.cjs.json ./tsconfig.esm.json ./tsconfig.types.json",
|
|
16
16
|
"build:clean": "rm -rf ./dist",
|
|
17
17
|
"build": "npm-run-all build:clean compile",
|
|
18
|
-
"test": "jest ./test
|
|
18
|
+
"test": "jest ./test/*.test.ts",
|
|
19
19
|
"generate-typedoc": "typedoc",
|
|
20
20
|
"npm:publish": "npm publish --tag latest",
|
|
21
21
|
"release": "release-it",
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const MerkleDistributorABI = {
|
|
2
|
+
abi: [
|
|
3
|
+
{
|
|
4
|
+
inputs: [
|
|
5
|
+
{ internalType: 'address', name: 'token_', type: 'address' },
|
|
6
|
+
{ internalType: 'bytes32', name: 'merkleRoot_', type: 'bytes32' },
|
|
7
|
+
],
|
|
8
|
+
stateMutability: 'nonpayable',
|
|
9
|
+
type: 'constructor',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
anonymous: false,
|
|
13
|
+
inputs: [
|
|
14
|
+
{
|
|
15
|
+
indexed: false,
|
|
16
|
+
internalType: 'uint256',
|
|
17
|
+
name: 'index',
|
|
18
|
+
type: 'uint256',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
indexed: false,
|
|
22
|
+
internalType: 'address',
|
|
23
|
+
name: 'account',
|
|
24
|
+
type: 'address',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
indexed: false,
|
|
28
|
+
internalType: 'uint256',
|
|
29
|
+
name: 'amount',
|
|
30
|
+
type: 'uint256',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
name: 'Claimed',
|
|
34
|
+
type: 'event',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
inputs: [
|
|
38
|
+
{ internalType: 'uint256', name: 'index', type: 'uint256' },
|
|
39
|
+
{ internalType: 'address', name: 'account', type: 'address' },
|
|
40
|
+
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
|
|
41
|
+
{ internalType: 'bytes32[]', name: 'merkleProof', type: 'bytes32[]' },
|
|
42
|
+
],
|
|
43
|
+
name: 'claim',
|
|
44
|
+
outputs: [],
|
|
45
|
+
stateMutability: 'nonpayable',
|
|
46
|
+
type: 'function',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
inputs: [{ internalType: 'uint256', name: 'index', type: 'uint256' }],
|
|
50
|
+
name: 'isClaimed',
|
|
51
|
+
outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
|
|
52
|
+
stateMutability: 'view',
|
|
53
|
+
type: 'function',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
inputs: [],
|
|
57
|
+
name: 'merkleRoot',
|
|
58
|
+
outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],
|
|
59
|
+
stateMutability: 'view',
|
|
60
|
+
type: 'function',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
inputs: [],
|
|
64
|
+
name: 'token',
|
|
65
|
+
outputs: [{ internalType: 'address', name: '', type: 'address' }],
|
|
66
|
+
stateMutability: 'view',
|
|
67
|
+
type: 'function',
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|