@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.
@@ -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 { preLaunchReceipt, StakedEvent, WithdrawnStakeEvent, WithdrawnStakeResult } from "../types";
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 { DepositClient } from './clients/deposit.client';
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 { buildEthereumTrancheSnapshot } from './utils';
10
- import { LiqClient } from './clients/liq.client';
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 depositClient: DepositClient;
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.depositClient = new DepositClient(this.contractService);
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.depositClient.performDeposit(amountWei);
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.liqClient.safeBurn(address, amountWei)
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.stakeClient.getOppStatus();
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
- let receipts = await this.stakeClient.fetchPreLaunchReceipts(address);
192
- return receipts
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 (actual)
231
- const stakedLiqBalance = await this.contract.Depositor.sharesOf(walletAddress);
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: stakedLiqBalance.toBigInt(),
225
+ amount: stakeBalanceBN.toBigInt(),
247
226
  decimals: nativeDecimals,
248
227
  symbol: liqSymbol,
249
228
  },
250
229
  wire: {
251
- amount: BigInt(0), // TODO
252
- decimals: 0,
230
+ amount: wireBalance.toBigInt(),
231
+ decimals: 18,
253
232
  symbol: '$WIRE',
254
233
  },
255
234
  chainID: this.network.chainId
@@ -20,6 +20,7 @@ export const CONTRACT_NAMES = [
20
20
  'Pretoken',
21
21
  'Aggregator',
22
22
  'EthUsdPriceConsumer',
23
+ 'Pool',
23
24
 
24
25
  ] as const;
25
26
 
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
- }