Skip to content

Commit 5fc0e65

Browse files
committed
enhancement: enhancements to the deploy script
1 parent 252d9ef commit 5fc0e65

File tree

1 file changed

+79
-5
lines changed

1 file changed

+79
-5
lines changed

src/commands/contract/deploy-utils.ts

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ export class ExchangeState extends Struct {
3737
export interface RamInfo {
3838
pricePerByte: number
3939
ramBytesNeeded: number
40+
existingContractRam: number // RAM used by existing contract code (will be freed on update)
41+
deltaRamNeeded: number // Actual new RAM needed (ramBytesNeeded - existingContractRam)
4042
costInTokens: Asset
4143
currentRamBytes: number
4244
currentRamAvailable: number
@@ -45,6 +47,7 @@ export interface RamInfo {
4547
hasEnoughTokens: boolean
4648
ramToBuy: number
4749
hasSystemContract: boolean // Whether the chain has full system contracts (RAM market)
50+
isUpdate: boolean // Whether this is an update to existing contract
4851
}
4952

5053
export interface AccountResources {
@@ -69,6 +72,51 @@ export function calculateRamNeeded(wasmSize: number, abiSize: number): number {
6972
return setcodeRam + setabiRam + buffer
7073
}
7174

75+
/**
76+
* Get existing contract RAM usage
77+
* When updating a contract, the existing code RAM will be freed and replaced
78+
* Returns 0 if no contract exists
79+
*/
80+
export async function getExistingContractRam(client: APIClient, accountName: string): Promise<number> {
81+
try {
82+
// Get the API URL from the client's provider
83+
const baseUrl = (client.provider as {url?: string}).url
84+
85+
if (!baseUrl) {
86+
return 0
87+
}
88+
89+
// Use fetch to call get_raw_code_and_abi endpoint directly
90+
// as wharfkit APIClient doesn't have this method built-in
91+
const response = await fetch(`${baseUrl}/v1/chain/get_raw_code_and_abi`, {
92+
method: 'POST',
93+
headers: {'Content-Type': 'application/json'},
94+
body: JSON.stringify({account_name: accountName}),
95+
})
96+
97+
if (!response.ok) {
98+
return 0
99+
}
100+
101+
const data = (await response.json()) as {wasm?: string; abi?: string}
102+
103+
// Check if there's existing code
104+
if (!data.wasm || data.wasm.length === 0) {
105+
return 0
106+
}
107+
108+
// Decode base64 to get actual sizes
109+
const wasmBytes = Buffer.from(data.wasm, 'base64')
110+
const abiBytes = data.abi ? Buffer.from(data.abi, 'base64') : Buffer.alloc(0)
111+
112+
// Calculate RAM used by existing contract using same formula
113+
return calculateRamNeeded(wasmBytes.length, abiBytes.length)
114+
} catch {
115+
// Account might not exist or have no code
116+
return 0
117+
}
118+
}
119+
72120
/**
73121
* Get the core token symbol for a chain
74122
*/
@@ -207,6 +255,8 @@ export function calculateRamCost(bytesNeeded: number, pricePerByte: number, symb
207255

208256
/**
209257
* Analyze RAM requirements for deployment
258+
* When updating an existing contract, calculates the delta RAM needed
259+
* (existing contract RAM will be freed when replaced)
210260
*/
211261
export async function analyzeRamRequirements(
212262
client: APIClient,
@@ -218,16 +268,27 @@ export async function analyzeRamRequirements(
218268
const {pricePerByte, symbol, hasSystemContract} = await getRamPrice(client)
219269
const resources = await getAccountResources(client, accountName, symbol)
220270

221-
const ramToBuy = Math.max(0, ramBytesNeeded - resources.ramAvailable)
271+
// Check for existing contract - its RAM will be freed when we update
272+
const existingContractRam = await getExistingContractRam(client, accountName)
273+
const isUpdate = existingContractRam > 0
274+
275+
// Calculate actual delta RAM needed (new - existing, minimum 0)
276+
// When updating, the existing contract RAM is freed and replaced
277+
const deltaRamNeeded = Math.max(0, ramBytesNeeded - existingContractRam)
278+
279+
// Only need to buy RAM for the delta beyond what's available
280+
const ramToBuy = Math.max(0, deltaRamNeeded - resources.ramAvailable)
222281
const costInTokens = calculateRamCost(ramToBuy, pricePerByte, symbol)
223282

224283
// On chains without system contracts, RAM is essentially free/unlimited
225-
const hasEnoughRam = !hasSystemContract || resources.ramAvailable >= ramBytesNeeded
284+
const hasEnoughRam = !hasSystemContract || resources.ramAvailable >= deltaRamNeeded
226285
const hasEnoughTokens = hasEnoughRam || resources.coreBalance.value >= costInTokens.value
227286

228287
return {
229288
pricePerByte,
230289
ramBytesNeeded,
290+
existingContractRam,
291+
deltaRamNeeded,
231292
costInTokens,
232293
currentRamBytes: resources.ramQuota,
233294
currentRamAvailable: resources.ramAvailable,
@@ -236,6 +297,7 @@ export async function analyzeRamRequirements(
236297
hasEnoughTokens,
237298
ramToBuy,
238299
hasSystemContract,
300+
isUpdate,
239301
}
240302
}
241303

@@ -490,7 +552,17 @@ export function displayRamAnalysis(ramInfo: RamInfo, accountName: string): void
490552
console.log('\n📊 RAM Analysis')
491553
console.log('─'.repeat(50))
492554
console.log(`Account: ${accountName}`)
493-
console.log(`RAM needed for deployment: ${formatBytes(ramInfo.ramBytesNeeded)}`)
555+
556+
if (ramInfo.isUpdate) {
557+
console.log(`📦 Updating existing contract`)
558+
console.log(` New contract RAM: ${formatBytes(ramInfo.ramBytesNeeded)}`)
559+
console.log(` Existing contract RAM: ${formatBytes(ramInfo.existingContractRam)}`)
560+
console.log(` Delta RAM needed: ${formatBytes(ramInfo.deltaRamNeeded)}`)
561+
} else {
562+
console.log(`📦 New contract deployment`)
563+
console.log(` RAM needed: ${formatBytes(ramInfo.ramBytesNeeded)}`)
564+
}
565+
494566
console.log(`Current RAM available: ${formatBytes(ramInfo.currentRamAvailable)}`)
495567

496568
if (!ramInfo.hasSystemContract) {
@@ -499,8 +571,10 @@ export function displayRamAnalysis(ramInfo: RamInfo, accountName: string): void
499571
return
500572
}
501573

502-
console.log(`RAM to purchase: ${formatBytes(ramInfo.ramToBuy)}`)
503-
console.log(`Estimated cost: ${ramInfo.costInTokens}`)
574+
if (ramInfo.ramToBuy > 0) {
575+
console.log(`RAM to purchase: ${formatBytes(ramInfo.ramToBuy)}`)
576+
console.log(`Estimated cost: ${ramInfo.costInTokens}`)
577+
}
504578
console.log(`Current balance: ${ramInfo.tokenBalance}`)
505579
console.log(
506580
`Price per KB: ${(ramInfo.pricePerByte * 1024).toFixed(4)} ${

0 commit comments

Comments
 (0)