@ar.io/sdk
Version:
[](https://codecov.io/gh/ar-io/ar-io-sdk)
105 lines (104 loc) • 4.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertHyperBeamStateToAoANTState = exports.isHyperBeamANTState = exports.sortANTRecords = void 0;
/**
* Sorts ANT records by priority and then lexicographically.
*
* Note: javascript guarantees that the order of objects in an object is persistent. Still, adding index to each record is useful for enforcing against undername limits.
*
* Reference: https://github.com/ar-io/ar-io-node/blob/e0a9ec56559cad1b3e35d668563871afb8649913/docs/madr/003-arns-undername-limits.md
*
* @param antRecords - The ANT records to sort.
*/
const sortANTRecords = (antRecords) => {
const sortedEntries = Object.entries(antRecords).sort(([a, aRecord], [b, bRecord]) => {
// '@' is the root name and should be resolved first
if (a === '@') {
return -1;
}
if (b === '@') {
return 1;
}
// if a record has a priority, it should be resolved before any other record without a priority
if ('priority' in aRecord && !('priority' in bRecord)) {
return -1;
}
if (!('priority' in aRecord) && 'priority' in bRecord) {
return 1;
}
// if both records have a priority, sort by priority and fallback to lexicographic sorting
if (aRecord.priority !== undefined && bRecord.priority !== undefined) {
if (aRecord.priority === bRecord.priority) {
// use deterministic comparison instead of localeCompare to avoid locale-specific sorting
return a < b ? -1 : a > b ? 1 : 0;
}
return aRecord.priority - bRecord.priority;
}
// all other records are sorted lexicographically, using deterministic comparison instead of localeCompare to avoid locale-specific sorting
return a < b ? -1 : a > b ? 1 : 0;
});
// now that they are sorted, add the index to each record - this is their position in the sorted list and is used to enforce undername limits
return Object.fromEntries(sortedEntries.map(([a, aRecord], index) => [a, { ...aRecord, index }]));
};
exports.sortANTRecords = sortANTRecords;
const isHyperBeamANTState = (state) => {
return ('name' in state &&
'ticker' in state &&
'description' in state &&
'keywords' in state &&
'denomination' in state &&
'owner' in state &&
'controllers' in state &&
'records' in state &&
'balances' in state &&
'logo' in state &&
'totalsupply' in state &&
'initialized' in state);
};
exports.isHyperBeamANTState = isHyperBeamANTState;
/**
* Convert HyperBeam serialized ANT state to backwards compatible format.
*
* @param state - The HyperBeam serialized ANT state.
*/
const convertHyperBeamStateToAoANTState = (initialState) => {
function lowerCaseKeys(obj) {
return Object.fromEntries(Object.entries(obj).map(([key, value]) => {
if (key.toLowerCase().includes('balances')) {
return [key.toLowerCase(), value];
}
if (typeof value === 'object' &&
!Array.isArray(value) &&
value !== null) {
return [key.toLowerCase(), lowerCaseKeys(value)];
}
return [key.toLowerCase(), value];
}));
}
// we need to ensure keys are lower cased because hyperbeam json serializes keys to lowercase inconsistently
const state = lowerCaseKeys(initialState);
return {
Name: state.name,
Ticker: state.ticker,
Description: state.description,
Keywords: state.keywords,
Denomination: parseInt(state.denomination),
Owner: state.owner,
Controllers: state.controllers,
Records: Object.entries(state.records).reduce((acc, [key, record]) => {
acc[key] = {
transactionId: record.transactionid,
ttlSeconds: record.ttlseconds,
...(record.priority !== undefined
? { priority: record.priority }
: {}),
};
return acc;
}, {}),
Balances: state.balances,
Logo: state.logo,
TotalSupply: state.totalsupply || 1,
Initialized: state.initialized,
};
};
exports.convertHyperBeamStateToAoANTState = convertHyperBeamStateToAoANTState;