Skip to content

Commit

Permalink
Merge pull request #95 from CityOfZion/CU-86duf6qwu
Browse files Browse the repository at this point in the history
CU-86duf6qwu - Implement Send in bulk
  • Loading branch information
melanke authored Sep 9, 2024
2 parents 8e9e253 + 0d788f1 commit 4414e8c
Show file tree
Hide file tree
Showing 20 changed files with 444 additions and 166 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/blockchain-service",
"comment": "Add support to send in bulk",
"type": "minor"
}
],
"packageName": "@cityofzion/blockchain-service"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-ethereum",
"comment": "Add support to send in bulk",
"type": "minor"
}
],
"packageName": "@cityofzion/bs-ethereum"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo-legacy",
"comment": "Add support to send in bulk",
"type": "minor"
}
],
"packageName": "@cityofzion/bs-neo-legacy"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@cityofzion/bs-neo3",
"comment": "Add support to send in bulk",
"type": "minor"
}
],
"packageName": "@cityofzion/bs-neo3"
}
4 changes: 2 additions & 2 deletions packages/blockchain-service/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export type IntentTransferParam = {

export type TransferParam = {
senderAccount: Account
intent: IntentTransferParam
intents: IntentTransferParam[]
tipIntent?: IntentTransferParam
priorityFee?: string
isLedger?: boolean
Expand All @@ -54,7 +54,7 @@ export interface BlockchainService<BSCustomName extends string = string, BSAvail
validateAddress(address: string): boolean
validateEncrypted(keyOrJson: string): boolean
validateKey(key: string): boolean
transfer(param: TransferParam): Promise<string>
transfer(param: TransferParam): Promise<string[]>
}

export interface BSCalculableFee {
Expand Down
79 changes: 50 additions & 29 deletions packages/bs-ethereum/src/BSEthereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
BlockchainService,
ExchangeDataService,
ExplorerService,
IntentTransferParam,
Network,
NftDataService,
Token,
Expand Down Expand Up @@ -80,29 +81,28 @@ export class BSEthereum<BSCustomName extends string = string>
return new ethers.Wallet(account.key, provider)
}

async #buildTransferParams(param: TransferParam) {
const signer = await this.#generateSigner(param.senderAccount, param.isLedger)
if (!signer.provider) throw new Error('Signer must have provider')
async #buildTransferParams(intent: IntentTransferParam) {
const provider = new ethers.providers.JsonRpcProvider(this.network.url)

const decimals = param.intent.tokenDecimals ?? 18
const amount = ethersBigNumber.parseFixed(param.intent.amount, decimals)
const decimals = intent.tokenDecimals ?? 18
const amount = ethersBigNumber.parseFixed(intent.amount, decimals)

const gasPrice = await signer.provider.getGasPrice()
const gasPrice = await provider.getGasPrice()

let transactionParams: ethers.utils.Deferrable<ethers.providers.TransactionRequest> = {
type: 2,
}

const isNative =
BSEthereumHelper.normalizeHash(this.feeToken.hash) === BSEthereumHelper.normalizeHash(param.intent.tokenHash)
BSEthereumHelper.normalizeHash(this.feeToken.hash) === BSEthereumHelper.normalizeHash(intent.tokenHash)
if (isNative) {
transactionParams.to = param.intent.receiverAddress
transactionParams.to = intent.receiverAddress
transactionParams.value = amount
} else {
const contract = new ethers.Contract(param.intent.tokenHash, [
const contract = new ethers.Contract(intent.tokenHash, [
'function transfer(address to, uint amount) returns (bool)',
])
const populatedTransaction = await contract.populateTransaction.transfer(param.intent.receiverAddress, amount)
const populatedTransaction = await contract.populateTransaction.transfer(intent.receiverAddress, amount)
transactionParams = {
...populatedTransaction,
...transactionParams,
Expand All @@ -111,7 +111,6 @@ export class BSEthereum<BSCustomName extends string = string>

return {
transactionParams,
signer,
gasPrice,
}
}
Expand Down Expand Up @@ -210,30 +209,52 @@ export class BSEthereum<BSCustomName extends string = string>
return wallet.encrypt(password)
}

async transfer(param: TransferParam): Promise<string> {
const { signer, transactionParams, gasPrice } = await this.#buildTransferParams(param)
async transfer(param: TransferParam): Promise<string[]> {
const signer = await this.#generateSigner(param.senderAccount, param.isLedger)

let gasLimit: ethers.BigNumberish
try {
gasLimit = await signer.estimateGas(transactionParams)
} catch {
gasLimit = BSEthereumConstants.DEFAULT_GAS_LIMIT
const sentTransactionHashes: string[] = []

for (const intent of param.intents) {
try {
const { transactionParams, gasPrice } = await this.#buildTransferParams(intent)

let gasLimit: ethers.BigNumberish
try {
gasLimit = await signer.estimateGas(transactionParams)
} catch {
gasLimit = BSEthereumConstants.DEFAULT_GAS_LIMIT
}

const transaction = await signer.sendTransaction({
...transactionParams,
gasLimit,
maxPriorityFeePerGas: gasPrice,
maxFeePerGas: gasPrice,
})

sentTransactionHashes.push(transaction.hash)
} catch {
/* empty */
}
}

const transaction = await signer.sendTransaction({
...transactionParams,
gasLimit,
maxPriorityFeePerGas: gasPrice,
maxFeePerGas: gasPrice,
})

return transaction.hash
return sentTransactionHashes
}

async calculateTransferFee(param: TransferParam): Promise<string> {
const { signer, transactionParams, gasPrice } = await this.#buildTransferParams(param)
const estimated = await signer.estimateGas(transactionParams)
return ethers.utils.formatEther(gasPrice.mul(estimated))
const signer = await this.#generateSigner(param.senderAccount, param.isLedger)

let fee = ethers.utils.parseEther('0')

for (const intent of param.intents) {
const { gasPrice, transactionParams } = await this.#buildTransferParams(intent)
const estimated = await signer.estimateGas(transactionParams)
const intentFee = gasPrice.mul(estimated)

fee = fee.add(intentFee)
}

return ethers.utils.formatEther(fee)
}

async resolveNameServiceDomain(domainName: string): Promise<string> {
Expand Down
Loading

0 comments on commit 4414e8c

Please sign in to comment.