@kadi.build/deploy-ability 0.0.3 → 0.0.5
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/targets/akash/bids.d.ts +183 -0
- package/dist/targets/akash/bids.d.ts.map +1 -0
- package/dist/targets/akash/bids.js +247 -0
- package/dist/targets/akash/bids.js.map +1 -0
- package/dist/targets/akash/certificate-manager.d.ts +89 -167
- package/dist/targets/akash/certificate-manager.d.ts.map +1 -1
- package/dist/targets/akash/certificate-manager.js +193 -301
- package/dist/targets/akash/certificate-manager.js.map +1 -1
- package/dist/targets/akash/client.d.ts +644 -0
- package/dist/targets/akash/client.d.ts.map +1 -0
- package/dist/targets/akash/client.js +972 -0
- package/dist/targets/akash/client.js.map +1 -0
- package/dist/targets/akash/constants.d.ts +12 -149
- package/dist/targets/akash/constants.d.ts.map +1 -1
- package/dist/targets/akash/constants.js +14 -136
- package/dist/targets/akash/constants.js.map +1 -1
- package/dist/targets/akash/deployer.d.ts +3 -82
- package/dist/targets/akash/deployer.d.ts.map +1 -1
- package/dist/targets/akash/deployer.js +122 -160
- package/dist/targets/akash/deployer.js.map +1 -1
- package/dist/targets/akash/environment.d.ts +16 -214
- package/dist/targets/akash/environment.d.ts.map +1 -1
- package/dist/targets/akash/environment.js +20 -210
- package/dist/targets/akash/environment.js.map +1 -1
- package/dist/targets/akash/index.d.ts +95 -189
- package/dist/targets/akash/index.d.ts.map +1 -1
- package/dist/targets/akash/index.js +69 -197
- package/dist/targets/akash/index.js.map +1 -1
- package/dist/targets/akash/lease-monitor.d.ts +3 -21
- package/dist/targets/akash/lease-monitor.d.ts.map +1 -1
- package/dist/targets/akash/lease-monitor.js +39 -56
- package/dist/targets/akash/lease-monitor.js.map +1 -1
- package/dist/targets/akash/logs.d.ts +103 -4
- package/dist/targets/akash/logs.d.ts.map +1 -1
- package/dist/targets/akash/logs.js +12 -3
- package/dist/targets/akash/logs.js.map +1 -1
- package/dist/targets/akash/pricing.d.ts +12 -191
- package/dist/targets/akash/pricing.d.ts.map +1 -1
- package/dist/targets/akash/pricing.js +12 -188
- package/dist/targets/akash/pricing.js.map +1 -1
- package/dist/targets/akash/provider-manager.d.ts +120 -0
- package/dist/targets/akash/provider-manager.d.ts.map +1 -0
- package/dist/targets/akash/provider-manager.js +574 -0
- package/dist/targets/akash/provider-manager.js.map +1 -0
- package/dist/targets/akash/sdl-generator.d.ts +2 -2
- package/dist/targets/akash/sdl-generator.d.ts.map +1 -1
- package/dist/targets/akash/sdl-generator.js +6 -39
- package/dist/targets/akash/sdl-generator.js.map +1 -1
- package/dist/targets/akash/types.d.ts +66 -243
- package/dist/targets/akash/types.d.ts.map +1 -1
- package/dist/targets/akash/types.js +4 -41
- package/dist/targets/akash/types.js.map +1 -1
- package/dist/targets/akash/wallet-manager.d.ts +35 -352
- package/dist/targets/akash/wallet-manager.d.ts.map +1 -1
- package/dist/targets/akash/wallet-manager.js +37 -439
- package/dist/targets/akash/wallet-manager.js.map +1 -1
- package/dist/targets/local/compose-generator.d.ts.map +1 -1
- package/dist/targets/local/compose-generator.js +1 -0
- package/dist/targets/local/compose-generator.js.map +1 -1
- package/dist/targets/local/deployer.js +4 -4
- package/dist/targets/local/deployer.js.map +1 -1
- package/dist/targets/local/types.d.ts +4 -0
- package/dist/targets/local/types.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/options.d.ts +45 -4
- package/dist/types/options.d.ts.map +1 -1
- package/dist/utils/registry/manager.js +6 -6
- package/dist/utils/registry/manager.js.map +1 -1
- package/dist/utils/registry/setup.js +4 -4
- package/dist/utils/registry/setup.js.map +1 -1
- package/docs/KADI_ABILITY_CONVERSION.md +1365 -0
- package/docs/PIPELINE_BUILDER_DESIGN.md +1149 -0
- package/package.json +8 -11
- package/dist/targets/akash/bid-selectors.d.ts +0 -251
- package/dist/targets/akash/bid-selectors.d.ts.map +0 -1
- package/dist/targets/akash/bid-selectors.js +0 -322
- package/dist/targets/akash/bid-selectors.js.map +0 -1
- package/dist/targets/akash/bid-types.d.ts +0 -297
- package/dist/targets/akash/bid-types.d.ts.map +0 -1
- package/dist/targets/akash/bid-types.js +0 -89
- package/dist/targets/akash/bid-types.js.map +0 -1
- package/dist/targets/akash/blockchain-client.d.ts +0 -577
- package/dist/targets/akash/blockchain-client.d.ts.map +0 -1
- package/dist/targets/akash/blockchain-client.js +0 -803
- package/dist/targets/akash/blockchain-client.js.map +0 -1
- package/dist/targets/akash/logs.types.d.ts +0 -102
- package/dist/targets/akash/logs.types.d.ts.map +0 -1
- package/dist/targets/akash/logs.types.js +0 -9
- package/dist/targets/akash/logs.types.js.map +0 -1
- package/dist/targets/akash/provider-client.d.ts +0 -114
- package/dist/targets/akash/provider-client.d.ts.map +0 -1
- package/dist/targets/akash/provider-client.js +0 -318
- package/dist/targets/akash/provider-client.js.map +0 -1
- package/dist/targets/akash/provider-metadata.d.ts +0 -228
- package/dist/targets/akash/provider-metadata.d.ts.map +0 -1
- package/dist/targets/akash/provider-metadata.js +0 -14
- package/dist/targets/akash/provider-metadata.js.map +0 -1
- package/dist/targets/akash/provider-service.d.ts +0 -133
- package/dist/targets/akash/provider-service.d.ts.map +0 -1
- package/dist/targets/akash/provider-service.js +0 -391
- package/dist/targets/akash/provider-service.js.map +0 -1
- package/dist/targets/akash/query-client.d.ts +0 -125
- package/dist/targets/akash/query-client.d.ts.map +0 -1
- package/dist/targets/akash/query-client.js +0 -332
- package/dist/targets/akash/query-client.js.map +0 -1
- package/docs/EXAMPLES.md +0 -293
- package/docs/PLACEMENT.md +0 -433
- package/docs/STORAGE.md +0 -318
|
@@ -1,803 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Akash Network Blockchain Client Module
|
|
3
|
-
*
|
|
4
|
-
* Handles all blockchain operations for Akash Network deployments including:
|
|
5
|
-
* - Signing client creation and management
|
|
6
|
-
* - Deployment creation on blockchain
|
|
7
|
-
* - Provider bid collection and filtering
|
|
8
|
-
* - Lease creation with selected providers
|
|
9
|
-
*
|
|
10
|
-
* Design Philosophy:
|
|
11
|
-
* This is a LIBRARY, not a CLI. Operations return Result types with detailed
|
|
12
|
-
* data. The caller (deployer.ts) handles progress tracking and user feedback.
|
|
13
|
-
*
|
|
14
|
-
* We use the Akash SDK types and helpers directly rather than reinventing them.
|
|
15
|
-
* The SDK is well-designed and thoroughly tested - we enhance the DX with Result
|
|
16
|
-
* types and comprehensive comments.
|
|
17
|
-
*
|
|
18
|
-
* @module targets/akash/blockchain-client
|
|
19
|
-
*/
|
|
20
|
-
import { SigningStargateClient } from '@cosmjs/stargate';
|
|
21
|
-
import { Registry } from '@cosmjs/proto-signing';
|
|
22
|
-
import { getAkashTypeRegistry, getTypeUrl } from '@akashnetwork/akashjs/build/stargate/index.js';
|
|
23
|
-
import { getRpc } from '@akashnetwork/akashjs/build/rpc/index.js';
|
|
24
|
-
import { QueryBidsRequest, QueryClientImpl as QueryMarketClient, MsgCreateLease, LeaseID, } from '@akashnetwork/akash-api/akash/market/v1beta4';
|
|
25
|
-
import { MsgCreateDeployment, MsgCloseDeployment, } from '@akashnetwork/akash-api/akash/deployment/v1beta3';
|
|
26
|
-
import { success, failure } from '../../types/index.js';
|
|
27
|
-
import { DeploymentError } from '../../errors/index.js';
|
|
28
|
-
import { getNetworkConfig, isProviderBlacklisted } from './environment.js';
|
|
29
|
-
import { createBidPricing } from './bid-types.js';
|
|
30
|
-
import { fetchAllProviders } from './provider-service.js';
|
|
31
|
-
/**
|
|
32
|
-
* Create a signing client for Akash blockchain operations
|
|
33
|
-
*
|
|
34
|
-
* Creates a SigningStargateClient configured with Akash-specific message
|
|
35
|
-
* types. This client is used for all blockchain transactions including
|
|
36
|
-
* deployment creation, lease creation, and certificate broadcasting.
|
|
37
|
-
*
|
|
38
|
-
* **Why you need this:**
|
|
39
|
-
* The Akash blockchain uses custom message types (MsgCreateDeployment,
|
|
40
|
-
* MsgCreateLease, etc.) that aren't in the standard Cosmos SDK. We need
|
|
41
|
-
* to register these types so the client can encode/decode them correctly.
|
|
42
|
-
*
|
|
43
|
-
* **What you get:**
|
|
44
|
-
* - A signing client connected to Akash RPC
|
|
45
|
-
* - Account information for transaction signing
|
|
46
|
-
* - Ability to broadcast any Akash transaction
|
|
47
|
-
*
|
|
48
|
-
* @param wallet - Wallet context with offline signer
|
|
49
|
-
* @param network - Akash network to connect to
|
|
50
|
-
* @returns Result with signing client and account info
|
|
51
|
-
*
|
|
52
|
-
* @example Basic usage
|
|
53
|
-
* ```typescript
|
|
54
|
-
* const clientResult = await createSigningClient(wallet, 'mainnet');
|
|
55
|
-
* if (!clientResult.success) {
|
|
56
|
-
* console.error('Failed to create client:', clientResult.error.message);
|
|
57
|
-
* return;
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* const { client, account } = clientResult.data;
|
|
61
|
-
* console.log('Connected with address:', account.address);
|
|
62
|
-
* ```
|
|
63
|
-
*
|
|
64
|
-
* @example Error handling
|
|
65
|
-
* ```typescript
|
|
66
|
-
* const result = await createSigningClient(wallet, 'testnet');
|
|
67
|
-
* if (!result.success) {
|
|
68
|
-
* if (result.error.code === 'WALLET_ERROR') {
|
|
69
|
-
* console.error('Wallet issue - check connection');
|
|
70
|
-
* } else if (result.error.code === 'RPC_ERROR') {
|
|
71
|
-
* console.error('Network issue - try different RPC endpoint');
|
|
72
|
-
* }
|
|
73
|
-
* return;
|
|
74
|
-
* }
|
|
75
|
-
* ```
|
|
76
|
-
*/
|
|
77
|
-
export async function createSigningClient(wallet, network) {
|
|
78
|
-
try {
|
|
79
|
-
// Step 1: Create Cosmos SDK type registry with Akash-specific message types
|
|
80
|
-
// The Akash type registry includes all necessary Cosmos SDK types plus
|
|
81
|
-
// Akash deployment/market/provider message types. We don't need to merge
|
|
82
|
-
// with defaultRegistryTypes as the Akash registry is already complete.
|
|
83
|
-
const registry = new Registry(getAkashTypeRegistry());
|
|
84
|
-
// Step 2: Get RPC endpoint for the selected network
|
|
85
|
-
const networkConfig = getNetworkConfig(network);
|
|
86
|
-
const rpc = networkConfig.rpc;
|
|
87
|
-
// Step 3: Get accounts from wallet's offline signer
|
|
88
|
-
// The offline signer provides accounts without needing network access
|
|
89
|
-
const accounts = await wallet.offlineSigner.getAccounts();
|
|
90
|
-
if (accounts.length === 0) {
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
error: new DeploymentError('No accounts found in wallet', 'WALLET_ERROR', {}, false, 'Please check your wallet connection and ensure it has at least one account'),
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
// Step 4: Create SigningStargateClient connected to Akash RPC
|
|
97
|
-
// This client can sign and broadcast transactions using the wallet's signer
|
|
98
|
-
const client = await SigningStargateClient.connectWithSigner(rpc, wallet.offlineSigner, { registry });
|
|
99
|
-
// Step 5: Return client and account info for transaction operations
|
|
100
|
-
const account = accounts[0];
|
|
101
|
-
return {
|
|
102
|
-
success: true,
|
|
103
|
-
data: {
|
|
104
|
-
client,
|
|
105
|
-
account: {
|
|
106
|
-
address: account.address,
|
|
107
|
-
pubkey: account.pubkey,
|
|
108
|
-
accountNumber: 0, // Will be fetched from chain when needed
|
|
109
|
-
sequence: 0, // Will be fetched from chain when needed
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
catch (error) {
|
|
115
|
-
return {
|
|
116
|
-
success: false,
|
|
117
|
-
error: new DeploymentError(`Failed to create signing client: ${error}`, 'RPC_ERROR', { error: String(error) }, false, 'Check network connection and RPC endpoint availability'),
|
|
118
|
-
};
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Create a new Akash deployment on the blockchain
|
|
123
|
-
*
|
|
124
|
-
* Broadcasts a MsgCreateDeployment transaction that registers your application
|
|
125
|
-
* with the Akash marketplace. Providers will see this deployment and submit bids.
|
|
126
|
-
*
|
|
127
|
-
* **The deployment process:**
|
|
128
|
-
* 1. Your deployment gets a unique identifier (dseq = deployment sequence)
|
|
129
|
-
* 2. Deployment is posted to the blockchain with resource requirements
|
|
130
|
-
* 3. An escrow deposit is held (default 5 AKT, returned when you close)
|
|
131
|
-
* 4. Providers see your deployment and submit competitive bids
|
|
132
|
-
* 5. You choose a bid and create a lease
|
|
133
|
-
*
|
|
134
|
-
* **Escrow Deposit:**
|
|
135
|
-
* The deposit ensures you can pay for resources. It's returned when you
|
|
136
|
-
* close the deployment. Default is 5 AKT but you can customize it.
|
|
137
|
-
*
|
|
138
|
-
* **About dseq:**
|
|
139
|
-
* The deployment sequence number (dseq) is taken from the current block
|
|
140
|
-
* height, ensuring it's unique and monotonically increasing.
|
|
141
|
-
*
|
|
142
|
-
* @param clientContext - Signing client and account info
|
|
143
|
-
* @param wallet - Wallet context with address
|
|
144
|
-
* @param sdl - SDL object with deployment configuration
|
|
145
|
-
* @param depositAkt - Optional deposit amount in AKT (default: 5)
|
|
146
|
-
* @returns Result with deployment sequence number and transaction info
|
|
147
|
-
*
|
|
148
|
-
* @example Basic deployment
|
|
149
|
-
* ```typescript
|
|
150
|
-
* import { SDL } from '@akashnetwork/akashjs/build/sdl';
|
|
151
|
-
*
|
|
152
|
-
* // Parse SDL from YAML
|
|
153
|
-
* const sdl = SDL.fromString(yamlContent, 'beta3');
|
|
154
|
-
*
|
|
155
|
-
* // Create signing client
|
|
156
|
-
* const clientResult = await createSigningClient(wallet, 'mainnet');
|
|
157
|
-
* if (!clientResult.success) return clientResult;
|
|
158
|
-
*
|
|
159
|
-
* // Deploy with default 5 AKT deposit
|
|
160
|
-
* const deployResult = await createDeployment(
|
|
161
|
-
* clientResult.data,
|
|
162
|
-
* wallet,
|
|
163
|
-
* sdl
|
|
164
|
-
* );
|
|
165
|
-
*
|
|
166
|
-
* if (deployResult.success) {
|
|
167
|
-
* console.log('Deployment created!');
|
|
168
|
-
* console.log('DSEQ:', deployResult.data.dseq);
|
|
169
|
-
* console.log('TX:', deployResult.data.transactionHash);
|
|
170
|
-
* }
|
|
171
|
-
* ```
|
|
172
|
-
*
|
|
173
|
-
* @example Custom deposit
|
|
174
|
-
* ```typescript
|
|
175
|
-
* // Deploy with 10 AKT deposit for larger deployments
|
|
176
|
-
* const result = await createDeployment(
|
|
177
|
-
* clientContext,
|
|
178
|
-
* wallet,
|
|
179
|
-
* sdl,
|
|
180
|
-
* 10 // 10 AKT deposit
|
|
181
|
-
* );
|
|
182
|
-
* ```
|
|
183
|
-
*/
|
|
184
|
-
export async function createDeployment(clientContext, wallet, sdl, depositAkt = 5) {
|
|
185
|
-
try {
|
|
186
|
-
const { client, account } = clientContext;
|
|
187
|
-
const owner = wallet.address;
|
|
188
|
-
// Step 1: Get current block height for dseq
|
|
189
|
-
// The deployment sequence number (dseq) uniquely identifies this deployment.
|
|
190
|
-
// Using block height ensures uniqueness and monotonic increase.
|
|
191
|
-
const dseq = await client.getHeight();
|
|
192
|
-
// Step 2: Extract deployment groups and manifest version from SDL
|
|
193
|
-
// The SDL library from @akashnetwork/akashjs handles all validation
|
|
194
|
-
// and returns properly structured deployment groups ready for blockchain.
|
|
195
|
-
// We trust the SDK - no manual normalization needed!
|
|
196
|
-
const groups = sdl.groups();
|
|
197
|
-
const manifestVersion = await sdl.manifestVersion();
|
|
198
|
-
// Step 3: Calculate escrow deposit in uakt (micro-AKT)
|
|
199
|
-
// 1 AKT = 1,000,000 uakt
|
|
200
|
-
// The deposit is held in escrow and returned when deployment closes
|
|
201
|
-
const aktAmount = Number.isFinite(depositAkt) && depositAkt > 0 ? depositAkt : 5;
|
|
202
|
-
const depositUakt = Math.round(aktAmount * 1_000_000).toString();
|
|
203
|
-
// Step 4: Create deployment message with all parameters
|
|
204
|
-
const msg = MsgCreateDeployment.fromPartial({
|
|
205
|
-
id: { owner, dseq },
|
|
206
|
-
groups: groups, // Trust SDL - it returns correct structure
|
|
207
|
-
version: manifestVersion,
|
|
208
|
-
deposit: { amount: depositUakt, denom: 'uakt' },
|
|
209
|
-
depositor: owner,
|
|
210
|
-
});
|
|
211
|
-
// Step 5: Wrap message with type-safe URL
|
|
212
|
-
// getTypeUrl() ensures we use the correct protobuf type identifier
|
|
213
|
-
// for this message type, preventing runtime errors from typos
|
|
214
|
-
const anyMsg = {
|
|
215
|
-
typeUrl: getTypeUrl(MsgCreateDeployment),
|
|
216
|
-
value: msg,
|
|
217
|
-
};
|
|
218
|
-
// Step 6: Set transaction fee
|
|
219
|
-
// Gas estimation: 300,000 gas units
|
|
220
|
-
// Fee: 8,000 uakt (approximately 0.008 AKT)
|
|
221
|
-
const fee = {
|
|
222
|
-
amount: [{ denom: 'uakt', amount: '8000' }],
|
|
223
|
-
gas: '300000',
|
|
224
|
-
};
|
|
225
|
-
// Step 7: Sign and broadcast deployment transaction
|
|
226
|
-
const res = await client.signAndBroadcast(account.address, [anyMsg], fee, 'Create deployment via deploy-ability');
|
|
227
|
-
// Step 8: Check transaction result
|
|
228
|
-
// code === 0 means success, any other code is an error
|
|
229
|
-
if (res.code !== 0) {
|
|
230
|
-
return {
|
|
231
|
-
success: false,
|
|
232
|
-
error: new DeploymentError(`Deployment transaction failed: ${res.rawLog}`, 'TRANSACTION_FAILED', {
|
|
233
|
-
code: res.code,
|
|
234
|
-
rawLog: res.rawLog,
|
|
235
|
-
transactionHash: res.transactionHash,
|
|
236
|
-
}, false, 'Check wallet balance (need funds for deposit + fees) and SDL validity'),
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
// Step 9: Return deployment result with dseq
|
|
240
|
-
return {
|
|
241
|
-
success: true,
|
|
242
|
-
data: {
|
|
243
|
-
dseq,
|
|
244
|
-
transactionHash: res.transactionHash,
|
|
245
|
-
height: res.height,
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
catch (error) {
|
|
250
|
-
return {
|
|
251
|
-
success: false,
|
|
252
|
-
error: new DeploymentError(`Failed to create deployment: ${error}`, 'DEPLOYMENT_FAILED', { error: String(error) }, false, 'Check wallet connection, network status, and SDL validity'),
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Extract valid bids from marketplace response
|
|
258
|
-
*
|
|
259
|
-
* The marketplace returns bid responses in a wrapped format. We filter
|
|
260
|
-
* for bids that exist and have valid provider addresses, then filter out
|
|
261
|
-
* blacklisted providers.
|
|
262
|
-
*
|
|
263
|
-
* **Why this is needed:**
|
|
264
|
-
* QueryBidsResponse.bids is an array of { bid?: Bid } where bid might be
|
|
265
|
-
* undefined. We extract the actual Bid objects and validate them.
|
|
266
|
-
*
|
|
267
|
-
* @param response - Raw bids response from marketplace query
|
|
268
|
-
* @returns Array of valid provider bids
|
|
269
|
-
*/
|
|
270
|
-
function extractValidBids(response) {
|
|
271
|
-
if (!response.bids)
|
|
272
|
-
return [];
|
|
273
|
-
return response.bids
|
|
274
|
-
.filter((b) => b.bid !== undefined && b.bid !== null)
|
|
275
|
-
.map((b) => b.bid)
|
|
276
|
-
.filter((bid) => {
|
|
277
|
-
const provider = bid.bidId?.provider ?? '';
|
|
278
|
-
return provider !== '';
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
/**
|
|
282
|
-
* Query provider bids for a deployment with enhanced information
|
|
283
|
-
*
|
|
284
|
-
* Queries the Akash marketplace for provider bids and enriches each bid with:
|
|
285
|
-
* - Complete provider information (name, location, audit status)
|
|
286
|
-
* - Reliability metrics (uptime percentages)
|
|
287
|
-
* - Pre-calculated pricing for all time periods (hour, day, week, month)
|
|
288
|
-
*
|
|
289
|
-
* Returns ALL valid bids so the caller can implement custom selection logic.
|
|
290
|
-
*
|
|
291
|
-
* **The Akash Bidding Process:**
|
|
292
|
-
* After you create a deployment, here's what happens:
|
|
293
|
-
* 1. Providers monitor the blockchain for new deployments
|
|
294
|
-
* 2. They check if they can fulfill your resource requirements
|
|
295
|
-
* 3. They submit competitive bids with their pricing
|
|
296
|
-
* 4. You query to see available bids (this function)
|
|
297
|
-
* 5. You choose the best bid based on your criteria
|
|
298
|
-
* 6. You create a lease with the selected provider
|
|
299
|
-
*
|
|
300
|
-
* **Bid Filtering:**
|
|
301
|
-
* We automatically exclude:
|
|
302
|
-
* - Blacklisted providers (known to be unreliable)
|
|
303
|
-
* - Custom blacklist from your deployment configuration
|
|
304
|
-
* - Bids without valid provider addresses
|
|
305
|
-
*
|
|
306
|
-
* **Note:** This returns immediately with current state. Use `waitForBids()`
|
|
307
|
-
* if you want to poll until bids arrive.
|
|
308
|
-
*
|
|
309
|
-
* @param wallet - Wallet context with owner address
|
|
310
|
-
* @param network - Akash network to query
|
|
311
|
-
* @param dseq - Deployment sequence number
|
|
312
|
-
* @param options - Optional query options
|
|
313
|
-
* @param options.customBlacklist - Additional provider addresses to exclude
|
|
314
|
-
* @param options.includeOffline - Include offline providers (default: false)
|
|
315
|
-
* @returns Result with array of enhanced bids (empty array if none found)
|
|
316
|
-
*
|
|
317
|
-
* @example Query and display bids
|
|
318
|
-
* ```typescript
|
|
319
|
-
* const result = await queryBids(wallet, 'mainnet', dseq);
|
|
320
|
-
*
|
|
321
|
-
* if (result.success) {
|
|
322
|
-
* console.log(`Received ${result.data.length} bids`);
|
|
323
|
-
* for (const bid of result.data) {
|
|
324
|
-
* const provider = bid.provider;
|
|
325
|
-
* const uptime = provider.reliability?.uptime7d;
|
|
326
|
-
* console.log(`
|
|
327
|
-
* Provider: ${provider.name || provider.owner}
|
|
328
|
-
* Price: ${bid.pricing.akt.perMonth.toFixed(2)} AKT/month
|
|
329
|
-
* Uptime (7d): ${uptime ? (uptime * 100).toFixed(1) + '%' : 'Unknown'}
|
|
330
|
-
* Location: ${provider.location?.country || 'Unknown'}
|
|
331
|
-
* `);
|
|
332
|
-
* }
|
|
333
|
-
* }
|
|
334
|
-
* ```
|
|
335
|
-
*
|
|
336
|
-
* @example With filtering options
|
|
337
|
-
* ```typescript
|
|
338
|
-
* const blacklist = ['akash1badprovider...', 'akash1another...'];
|
|
339
|
-
* const result = await queryBids(wallet, 'mainnet', dseq, {
|
|
340
|
-
* customBlacklist: blacklist,
|
|
341
|
-
* includeOffline: false
|
|
342
|
-
* });
|
|
343
|
-
* ```
|
|
344
|
-
*/
|
|
345
|
-
export async function queryBids(wallet, network, dseq, options) {
|
|
346
|
-
try {
|
|
347
|
-
// Step 1: Get RPC endpoint for network
|
|
348
|
-
const networkConfig = getNetworkConfig(network);
|
|
349
|
-
const rpc = await getRpc(networkConfig.rpc);
|
|
350
|
-
// Step 2: Create marketplace query client
|
|
351
|
-
const queryClient = new QueryMarketClient(rpc);
|
|
352
|
-
// Step 3: Build bid query request
|
|
353
|
-
// Filter for open bids for this specific deployment
|
|
354
|
-
const request = QueryBidsRequest.fromPartial({
|
|
355
|
-
filters: {
|
|
356
|
-
owner: wallet.address,
|
|
357
|
-
dseq: dseq.toString(),
|
|
358
|
-
state: 'open',
|
|
359
|
-
},
|
|
360
|
-
});
|
|
361
|
-
// Step 4: Query marketplace for bids
|
|
362
|
-
const response = await queryClient.Bids(request);
|
|
363
|
-
// Step 5: Build effective blacklist (built-in + custom)
|
|
364
|
-
// Convert custom blacklist to Set for O(1) lookup
|
|
365
|
-
const customBlacklistSet = new Set((options?.customBlacklist || [])
|
|
366
|
-
.map((addr) => (typeof addr === 'string' ? addr.trim() : ''))
|
|
367
|
-
.filter((addr) => addr.length > 0));
|
|
368
|
-
// Step 6: Extract and filter valid bids
|
|
369
|
-
// Remove bids from blacklisted providers (unreliable/problematic)
|
|
370
|
-
const validBids = extractValidBids(response).filter((bid) => {
|
|
371
|
-
const provider = bid.bidId?.provider ?? '';
|
|
372
|
-
return (provider !== '' &&
|
|
373
|
-
!isProviderBlacklisted(provider) &&
|
|
374
|
-
!customBlacklistSet.has(provider));
|
|
375
|
-
});
|
|
376
|
-
// Step 7: If no bids found, return empty array
|
|
377
|
-
if (validBids.length === 0) {
|
|
378
|
-
return success([]);
|
|
379
|
-
}
|
|
380
|
-
// Step 8: Fetch ALL provider metadata from Console API
|
|
381
|
-
// This is much more efficient than fetching individual providers
|
|
382
|
-
// and matches how the web console works
|
|
383
|
-
const providerInfoResult = await fetchAllProviders(network);
|
|
384
|
-
// If provider info fetch failed, we can still continue with basic data
|
|
385
|
-
const providerInfoMap = providerInfoResult.success
|
|
386
|
-
? providerInfoResult.data
|
|
387
|
-
: new Map();
|
|
388
|
-
// Step 9: Transform raw bids into EnhancedBids
|
|
389
|
-
const enhancedBids = [];
|
|
390
|
-
for (const bid of validBids) {
|
|
391
|
-
const provider = bid.bidId?.provider;
|
|
392
|
-
if (!provider)
|
|
393
|
-
continue;
|
|
394
|
-
// Get provider info (or create minimal fallback)
|
|
395
|
-
let providerInfo = providerInfoMap.get(provider);
|
|
396
|
-
if (!providerInfo) {
|
|
397
|
-
providerInfo = {
|
|
398
|
-
owner: provider,
|
|
399
|
-
hostUri: '', // Will be populated when creating lease
|
|
400
|
-
isAudited: false,
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
// Filter out offline providers if requested
|
|
404
|
-
if (!options?.includeOffline &&
|
|
405
|
-
providerInfo.reliability &&
|
|
406
|
-
!providerInfo.reliability.isOnline) {
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
// Create pricing information
|
|
410
|
-
const pricing = createBidPricing({
|
|
411
|
-
denom: bid.price?.denom || 'uakt',
|
|
412
|
-
amount: bid.price?.amount || '0',
|
|
413
|
-
});
|
|
414
|
-
// Construct enhanced bid with unique ID
|
|
415
|
-
const bidId = `${provider}-${dseq}-${bid.bidId?.gseq}-${bid.bidId?.oseq}`;
|
|
416
|
-
const enhancedBid = {
|
|
417
|
-
id: bidId,
|
|
418
|
-
bid,
|
|
419
|
-
provider: providerInfo,
|
|
420
|
-
pricing,
|
|
421
|
-
createdAt: new Date(), // Bid creation time
|
|
422
|
-
};
|
|
423
|
-
enhancedBids.push(enhancedBid);
|
|
424
|
-
}
|
|
425
|
-
return success(enhancedBids);
|
|
426
|
-
}
|
|
427
|
-
catch (error) {
|
|
428
|
-
return failure(new DeploymentError(`Failed to query bids: ${error}`, 'QUERY_FAILED', { error: String(error), dseq }, true, 'Check network connection and try again'));
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
/**
|
|
432
|
-
* Wait for provider bids with polling
|
|
433
|
-
*
|
|
434
|
-
* Polls the marketplace for provider bids until at least one valid bid is received
|
|
435
|
-
* or timeout is reached. This is a convenience wrapper around `queryBids()` that
|
|
436
|
-
* handles the polling logic for you.
|
|
437
|
-
*
|
|
438
|
-
* Returns ALL enhanced bids received, allowing the caller to implement custom
|
|
439
|
-
* selection logic based on price, reliability, location, or other criteria.
|
|
440
|
-
*
|
|
441
|
-
* **Why this is useful:**
|
|
442
|
-
* After creating a deployment, providers need time to:
|
|
443
|
-
* 1. See your deployment on the blockchain
|
|
444
|
-
* 2. Check if they can fulfill requirements
|
|
445
|
-
* 3. Calculate pricing
|
|
446
|
-
* 4. Submit their bid
|
|
447
|
-
*
|
|
448
|
-
* This usually takes 30-60 seconds. This function handles the wait for you.
|
|
449
|
-
*
|
|
450
|
-
* **Polling Strategy:**
|
|
451
|
-
* - Poll interval: 5 seconds (reasonable for network latency)
|
|
452
|
-
* - Default timeout: 5 minutes (enough for providers to respond)
|
|
453
|
-
* - Returns immediately when at least one bid is found
|
|
454
|
-
* - Returns all errors from query operation
|
|
455
|
-
*
|
|
456
|
-
* @param wallet - Wallet context with owner address
|
|
457
|
-
* @param network - Akash network to query
|
|
458
|
-
* @param dseq - Deployment sequence number
|
|
459
|
-
* @param options - Optional query and polling options
|
|
460
|
-
* @param options.customBlacklist - Provider addresses to exclude
|
|
461
|
-
* @param options.includeOffline - Include offline providers (default: false)
|
|
462
|
-
* @param options.timeoutMs - Timeout in milliseconds (default: 300000 = 5 min)
|
|
463
|
-
* @returns Result with array of enhanced bids or timeout error
|
|
464
|
-
*
|
|
465
|
-
* @example Wait for bids and display
|
|
466
|
-
* ```typescript
|
|
467
|
-
* console.log('Waiting for provider bids...');
|
|
468
|
-
*
|
|
469
|
-
* const result = await waitForBids(wallet, 'mainnet', dseq);
|
|
470
|
-
*
|
|
471
|
-
* if (result.success) {
|
|
472
|
-
* console.log(`Received ${result.data.length} bids!`);
|
|
473
|
-
* for (const bid of result.data) {
|
|
474
|
-
* console.log(`Provider: ${bid.provider.name || bid.provider.owner}`);
|
|
475
|
-
* console.log(`Price: ${bid.pricing.akt.perMonth} AKT/month`);
|
|
476
|
-
* }
|
|
477
|
-
* } else {
|
|
478
|
-
* if (result.error.code === 'TIMEOUT') {
|
|
479
|
-
* console.error('No bids received within timeout');
|
|
480
|
-
* console.log('Try increasing deployment resources or deposit');
|
|
481
|
-
* } else {
|
|
482
|
-
* console.error('Query failed:', result.error.message);
|
|
483
|
-
* }
|
|
484
|
-
* }
|
|
485
|
-
* ```
|
|
486
|
-
*
|
|
487
|
-
* @example Custom timeout and options
|
|
488
|
-
* ```typescript
|
|
489
|
-
* // Wait up to 10 minutes, excluding specific providers
|
|
490
|
-
* const result = await waitForBids(wallet, 'mainnet', dseq, {
|
|
491
|
-
* customBlacklist: ['akash1bad...', 'akash1another...'],
|
|
492
|
-
* includeOffline: false,
|
|
493
|
-
* timeoutMs: 600000 // 10 minutes
|
|
494
|
-
* });
|
|
495
|
-
* ```
|
|
496
|
-
*/
|
|
497
|
-
export async function waitForBids(wallet, network, dseq, options) {
|
|
498
|
-
const pollInterval = 5000; // 5 seconds
|
|
499
|
-
const timeoutMs = options?.timeoutMs ?? 300000; // Default: 5 minutes
|
|
500
|
-
const startTime = Date.now();
|
|
501
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
502
|
-
// Query for bids with provided options
|
|
503
|
-
const bidResult = await queryBids(wallet, network, dseq, {
|
|
504
|
-
customBlacklist: options?.customBlacklist,
|
|
505
|
-
includeOffline: options?.includeOffline,
|
|
506
|
-
});
|
|
507
|
-
// Check for query errors
|
|
508
|
-
if (!bidResult.success) {
|
|
509
|
-
return bidResult;
|
|
510
|
-
}
|
|
511
|
-
// Check if we got at least one bid
|
|
512
|
-
if (bidResult.data.length > 0) {
|
|
513
|
-
return success(bidResult.data);
|
|
514
|
-
}
|
|
515
|
-
// Wait before next poll
|
|
516
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
517
|
-
}
|
|
518
|
-
// Timeout reached without receiving bids
|
|
519
|
-
return failure(new DeploymentError('Timeout waiting for provider bids', 'TIMEOUT', { dseq, timeoutMs }, true, 'No providers bid within timeout. Try: 1) Increase resources to attract more providers, 2) Increase deposit amount, 3) Check if your requirements are too specific'));
|
|
520
|
-
}
|
|
521
|
-
/**
|
|
522
|
-
* Create a lease by accepting a provider bid
|
|
523
|
-
*
|
|
524
|
-
* Broadcasts a MsgCreateLease transaction to accept a provider's bid and
|
|
525
|
-
* establish a lease. This commits the deployment to the selected provider
|
|
526
|
-
* and allows them to start running your containers.
|
|
527
|
-
*
|
|
528
|
-
* **What happens when you create a lease:**
|
|
529
|
-
* 1. You accept a specific provider's bid
|
|
530
|
-
* 2. A lease is created on the blockchain
|
|
531
|
-
* 3. The provider is notified of the accepted bid
|
|
532
|
-
* 4. The provider prepares to receive your manifest
|
|
533
|
-
* 5. You send the manifest (deployment details) to the provider
|
|
534
|
-
* 6. The provider starts your containers
|
|
535
|
-
*
|
|
536
|
-
* **Important:** After creating the lease, you MUST send the manifest
|
|
537
|
-
* to the provider within a reasonable time, or they may close the lease.
|
|
538
|
-
*
|
|
539
|
-
* @param clientContext - Signing client and account info
|
|
540
|
-
* @param bid - Provider bid to accept
|
|
541
|
-
* @returns Result with lease identifier and transaction info
|
|
542
|
-
*
|
|
543
|
-
* @example Accept bid and create lease
|
|
544
|
-
* ```typescript
|
|
545
|
-
* // Wait for bids
|
|
546
|
-
* const bidResult = await waitForBids(wallet, 'mainnet', dseq);
|
|
547
|
-
* if (!bidResult.success) return bidResult;
|
|
548
|
-
*
|
|
549
|
-
* // Accept the bid by creating a lease
|
|
550
|
-
* const leaseResult = await createLease(clientContext, bidResult.data);
|
|
551
|
-
*
|
|
552
|
-
* if (leaseResult.success) {
|
|
553
|
-
* const lease = leaseResult.data.leaseId;
|
|
554
|
-
* console.log('Lease created!');
|
|
555
|
-
* console.log('DSEQ:', lease.dseq);
|
|
556
|
-
* console.log('Provider:', lease.provider);
|
|
557
|
-
* console.log('TX:', leaseResult.data.transactionHash);
|
|
558
|
-
*
|
|
559
|
-
* // Next step: send manifest to provider
|
|
560
|
-
* await sendManifest(lease, manifest, certificate);
|
|
561
|
-
* }
|
|
562
|
-
* ```
|
|
563
|
-
*
|
|
564
|
-
* @example Error handling
|
|
565
|
-
* ```typescript
|
|
566
|
-
* const result = await createLease(clientContext, bid);
|
|
567
|
-
* if (!result.success) {
|
|
568
|
-
* if (result.error.code === 'TRANSACTION_FAILED') {
|
|
569
|
-
* console.error('Transaction failed:', result.error.context.rawLog);
|
|
570
|
-
* console.log('Common causes: insufficient funds, bid expired');
|
|
571
|
-
* }
|
|
572
|
-
* }
|
|
573
|
-
* ```
|
|
574
|
-
*/
|
|
575
|
-
export async function createLease(clientContext, bid) {
|
|
576
|
-
try {
|
|
577
|
-
const { client, account } = clientContext;
|
|
578
|
-
const { bidId } = bid;
|
|
579
|
-
// Step 1: Create lease message from accepted bid
|
|
580
|
-
// The bid ID contains all coordinates needed to create the lease
|
|
581
|
-
const msg = {
|
|
582
|
-
typeUrl: getTypeUrl(MsgCreateLease),
|
|
583
|
-
value: MsgCreateLease.fromPartial({ bidId }),
|
|
584
|
-
};
|
|
585
|
-
// Step 2: Estimate gas dynamically
|
|
586
|
-
// Simulate the transaction to get accurate gas estimation
|
|
587
|
-
const gasEstimation = await client.simulate(account.address, [msg], 'Create lease via deploy-ability');
|
|
588
|
-
// Add 60% safety margin for Akash Network transactions
|
|
589
|
-
// Matches Akash Console's GAS_SAFETY_MULTIPLIER (1.6x)
|
|
590
|
-
const gasLimit = Math.ceil(gasEstimation * 1.6);
|
|
591
|
-
// Set transaction fee with dynamic gas limit
|
|
592
|
-
// Fee: 5,000 uakt (approximately 0.005 AKT)
|
|
593
|
-
const fee = {
|
|
594
|
-
amount: [{ denom: 'uakt', amount: '5000' }],
|
|
595
|
-
gas: gasLimit.toString(),
|
|
596
|
-
};
|
|
597
|
-
// Step 3: Sign and broadcast lease transaction
|
|
598
|
-
const res = await client.signAndBroadcast(account.address, [msg], fee, 'Create lease via deploy-ability');
|
|
599
|
-
// Step 4: Check transaction result
|
|
600
|
-
if (res.code !== 0) {
|
|
601
|
-
return {
|
|
602
|
-
success: false,
|
|
603
|
-
error: new DeploymentError(`Lease transaction failed: ${res.rawLog}`, 'TRANSACTION_FAILED', {
|
|
604
|
-
code: res.code,
|
|
605
|
-
rawLog: res.rawLog,
|
|
606
|
-
transactionHash: res.transactionHash,
|
|
607
|
-
}, false, 'Check wallet balance and bid validity. The bid may have expired or been withdrawn by the provider.'),
|
|
608
|
-
};
|
|
609
|
-
}
|
|
610
|
-
// Step 5: Return lease result with full coordinates
|
|
611
|
-
// The lease ID contains all information needed to interact with the provider
|
|
612
|
-
// BidID and LeaseID are structurally identical, so we extract the fields
|
|
613
|
-
// rather than using type casting (TypeScript sees them as different nominal types)
|
|
614
|
-
if (!bidId) {
|
|
615
|
-
return {
|
|
616
|
-
success: false,
|
|
617
|
-
error: new DeploymentError('Bid ID is missing from bid', 'INVALID_BID', { bid }, false, 'This should not happen - verify bid data structure'),
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
return {
|
|
621
|
-
success: true,
|
|
622
|
-
data: {
|
|
623
|
-
// Use LeaseID.fromPartial() to create proper protobuf type with $type field
|
|
624
|
-
leaseId: LeaseID.fromPartial({
|
|
625
|
-
owner: bidId.owner,
|
|
626
|
-
provider: bidId.provider,
|
|
627
|
-
dseq: bidId.dseq,
|
|
628
|
-
gseq: bidId.gseq,
|
|
629
|
-
oseq: bidId.oseq,
|
|
630
|
-
}),
|
|
631
|
-
transactionHash: res.transactionHash,
|
|
632
|
-
height: res.height,
|
|
633
|
-
},
|
|
634
|
-
};
|
|
635
|
-
}
|
|
636
|
-
catch (error) {
|
|
637
|
-
return {
|
|
638
|
-
success: false,
|
|
639
|
-
error: new DeploymentError(`Failed to create lease: ${error}`, 'LEASE_FAILED', { error: String(error) }, false, 'Check wallet connection and bid parameters'),
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
/**
|
|
644
|
-
* Close an active Akash deployment
|
|
645
|
-
*
|
|
646
|
-
* Broadcasts a MsgCloseDeployment transaction that terminates all leases
|
|
647
|
-
* associated with the deployment and returns the escrow deposit to the owner.
|
|
648
|
-
*
|
|
649
|
-
* **What happens when you close a deployment:**
|
|
650
|
-
* 1. All active leases for this deployment are terminated
|
|
651
|
-
* 2. Providers stop running your containers
|
|
652
|
-
* 3. The escrow deposit (typically 5 AKT) is returned to your wallet
|
|
653
|
-
* 4. The deployment is marked as closed on the blockchain
|
|
654
|
-
*
|
|
655
|
-
* **When to close a deployment:**
|
|
656
|
-
* - When you're done with the deployment and want to stop paying
|
|
657
|
-
* - When migrating to a different provider or configuration
|
|
658
|
-
* - When cleaning up test/development deployments
|
|
659
|
-
* - Before wallet maintenance (to recover locked funds)
|
|
660
|
-
*
|
|
661
|
-
* **Important Notes:**
|
|
662
|
-
* - You can only close deployments you own
|
|
663
|
-
* - Closed deployments cannot be reopened (create a new deployment instead)
|
|
664
|
-
* - Always close deployments when done to avoid ongoing charges
|
|
665
|
-
* - The escrow deposit is returned immediately upon closure
|
|
666
|
-
*
|
|
667
|
-
* @param clientContext - Signing client and account info
|
|
668
|
-
* @param wallet - Wallet context (must be deployment owner)
|
|
669
|
-
* @param dseq - Deployment sequence number to close
|
|
670
|
-
* @returns Result with closure confirmation or error
|
|
671
|
-
*
|
|
672
|
-
* @example Close a deployment
|
|
673
|
-
* ```typescript
|
|
674
|
-
* import { closeDeployment, createSigningClient } from '@kadi.build/deploy-ability/akash';
|
|
675
|
-
*
|
|
676
|
-
* // Create signing client
|
|
677
|
-
* const clientResult = await createSigningClient(wallet, 'mainnet');
|
|
678
|
-
* if (!clientResult.success) {
|
|
679
|
-
* console.error('Failed to create client:', clientResult.error.message);
|
|
680
|
-
* return;
|
|
681
|
-
* }
|
|
682
|
-
*
|
|
683
|
-
* // Close the deployment
|
|
684
|
-
* const result = await closeDeployment(
|
|
685
|
-
* clientResult.data,
|
|
686
|
-
* wallet,
|
|
687
|
-
* 1234567 // DSEQ from deployment
|
|
688
|
-
* );
|
|
689
|
-
*
|
|
690
|
-
* if (result.success) {
|
|
691
|
-
* console.log('Deployment closed successfully!');
|
|
692
|
-
* console.log('DSEQ:', result.data.dseq);
|
|
693
|
-
* console.log('TX:', result.data.transactionHash);
|
|
694
|
-
* console.log('Deposit returned to:', result.data.owner);
|
|
695
|
-
* } else {
|
|
696
|
-
* console.error('Failed to close:', result.error.message);
|
|
697
|
-
* }
|
|
698
|
-
* ```
|
|
699
|
-
*
|
|
700
|
-
* @example Close with error handling
|
|
701
|
-
* ```typescript
|
|
702
|
-
* const result = await closeDeployment(clientContext, wallet, dseq);
|
|
703
|
-
*
|
|
704
|
-
* if (!result.success) {
|
|
705
|
-
* if (result.error.code === 'TRANSACTION_FAILED') {
|
|
706
|
-
* console.error('Transaction failed:', result.error.context.rawLog);
|
|
707
|
-
* // Common causes:
|
|
708
|
-
* // - Not the deployment owner
|
|
709
|
-
* // - Deployment already closed
|
|
710
|
-
* // - Insufficient funds for transaction fee
|
|
711
|
-
* } else if (result.error.code === 'WALLET_ERROR') {
|
|
712
|
-
* console.error('Wallet issue - check connection');
|
|
713
|
-
* }
|
|
714
|
-
* }
|
|
715
|
-
* ```
|
|
716
|
-
*
|
|
717
|
-
* @example Complete deployment lifecycle
|
|
718
|
-
* ```typescript
|
|
719
|
-
* // Deploy
|
|
720
|
-
* const deployment = await deployToAkash({
|
|
721
|
-
* wallet,
|
|
722
|
-
* certificate,
|
|
723
|
-
* projectRoot: './',
|
|
724
|
-
* profile: 'dev',
|
|
725
|
-
* bidSelector: selectCheapestBid
|
|
726
|
-
* });
|
|
727
|
-
*
|
|
728
|
-
* if (deployment.success) {
|
|
729
|
-
* console.log('Deployed with DSEQ:', deployment.data.dseq);
|
|
730
|
-
*
|
|
731
|
-
* // ... use the deployment ...
|
|
732
|
-
*
|
|
733
|
-
* // Close when done
|
|
734
|
-
* const close = await closeDeployment(
|
|
735
|
-
* clientContext,
|
|
736
|
-
* wallet,
|
|
737
|
-
* deployment.data.dseq
|
|
738
|
-
* );
|
|
739
|
-
*
|
|
740
|
-
* if (close.success) {
|
|
741
|
-
* console.log('Cleaned up successfully');
|
|
742
|
-
* }
|
|
743
|
-
* }
|
|
744
|
-
* ```
|
|
745
|
-
*/
|
|
746
|
-
export async function closeDeployment(clientContext, wallet, dseq) {
|
|
747
|
-
try {
|
|
748
|
-
const { client, account } = clientContext;
|
|
749
|
-
// Convert dseq to string for the message
|
|
750
|
-
const dseqString = typeof dseq === 'string' ? dseq : dseq.toString();
|
|
751
|
-
// Step 1: Create close deployment message
|
|
752
|
-
// This message tells the blockchain to terminate the deployment
|
|
753
|
-
// and return the escrow deposit to the owner
|
|
754
|
-
const msg = MsgCloseDeployment.fromPartial({
|
|
755
|
-
id: {
|
|
756
|
-
dseq: dseqString,
|
|
757
|
-
owner: wallet.address,
|
|
758
|
-
},
|
|
759
|
-
});
|
|
760
|
-
// Step 2: Wrap message with type-safe URL
|
|
761
|
-
const anyMsg = {
|
|
762
|
-
typeUrl: getTypeUrl(MsgCloseDeployment),
|
|
763
|
-
value: msg,
|
|
764
|
-
};
|
|
765
|
-
// Step 3: Estimate gas dynamically
|
|
766
|
-
// Simulate the transaction to get accurate gas estimation
|
|
767
|
-
// This prevents out-of-gas errors for deployments with many resources
|
|
768
|
-
const gasEstimation = await client.simulate(account.address, [anyMsg], 'Close deployment via deploy-ability');
|
|
769
|
-
// Add 60% safety margin for Akash Network transactions
|
|
770
|
-
// Matches Akash Console's GAS_SAFETY_MULTIPLIER (1.6x)
|
|
771
|
-
const gasLimit = Math.ceil(gasEstimation * 1.6);
|
|
772
|
-
// Set transaction fee with dynamic gas limit
|
|
773
|
-
// Fee: 5,000 uakt (approximately 0.005 AKT)
|
|
774
|
-
const fee = {
|
|
775
|
-
amount: [{ denom: 'uakt', amount: '5000' }],
|
|
776
|
-
gas: gasLimit.toString(),
|
|
777
|
-
};
|
|
778
|
-
// Step 4: Sign and broadcast close deployment transaction
|
|
779
|
-
const res = await client.signAndBroadcast(account.address, [anyMsg], fee, 'Close deployment via deploy-ability');
|
|
780
|
-
// Step 5: Check transaction result
|
|
781
|
-
// code === 0 means success, any other code is an error
|
|
782
|
-
if (res.code !== 0) {
|
|
783
|
-
return failure(new DeploymentError(`Close deployment transaction failed: ${res.rawLog}`, 'TRANSACTION_FAILED', {
|
|
784
|
-
code: res.code,
|
|
785
|
-
rawLog: res.rawLog,
|
|
786
|
-
transactionHash: res.transactionHash,
|
|
787
|
-
dseq: dseqString,
|
|
788
|
-
}, false, 'Common causes: Not deployment owner, deployment already closed, or insufficient funds for fees'));
|
|
789
|
-
}
|
|
790
|
-
// Step 6: Return closure confirmation
|
|
791
|
-
return success({
|
|
792
|
-
dseq: dseqString,
|
|
793
|
-
owner: wallet.address,
|
|
794
|
-
transactionHash: res.transactionHash,
|
|
795
|
-
height: res.height,
|
|
796
|
-
closedAt: new Date(),
|
|
797
|
-
});
|
|
798
|
-
}
|
|
799
|
-
catch (error) {
|
|
800
|
-
return failure(new DeploymentError(`Failed to close deployment: ${error}`, 'DEPLOYMENT_CLOSE_FAILED', { error: String(error), dseq: String(dseq) }, false, 'Check wallet connection, network status, and deployment ownership'));
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
//# sourceMappingURL=blockchain-client.js.map
|