Skip to content

Commit 6dec80d

Browse files
authored
Feat: Rework encodeRunestoneUnsafe logic to support SpacedRunes in a seamless manner; add support for returning commitment (#37)
* fix spaced runes support * fix spaced runes support - need to export rune * rework the lib a bit to take into consideration calculating itself if there are spacers and which position they are in; and add etchingCommitment return value * fix return typing * fix spacers logic * add spaced rune export again
1 parent 381b2b9 commit 6dec80d

File tree

2 files changed

+31
-24
lines changed

2 files changed

+31
-24
lines changed

index.ts

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { None, Option, Some } from './src/monads';
66
import { Rune } from './src/rune';
77
import { RuneId } from './src/runeid';
88
import { Runestone } from './src/runestone';
9+
import { SpacedRune } from './src/spacedrune';
910
import { Terms } from './src/terms';
1011

1112
export {
@@ -28,9 +29,9 @@ export { Edict } from './src/edict';
2829
export { Etching } from './src/etching';
2930
export { Network } from './src/network';
3031
export { Rune } from './src/rune';
32+
export { SpacedRune } from './src/spacedrune';
3133
export { RuneId } from './src/runeid';
3234
export { Runestone } from './src/runestone';
33-
export { SpacedRune } from './src/spacedrune';
3435
export { Terms } from './src/terms';
3536

3637
export {
@@ -90,6 +91,8 @@ const u128Strict = (n: bigint) => {
9091
return u128(bigN);
9192
};
9293

94+
const SPACERS = ['•', '.'];
95+
9396
// TODO: Add unit tests
9497
/**
9598
* Low level function to allow for encoding runestones without any indexer and transaction checks.
@@ -98,7 +101,10 @@ const u128Strict = (n: bigint) => {
98101
* @returns encoded runestone bytes
99102
* @throws Error if encoding is detected to be considered a cenotaph
100103
*/
101-
export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
104+
export function encodeRunestoneUnsafe(runestone: RunestoneSpec): {
105+
encodedRune: Buffer;
106+
etchingCommitment: Buffer | undefined;
107+
} {
102108
const mint = runestone.mint
103109
? Some(new RuneId(u64Strict(runestone.mint.block), u32Strict(runestone.mint.tx)))
104110
: None;
@@ -112,20 +118,28 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
112118
}));
113119

114120
let etching: Option<Etching> = None;
121+
let etchingCommitment: string | undefined = undefined;
115122
if (runestone.etching) {
116123
const etchingSpec = runestone.etching;
117-
118-
if (!etchingSpec.rune && etchingSpec.spacers?.length) {
119-
throw Error('Spacers specified with no rune');
124+
let hasSpacers = false;
125+
for (const spacer of SPACERS) {
126+
if (runestone.etching?.rune?.includes(spacer)) {
127+
hasSpacers = true;
128+
break;
129+
}
120130
}
121131

122-
if (
123-
etchingSpec.rune &&
124-
etchingSpec.spacers?.length &&
125-
Math.max(...etchingSpec.spacers)! >= etchingSpec.rune.length - 1
126-
) {
127-
throw Error('Spacers specified out of bounds of rune');
132+
let runeSpacers: number | undefined = undefined;
133+
let parsedRawRune: Rune | undefined = undefined;
134+
if (hasSpacers) {
135+
const spacedRune = etchingSpec.rune ? SpacedRune.fromString(etchingSpec.rune) : undefined;
136+
runeSpacers = spacedRune?.spacers;
137+
parsedRawRune = spacedRune?.rune;
138+
} else {
139+
parsedRawRune = etchingSpec.rune ? Rune.fromString(etchingSpec.rune) : undefined;
128140
}
141+
const rune: Option<Rune> =
142+
parsedRawRune !== undefined ? Some(parsedRawRune).map(() => parsedRawRune!) : None;
129143

130144
if (etchingSpec.symbol && etchingSpec.symbol.codePointAt(1) !== undefined) {
131145
throw Error('Symbol must be one code point');
@@ -135,17 +149,7 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
135149
etchingSpec.divisibility !== undefined ? Some(etchingSpec.divisibility).map(u8Strict) : None;
136150
const premine =
137151
etchingSpec.premine !== undefined ? Some(etchingSpec.premine).map(u128Strict) : None;
138-
const rune =
139-
etchingSpec.rune !== undefined
140-
? Some(etchingSpec.rune).map((rune) => Rune.fromString(rune))
141-
: None;
142-
const spacers = etchingSpec.spacers
143-
? Some(
144-
u32Strict(
145-
etchingSpec.spacers.reduce((spacers, flagIndex) => spacers | (1 << flagIndex), 0)
146-
)
147-
)
148-
: None;
152+
const spacers: Option<u32> = hasSpacers && runeSpacers ? Some(u32Strict(runeSpacers)) : None;
149153
const symbol = etchingSpec.symbol ? Some(etchingSpec.symbol) : None;
150154

151155
if (divisibility.isSome() && divisibility.unwrap() > MAX_DIVISIBILITY) {
@@ -185,7 +189,11 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
185189
const turbo = etchingSpec.turbo ?? false;
186190

187191
etching = Some(new Etching(divisibility, rune, spacers, symbol, terms, premine, turbo));
192+
etchingCommitment = (parsedRawRune as Rune)?.commitment;
188193
}
189194

190-
return new Runestone(mint, pointer, edicts, etching).encipher();
195+
return {
196+
encodedRune: new Runestone(mint, pointer, edicts, etching).encipher(),
197+
etchingCommitment,
198+
};
191199
}

src/indexer/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ export type RuneEtchingSpec = {
122122
rune?: string;
123123
divisibility?: number;
124124
premine?: bigint;
125-
spacers?: number[];
126125
symbol?: string;
127126
terms?: {
128127
cap?: bigint;

0 commit comments

Comments
 (0)