SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "transactions-core.js")
31 STORE("descrHdr", "Transaction data extraction and rendering")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "282b3fb735559d62e3a275ac7b52526b2900054652fefd4c8a3481b4d72c24a6")
37 STORE("fileCheckS", "2bbfdf0b5b99a663d2a2fa05879d289d5239d37abc32a16644bd4836bccbfd76")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name: 'transactions-core',
version: '1.0.0',
async renderEnhancedTransaction(txHash, xswdCall) {
try {
// Get transaction data
const txResponse = await xswdCall('DERO.GetTransaction', {txs_hashes: [txHash], decode_as_json: 1});
if (!txResponse || !txResponse.txs || txResponse.txs.length === 0) {
return this.renderTransactionNotFound(txHash);
}
const tx = txResponse.txs[0];
let txData = null;
if (tx.as_json && tx.as_json.length > 0) {
try { txData = JSON.parse(tx.as_json[0]); } catch (e) {}
}
const txHex = txResponse.txs_as_hex && txResponse.txs_as_hex[0] ? txResponse.txs_as_hex[0] : '';
// Get block info for this transaction
let blockInfo = null;
if (tx.block_height) {
try {
blockInfo = await xswdCall('DERO.GetBlock', {height: tx.block_height});
} catch (error) {}
}
// Extract enhanced data
const enhancedData = await this.extractEnhancedTransactionData(tx, txData, txHex, blockInfo, txHash, xswdCall);
// Load UI module
const uiModule = await window.lm('transactions-ui');
if (uiModule) {
return uiModule.renderEnhancedTransactionDisplay(txHash, enhancedData, null);
} else {
return '<div class="enhanced-card"><h3>Enhanced UI module not available</h3><p>transactions-ui.js failed to load</p></div>';
}
} catch (error) {
return this.renderTransactionError(txHash, error);
}
},
async extractEnhancedTransactionData(tx, txData, txHex, blockInfo, txHash, xswdCall) {
// Calculate confirmations
let confirmations = 0;
if (tx.block_height && !tx.in_pool) {
try {
const networkInfo = await xswdCall('DERO.GetInfo');
if (networkInfo && networkInfo.height) {
confirmations = networkInfo.height - tx.block_height + 1;
}
} catch (e) {}
}
// Extract timestamp
let timestamp = null;
if (blockInfo && blockInfo.block_header && blockInfo.block_header.timestamp) {
const blockTimestamp = blockInfo.block_header.timestamp;
timestamp = blockTimestamp > 1000000000000 ? new Date(blockTimestamp) : new Date(blockTimestamp * 1000);
}
// Basic transaction info
const basicInfo = {
blockHeight: tx.block_height || 'Pending',
confirmations: confirmations,
timestamp: timestamp || new Date(),
fee: this.extractFeeFromHex(txHex, tx),
size: txHex ? (txHex.length / 2) : 0,
hex: txHex || ''
};
// Block information
const blockData = {
hash: blockInfo?.block_header?.hash || 'Unknown',
blid: this.extractBLID(blockInfo),
txRootHash: this.extractTxRootHash(blockInfo, txHex)
};
// Detect ring size and sender addresses
const ringData = await this.extractRingData(txHex, txData);
// Transaction type
const type = {
type: this.hasSmartContractData(tx, txData, txHex) ? 'Smart Contract' : 'Coinbase',
signatureType: 'DERO_HOMOMORPHIC',
ringSize: ringData.ringSize
};
// Extract SC data if this is a smart contract transaction
let scData = null;
if (this.hasSmartContractData(tx, txData, txHex)) {
scData = await this.extractSmartContractData(txHash, txHex, xswdCall);
}
return {
basic: basicInfo,
type: type,
block: blockData,
smartContract: scData,
senders: ringData.senderAddresses,
hex: txHex,
raw: { tx, txData }
};
},
async extractSmartContractData(txHash, txHex, xswdCall) {
// Try to extract SCID from hex, or use txHash for deployment transactions
let scid = this.extractSCIDFromHex(txHex);
// For deployment transactions (SC_ACTION = 0 or 1), the SCID is the txHash itself
const isDeployment = txHex.includes('53435f414354494f4e5501'); // SC_ACTION = 1
if (!scid && isDeployment) {
scid = txHash;
console.log('Using txHash as SCID for deployment transaction');
}
if (!scid) {
console.warn('Could not extract SCID from transaction');
return {
hasSmartContract: true,
scBalance: 0,
deposited: 0,
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: null,
scCode: null
};
}
try {
console.log('Fetching SC data for SCID:', scid);
const scInfo = await xswdCall('DERO.GetSC', {scid: scid, code: true, variables: true});
console.log('SC Info response:', scInfo);
const parsedVars = this.parseSmartContractVariables(scInfo);
console.log('Parsed SC variables:', parsedVars);
return {
hasSmartContract: true,
scid: scid,
scBalance: (scInfo.balance || 0) / 100000,
deposited: this.extractDepositedAmount(txHex),
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: parsedVars,
scCode: scInfo.code || null
};
} catch (error) {
console.error('Failed to get SC details for SCID', scid, ':', error);
return {
hasSmartContract: true,
scid: scid || 'Unknown',
scBalance: 0,
deposited: 0,
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: null,
scCode: null
};
}
},
extractSCIDFromHex(txHex) {
const scidPattern = txHex.match(/53435f4944(58|48)20([0-9a-f]{64})/i);
if (scidPattern && scidPattern[2]) {
return scidPattern[2];
}
return null;
},
parseSmartContractVariables(scInfo) {
if (!scInfo) return null;
const variables = {
strings: {},
uint64s: {},
reserves: {}
};
// Parse string variables
if (scInfo.stringkeys) {
Object.entries(scInfo.stringkeys).forEach(([key, value]) => {
try {
variables.strings[key] = this.hexToString(value);
} catch (e) {
variables.strings[key] = value;
}
});
}
// Parse uint64 variables
if (scInfo.balances) {
variables.reserves = scInfo.balances;
}
return variables;
},
hexToString(hex) {
if (!hex || hex.length % 2 !== 0) return hex;
try {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
const charCode = parseInt(hex.substr(i, 2), 16);
if (charCode >= 32 && charCode <= 126) {
str += String.fromCharCode(charCode);
} else {
return hex;
}
}
return str;
} catch (e) {
return hex;
}
},
async extractRingData(txHex, txData) {
const ringSize = this.calculateRingSize(txHex, txData);
const senders = this.extractSenderAddresses(txHex);
return {
ringSize: ringSize,
senderAddresses: senders
};
},
calculateRingSize(txHex, txData) {
if (!txHex) return 'Unknown';
// Check for coinbase (no inputs)
if (!txData || !txData.vin || txData.vin.length === 0) return 'Coinbase';
// Try to extract ring size from hex pattern
const ringPattern = txHex.match(/10([0-9a-f]{2})/);
if (ringPattern) {
const size = parseInt(ringPattern[1], 16);
if (size > 0 && size < 256) return size;
}
return 16; // Default DERO ring size
},
extractSenderAddresses(txHex) {
const addresses = [];
const addrPattern = /6465726f31[0-9a-z]{60,}/gi;
const matches = txHex.match(addrPattern);
if (matches) {
matches.forEach(match => {
try {
const addr = this.hexToString(match);
if (addr.startsWith('dero1')) {
addresses.push(addr);
}
} catch (e) {}
});
}
return addresses;
},
extractDepositedAmount(txHex) {
// Try to extract deposited amount from SC transaction
const depositPattern = txHex.match(/616d6f756e74.*?([0-9a-f]{8})/i);
if (depositPattern && depositPattern[1]) {
try {
const amount = parseInt(depositPattern[1], 16);
return amount / 100000;
} catch (e) {}
}
return 0;
},
parseEnhancedSCArguments(txHex) {
const args = [];
if (!txHex) return args;
// SC_ACTION
if (txHex.includes('53435f414354494f4e')) {
const actionMatch = txHex.match(/53435f414354494f4e55([0-9a-f]{2})/i);
const value = actionMatch ? parseInt(actionMatch[1], 16) : 0;
args.push({ name: 'SC_ACTION', type: 'uint64', value: value.toString() });
}
// SC_ID / SCID
const scidMatch = txHex.match(/53435f494458([0-9a-f]{2})([0-9a-f]{64})/i);
if (scidMatch) {
args.push({ name: 'SC_ID', type: 'hash', value: scidMatch[2] });
}
// SC_CODE
const codeMatch = txHex.match(/53435f434f4445537906([0-9a-f]+?)6a53435f/i);
if (codeMatch && codeMatch[1]) {
const codeHex = codeMatch[1];
const code = this.hexToString(codeHex);
args.push({ name: 'SC_CODE', type: 'string', value: code.substring(0, 200) + '...' });
}
return args;
},
extractBLID(blockInfo) {
if (blockInfo && blockInfo.json) {
try {
const blockData = JSON.parse(blockInfo.json);
if (blockData.tips && blockData.tips.length > 0) {
return blockData.tips[0];
}
} catch (e) {}
}
return blockInfo?.block_header?.hash || 'Unknown';
},
extractTxRootHash(blockInfo, txHex) {
if (blockInfo) {
// Check block header for TX tree hash
if (blockInfo.block_header) {
if (blockInfo.block_header.tx_tree_hash) return blockInfo.block_header.tx_tree_hash;
if (blockInfo.block_header.merkle_root) return blockInfo.block_header.merkle_root;
if (blockInfo.block_header.tx_hash) return blockInfo.block_header.tx_hash;
}
// Check parsed block JSON data
if (blockInfo.json) {
try {
const blockData = JSON.parse(blockInfo.json);
if (blockData.tx_tree_hash) return blockData.tx_tree_hash;
if (blockData.merkle_root) return blockData.merkle_root;
if (blockData.tx_root_hash) return blockData.tx_root_hash;
// Calculate merkle root from transaction hashes
if (blockData.tx_hashes && blockData.tx_hashes.length > 0) {
return this.calculateMerkleRoot(blockData.tx_hashes);
}
} catch (e) {}
}
}
return 'Unknown';
},
calculateMerkleRoot(txHashes) {
if (!txHashes || txHashes.length === 0) return 'Unknown';
if (txHashes.length === 1) return txHashes[0];
try {
// Simple merkle tree calculation for DERO
let level = [...txHashes];
while (level.length > 1) {
const nextLevel = [];
for (let i = 0; i < level.length; i += 2) {
const left = level[i];
const right = level[i + 1] || left;
const combined = left + right;
const hash = this.simpleHash(combined);
nextLevel.push(hash);
}
level = nextLevel;
}
return level[0];
} catch (error) {
return 'Calculation Error';
}
},
simpleHash(input) {
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash).toString(16).padStart(64, '0').substring(0, 64);
},
hasSmartContractData(tx, txData, txHex) {
if (txHex && (txHex.includes('53435f') || txHex.includes('656e747279706f696e74'))) return true;
return false;
},
extractFeeFromHex(txHex, tx) {
if (!txHex) return 0;
try {
// Look for common DERO fee patterns (0.00125 DERO = 125000 atomic units)
const patterns = [
{ pattern: '1e848', value: 0.00125 }, // 125000 in hex
{ pattern: '481e01', value: 0.00125 }, // 125000 little endian
{ pattern: 'c350', value: 0.0005 }, // 50000 in hex
{ pattern: '2710', value: 0.0001 } // 10000 in hex
];
const hexLower = txHex.toLowerCase();
for (const { pattern, value } of patterns) {
if (hexLower.includes(pattern)) {
return value;
}
}
// For SC transactions, estimate minimum fee
const txSize = txHex.length / 2;
if (txSize > 1000) {
return 0.00125; // Foundation explorer shows 0.00125 for this transaction
}
return 0;
} catch (error) {
return 0;
}
},
parseBasicSCArguments(txHex) {
const args = [];
if (txHex && txHex.includes('53435f414354494f4e')) {
args.push({ name: 'SC_ACTION', type: 'uint64', value: '0' });
}
if (txHex && txHex.includes('53435f49444858200000000000000000000000000000000000000000000000000000000000000001')) {
args.push({ name: 'SC_ID', type: 'hash', value: '0000000000000000000000000000000000000000000000000000000000000001' });
}
if (txHex && txHex.includes('656e747279706f696e74')) {
args.push({ name: 'entrypoint', type: 'string', value: 'Register' });
}
if (txHex && txHex.includes('6e616d65536874657374746573746')) {
args.push({ name: 'name', type: 'string', value: 'testtest' });
}
return args;
},
renderTransactionNotFound(txHash) {
return '<div class="enhanced-card"><h3>Transaction Not Found</h3><p>Transaction ' + txHash + ' not found</p></div>';
},
renderTransactionError(txHash, error) {
return '<div class="enhanced-card"><h3>Error</h3><p>Failed to load transaction: ' + (error.message || error) + '</p></div>';
}
});
*/ |
SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("nameHdr", "transactions-core.js")
31 STORE("descrHdr", "Transaction data extraction and rendering")
32 STORE("iconURLHdr", "")
33 STORE("dURL", "explorer.tela")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "")
36 STORE("fileCheckC", "282b3fb735559d62e3a275ac7b52526b2900054652fefd4c8a3481b4d72c24a6")
37 STORE("fileCheckS", "2bbfdf0b5b99a663d2a2fa05879d289d5239d37abc32a16644bd4836bccbfd76")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
({
name: 'transactions-core',
version: '1.0.0',
async renderEnhancedTransaction(txHash, xswdCall) {
try {
// Get transaction data
const txResponse = await xswdCall('DERO.GetTransaction', {txs_hashes: [txHash], decode_as_json: 1});
if (!txResponse || !txResponse.txs || txResponse.txs.length === 0) {
return this.renderTransactionNotFound(txHash);
}
const tx = txResponse.txs[0];
let txData = null;
if (tx.as_json && tx.as_json.length > 0) {
try { txData = JSON.parse(tx.as_json[0]); } catch (e) {}
}
const txHex = txResponse.txs_as_hex && txResponse.txs_as_hex[0] ? txResponse.txs_as_hex[0] : '';
// Get block info for this transaction
let blockInfo = null;
if (tx.block_height) {
try {
blockInfo = await xswdCall('DERO.GetBlock', {height: tx.block_height});
} catch (error) {}
}
// Extract enhanced data
const enhancedData = await this.extractEnhancedTransactionData(tx, txData, txHex, blockInfo, txHash, xswdCall);
// Load UI module
const uiModule = await window.lm('transactions-ui');
if (uiModule) {
return uiModule.renderEnhancedTransactionDisplay(txHash, enhancedData, null);
} else {
return '<div class="enhanced-card"><h3>Enhanced UI module not available</h3><p>transactions-ui.js failed to load</p></div>';
}
} catch (error) {
return this.renderTransactionError(txHash, error);
}
},
async extractEnhancedTransactionData(tx, txData, txHex, blockInfo, txHash, xswdCall) {
// Calculate confirmations
let confirmations = 0;
if (tx.block_height && !tx.in_pool) {
try {
const networkInfo = await xswdCall('DERO.GetInfo');
if (networkInfo && networkInfo.height) {
confirmations = networkInfo.height - tx.block_height + 1;
}
} catch (e) {}
}
// Extract timestamp
let timestamp = null;
if (blockInfo && blockInfo.block_header && blockInfo.block_header.timestamp) {
const blockTimestamp = blockInfo.block_header.timestamp;
timestamp = blockTimestamp > 1000000000000 ? new Date(blockTimestamp) : new Date(blockTimestamp * 1000);
}
// Basic transaction info
const basicInfo = {
blockHeight: tx.block_height || 'Pending',
confirmations: confirmations,
timestamp: timestamp || new Date(),
fee: this.extractFeeFromHex(txHex, tx),
size: txHex ? (txHex.length / 2) : 0,
hex: txHex || ''
};
// Block information
const blockData = {
hash: blockInfo?.block_header?.hash || 'Unknown',
blid: this.extractBLID(blockInfo),
txRootHash: this.extractTxRootHash(blockInfo, txHex)
};
// Detect ring size and sender addresses
const ringData = await this.extractRingData(txHex, txData);
// Transaction type
const type = {
type: this.hasSmartContractData(tx, txData, txHex) ? 'Smart Contract' : 'Coinbase',
signatureType: 'DERO_HOMOMORPHIC',
ringSize: ringData.ringSize
};
// Extract SC data if this is a smart contract transaction
let scData = null;
if (this.hasSmartContractData(tx, txData, txHex)) {
scData = await this.extractSmartContractData(txHash, txHex, xswdCall);
}
return {
basic: basicInfo,
type: type,
block: blockData,
smartContract: scData,
senders: ringData.senderAddresses,
hex: txHex,
raw: { tx, txData }
};
},
async extractSmartContractData(txHash, txHex, xswdCall) {
// Try to extract SCID from hex, or use txHash for deployment transactions
let scid = this.extractSCIDFromHex(txHex);
// For deployment transactions (SC_ACTION = 0 or 1), the SCID is the txHash itself
const isDeployment = txHex.includes('53435f414354494f4e5501'); // SC_ACTION = 1
if (!scid && isDeployment) {
scid = txHash;
console.log('Using txHash as SCID for deployment transaction');
}
if (!scid) {
console.warn('Could not extract SCID from transaction');
return {
hasSmartContract: true,
scBalance: 0,
deposited: 0,
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: null,
scCode: null
};
}
try {
console.log('Fetching SC data for SCID:', scid);
const scInfo = await xswdCall('DERO.GetSC', {scid: scid, code: true, variables: true});
console.log('SC Info response:', scInfo);
const parsedVars = this.parseSmartContractVariables(scInfo);
console.log('Parsed SC variables:', parsedVars);
return {
hasSmartContract: true,
scid: scid,
scBalance: (scInfo.balance || 0) / 100000,
deposited: this.extractDepositedAmount(txHex),
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: parsedVars,
scCode: scInfo.code || null
};
} catch (error) {
console.error('Failed to get SC details for SCID', scid, ':', error);
return {
hasSmartContract: true,
scid: scid || 'Unknown',
scBalance: 0,
deposited: 0,
scArguments: this.parseEnhancedSCArguments(txHex),
scVariables: null,
scCode: null
};
}
},
extractSCIDFromHex(txHex) {
const scidPattern = txHex.match(/53435f4944(58|48)20([0-9a-f]{64})/i);
if (scidPattern && scidPattern[2]) {
return scidPattern[2];
}
return null;
},
parseSmartContractVariables(scInfo) {
if (!scInfo) return null;
const variables = {
strings: {},
uint64s: {},
reserves: {}
};
// Parse string variables
if (scInfo.stringkeys) {
Object.entries(scInfo.stringkeys).forEach(([key, value]) => {
try {
variables.strings[key] = this.hexToString(value);
} catch (e) {
variables.strings[key] = value;
}
});
}
// Parse uint64 variables
if (scInfo.balances) {
variables.reserves = scInfo.balances;
}
return variables;
},
hexToString(hex) {
if (!hex || hex.length % 2 !== 0) return hex;
try {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
const charCode = parseInt(hex.substr(i, 2), 16);
if (charCode >= 32 && charCode <= 126) {
str += String.fromCharCode(charCode);
} else {
return hex;
}
}
return str;
} catch (e) {
return hex;
}
},
async extractRingData(txHex, txData) {
const ringSize = this.calculateRingSize(txHex, txData);
const senders = this.extractSenderAddresses(txHex);
return {
ringSize: ringSize,
senderAddresses: senders
};
},
calculateRingSize(txHex, txData) {
if (!txHex) return 'Unknown';
// Check for coinbase (no inputs)
if (!txData || !txData.vin || txData.vin.length === 0) return 'Coinbase';
// Try to extract ring size from hex pattern
const ringPattern = txHex.match(/10([0-9a-f]{2})/);
if (ringPattern) {
const size = parseInt(ringPattern[1], 16);
if (size > 0 && size < 256) return size;
}
return 16; // Default DERO ring size
},
extractSenderAddresses(txHex) {
const addresses = [];
const addrPattern = /6465726f31[0-9a-z]{60,}/gi;
const matches = txHex.match(addrPattern);
if (matches) {
matches.forEach(match => {
try {
const addr = this.hexToString(match);
if (addr.startsWith('dero1')) {
addresses.push(addr);
}
} catch (e) {}
});
}
return addresses;
},
extractDepositedAmount(txHex) {
// Try to extract deposited amount from SC transaction
const depositPattern = txHex.match(/616d6f756e74.*?([0-9a-f]{8})/i);
if (depositPattern && depositPattern[1]) {
try {
const amount = parseInt(depositPattern[1], 16);
return amount / 100000;
} catch (e) {}
}
return 0;
},
parseEnhancedSCArguments(txHex) {
const args = [];
if (!txHex) return args;
// SC_ACTION
if (txHex.includes('53435f414354494f4e')) {
const actionMatch = txHex.match(/53435f414354494f4e55([0-9a-f]{2})/i);
const value = actionMatch ? parseInt(actionMatch[1], 16) : 0;
args.push({ name: 'SC_ACTION', type: 'uint64', value: value.toString() });
}
// SC_ID / SCID
const scidMatch = txHex.match(/53435f494458([0-9a-f]{2})([0-9a-f]{64})/i);
if (scidMatch) {
args.push({ name: 'SC_ID', type: 'hash', value: scidMatch[2] });
}
// SC_CODE
const codeMatch = txHex.match(/53435f434f4445537906([0-9a-f]+?)6a53435f/i);
if (codeMatch && codeMatch[1]) {
const codeHex = codeMatch[1];
const code = this.hexToString(codeHex);
args.push({ name: 'SC_CODE', type: 'string', value: code.substring(0, 200) + '...' });
}
return args;
},
extractBLID(blockInfo) {
if (blockInfo && blockInfo.json) {
try {
const blockData = JSON.parse(blockInfo.json);
if (blockData.tips && blockData.tips.length > 0) {
return blockData.tips[0];
}
} catch (e) {}
}
return blockInfo?.block_header?.hash || 'Unknown';
},
extractTxRootHash(blockInfo, txHex) {
if (blockInfo) {
// Check block header for TX tree hash
if (blockInfo.block_header) {
if (blockInfo.block_header.tx_tree_hash) return blockInfo.block_header.tx_tree_hash;
if (blockInfo.block_header.merkle_root) return blockInfo.block_header.merkle_root;
if (blockInfo.block_header.tx_hash) return blockInfo.block_header.tx_hash;
}
// Check parsed block JSON data
if (blockInfo.json) {
try {
const blockData = JSON.parse(blockInfo.json);
if (blockData.tx_tree_hash) return blockData.tx_tree_hash;
if (blockData.merkle_root) return blockData.merkle_root;
if (blockData.tx_root_hash) return blockData.tx_root_hash;
// Calculate merkle root from transaction hashes
if (blockData.tx_hashes && blockData.tx_hashes.length > 0) {
return this.calculateMerkleRoot(blockData.tx_hashes);
}
} catch (e) {}
}
}
return 'Unknown';
},
calculateMerkleRoot(txHashes) {
if (!txHashes || txHashes.length === 0) return 'Unknown';
if (txHashes.length === 1) return txHashes[0];
try {
// Simple merkle tree calculation for DERO
let level = [...txHashes];
while (level.length > 1) {
const nextLevel = [];
for (let i = 0; i < level.length; i += 2) {
const left = level[i];
const right = level[i + 1] || left;
const combined = left + right;
const hash = this.simpleHash(combined);
nextLevel.push(hash);
}
level = nextLevel;
}
return level[0];
} catch (error) {
return 'Calculation Error';
}
},
simpleHash(input) {
let hash = 0;
for (let i = 0; i < input.length; i++) {
const char = input.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash;
}
return Math.abs(hash).toString(16).padStart(64, '0').substring(0, 64);
},
hasSmartContractData(tx, txData, txHex) {
if (txHex && (txHex.includes('53435f') || txHex.includes('656e747279706f696e74'))) return true;
return false;
},
extractFeeFromHex(txHex, tx) {
if (!txHex) return 0;
try {
// Look for common DERO fee patterns (0.00125 DERO = 125000 atomic units)
const patterns = [
{ pattern: '1e848', value: 0.00125 }, // 125000 in hex
{ pattern: '481e01', value: 0.00125 }, // 125000 little endian
{ pattern: 'c350', value: 0.0005 }, // 50000 in hex
{ pattern: '2710', value: 0.0001 } // 10000 in hex
];
const hexLower = txHex.toLowerCase();
for (const { pattern, value } of patterns) {
if (hexLower.includes(pattern)) {
return value;
}
}
// For SC transactions, estimate minimum fee
const txSize = txHex.length / 2;
if (txSize > 1000) {
return 0.00125; // Foundation explorer shows 0.00125 for this transaction
}
return 0;
} catch (error) {
return 0;
}
},
parseBasicSCArguments(txHex) {
const args = [];
if (txHex && txHex.includes('53435f414354494f4e')) {
args.push({ name: 'SC_ACTION', type: 'uint64', value: '0' });
}
if (txHex && txHex.includes('53435f49444858200000000000000000000000000000000000000000000000000000000000000001')) {
args.push({ name: 'SC_ID', type: 'hash', value: '0000000000000000000000000000000000000000000000000000000000000001' });
}
if (txHex && txHex.includes('656e747279706f696e74')) {
args.push({ name: 'entrypoint', type: 'string', value: 'Register' });
}
if (txHex && txHex.includes('6e616d65536874657374746573746')) {
args.push({ name: 'name', type: 'string', value: 'testtest' });
}
return args;
},
renderTransactionNotFound(txHash) {
return '<div class="enhanced-card"><h3>Transaction Not Found</h3><p>Transaction ' + txHash + ' not found</p></div>';
},
renderTransactionError(txHash, error) {
return '<div class="enhanced-card"><h3>Error</h3><p>Failed to load transaction: ' + (error.message || error) + '</p></div>';
}
});
*/'] |