@wireio/stake 0.4.0 → 0.4.1
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/lib/stake.browser.js +1738 -549
- package/lib/stake.browser.js.map +1 -1
- package/lib/stake.d.ts +41 -8
- package/lib/stake.js +1863 -642
- package/lib/stake.js.map +1 -1
- package/lib/stake.m.js +1738 -549
- package/lib/stake.m.js.map +1 -1
- package/package.json +1 -1
- package/src/networks/ethereum/clients/{deposit.client.ts → convert.client.ts} +36 -4
- package/src/networks/ethereum/clients/opp.client.ts +390 -0
- package/src/networks/ethereum/clients/pretoken.client.ts +88 -49
- package/src/networks/ethereum/clients/receipt.client.ts +129 -0
- package/src/networks/ethereum/clients/stake.client.ts +1 -148
- package/src/networks/ethereum/contract.ts +7 -4
- package/src/networks/ethereum/ethereum.ts +44 -65
- package/src/networks/ethereum/types.ts +1 -0
- package/src/types.ts +53 -0
- package/src/networks/ethereum/clients/liq.client.ts +0 -47
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { BigNumber } from "ethers";
|
|
2
|
+
import { preLaunchReceipt } from "../types";
|
|
3
|
+
import { EthereumContractService } from "../contract";
|
|
4
|
+
import { ReceiptNFTKind } from "../../../types";
|
|
5
|
+
|
|
6
|
+
export class ReceiptClient {
|
|
7
|
+
|
|
8
|
+
private readonly contractService: EthereumContractService;
|
|
9
|
+
|
|
10
|
+
get contract() { return this.contractService.contract; }
|
|
11
|
+
|
|
12
|
+
constructor(contract: EthereumContractService) {
|
|
13
|
+
this.contractService = contract;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async allReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
19
|
+
return this.fetchPreLaunchReceipts(address);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async stakeReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
23
|
+
return this.fetchPreLaunchReceipts(address, ReceiptNFTKind.STAKE);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async pretokenReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
27
|
+
return this.fetchPreLaunchReceipts(address, ReceiptNFTKind.PRETOKEN_PURCHASE);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param address (string) to fetch receipts for
|
|
35
|
+
* @returns preLaunchReceipt[]
|
|
36
|
+
*/
|
|
37
|
+
async fetchPreLaunchReceipts(address: string, type?: ReceiptNFTKind): Promise<preLaunchReceipt[]> {
|
|
38
|
+
const receiptContract = this.contract.ReceiptNFT;
|
|
39
|
+
|
|
40
|
+
// first figure out which tokenIds this address owns, from events
|
|
41
|
+
const tokenIds = await this.getOwnedTokenIdsFor(address);
|
|
42
|
+
|
|
43
|
+
const results: preLaunchReceipt[] = [];
|
|
44
|
+
|
|
45
|
+
// next fetch on-chain receipt data just for those ids
|
|
46
|
+
for (const idBN of tokenIds) {
|
|
47
|
+
try {
|
|
48
|
+
const receiptData = await receiptContract.getReceipt(idBN);
|
|
49
|
+
|
|
50
|
+
//skip any receipt not of the requested type
|
|
51
|
+
if(type !== undefined && receiptData.kind !== type) continue;
|
|
52
|
+
|
|
53
|
+
results.push({
|
|
54
|
+
tokenId: idBN.toBigInt(),
|
|
55
|
+
receipt: {
|
|
56
|
+
account: receiptData.account,
|
|
57
|
+
currency: receiptData.currency,
|
|
58
|
+
kind: receiptData.kind,
|
|
59
|
+
indexAtMint: receiptData.indexAtMint.toBigInt(),
|
|
60
|
+
principal: {
|
|
61
|
+
amount: receiptData.principal.toBigInt(),
|
|
62
|
+
decimals: 18,
|
|
63
|
+
symbol: "LiqETH"
|
|
64
|
+
},
|
|
65
|
+
shares: {
|
|
66
|
+
amount: receiptData.shares.toBigInt(),
|
|
67
|
+
decimals: 18,
|
|
68
|
+
symbol: "LiqETH"
|
|
69
|
+
},
|
|
70
|
+
timestamp: new Date(Number(receiptData.timestamp.toString()) * 1000).toLocaleString(),
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
} catch (err) {
|
|
74
|
+
// in case of any mismatch or race, just skip this id
|
|
75
|
+
console.warn(`Failed to load receipt for tokenId=${idBN.toString()}`, err);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
private async getOwnedTokenIdsFor(
|
|
87
|
+
owner: string,
|
|
88
|
+
fromBlock = 0,
|
|
89
|
+
toBlock: number | string = "latest"
|
|
90
|
+
): Promise<BigNumber[]> {
|
|
91
|
+
const receiptContract = this.contract.ReceiptNFT;
|
|
92
|
+
|
|
93
|
+
// Logs where address received tokens
|
|
94
|
+
const toLogs = await receiptContract.queryFilter(
|
|
95
|
+
receiptContract.filters.Transfer(null, owner),
|
|
96
|
+
fromBlock,
|
|
97
|
+
toBlock
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Logs where address sent tokens (including burns from owner → 0)
|
|
101
|
+
const fromLogs = await receiptContract.queryFilter(
|
|
102
|
+
receiptContract.filters.Transfer(owner, null),
|
|
103
|
+
fromBlock,
|
|
104
|
+
toBlock
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const owned = new Set<string>();
|
|
108
|
+
|
|
109
|
+
// Add all received tokenIds
|
|
110
|
+
for (const e of toLogs) {
|
|
111
|
+
const tokenId = e.args?.tokenId;
|
|
112
|
+
if (!tokenId) continue;
|
|
113
|
+
owned.add(tokenId.toString());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Remove all sent tokenIds
|
|
117
|
+
for (const e of fromLogs) {
|
|
118
|
+
const tokenId = e.args?.tokenId;
|
|
119
|
+
if (!tokenId) continue;
|
|
120
|
+
owned.delete(tokenId.toString());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Convert to BigNumbers
|
|
124
|
+
return Array.from(owned).map((id) => BigNumber.from(id));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BigNumber, ethers } from "ethers";
|
|
2
|
-
import {
|
|
2
|
+
import { StakedEvent, WithdrawnStakeEvent, WithdrawnStakeResult } from "../types";
|
|
3
3
|
import { EthereumContractService } from "../contract";
|
|
4
4
|
import { formatContractErrors } from "../utils";
|
|
5
5
|
|
|
@@ -28,62 +28,6 @@ export class StakeClient {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
/**
|
|
32
|
-
* Read OPP / Outpost state used by the Depositor to decide whether staking is allowed.
|
|
33
|
-
* Returns various data
|
|
34
|
-
*/
|
|
35
|
-
async getOppStatus(): Promise<any> {
|
|
36
|
-
const depositor = this.contract.Depositor;
|
|
37
|
-
const opp = this.contract.OPP;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const oppAddress: string = await depositor.oppAddress();
|
|
41
|
-
const oppInboundAddress: string = await depositor.oppInboundAddress();
|
|
42
|
-
const prevEpochSent = await opp.prevEpochSent();
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const inbound = this.contractService.getReadOnly('OPPInbound');
|
|
46
|
-
|
|
47
|
-
// Query useful getters
|
|
48
|
-
const nextEpochBN: any = await inbound.nextEpochNum();
|
|
49
|
-
const pendingEpochRaw: any = await inbound.pendingEpoch();
|
|
50
|
-
const pendingMessageCount: any = await inbound.pendingMessageCount();
|
|
51
|
-
const previousEpochHash: string = await inbound.previousEpochHash();
|
|
52
|
-
const nextEpochNum = (nextEpochBN && typeof nextEpochBN.toNumber === 'function') ? nextEpochBN.toNumber() : Number(nextEpochBN || 0);
|
|
53
|
-
|
|
54
|
-
const pendingEpoch = (pendingEpochRaw && pendingEpochRaw.epochNumber !== undefined)
|
|
55
|
-
? {
|
|
56
|
-
epochNumber: (pendingEpochRaw.epochNumber && typeof pendingEpochRaw.epochNumber.toNumber === 'function') ? pendingEpochRaw.epochNumber.toNumber() : Number(pendingEpochRaw.epochNumber || 0),
|
|
57
|
-
timestamp: (pendingEpochRaw.timestamp && typeof pendingEpochRaw.timestamp.toNumber === 'function') ? pendingEpochRaw.timestamp.toNumber() : Number(pendingEpochRaw.timestamp || 0),
|
|
58
|
-
prevEpochHash: pendingEpochRaw.prevEpochHash,
|
|
59
|
-
merkleRoot: pendingEpochRaw.merkleRoot,
|
|
60
|
-
firstMessageID: pendingEpochRaw.firstMessageID,
|
|
61
|
-
lastMessageID: pendingEpochRaw.lastMessageID,
|
|
62
|
-
}
|
|
63
|
-
: null;
|
|
64
|
-
|
|
65
|
-
const pendingMessagesBN = pendingMessageCount;
|
|
66
|
-
const pendingMessages = (pendingMessagesBN && typeof pendingMessagesBN.toString === 'function') ? pendingMessagesBN.toString() : String(pendingMessagesBN || '0');
|
|
67
|
-
|
|
68
|
-
const hasPendingMessages = (pendingMessagesBN && typeof pendingMessagesBN.gt === 'function') ? pendingMessagesBN.gt(0) : (Number(pendingMessages) > 0);
|
|
69
|
-
|
|
70
|
-
return {
|
|
71
|
-
oppAddress,
|
|
72
|
-
prevEpochSent,
|
|
73
|
-
oppInboundAddress,
|
|
74
|
-
nextEpochNum,
|
|
75
|
-
pendingEpoch,
|
|
76
|
-
pendingMessageCount: pendingMessages,
|
|
77
|
-
previousEpochHash,
|
|
78
|
-
hasPendingMessages,
|
|
79
|
-
raw: {
|
|
80
|
-
nextEpochBN,
|
|
81
|
-
pendingEpochRaw,
|
|
82
|
-
pendingMessageCount: pendingMessagesBN,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
31
|
|
|
88
32
|
/**
|
|
89
33
|
*
|
|
@@ -153,97 +97,6 @@ export class StakeClient {
|
|
|
153
97
|
|
|
154
98
|
|
|
155
99
|
|
|
156
|
-
async getOwnedTokenIdsFor(
|
|
157
|
-
owner: string,
|
|
158
|
-
fromBlock = 1850820,
|
|
159
|
-
toBlock: number | string = "latest"
|
|
160
|
-
): Promise<BigNumber[]> {
|
|
161
|
-
const receiptContract = this.contract.ReceiptNFT;
|
|
162
|
-
|
|
163
|
-
// Logs where address received tokens
|
|
164
|
-
const toLogs = await receiptContract.queryFilter(
|
|
165
|
-
receiptContract.filters.Transfer(null, owner),
|
|
166
|
-
fromBlock,
|
|
167
|
-
toBlock
|
|
168
|
-
);
|
|
169
|
-
|
|
170
|
-
// Logs where address sent tokens (including burns from owner → 0)
|
|
171
|
-
const fromLogs = await receiptContract.queryFilter(
|
|
172
|
-
receiptContract.filters.Transfer(owner, null),
|
|
173
|
-
fromBlock,
|
|
174
|
-
toBlock
|
|
175
|
-
);
|
|
176
|
-
|
|
177
|
-
const owned = new Set<string>();
|
|
178
|
-
|
|
179
|
-
// Add all received tokenIds
|
|
180
|
-
for (const e of toLogs) {
|
|
181
|
-
const tokenId = e.args?.tokenId;
|
|
182
|
-
if (!tokenId) continue;
|
|
183
|
-
owned.add(tokenId.toString());
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Remove all sent tokenIds
|
|
187
|
-
for (const e of fromLogs) {
|
|
188
|
-
const tokenId = e.args?.tokenId;
|
|
189
|
-
if (!tokenId) continue;
|
|
190
|
-
owned.delete(tokenId.toString());
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Convert to BigNumbers
|
|
194
|
-
return Array.from(owned).map((id) => BigNumber.from(id));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
*
|
|
200
|
-
* @param amountWei an amount of liqETH (in WEI) to stake to the Outpost
|
|
201
|
-
* @returns txHash (hash of the transaction), receipt, WithdrawnStake event
|
|
202
|
-
*/
|
|
203
|
-
async fetchPreLaunchReceipts(address: string): Promise<preLaunchReceipt[]> {
|
|
204
|
-
const receiptContract = this.contract.ReceiptNFT;
|
|
205
|
-
|
|
206
|
-
// first figure out which tokenIds this address owns, from events
|
|
207
|
-
const tokenIds = await this.getOwnedTokenIdsFor(address);
|
|
208
|
-
|
|
209
|
-
const results: preLaunchReceipt[] = [];
|
|
210
|
-
|
|
211
|
-
// next fetch on-chain receipt data just for those ids
|
|
212
|
-
for (const idBN of tokenIds) {
|
|
213
|
-
try {
|
|
214
|
-
const receiptData = await receiptContract.getReceipt(idBN);
|
|
215
|
-
const formattedReceipt = {
|
|
216
|
-
account: receiptData.account,
|
|
217
|
-
currency: receiptData.currency,
|
|
218
|
-
kind: receiptData.kind,
|
|
219
|
-
indexAtMint: receiptData.indexAtMint.toBigInt(),
|
|
220
|
-
principal: {
|
|
221
|
-
amount: receiptData.principal.toBigInt(),
|
|
222
|
-
decimals: 18,
|
|
223
|
-
symbol: "LiqETH"
|
|
224
|
-
},
|
|
225
|
-
shares: {
|
|
226
|
-
amount: receiptData.shares.toBigInt(),
|
|
227
|
-
decimals: 18,
|
|
228
|
-
symbol: "LiqETH"
|
|
229
|
-
},
|
|
230
|
-
timestamp: new Date(Number(receiptData.timestamp.toString()) * 1000).toLocaleString(),
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Only fetch staking receipts (kind 1 is a wire pretoken receipt)
|
|
234
|
-
if(receiptData.kind == 0) results.push({ tokenId: idBN.toBigInt(), receipt: formattedReceipt } as any);
|
|
235
|
-
} catch (err) {
|
|
236
|
-
// in case of any mismatch or race, just skip this id
|
|
237
|
-
console.warn(`Failed to load receipt for tokenId=${idBN.toString()}`, err);
|
|
238
|
-
continue;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
console.log('results of prelaunch receipts', results)
|
|
243
|
-
return results;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
247
100
|
/**
|
|
248
101
|
*
|
|
249
102
|
* @param amountWei an amount of liqETH (in WEI) to stake to the Outpost
|
|
@@ -21,6 +21,7 @@ import OPPInboundArtifact from '../../assets/ethereum/ABI/outpost/OPPInbound.sol
|
|
|
21
21
|
import PretokenArtifact from '../../assets/ethereum/ABI/outpost/Pretoken.sol/Pretoken.json';
|
|
22
22
|
import AggregatorArtifact from '../../assets/ethereum/ABI/outpost/Aggregator.sol/Aggregator.json';
|
|
23
23
|
import EthUsdPriceConsumerArtifact from '../../assets/ethereum/ABI/outpost/EthUsdPriceConsumer.sol/EthUsdPriceConsumer.json';
|
|
24
|
+
import PoolArtifact from '../../assets/ethereum/ABI/outpost/Pool.sol/Pool.json';
|
|
24
25
|
|
|
25
26
|
import ERC20Artifact from '../../assets/ethereum/ABI/token/ERC20Token.sol/ERC20Token.json';
|
|
26
27
|
import ERC721Artifact from '../../assets/ethereum/ABI/token/ERC721Token.sol/ERC721Token.json';
|
|
@@ -41,6 +42,7 @@ export const ERC1155Abi = ERC1155Artifact.abi;
|
|
|
41
42
|
|
|
42
43
|
// Make sure ContractName in ./types includes all of these keys.
|
|
43
44
|
export const ADDRESSES: AddressBook = {
|
|
45
|
+
// LiqETH contracts
|
|
44
46
|
Accounting: "0xd333A03a44D5d602A98c1B7bcd7ED1f042DD0dEd",
|
|
45
47
|
DepositManager: "0x601eaA31e8d33D8725786f1733f4cE6cCEf740D4",
|
|
46
48
|
LiqEth: "0x08252e1Dcbaa86A2887927b02536CD3E67a802c8", // AKA LiqEthToken
|
|
@@ -48,10 +50,6 @@ export const ADDRESSES: AddressBook = {
|
|
|
48
50
|
WithdrawalQueue: "0x951E413FC81a2CE133078ABE8B88677F5296abE7",
|
|
49
51
|
WithdrawalVault: "0x0D2bf834DD560839e986d42D06DeE268A17c2d13",
|
|
50
52
|
|
|
51
|
-
// LiqEthAuthority: "0x7A9cf59EC53F32577Cc8200466Cc7693713129D5",
|
|
52
|
-
// BeaconState: "0xD3860E5977C94b343341635a2dEEBD20B651c48f",
|
|
53
|
-
// YieldOracle: "0x307b35816674913cf122975B3CF912b5709653F3",
|
|
54
|
-
|
|
55
53
|
//Outpost contracts
|
|
56
54
|
Depositor: "0x69Aa53Ef02F124dB421AeDda509d6912341299Cc",
|
|
57
55
|
ReceiptNFT: "0x13588fF41E2f47D047874162B1eD15AaF6818f5a",
|
|
@@ -63,6 +61,7 @@ export const ADDRESSES: AddressBook = {
|
|
|
63
61
|
Pretoken: "0xcf6A1209A7A391cc576174204386F4e5462323dC",
|
|
64
62
|
EthUsdPriceConsumer: "0x1Ef180FF49313fCB8B5c0470268295d0d24CDE69",
|
|
65
63
|
Aggregator: "0xFCfc3ddd4CBd9Ad3b3af3A374B8bdA1b66eE6FFF",
|
|
64
|
+
Pool: "0x29DEf0fA009e02d108d9505018EAe0168F233e03",
|
|
66
65
|
};
|
|
67
66
|
|
|
68
67
|
export type Contracts<T extends string = ContractName> = Record<T, ContractConfig>;
|
|
@@ -142,6 +141,10 @@ export const CONTRACTS: Contracts<ContractName> = {
|
|
|
142
141
|
EthUsdPriceConsumer: {
|
|
143
142
|
address: ADDRESSES.EthUsdPriceConsumer,
|
|
144
143
|
abi: EthUsdPriceConsumerArtifact.abi as JsonFragment[],
|
|
144
|
+
},
|
|
145
|
+
Pool: {
|
|
146
|
+
address: ADDRESSES.Pool,
|
|
147
|
+
abi: PoolArtifact.abi as JsonFragment[],
|
|
145
148
|
}
|
|
146
149
|
};
|
|
147
150
|
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import { BigNumber, ethers } from 'ethers';
|
|
2
|
-
import { IStakingClient, Portfolio, StakerConfig, TrancheSnapshot } from '../../types';
|
|
3
2
|
import { ChainID, EvmChainID, PublicKey as WirePubKey } from '@wireio/core';
|
|
3
|
+
import {
|
|
4
|
+
IStakingClient,
|
|
5
|
+
OPPAssertion,
|
|
6
|
+
Portfolio,
|
|
7
|
+
StakerConfig,
|
|
8
|
+
TrancheSnapshot
|
|
9
|
+
} from '../../types';
|
|
4
10
|
import { EthereumContractService } from './contract';
|
|
5
11
|
import { preLaunchReceipt } from './types';
|
|
6
|
-
import {
|
|
12
|
+
import { buildEthereumTrancheSnapshot } from './utils';
|
|
13
|
+
import { ConvertClient } from './clients/convert.client';
|
|
7
14
|
import { StakeClient } from './clients/stake.client';
|
|
8
15
|
import { PretokenClient } from './clients/pretoken.client';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
16
|
+
import { OPPClient } from './clients/opp.client';
|
|
17
|
+
import { ReceiptClient } from './clients/receipt.client';
|
|
11
18
|
|
|
12
19
|
|
|
13
20
|
|
|
@@ -18,10 +25,11 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
18
25
|
private readonly signer: ethers.Signer;
|
|
19
26
|
private readonly contractService: EthereumContractService;
|
|
20
27
|
|
|
21
|
-
private
|
|
22
|
-
private liqClient: LiqClient;
|
|
28
|
+
private convertClient: ConvertClient;
|
|
23
29
|
private pretokenClient: PretokenClient;
|
|
24
30
|
private stakeClient: StakeClient;
|
|
31
|
+
private oppClient: OPPClient;
|
|
32
|
+
private receiptClient: ReceiptClient;
|
|
25
33
|
|
|
26
34
|
|
|
27
35
|
get contract() { return this.contractService.contract; }
|
|
@@ -38,10 +46,11 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
38
46
|
signer: this.signer,
|
|
39
47
|
});
|
|
40
48
|
|
|
41
|
-
this.
|
|
42
|
-
this.liqClient = new LiqClient(this.contractService);
|
|
49
|
+
this.convertClient = new ConvertClient(this.contractService);
|
|
43
50
|
this.pretokenClient = new PretokenClient(this.contractService);
|
|
44
51
|
this.stakeClient = new StakeClient(this.contractService);
|
|
52
|
+
this.oppClient = new OPPClient(this.contractService);
|
|
53
|
+
this.receiptClient = new ReceiptClient(this.contractService);
|
|
45
54
|
}
|
|
46
55
|
catch (error) {
|
|
47
56
|
// console.error('Error initializing EthereumStakingClient:', error);
|
|
@@ -66,7 +75,7 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
66
75
|
? amount
|
|
67
76
|
: BigNumber.from(amount);
|
|
68
77
|
|
|
69
|
-
const result = await this.
|
|
78
|
+
const result = await this.convertClient.performDeposit(amountWei);
|
|
70
79
|
return result.txHash;
|
|
71
80
|
}
|
|
72
81
|
|
|
@@ -80,18 +89,15 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
80
89
|
async withdraw(amount: bigint): Promise<string> {
|
|
81
90
|
const address = await this.signer.getAddress();
|
|
82
91
|
const amountWei = BigNumber.from(amount);
|
|
83
|
-
// const chainId = this.network?.chainId ?? (await this.provider.getNetwork()).chainId;
|
|
84
|
-
// const result = await this.depositClient.requestWithdraw(amountWei, this.signer, chainId);
|
|
85
92
|
|
|
86
|
-
const result = await this.
|
|
93
|
+
const result = await this.convertClient.performWithdraw(address, amountWei)
|
|
87
94
|
return result.txHash;
|
|
88
95
|
}
|
|
89
96
|
|
|
90
97
|
|
|
91
98
|
/**
|
|
92
99
|
* Stake liqETH via DepositManager.
|
|
93
|
-
* @param amount Amount in wei
|
|
94
|
-
* Keep this as a bigint / string in the caller; avoid JS floats.
|
|
100
|
+
* @param amount Amount in wei - Keep this as a bigint / string in the caller; avoid JS floats.
|
|
95
101
|
* @returns transaction hash
|
|
96
102
|
*/
|
|
97
103
|
async stake(amount: bigint): Promise<string> {
|
|
@@ -125,71 +131,38 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
125
131
|
|
|
126
132
|
async buy(amount: bigint): Promise<string> {
|
|
127
133
|
const buyer = await this.signer.getAddress();
|
|
128
|
-
const amountBigNum = BigNumber.from(amount)
|
|
129
134
|
|
|
130
135
|
// ! Hoodi only - check if the mock aggregator price is stale, and if so, update it before submitting the buy request
|
|
131
136
|
await this.updateMockAggregatorPrice();
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const bal = await this.contract.LiqEth.balanceOf(buyer);
|
|
135
|
-
const paused = await this.contract.Depositor.paused();
|
|
136
|
-
if(paused) {
|
|
137
|
-
throw new Error("Error - Depositor is in a paused state");
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// if current liq balance is less than the requested buy amount, throw an error
|
|
141
|
-
if (bal.lt(amount)) {
|
|
142
|
-
throw new Error(`Balance insufficient for pre-token purchase`);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
//check that the contract has allowance for the token
|
|
146
|
-
const depositorAddr = this.contract.Depositor.address;
|
|
147
|
-
const allowance = await this.contract.LiqEth.allowance(buyer, depositorAddr);
|
|
148
|
-
|
|
149
|
-
// if allowance is less than the requested stake amount, request permission to spend LiqEth
|
|
150
|
-
if (allowance.lt(amount)) {
|
|
151
|
-
const liqWrite = this.contractService.getWrite('LiqEth');
|
|
152
|
-
|
|
153
|
-
// currently requested unlimited amount - potentially change to only request up to the current amount?
|
|
154
|
-
const approveAmount = ethers.constants.MaxUint256;
|
|
155
|
-
|
|
156
|
-
console.warn(`allowance insufficient (${allowance.toString()} < ${amount.toString()}); sending approve(${depositorAddr}, ${approveAmount.toString()})`);
|
|
157
|
-
|
|
158
|
-
const approveTx = await liqWrite.approve(depositorAddr, approveAmount);
|
|
159
|
-
await approveTx.wait(1);
|
|
160
|
-
|
|
161
|
-
// re-read allowance to ensure approval succeeded
|
|
162
|
-
const newAllowance = await this.contract.LiqEth.allowance(buyer, depositorAddr);
|
|
163
|
-
if (newAllowance.lt(amount)) {
|
|
164
|
-
throw new Error('Approval failed or allowance still insufficient after approve');
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
let result = await this.pretokenClient.purchasePretokensWithLiqETH(amountBigNum, buyer);
|
|
170
137
|
|
|
138
|
+
let result = await this.pretokenClient.purchasePretokensWithLiqETH(amount, buyer);
|
|
171
139
|
return result && result.txHash ? result.txHash : "Error - no resulting txHash";
|
|
172
140
|
}
|
|
173
141
|
|
|
174
142
|
|
|
175
|
-
|
|
143
|
+
async getOPPMessages(address?: string): Promise<OPPAssertion[]> {
|
|
144
|
+
if(!address) address = await this.signer.getAddress();
|
|
145
|
+
|
|
146
|
+
return await this.oppClient.getMessages(address);
|
|
147
|
+
}
|
|
148
|
+
|
|
176
149
|
|
|
177
150
|
async getOPPStatus(): Promise<any> {
|
|
178
|
-
return await this.
|
|
151
|
+
return await this.oppClient.getStatus();
|
|
179
152
|
}
|
|
180
153
|
|
|
181
154
|
|
|
182
155
|
|
|
183
156
|
/**
|
|
184
|
-
* ETH Prelaunch function to list the ReceiptNFTs owned by a specific user
|
|
157
|
+
* ETH Prelaunch function to list the Stake ReceiptNFTs owned by a specific user
|
|
185
158
|
* @param address address to query the receipts for
|
|
186
159
|
* @returns array of receipts
|
|
187
160
|
*/
|
|
188
161
|
async fetchPrelaunchReceipts(address?: string): Promise<preLaunchReceipt[]> {
|
|
189
162
|
if(address === undefined) address = await this.signer.getAddress();
|
|
190
163
|
|
|
191
|
-
|
|
192
|
-
return
|
|
164
|
+
//default to stake receipts
|
|
165
|
+
return await this.receiptClient.stakeReceipts(address);
|
|
193
166
|
}
|
|
194
167
|
|
|
195
168
|
|
|
@@ -206,6 +179,7 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
206
179
|
}
|
|
207
180
|
}
|
|
208
181
|
|
|
182
|
+
|
|
209
183
|
/**
|
|
210
184
|
* Resolve the user's ETH + liqETH balances.
|
|
211
185
|
*
|
|
@@ -215,8 +189,6 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
215
189
|
*/
|
|
216
190
|
async getPortfolio(): Promise<Portfolio> {
|
|
217
191
|
const walletAddress = await this.signer.getAddress();
|
|
218
|
-
// console.log('getPortfolio() wallet address', walletAddress)
|
|
219
|
-
|
|
220
192
|
|
|
221
193
|
// 1) Native ETH balance
|
|
222
194
|
const nativeBalance = await this.provider.getBalance(walletAddress);
|
|
@@ -227,9 +199,16 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
227
199
|
const liqBalance: ethers.BigNumber = await this.contract.LiqEth.balanceOf(walletAddress);
|
|
228
200
|
const liqSymbol = 'Liq' + (this.network?.nativeCurrency?.symbol ?? 'ETH');
|
|
229
201
|
|
|
230
|
-
// 3) staked liqEth ERC-20 balance (
|
|
231
|
-
|
|
202
|
+
// 3) staked liqEth ERC-20 balance (calculate from receipts)
|
|
203
|
+
let stakeReceipts = await this.receiptClient.stakeReceipts(walletAddress);
|
|
204
|
+
let stakeBalanceBN = BigNumber.from(0);
|
|
205
|
+
for (let r of stakeReceipts) {
|
|
206
|
+
stakeBalanceBN = stakeBalanceBN.add(BigNumber.from(r.receipt.principal.amount));
|
|
207
|
+
}
|
|
208
|
+
|
|
232
209
|
|
|
210
|
+
// 4) WIRE pretoken balance
|
|
211
|
+
const wireBalance: ethers.BigNumber = await this.contract.Pretoken.balanceOf(walletAddress);
|
|
233
212
|
|
|
234
213
|
const portfolio: Portfolio = {
|
|
235
214
|
native: {
|
|
@@ -243,13 +222,13 @@ export class EthereumStakingClient implements IStakingClient {
|
|
|
243
222
|
symbol: liqSymbol,
|
|
244
223
|
},
|
|
245
224
|
staked: {
|
|
246
|
-
amount:
|
|
225
|
+
amount: stakeBalanceBN.toBigInt(),
|
|
247
226
|
decimals: nativeDecimals,
|
|
248
227
|
symbol: liqSymbol,
|
|
249
228
|
},
|
|
250
229
|
wire: {
|
|
251
|
-
amount:
|
|
252
|
-
decimals:
|
|
230
|
+
amount: wireBalance.toBigInt(),
|
|
231
|
+
decimals: 18,
|
|
253
232
|
symbol: '$WIRE',
|
|
254
233
|
},
|
|
255
234
|
chainID: this.network.chainId
|
package/src/types.ts
CHANGED
|
@@ -216,4 +216,57 @@ export interface TrancheSnapshot {
|
|
|
216
216
|
* Used directly by the frontend for ladder graphs.
|
|
217
217
|
*/
|
|
218
218
|
ladder: TrancheLadderItem[];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
// Enum describing which asset is being used to buy pretoken
|
|
223
|
+
export enum PurchaseAsset {
|
|
224
|
+
SOL = 'SOL',
|
|
225
|
+
LIQSOL = 'LIQSOL',
|
|
226
|
+
ETH = 'ETH',
|
|
227
|
+
LIQETH = 'LIQETH',
|
|
228
|
+
YIELD = 'YIELD',
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export interface PurchaseQuote {
|
|
232
|
+
purchaseAsset: PurchaseAsset;
|
|
233
|
+
amountIn: bigint; // lamports / wei / token units
|
|
234
|
+
|
|
235
|
+
/** Expected pretoken “shares” (pretokens) and decimals */
|
|
236
|
+
wireShares: bigint; // 1e8 scale
|
|
237
|
+
wireDecimals: number; // always 8 for now
|
|
238
|
+
|
|
239
|
+
/** Current price + notional in USD (1e8 scale) */
|
|
240
|
+
wirePriceUsd: bigint;
|
|
241
|
+
notionalUsd: bigint;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// export interface OPPEvent {
|
|
245
|
+
// type: 'liq_pretoken_purchase' | 'yield_pretoken_purchase' | 'pretoken_purchase' | 'stake' | 'unstake' | 'unknown';
|
|
246
|
+
// amount: bigint | null;
|
|
247
|
+
// chain: 'ETH' | 'SOL';
|
|
248
|
+
// timestamp: number | null;
|
|
249
|
+
// from: string | null;
|
|
250
|
+
// to: string | null;
|
|
251
|
+
// txHash: string;
|
|
252
|
+
// raw: any;
|
|
253
|
+
// assertions: OPPAssertion[]
|
|
254
|
+
// }
|
|
255
|
+
|
|
256
|
+
export interface OPPAssertion {
|
|
257
|
+
type: 'liq_pretoken_purchase' | 'yield_pretoken_purchase' | 'pretoken_purchase' | 'stake' | 'unstake' | 'bonded_actor' | 'unbonded_actor' | 'unknown',
|
|
258
|
+
data: any
|
|
259
|
+
chain: 'ETH' | 'SOL';
|
|
260
|
+
timestamp: number | null;
|
|
261
|
+
from: string | null;
|
|
262
|
+
to: string | null;
|
|
263
|
+
txHash: string;
|
|
264
|
+
raw: any;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
export enum ReceiptNFTKind {
|
|
270
|
+
STAKE = 0,
|
|
271
|
+
PRETOKEN_PURCHASE = 1,
|
|
219
272
|
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { BigNumber, ethers } from "ethers";
|
|
2
|
-
import { preLaunchReceipt, SharesBurnedEvent, StakedEvent, WithdrawnStakeEvent, WithdrawnStakeResult } from "../types";
|
|
3
|
-
import { EthereumContractService } from "../contract";
|
|
4
|
-
import { formatContractErrors } from "../utils";
|
|
5
|
-
|
|
6
|
-
export class LiqClient {
|
|
7
|
-
|
|
8
|
-
private readonly contractService: EthereumContractService;
|
|
9
|
-
|
|
10
|
-
get contract() { return this.contractService.contract; }
|
|
11
|
-
|
|
12
|
-
constructor(contract: EthereumContractService) {
|
|
13
|
-
this.contractService = contract;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
public async safeBurn(signerAddress: string, amountWei: BigNumber): Promise<any> {
|
|
18
|
-
let tx, receipt;
|
|
19
|
-
try {
|
|
20
|
-
tx = await this.contract.LiqEth.safeBurn(signerAddress, amountWei);
|
|
21
|
-
receipt = await tx.wait(1);
|
|
22
|
-
} catch (err: any) {
|
|
23
|
-
let errorObj = formatContractErrors(err);
|
|
24
|
-
throw new Error(errorObj.name ?? errorObj.raw)
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Parse SharesBurned event if present
|
|
28
|
-
let event: SharesBurnedEvent | undefined;
|
|
29
|
-
const ev = receipt.events?.find((e) => e.event === 'SharesBurned');
|
|
30
|
-
|
|
31
|
-
if (ev && ev.args) {
|
|
32
|
-
const { from, shares, tokenValue } = ev.args;
|
|
33
|
-
event = {
|
|
34
|
-
from,
|
|
35
|
-
shares: BigNumber.from(shares),
|
|
36
|
-
tokenValue: BigNumber.from(tokenValue),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
txHash: tx.hash,
|
|
42
|
-
receipt,
|
|
43
|
-
event,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
}
|