Skip to content

Commit 649b03c

Browse files
authored
feat: add command to create external batch (#584)
* feat: add command to create external batch * chore: lint
1 parent ba55564 commit 649b03c

File tree

7 files changed

+236
-88
lines changed

7 files changed

+236
-88
lines changed

src/command/utility/cid.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export class Cid extends RootCommand implements LeafCommand {
1515
})
1616
public value!: string
1717

18-
public async run(): Promise<void> {
18+
public run(): void {
1919
super.init()
2020

2121
const reference = new Reference(this.value)

src/command/utility/create-batch.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { Utils } from '@ethersphere/bee-js'
2+
import { Numbers, Strings } from 'cafe-utility'
3+
import { Contract, Event, Wallet } from 'ethers'
4+
import { LeafCommand, Option } from 'furious-commander'
5+
import { ABI, Contracts } from '../../utils/contracts'
6+
import { makeReadySigner } from '../../utils/rpc'
7+
import { RootCommand } from '../root-command'
8+
9+
export class CreateBatch extends RootCommand implements LeafCommand {
10+
public readonly name = 'create-batch'
11+
12+
public readonly description = 'Create a postage batch for a given funded private key'
13+
14+
@Option({
15+
key: 'private-key',
16+
description: 'Private key of the wallet to create a postage batch for',
17+
type: 'hex-string',
18+
required: true,
19+
})
20+
public privateKey!: string
21+
22+
@Option({
23+
key: 'depth',
24+
description: 'Depth of the postage stamp',
25+
type: 'number',
26+
required: true,
27+
minimum: 17,
28+
maximum: 255,
29+
})
30+
public depth!: number
31+
32+
@Option({
33+
key: 'amount',
34+
description: 'Value per chunk in PLUR, deprecates over time with new blocks mined',
35+
type: 'bigint',
36+
required: true,
37+
minimum: 1,
38+
})
39+
public amount!: bigint
40+
41+
@Option({
42+
key: 'json-rpc-url',
43+
type: 'string',
44+
description: 'Gnosis JSON-RPC URL',
45+
default: 'https://xdai.fairdatasociety.org',
46+
})
47+
public jsonRpcUrl!: string
48+
49+
public async run(): Promise<void> {
50+
super.init()
51+
52+
if (!this.yes) {
53+
this.yes = await this.console.confirm(
54+
'This command creates an external batch for advanced usage. Do you want to continue?',
55+
)
56+
}
57+
58+
if (!this.yes) {
59+
return
60+
}
61+
62+
const wallet = new Wallet(this.privateKey)
63+
const cost = Utils.getStampCost(this.depth, this.amount)
64+
const signer = await makeReadySigner(wallet.privateKey, this.jsonRpcUrl)
65+
66+
this.console.log(`Approving spending of ${cost.toDecimalString()} BZZ to ${wallet.address}`)
67+
const tokenProxyContract = new Contract(Contracts.bzz, ABI.tokenProxy, signer)
68+
const approve = await tokenProxyContract.approve(Contracts.postageStamp, cost.toPLURBigInt().toString(), {
69+
gasLimit: 130_000,
70+
type: 2,
71+
maxFeePerGas: Numbers.make('2gwei'),
72+
maxPriorityFeePerGas: Numbers.make('1gwei'),
73+
})
74+
this.console.log(`Waiting 3 blocks on approval tx ${approve.hash}`)
75+
await approve.wait(3)
76+
77+
this.console.log(`Creating postage batch for ${wallet.address} with depth ${this.depth} and amount ${this.amount}`)
78+
const postageStampContract = new Contract(Contracts.postageStamp, ABI.postageStamp, signer)
79+
const createBatch = await postageStampContract.createBatch(
80+
signer.address,
81+
this.amount,
82+
this.depth,
83+
16,
84+
`0x${Strings.randomHex(64)}`,
85+
false,
86+
{
87+
gasLimit: 1_000_000,
88+
type: 2,
89+
maxFeePerGas: Numbers.make('3gwei'),
90+
maxPriorityFeePerGas: Numbers.make('2gwei'),
91+
},
92+
)
93+
this.console.log(`Waiting 3 blocks on create batch tx ${createBatch.hash}`)
94+
const receipt = await createBatch.wait(3)
95+
96+
const batchId = receipt.events.find((x: Event) => x.address === Contracts.postageStamp).topics[1]
97+
this.console.log(`Batch created with ID ${batchId}`)
98+
}
99+
}

src/command/utility/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GroupCommand } from 'furious-commander'
44
import { fileExists } from '../../utils'
55
import { CommandLog } from '../root-command/command-log'
66
import { Cid } from './cid'
7+
import { CreateBatch } from './create-batch'
78
import { GetBee } from './get-bee'
89
import { Lock } from './lock'
910
import { Redeem } from './redeem'
@@ -14,7 +15,7 @@ export class Utility implements GroupCommand {
1415

1516
public readonly description = 'Utility commands related to Swarm and wallets'
1617

17-
public subCommandClasses = [Cid, Lock, Unlock, GetBee, Redeem]
18+
public subCommandClasses = [Cid, Lock, Unlock, GetBee, Redeem, CreateBatch]
1819
}
1920

2021
export async function createWallet(pathOrPrivateKey: string, console: CommandLog): Promise<Wallet> {

src/command/utility/redeem.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { Dates, System } from 'cafe-utility'
22
import { BigNumber, providers, Wallet } from 'ethers'
33
import { Argument, LeafCommand, Option } from 'furious-commander'
4-
import { NETWORK_ID } from '../../utils/bzz-abi'
5-
import { estimateNativeTransferTransactionCost, Rpc } from '../../utils/rpc'
4+
import { NETWORK_ID } from '../../utils/contracts'
5+
import {
6+
estimateNativeTransferTransactionCost,
7+
eth_getBalance,
8+
eth_getBalanceERC20,
9+
sendBzzTransaction,
10+
sendNativeTransaction,
11+
} from '../../utils/rpc'
612
import { RootCommand } from '../root-command'
713

814
export class Redeem extends RootCommand implements LeafCommand {
@@ -21,7 +27,7 @@ export class Redeem extends RootCommand implements LeafCommand {
2127
@Option({
2228
key: 'json-rpc-url',
2329
type: 'string',
24-
description: 'Ethereum JSON-RPC URL',
30+
description: 'Gnosis JSON-RPC URL',
2531
default: 'https://xdai.fairdatasociety.org',
2632
})
2733
public jsonRpcUrl!: string
@@ -48,10 +54,10 @@ export class Redeem extends RootCommand implements LeafCommand {
4854
this.console.log('Creating wallet...')
4955
const wallet = new Wallet(this.wallet, provider)
5056
this.console.log('Fetching xBZZ balance...')
51-
const xBZZ = await Rpc._eth_getBalanceERC20(wallet.address, provider)
57+
const xBZZ = await eth_getBalanceERC20(wallet.address, provider)
5258
this.console.log(`xBZZ balance: ${xBZZ}`)
5359
this.console.log('Fetching xDAI balance...')
54-
let xDAI = await Rpc.eth_getBalance(wallet.address, provider)
60+
let xDAI = await eth_getBalance(wallet.address, provider)
5561
this.console.log(`xDAI balance: ${xDAI}`)
5662

5763
if (!this.quiet && !this.yes) {
@@ -66,11 +72,11 @@ export class Redeem extends RootCommand implements LeafCommand {
6672

6773
if (xBZZ !== '0') {
6874
this.console.log('Transferring xBZZ to Bee wallet...')
69-
await Rpc.sendBzzTransaction(this.wallet, this.target, xBZZ, this.jsonRpcUrl)
75+
await sendBzzTransaction(this.wallet, this.target, xBZZ, this.jsonRpcUrl)
7076

7177
for (let i = 0; i < 10; i++) {
7278
this.console.log(`Refreshing xDAI balance #${i + 1}...`)
73-
xDAI = await Rpc.eth_getBalance(wallet.address, provider)
79+
xDAI = await eth_getBalance(wallet.address, provider)
7480

7581
if (xDAI !== firstKnownxDAI) {
7682
this.console.log(`xDAI balance: ${xDAI}`)
@@ -90,7 +96,7 @@ export class Redeem extends RootCommand implements LeafCommand {
9096

9197
if (xDAIValue.gt(totalCost)) {
9298
this.console.log('Transferring xDAI to Bee wallet...')
93-
await Rpc.sendNativeTransaction(
99+
await sendNativeTransaction(
94100
this.wallet,
95101
this.target,
96102
xDAIValue.sub(totalCost).toString(),

src/utils/bzz-abi.ts

Lines changed: 0 additions & 46 deletions
This file was deleted.

src/utils/contracts.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
export const NETWORK_ID = 100
2+
3+
export const Contracts = {
4+
bzz: '0xdBF3Ea6F5beE45c02255B2c26a16F300502F68da',
5+
postageStamp: '0x45a1502382541Cd610CC9068e88727426b696293',
6+
}
7+
8+
export const ABI = {
9+
tokenProxy: [
10+
{
11+
type: 'function',
12+
stateMutability: 'nonpayable',
13+
payable: false,
14+
outputs: [{ type: 'bool', name: 'result' }],
15+
name: 'approve',
16+
inputs: [
17+
{ type: 'address', name: '_to' },
18+
{ type: 'uint256', name: '_value' },
19+
],
20+
constant: false,
21+
},
22+
],
23+
bzz: [
24+
{
25+
type: 'function',
26+
stateMutability: 'view',
27+
payable: false,
28+
outputs: [
29+
{
30+
type: 'uint256',
31+
name: '',
32+
},
33+
],
34+
name: 'balanceOf',
35+
inputs: [
36+
{
37+
type: 'address',
38+
name: '_owner',
39+
},
40+
],
41+
constant: true,
42+
},
43+
{
44+
type: 'function',
45+
stateMutability: 'nonpayable',
46+
payable: false,
47+
outputs: [
48+
{
49+
type: 'bool',
50+
name: '',
51+
},
52+
],
53+
name: 'transfer',
54+
inputs: [
55+
{
56+
type: 'address',
57+
name: '_to',
58+
},
59+
{
60+
type: 'uint256',
61+
name: '_value',
62+
},
63+
],
64+
constant: false,
65+
},
66+
],
67+
postageStamp: [
68+
{
69+
inputs: [
70+
{
71+
internalType: 'address',
72+
name: '_owner',
73+
type: 'address',
74+
},
75+
{
76+
internalType: 'uint256',
77+
name: '_initialBalancePerChunk',
78+
type: 'uint256',
79+
},
80+
{
81+
internalType: 'uint8',
82+
name: '_depth',
83+
type: 'uint8',
84+
},
85+
{
86+
internalType: 'uint8',
87+
name: '_bucketDepth',
88+
type: 'uint8',
89+
},
90+
{
91+
internalType: 'bytes32',
92+
name: '_nonce',
93+
type: 'bytes32',
94+
},
95+
{
96+
internalType: 'bool',
97+
name: '_immutable',
98+
type: 'bool',
99+
},
100+
],
101+
name: 'createBatch',
102+
outputs: [
103+
{
104+
internalType: 'bytes32',
105+
name: '',
106+
type: 'bytes32',
107+
},
108+
],
109+
stateMutability: 'nonpayable',
110+
type: 'function',
111+
},
112+
],
113+
}

0 commit comments

Comments
 (0)