@cogcoin/client 0.5.15 → 1.0.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.
Files changed (172) hide show
  1. package/README.md +80 -25
  2. package/dist/app-paths.d.ts +5 -6
  3. package/dist/app-paths.js +8 -16
  4. package/dist/art/balance.txt +10 -0
  5. package/dist/art/welcome.txt +16 -0
  6. package/dist/bitcoind/bootstrap/controller.d.ts +1 -0
  7. package/dist/bitcoind/bootstrap/controller.js +53 -1
  8. package/dist/bitcoind/client/follow-block-times.d.ts +1 -0
  9. package/dist/bitcoind/client/follow-block-times.js +1 -1
  10. package/dist/bitcoind/client/internal-types.d.ts +7 -3
  11. package/dist/bitcoind/client/managed-client.d.ts +4 -2
  12. package/dist/bitcoind/client/managed-client.js +14 -0
  13. package/dist/bitcoind/client/sync-engine.js +72 -11
  14. package/dist/bitcoind/hash-order.d.ts +4 -0
  15. package/dist/bitcoind/hash-order.js +13 -0
  16. package/dist/bitcoind/indexer-daemon-main.js +11 -3
  17. package/dist/bitcoind/normalize.js +3 -2
  18. package/dist/bitcoind/processing-start-height.d.ts +5 -0
  19. package/dist/bitcoind/processing-start-height.js +7 -0
  20. package/dist/bitcoind/progress/constants.d.ts +4 -0
  21. package/dist/bitcoind/progress/constants.js +4 -0
  22. package/dist/bitcoind/progress/controller.d.ts +2 -1
  23. package/dist/bitcoind/progress/controller.js +3 -3
  24. package/dist/bitcoind/progress/follow-scene.d.ts +6 -2
  25. package/dist/bitcoind/progress/follow-scene.js +29 -6
  26. package/dist/bitcoind/progress/formatting.d.ts +1 -0
  27. package/dist/bitcoind/progress/formatting.js +6 -0
  28. package/dist/bitcoind/progress/train-scene.js +37 -18
  29. package/dist/bitcoind/progress/tty-renderer.d.ts +6 -1
  30. package/dist/bitcoind/progress/tty-renderer.js +8 -4
  31. package/dist/bitcoind/rpc.d.ts +2 -1
  32. package/dist/bitcoind/rpc.js +3 -0
  33. package/dist/bitcoind/types.d.ts +6 -0
  34. package/dist/bytes.d.ts +1 -0
  35. package/dist/bytes.js +3 -0
  36. package/dist/cli/art.d.ts +2 -0
  37. package/dist/cli/art.js +37 -0
  38. package/dist/cli/commands/client-admin.d.ts +2 -0
  39. package/dist/cli/commands/client-admin.js +91 -0
  40. package/dist/cli/commands/follow.js +0 -2
  41. package/dist/cli/commands/mining-admin.js +6 -47
  42. package/dist/cli/commands/mining-read.js +11 -50
  43. package/dist/cli/commands/mining-runtime.js +38 -3
  44. package/dist/cli/commands/service-runtime.js +0 -2
  45. package/dist/cli/commands/status.js +8 -2
  46. package/dist/cli/commands/sync.js +51 -4
  47. package/dist/cli/commands/wallet-admin.js +142 -136
  48. package/dist/cli/commands/wallet-mutation.js +91 -79
  49. package/dist/cli/commands/wallet-read.js +15 -18
  50. package/dist/cli/context.js +4 -14
  51. package/dist/cli/mining-format.d.ts +0 -1
  52. package/dist/cli/mining-format.js +5 -37
  53. package/dist/cli/mining-json.d.ts +0 -18
  54. package/dist/cli/mining-json.js +0 -35
  55. package/dist/cli/mutation-command-groups.d.ts +1 -2
  56. package/dist/cli/mutation-command-groups.js +0 -5
  57. package/dist/cli/mutation-json.d.ts +24 -145
  58. package/dist/cli/mutation-json.js +30 -136
  59. package/dist/cli/mutation-resolved-json.d.ts +0 -7
  60. package/dist/cli/mutation-resolved-json.js +4 -10
  61. package/dist/cli/mutation-success.d.ts +2 -0
  62. package/dist/cli/mutation-success.js +11 -1
  63. package/dist/cli/mutation-text-format.js +1 -3
  64. package/dist/cli/output.d.ts +1 -1
  65. package/dist/cli/output.js +254 -231
  66. package/dist/cli/parse.d.ts +1 -1
  67. package/dist/cli/parse.js +93 -122
  68. package/dist/cli/preview-json.d.ts +17 -120
  69. package/dist/cli/preview-json.js +14 -97
  70. package/dist/cli/prompt.js +8 -13
  71. package/dist/cli/read-json.d.ts +15 -37
  72. package/dist/cli/read-json.js +44 -140
  73. package/dist/cli/runner.js +10 -13
  74. package/dist/cli/types.d.ts +8 -17
  75. package/dist/cli/types.js +0 -2
  76. package/dist/cli/wallet-format.d.ts +1 -0
  77. package/dist/cli/wallet-format.js +205 -144
  78. package/dist/cli/workflow-hints.d.ts +3 -3
  79. package/dist/cli/workflow-hints.js +11 -8
  80. package/dist/client/default-client.d.ts +3 -1
  81. package/dist/client/default-client.js +45 -2
  82. package/dist/client/factory.js +1 -1
  83. package/dist/client/initialization.js +23 -0
  84. package/dist/client/persistence.js +5 -5
  85. package/dist/client/store-adapter.js +1 -0
  86. package/dist/sqlite/checkpoints.d.ts +1 -0
  87. package/dist/sqlite/checkpoints.js +7 -0
  88. package/dist/sqlite/store.js +14 -1
  89. package/dist/types.d.ts +1 -0
  90. package/dist/wallet/coin-control.d.ts +41 -12
  91. package/dist/wallet/coin-control.js +100 -428
  92. package/dist/wallet/descriptor-normalization.d.ts +1 -3
  93. package/dist/wallet/descriptor-normalization.js +0 -16
  94. package/dist/wallet/lifecycle.d.ts +7 -99
  95. package/dist/wallet/lifecycle.js +513 -968
  96. package/dist/wallet/managed-core-wallet.d.ts +13 -0
  97. package/dist/wallet/managed-core-wallet.js +20 -0
  98. package/dist/wallet/mining/constants.d.ts +5 -12
  99. package/dist/wallet/mining/constants.js +5 -12
  100. package/dist/wallet/mining/control.d.ts +1 -13
  101. package/dist/wallet/mining/control.js +45 -349
  102. package/dist/wallet/mining/index.d.ts +3 -4
  103. package/dist/wallet/mining/index.js +1 -2
  104. package/dist/wallet/mining/runner.d.ts +116 -13
  105. package/dist/wallet/mining/runner.js +885 -501
  106. package/dist/wallet/mining/runtime-artifacts.js +23 -3
  107. package/dist/wallet/mining/sentence-protocol.d.ts +44 -0
  108. package/dist/wallet/mining/sentence-protocol.js +123 -0
  109. package/dist/wallet/mining/sentences.d.ts +4 -8
  110. package/dist/wallet/mining/sentences.js +3 -52
  111. package/dist/wallet/mining/state.d.ts +11 -6
  112. package/dist/wallet/mining/state.js +7 -6
  113. package/dist/wallet/mining/types.d.ts +2 -30
  114. package/dist/wallet/mining/visualizer.d.ts +31 -3
  115. package/dist/wallet/mining/visualizer.js +135 -13
  116. package/dist/wallet/read/context.d.ts +0 -2
  117. package/dist/wallet/read/context.js +119 -140
  118. package/dist/wallet/read/filter.js +2 -11
  119. package/dist/wallet/read/index.d.ts +1 -1
  120. package/dist/wallet/read/project.js +24 -77
  121. package/dist/wallet/read/types.d.ts +10 -25
  122. package/dist/wallet/reset.d.ts +0 -1
  123. package/dist/wallet/reset.js +60 -138
  124. package/dist/wallet/root-resolution.d.ts +1 -5
  125. package/dist/wallet/root-resolution.js +0 -18
  126. package/dist/wallet/runtime.d.ts +0 -6
  127. package/dist/wallet/runtime.js +0 -8
  128. package/dist/wallet/state/client-password-agent.js +208 -0
  129. package/dist/wallet/state/client-password.d.ts +65 -0
  130. package/dist/wallet/state/client-password.js +952 -0
  131. package/dist/wallet/state/crypto.d.ts +1 -20
  132. package/dist/wallet/state/crypto.js +0 -63
  133. package/dist/wallet/state/provider.d.ts +23 -11
  134. package/dist/wallet/state/provider.js +248 -290
  135. package/dist/wallet/state/storage.d.ts +2 -2
  136. package/dist/wallet/state/storage.js +48 -16
  137. package/dist/wallet/tx/anchor.d.ts +3 -28
  138. package/dist/wallet/tx/anchor.js +349 -1250
  139. package/dist/wallet/tx/bitcoin-transfer.d.ts +35 -0
  140. package/dist/wallet/tx/bitcoin-transfer.js +200 -0
  141. package/dist/wallet/tx/cog.d.ts +5 -1
  142. package/dist/wallet/tx/cog.js +149 -185
  143. package/dist/wallet/tx/common.d.ts +61 -8
  144. package/dist/wallet/tx/common.js +266 -146
  145. package/dist/wallet/tx/domain-admin.d.ts +3 -1
  146. package/dist/wallet/tx/domain-admin.js +61 -99
  147. package/dist/wallet/tx/domain-market.d.ts +5 -1
  148. package/dist/wallet/tx/domain-market.js +221 -228
  149. package/dist/wallet/tx/field.d.ts +4 -10
  150. package/dist/wallet/tx/field.js +83 -924
  151. package/dist/wallet/tx/identity-selector.d.ts +9 -3
  152. package/dist/wallet/tx/identity-selector.js +17 -35
  153. package/dist/wallet/tx/index.d.ts +3 -1
  154. package/dist/wallet/tx/index.js +2 -1
  155. package/dist/wallet/tx/register.d.ts +3 -1
  156. package/dist/wallet/tx/register.js +62 -220
  157. package/dist/wallet/tx/reputation.d.ts +3 -1
  158. package/dist/wallet/tx/reputation.js +58 -95
  159. package/dist/wallet/types.d.ts +8 -122
  160. package/package.json +5 -5
  161. package/dist/wallet/archive.d.ts +0 -4
  162. package/dist/wallet/archive.js +0 -41
  163. package/dist/wallet/mining/hook-protocol.d.ts +0 -47
  164. package/dist/wallet/mining/hook-protocol.js +0 -161
  165. package/dist/wallet/mining/hook-runner.js +0 -52
  166. package/dist/wallet/mining/hooks.d.ts +0 -38
  167. package/dist/wallet/mining/hooks.js +0 -520
  168. package/dist/wallet/state/explicit-lock.d.ts +0 -4
  169. package/dist/wallet/state/explicit-lock.js +0 -19
  170. package/dist/wallet/state/session.d.ts +0 -12
  171. package/dist/wallet/state/session.js +0 -23
  172. /package/dist/wallet/{mining/hook-runner.d.ts → state/client-password-agent.d.ts} +0 -0
@@ -0,0 +1,35 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import type { WalletPrompter } from "../lifecycle.js";
4
+ import { openWalletReadContext } from "../read/index.js";
5
+ import { type WalletRuntimePaths } from "../runtime.js";
6
+ import { type WalletSecretProvider } from "../state/provider.js";
7
+ import { type WalletMutationRpcClient } from "./common.js";
8
+ interface WalletBitcoinTransferRpcClient extends WalletMutationRpcClient {
9
+ sendRawTransaction(hex: string): Promise<string>;
10
+ }
11
+ export interface BitcoinTransferResult {
12
+ amountSats: bigint;
13
+ feeSats: bigint;
14
+ senderAddress: string;
15
+ recipientAddress: string;
16
+ recipientScriptPubKeyHex: string;
17
+ changeAddress: string;
18
+ txid: string;
19
+ wtxid: string | null;
20
+ }
21
+ export interface TransferBitcoinOptions {
22
+ amountSatsText: string;
23
+ target: string;
24
+ dataDir: string;
25
+ databasePath: string;
26
+ provider?: WalletSecretProvider;
27
+ prompter: WalletPrompter;
28
+ assumeYes?: boolean;
29
+ paths?: WalletRuntimePaths;
30
+ openReadContext?: typeof openWalletReadContext;
31
+ attachService?: typeof attachOrStartManagedBitcoindService;
32
+ rpcFactory?: (config: Parameters<typeof createRpcClient>[0]) => WalletBitcoinTransferRpcClient;
33
+ }
34
+ export declare function transferBitcoin(options: TransferBitcoinOptions): Promise<BitcoinTransferResult>;
35
+ export {};
@@ -0,0 +1,200 @@
1
+ import { attachOrStartManagedBitcoindService } from "../../bitcoind/service.js";
2
+ import { createRpcClient } from "../../bitcoind/node.js";
3
+ import { acquireFileLock } from "../fs/lock.js";
4
+ import { openWalletReadContext } from "../read/index.js";
5
+ import { resolveWalletRuntimePathsForTesting } from "../runtime.js";
6
+ import { createDefaultWalletSecretProvider, } from "../state/provider.js";
7
+ import { confirmYesNo } from "./confirm.js";
8
+ import { assertWalletBitcoinTransferContextReady, buildWalletMutationTransaction, isAlreadyAcceptedError, isBroadcastUnknownError, isInsufficientFundsError, outpointKey, pauseMiningForWalletMutation, unlockTemporaryBuilderLocks, } from "./common.js";
9
+ import { normalizeBtcTarget } from "./targets.js";
10
+ function parsePositiveSats(value) {
11
+ const trimmed = value.trim();
12
+ if (!/^[1-9]\d*$/.test(trimmed)) {
13
+ throw new Error("wallet_bitcoin_transfer_invalid_amount");
14
+ }
15
+ return BigInt(trimmed);
16
+ }
17
+ function satsToBtcNumber(value) {
18
+ return Number(value) / 100_000_000;
19
+ }
20
+ function btcValueToSats(value) {
21
+ const numeric = typeof value === "string" ? Number(value) : value;
22
+ return BigInt(Math.round(numeric * 100_000_000));
23
+ }
24
+ function normalizeRecipientAddress(target) {
25
+ const trimmed = target.trim();
26
+ try {
27
+ const normalized = normalizeBtcTarget(trimmed);
28
+ if (trimmed.startsWith("spk:") || normalized.opaque || normalized.address === null) {
29
+ throw new Error("wallet_bitcoin_transfer_address_required");
30
+ }
31
+ return {
32
+ address: normalized.address,
33
+ scriptPubKeyHex: normalized.scriptPubKeyHex,
34
+ };
35
+ }
36
+ catch (error) {
37
+ if (error instanceof Error && error.message === "wallet_bitcoin_transfer_address_required") {
38
+ throw error;
39
+ }
40
+ if (trimmed.startsWith("spk:")) {
41
+ throw new Error("wallet_bitcoin_transfer_address_required", { cause: error });
42
+ }
43
+ if (error instanceof Error
44
+ && (error.message === "wallet_target_missing"
45
+ || error.message === "wallet_target_invalid_address"
46
+ || error.message === "wallet_target_invalid_script")) {
47
+ throw new Error("wallet_bitcoin_transfer_invalid_address", { cause: error });
48
+ }
49
+ throw error;
50
+ }
51
+ }
52
+ function isSpendableFundingUtxo(entry, fundingScriptPubKeyHex) {
53
+ return entry.scriptPubKey === fundingScriptPubKeyHex
54
+ && entry.confirmations >= 1
55
+ && entry.spendable !== false
56
+ && entry.safe !== false;
57
+ }
58
+ function buildPlanForBitcoinTransfer(options) {
59
+ const fundingUtxos = options.allUtxos.filter((entry) => isSpendableFundingUtxo(entry, options.state.funding.scriptPubKeyHex));
60
+ return {
61
+ fixedInputs: [],
62
+ outputs: [
63
+ {
64
+ [options.recipientAddress]: satsToBtcNumber(options.amountSats),
65
+ },
66
+ ],
67
+ changeAddress: options.state.funding.address,
68
+ changePosition: null,
69
+ allowedFundingScriptPubKeyHex: options.state.funding.scriptPubKeyHex,
70
+ eligibleFundingOutpointKeys: new Set(fundingUtxos.map((entry) => outpointKey({ txid: entry.txid, vout: entry.vout }))),
71
+ recipientScriptPubKeyHex: options.recipientScriptPubKeyHex,
72
+ amountSats: options.amountSats,
73
+ };
74
+ }
75
+ function validateFundedBitcoinTransfer(decoded, _funded, plan) {
76
+ if (decoded.tx.vin.length === 0) {
77
+ throw new Error("wallet_bitcoin_transfer_missing_sender_input");
78
+ }
79
+ const recipientOutputs = decoded.tx.vout.filter((output) => output.scriptPubKey?.hex === plan.recipientScriptPubKeyHex);
80
+ if (recipientOutputs.length !== 1) {
81
+ throw new Error("wallet_bitcoin_transfer_missing_recipient_output");
82
+ }
83
+ if (btcValueToSats(recipientOutputs[0].value) !== plan.amountSats) {
84
+ throw new Error("wallet_bitcoin_transfer_recipient_amount_mismatch");
85
+ }
86
+ const hasUnexpectedOutput = decoded.tx.vout.some((output) => output.scriptPubKey?.hex !== plan.recipientScriptPubKeyHex
87
+ && output.scriptPubKey?.hex !== plan.allowedFundingScriptPubKeyHex);
88
+ if (hasUnexpectedOutput) {
89
+ throw new Error("wallet_bitcoin_transfer_unexpected_output");
90
+ }
91
+ }
92
+ async function confirmBitcoinTransfer(prompter, senderAddress, recipientAddress, amountSats, assumeYes = false) {
93
+ prompter.writeLine(`You are sending ${amountSats.toString()} sats.`);
94
+ prompter.writeLine(`Wallet address: ${senderAddress}`);
95
+ prompter.writeLine(`Recipient: ${recipientAddress}`);
96
+ await confirmYesNo(prompter, "This will publish a standard Bitcoin payment from the wallet address.", {
97
+ assumeYes,
98
+ errorCode: "wallet_bitcoin_transfer_confirmation_rejected",
99
+ requiresTtyErrorCode: "wallet_bitcoin_transfer_requires_tty",
100
+ });
101
+ }
102
+ export async function transferBitcoin(options) {
103
+ const amountSats = parsePositiveSats(options.amountSatsText);
104
+ const recipient = normalizeRecipientAddress(options.target);
105
+ const provider = options.provider ?? createDefaultWalletSecretProvider();
106
+ const paths = options.paths ?? resolveWalletRuntimePathsForTesting();
107
+ const controlLock = await acquireFileLock(paths.walletControlLockPath, {
108
+ purpose: "wallet-bitcoin-transfer",
109
+ walletRootId: null,
110
+ });
111
+ try {
112
+ const miningPreemption = await pauseMiningForWalletMutation({
113
+ paths,
114
+ reason: "wallet-bitcoin-transfer",
115
+ });
116
+ const readContext = await (options.openReadContext ?? openWalletReadContext)({
117
+ dataDir: options.dataDir,
118
+ databasePath: options.databasePath,
119
+ secretProvider: provider,
120
+ walletControlLockHeld: true,
121
+ paths,
122
+ });
123
+ try {
124
+ assertWalletBitcoinTransferContextReady(readContext, "wallet_bitcoin_transfer");
125
+ const state = readContext.localState.state;
126
+ if (state.funding.scriptPubKeyHex === recipient.scriptPubKeyHex) {
127
+ throw new Error("wallet_bitcoin_transfer_self_transfer");
128
+ }
129
+ await confirmBitcoinTransfer(options.prompter, state.funding.address, recipient.address, amountSats, options.assumeYes);
130
+ const node = await (options.attachService ?? attachOrStartManagedBitcoindService)({
131
+ dataDir: options.dataDir,
132
+ chain: "main",
133
+ startHeight: 0,
134
+ walletRootId: state.walletRootId,
135
+ });
136
+ const rpc = (options.rpcFactory ?? createRpcClient)(node.rpc);
137
+ const walletName = state.managedCoreWallet.walletName;
138
+ const allUtxos = await rpc.listUnspent(walletName, 1);
139
+ const plan = buildPlanForBitcoinTransfer({
140
+ state,
141
+ allUtxos,
142
+ recipientAddress: recipient.address,
143
+ recipientScriptPubKeyHex: recipient.scriptPubKeyHex,
144
+ amountSats,
145
+ });
146
+ let built;
147
+ try {
148
+ built = await buildWalletMutationTransaction({
149
+ rpc,
150
+ walletName,
151
+ state,
152
+ plan,
153
+ validateFundedDraft: validateFundedBitcoinTransfer,
154
+ finalizeErrorCode: "wallet_bitcoin_transfer_finalize_failed",
155
+ mempoolRejectPrefix: "wallet_bitcoin_transfer_mempool_reject",
156
+ });
157
+ }
158
+ catch (error) {
159
+ if (isInsufficientFundsError(error)) {
160
+ throw new Error("wallet_bitcoin_transfer_insufficient_funds", { cause: error });
161
+ }
162
+ throw error;
163
+ }
164
+ try {
165
+ await rpc.sendRawTransaction(built.rawHex);
166
+ }
167
+ catch (error) {
168
+ if (!isAlreadyAcceptedError(error)) {
169
+ if (isInsufficientFundsError(error)) {
170
+ throw new Error("wallet_bitcoin_transfer_insufficient_funds", { cause: error });
171
+ }
172
+ if (isBroadcastUnknownError(error)) {
173
+ throw new Error("wallet_bitcoin_transfer_broadcast_unknown", { cause: error });
174
+ }
175
+ throw error;
176
+ }
177
+ }
178
+ finally {
179
+ await unlockTemporaryBuilderLocks(rpc, walletName, built.temporaryBuilderLockedOutpoints);
180
+ }
181
+ return {
182
+ amountSats,
183
+ feeSats: btcValueToSats(built.funded.fee),
184
+ senderAddress: state.funding.address,
185
+ recipientAddress: recipient.address,
186
+ recipientScriptPubKeyHex: recipient.scriptPubKeyHex,
187
+ changeAddress: state.funding.address,
188
+ txid: built.txid,
189
+ wtxid: built.wtxid,
190
+ };
191
+ }
192
+ finally {
193
+ await readContext.close();
194
+ await miningPreemption.release();
195
+ }
196
+ }
197
+ finally {
198
+ await controlLock.release();
199
+ }
200
+ }
@@ -5,7 +5,7 @@ import type { WalletPrompter } from "../lifecycle.js";
5
5
  import { type WalletRuntimePaths } from "../runtime.js";
6
6
  import { type WalletSecretProvider } from "../state/provider.js";
7
7
  import { openWalletReadContext } from "../read/index.js";
8
- import { type WalletMutationRpcClient } from "./common.js";
8
+ import { type WalletMutationFeeSummary, type WalletMutationRpcClient } from "./common.js";
9
9
  type CogMutationKind = "send" | "lock" | "claim";
10
10
  interface WalletCogRpcClient extends WalletMutationRpcClient {
11
11
  getBlockchainInfo(): Promise<{
@@ -35,11 +35,13 @@ export interface CogMutationResult {
35
35
  recipientDomainName?: string | null;
36
36
  lockId?: number | null;
37
37
  resolved: CogResolvedSummary;
38
+ fees: WalletMutationFeeSummary;
38
39
  }
39
40
  export interface SendCogOptions {
40
41
  amountCogtoshi: bigint;
41
42
  target: string;
42
43
  fromIdentity?: string | null;
44
+ feeRateSatVb?: number | null;
43
45
  dataDir: string;
44
46
  databasePath: string;
45
47
  provider?: WalletSecretProvider;
@@ -55,6 +57,7 @@ export interface LockCogToDomainOptions {
55
57
  amountCogtoshi: bigint;
56
58
  recipientDomainName: string;
57
59
  fromIdentity?: string | null;
60
+ feeRateSatVb?: number | null;
58
61
  timeoutHeight?: number | null;
59
62
  timeoutBlocksOrDuration?: string | null;
60
63
  conditionHex: string;
@@ -72,6 +75,7 @@ export interface LockCogToDomainOptions {
72
75
  export interface ClaimCogLockOptions {
73
76
  lockId: number;
74
77
  preimageHex: string;
78
+ feeRateSatVb?: number | null;
75
79
  dataDir: string;
76
80
  databasePath: string;
77
81
  provider?: WalletSecretProvider;