Skip to content

Commit 0e089cf

Browse files
committed
adjust fees
1 parent c8bb9ca commit 0e089cf

File tree

2 files changed

+96
-54
lines changed

2 files changed

+96
-54
lines changed

back/src/functions/allFunds.ts

Lines changed: 92 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,37 @@ export default async function (req: Request, res: Response) {
1111
// Check funding availability - important to note that the assumption made here
1212
// is that there's only one utxo which corresponds to this address.
1313
const utxos = await woc.getUtxos(address)
14-
const max = utxos.reduce((a, b) => a + b.satoshis - 1, 0)
14+
const max = utxos.reduce((a, b) => a + b.satoshis, 0)
15+
16+
const TOKEN_SATOSHIS = 13
17+
const MAX_TOKEN_OUTPUTS_PER_TX = 200
18+
const FUNDS_TX_FEE_BUFFER = 1000
19+
const TOKEN_TX_FEE_BUFFER = 1000
1520

1621
const lockingScript = new P2PKH().lock(address).toHex()
1722

18-
if (max < 1000) {
23+
if (max < TOKEN_SATOSHIS + FUNDS_TX_FEE_BUFFER) {
1924
res.send({ error: 'not enough satoshis, use the fund/{number} endpoint', utxos })
2025
return
2126
}
2227

2328
// create a bunch of funding transactions which we'll use to create tokens
24-
let batches = Math.floor(max / 1000)
25-
let change = max % 1000
29+
const maxAvailableForFundingOutputs = max - FUNDS_TX_FEE_BUFFER
30+
let batches = Math.ceil(maxAvailableForFundingOutputs / (TOKEN_SATOSHIS * MAX_TOKEN_OUTPUTS_PER_TX + TOKEN_TX_FEE_BUFFER))
31+
if (batches < 1) {
32+
batches = 1
33+
}
2634

2735
// temp limit during dev
2836
if (batches > 2) {
2937
batches = 2
3038
}
3139
// end of temp limit
3240

41+
const batchBase = Math.floor(maxAvailableForFundingOutputs / batches)
42+
const batchRemainder = maxAvailableForFundingOutputs % batches
43+
const batchInputSatoshis = Array.from({ length: batches }, (_, i) => batchBase + (i < batchRemainder ? 1 : 0))
44+
3345
const fundsTx = new Transaction()
3446
utxos.forEach((utxo) => {
3547
fundsTx.addInput(fromUtxo({
@@ -41,18 +53,15 @@ export default async function (req: Request, res: Response) {
4153
})
4254

4355
for (let i = 0; i < batches; i++) {
44-
// for each batch we create an output of 1000 satoshis
45-
fundsTx.addOutput({
46-
satoshis: 1000,
47-
lockingScript: new P2PKH().lock(address)
48-
})
49-
}
50-
if (change > 0) {
5156
fundsTx.addOutput({
52-
change: true,
57+
satoshis: batchInputSatoshis[i],
5358
lockingScript: new P2PKH().lock(address)
5459
})
5560
}
61+
fundsTx.addOutput({
62+
change: true,
63+
lockingScript: new P2PKH().lock(address)
64+
})
5665

5766
await fundsTx.fee(new SatoshisPerKilobyte(100))
5867
await fundsTx.sign()
@@ -70,32 +79,63 @@ export default async function (req: Request, res: Response) {
7079

7180

7281
// Generate unique secret-hash pairs for each token
73-
const secretPairs = []
74-
for (let i = 0; i < batches * 957; i++) {
75-
const pair = HashPuzzle.generateSecretPair()
76-
secretPairs.push(pair)
77-
}
82+
const secretsByTx: any[] = []
83+
const tokenOutputsByTx: number[] = []
7884

7985
const tokenCreationTxs: Transaction[] = []
8086

8187
for (let batch = 0; batch < batches; batch++) {
8288
// Create transaction with hash-locked outputs
83-
const tx = new Transaction()
84-
tx.addInput(fromUtxo({
85-
txid: fundsTxId,
86-
vout: batch,
87-
satoshis: 1000,
88-
script: lockingScript,
89-
}, new P2PKH().unlock(key)))
90-
secretPairs.slice(batch * 957, (batch + 1) * 957).forEach(( pair ) => {
89+
const batchSatoshis = batchInputSatoshis[batch]
90+
let outputs = Math.floor((batchSatoshis - TOKEN_TX_FEE_BUFFER) / TOKEN_SATOSHIS)
91+
if (outputs < 1) {
92+
res.send({ error: 'not enough satoshis to fund token creation transaction', batch, batchSatoshis })
93+
return
94+
}
95+
if (outputs > MAX_TOKEN_OUTPUTS_PER_TX) {
96+
outputs = MAX_TOKEN_OUTPUTS_PER_TX
97+
}
98+
99+
while (outputs > 0) {
100+
const tx = new Transaction()
101+
tx.addInput(fromUtxo({
102+
txid: fundsTxId,
103+
vout: batch,
104+
satoshis: batchSatoshis,
105+
script: lockingScript,
106+
}, new P2PKH().unlock(key)))
107+
108+
const pairs = []
109+
for (let i = 0; i < outputs; i++) {
110+
const pair = HashPuzzle.generateSecretPair()
111+
pairs.push(pair)
112+
tx.addOutput({
113+
satoshis: TOKEN_SATOSHIS,
114+
lockingScript: new HashPuzzle().lock(pair.hash)
115+
})
116+
}
117+
91118
tx.addOutput({
92-
satoshis: 1,
93-
lockingScript: new HashPuzzle().lock(pair.hash)
119+
change: true,
120+
lockingScript: new P2PKH().lock(address)
94121
})
95-
})
96-
await tx.fee(new SatoshisPerKilobyte(100))
97-
await tx.sign()
98-
tokenCreationTxs.push(tx)
122+
123+
try {
124+
await tx.fee(new SatoshisPerKilobyte(100))
125+
await tx.sign()
126+
tokenCreationTxs.push(tx)
127+
secretsByTx.push(pairs)
128+
tokenOutputsByTx.push(outputs)
129+
break
130+
} catch (e) {
131+
outputs -= 1
132+
}
133+
}
134+
135+
if (outputs === 0) {
136+
res.send({ error: 'not enough satoshis to fund token creation transaction', batch, batchSatoshis })
137+
return
138+
}
99139
}
100140

101141
// Broadcast transactions
@@ -114,31 +154,33 @@ export default async function (req: Request, res: Response) {
114154
// Store transaction data
115155
const txDbResponse = await db.collection('txs').insertMany(tokenTxs)
116156

117-
const tokenUtxos = secretPairs.map((secret, idx) => {
118-
const vout = idx % 957
119-
const creationTx = Math.floor(idx / 957)
157+
const tokenUtxos: any[] = []
158+
for (let creationTx = 0; creationTx < tokenTxs.length; creationTx++) {
120159
const txid = tokenTxs[creationTx].txid
121-
const script = tokenCreationTxs[creationTx].outputs[vout].lockingScript.toHex()
122-
const satoshis = 1
123-
const fileHash = null
124-
const confirmed = false
125-
const spent = false
126-
return {
127-
txid,
128-
vout,
129-
script,
130-
satoshis,
131-
secret,
132-
fileHash,
133-
confirmed,
134-
spent,
160+
for (let vout = 0; vout < tokenOutputsByTx[creationTx]; vout++) {
161+
const secret = secretsByTx[creationTx][vout]
162+
const script = tokenCreationTxs[creationTx].outputs[vout].lockingScript.toHex()
163+
const satoshis = TOKEN_SATOSHIS
164+
const fileHash = null
165+
const confirmed = false
166+
const spent = false
167+
tokenUtxos.push({
168+
txid,
169+
vout,
170+
script,
171+
satoshis,
172+
secret,
173+
fileHash,
174+
confirmed,
175+
spent,
176+
})
135177
}
136-
})
178+
}
137179

138180
// Store token data
139181
const utxosDbResponse = await db.collection('utxos').insertMany(tokenUtxos, { bypassDocumentValidation: true, ordered: false, forceServerObjectId: true })
140182

141-
res.send({ txid: tokenUtxos[0].txid, number: batches * 957, txDb: txDbResponse.insertedCount, utxosDb: utxosDbResponse.insertedCount })
183+
res.send({ txid: tokenUtxos[0].txid, number: tokenUtxos.length, txDb: txDbResponse.insertedCount, utxosDb: utxosDbResponse.insertedCount })
142184
} catch (error) {
143185
console.log(error)
144186
res.status(500)

back/src/functions/fund.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ export default async function (req: Request, res: Response) {
5050
// Check funding availability
5151
const utxos = await woc.getUtxos(address)
5252
const beef = await woc.getBeef(utxos[0].txid)
53-
const max = utxos.reduce((a, b) => a + b.satoshis - 1, 0)
53+
const max = utxos.reduce((a, b) => a + b.satoshis - 100, 0)
5454

55-
if (max < number) {
55+
if (max < (number * 13)) {
5656
res.send({ error: 'not enough satoshis', number, utxos })
5757
return
5858
}
@@ -75,7 +75,7 @@ export default async function (req: Request, res: Response) {
7575
})
7676
for (const pair of secretPairs) {
7777
tx.addOutput({
78-
satoshis: 10,
78+
satoshis: 13,
7979
lockingScript: new HashPuzzle().lock(pair.hash)
8080
})
8181
}
@@ -105,7 +105,7 @@ export default async function (req: Request, res: Response) {
105105
txid,
106106
vout,
107107
script: tx.outputs[vout].lockingScript.toHex(),
108-
satoshis: 1,
108+
satoshis: 13,
109109
secret,
110110
fileHash: null,
111111
confirmed: false,

0 commit comments

Comments
 (0)