Skip to content

Commit

Permalink
feat: Ether Custodian Proxy (#97)
Browse files Browse the repository at this point in the history
* use proxy for creating transactions

* use proxy for withdraw tx

* scan ETH transactions with proxy

* update ethCustodian for aurora-ether

* Commit `.yarn/version`

* Fix release strategy

* filter by Proxy Deposited event

* track events from both proxy and eth custodian contract

* fix types

* fix: Recover with proxy transactions.

* fix: Handle null event.

---------

Co-authored-by: karim-en <[email protected]>
Co-authored-by: paouvrard <[email protected]>
  • Loading branch information
3 people authored Jul 4, 2024
1 parent 3287c5c commit 19bae80
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 61 deletions.
10 changes: 10 additions & 0 deletions .yarn/versions/9dcc50ee.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
releases:
"@near-eth/aurora-ether": minor
"@near-eth/near-ether": minor
"@near-eth/rainbow": minor
rainbow-bridge-client-monorepo: minor

declined:
- "@near-eth/aurora-erc20"
- "@near-eth/aurora-nep141"
- "@near-eth/nep141-erc20"
14 changes: 4 additions & 10 deletions packages/aurora-ether/src/bridged-ether/sendToEthereum/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ export interface TransferOptions {
provider?: ethers.providers.Provider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
sendToEthereumSyncInterval?: number
ethChainId?: number
auroraChainId?: string
Expand Down Expand Up @@ -292,14 +294,6 @@ export async function recover (
nearBurnReceipt = await parseETHBurnReceipt(burnTx, auroraEvmAccount, nearProvider)
amount = nearBurnReceipt.event.amount
recipient = nearBurnReceipt.event.recipient
const etherCustodian: string = nearBurnReceipt.event.etherCustodian
const etherCustodianAddress: string = options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress
if (etherCustodian.toLowerCase() !== etherCustodianAddress.toLowerCase()) {
throw new Error(
`Unexpected ether custodian: got ${etherCustodian},
expected ${etherCustodianAddress}`
)
}
}
// A silo might not use ETH as its base currency.
const symbol = options.symbol ?? 'ETH'
Expand Down Expand Up @@ -811,8 +805,8 @@ export async function unlock (
const borshProof = borshifyOutcomeProof(proof)

const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi,
options.signer ?? provider.getSigner()
)
// If this tx is dropped and replaced, lower the search boundary
Expand Down
53 changes: 33 additions & 20 deletions packages/aurora-ether/src/natural-ether/sendToAurora/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,22 +165,36 @@ export async function findAllTransactions (
provider?: ethers.providers.Provider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
auroraEvmAccount?: string
}
}
): Promise<string[]> {
options = options ?? {}
const bridgeParams = getBridgeParams()
const provider = options.provider ?? getEthProvider()
const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!(sender)
const events = await ethTokenLocker.queryFilter(filter, fromBlock, toBlock)
const etherCustodians: Array<[string, string]> = [
[options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi],
[options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi]
]
const auroraAddress = options.auroraEvmAccount ?? bridgeParams.auroraEvmAccount as string + ':'
return events.filter(event => event.args!.recipient.startsWith(auroraAddress)).map(event => event.transactionHash)

const promises = etherCustodians.map(async ([ethCustodianAddress, ethCustodianAbi]) => {
const ethTokenLocker = new ethers.Contract(
ethCustodianAddress,
ethCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!(sender)
const events = await ethTokenLocker.queryFilter(filter, fromBlock, toBlock)
return events.filter(event => event.args!.recipient.startsWith(auroraAddress)).map(event => event.transactionHash)
})

const transactions = await Promise.all(promises)
return transactions.flat()
}

export async function findAllTransfers (
Expand Down Expand Up @@ -216,9 +230,8 @@ export async function recover (
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!()
const events = await ethTokenLocker.queryFilter(filter, receipt.blockNumber, receipt.blockNumber)
const lockedEvent = events.find(event => event.transactionHash === lockTxHash)
const events = receipt.logs.map(log => ethTokenLocker.interface.parseLog(log))
const lockedEvent = last(events.filter(event => event?.name === 'Deposited'))
if (!lockedEvent) {
throw new Error('Unable to process lock transaction event.')
}
Expand All @@ -238,7 +251,7 @@ export async function recover (
const destinationTokenName = 'a' + symbol
const decimals = 18

const txBlock = await lockedEvent.getBlock()
const txBlock = await provider.getBlock(receipt.blockNumber)

const transfer = {
...transferDraft,
Expand Down Expand Up @@ -276,8 +289,8 @@ export async function recover (
* @param params.options.sender Sender of tokens (defaults to the connected wallet address).
* @param params.options.ethChainId Ethereum chain id of the bridge.
* @param params.options.provider Ethereum provider to use.
* @param params.options.etherCustodianAddress Rainbow bridge ether custodian address.
* @param params.options.etherCustodianAbi Rainbow bridge ether custodian abi.
* @param params.options.etherCustodianProxyAddress Rainbow bridge ether custodian proxy address.
* @param params.options.etherCustodianProxyAbi Rainbow bridge ether custodian proxy abi.
* @param params.options.auroraEvmAccount Aurora Cloud silo account on NEAR.
* @param params.options.signer Ethers signer to use.
* @returns The created transfer object.
Expand All @@ -292,8 +305,8 @@ export async function initiate (
sender?: string
ethChainId?: number
provider?: ethers.providers.JsonRpcProvider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
auroraEvmAccount?: string
signer?: ethers.Signer
}
Expand Down Expand Up @@ -345,8 +358,8 @@ export async function lock (
options?: {
provider?: ethers.providers.JsonRpcProvider
ethChainId?: number
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
auroraEvmAccount?: string
signer?: ethers.Signer
}
Expand All @@ -365,8 +378,8 @@ export async function lock (
}

const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi,
options.signer ?? provider.getSigner()
)

Expand Down
15 changes: 4 additions & 11 deletions packages/near-ether/src/bridged-ether/sendToEthereum/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export interface TransferOptions {
provider?: ethers.providers.Provider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
sendToEthereumSyncInterval?: number
ethChainId?: number
nearAccount?: Account
Expand Down Expand Up @@ -292,15 +294,6 @@ export async function recover (
const withdrawReceipt = await parseETHBurnReceipt(burnTx, auroraEvmAccount, nearProvider)
const amount = withdrawReceipt.event.amount
const recipient = withdrawReceipt.event.recipient
const etherCustodian: string = withdrawReceipt.event.etherCustodian

const etherCustodianAddress: string = options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress
if (etherCustodian.toLowerCase() !== etherCustodianAddress.toLowerCase()) {
throw new Error(
`Unexpected ether custodian: got ${etherCustodian},
expected ${etherCustodianAddress}`
)
}
const symbol = 'ETH'
const destinationTokenName = symbol
const sourceTokenName = 'n' + symbol
Expand Down Expand Up @@ -817,8 +810,8 @@ export async function unlock (
const borshProof = borshifyOutcomeProof(proof)

const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi,
options.signer ?? provider.getSigner()
)
// If this tx is dropped and replaced, lower the search boundary
Expand Down
54 changes: 34 additions & 20 deletions packages/near-ether/src/natural-ether/sendToNear/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,20 +188,35 @@ export async function findAllTransactions (
provider?: ethers.providers.Provider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
}
}
): Promise<string[]> {
options = options ?? {}
const bridgeParams = getBridgeParams()
const provider = options.provider ?? getEthProvider()
const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!(sender)
const events = await ethTokenLocker.queryFilter(filter, fromBlock, toBlock)
return events.filter(event => !event.args!.recipient.startsWith('aurora:')).map(event => event.transactionHash)

const etherCustodians: Array<[string, string]> = [
[options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi],
[options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi]
]

const promises = etherCustodians.map(async ([ethCustodianAddress, ethCustodianAbi]) => {
const ethTokenLocker = new ethers.Contract(
ethCustodianAddress,
ethCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!(sender)
const events = await ethTokenLocker.queryFilter(filter, fromBlock, toBlock)
return events.filter(event => !event.args!.recipient.startsWith('aurora:')).map(event => event.transactionHash)
})

const transactions = await Promise.all(promises)
return transactions.flat()
}

/**
Expand Down Expand Up @@ -246,9 +261,8 @@ export async function recover (
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
provider
)
const filter = ethTokenLocker.filters.Deposited!()
const events = await ethTokenLocker.queryFilter(filter, receipt.blockNumber, receipt.blockNumber)
const lockedEvent = events.find(event => event.transactionHash === lockTxHash)
const events = receipt.logs.map(log => ethTokenLocker.interface.parseLog(log))
const lockedEvent = last(events.filter(event => event?.name === 'Deposited'))
if (!lockedEvent) {
throw new Error('Unable to process lock transaction event.')
}
Expand All @@ -261,7 +275,7 @@ export async function recover (
const destinationTokenName = 'n' + symbol
const decimals = 18

const txBlock = await lockedEvent.getBlock()
const txBlock = await provider.getBlock(receipt.blockNumber)

const transfer = {
...transferDraft,
Expand Down Expand Up @@ -298,8 +312,8 @@ export async function recover (
* @param params.options.sender Sender of tokens (defaults to the connected wallet address).
* @param params.options.ethChainId Ethereum chain id of the bridge.
* @param params.options.provider Ethereum provider to use.
* @param params.options.etherCustodianAddress Rainbow bridge ether custodian address.
* @param params.options.etherCustodianAbi Rainbow bridge ether custodian abi.
* @param params.options.etherCustodianProxyAddress Rainbow bridge ether custodian proxy address.
* @param params.options.etherCustodianProxyAbi Rainbow bridge ether custodian proxy abi.
* @param params.options.signer Ethers signer to use.
* @returns The created transfer object.
*/
Expand All @@ -313,8 +327,8 @@ export async function initiate (
sender?: string
ethChainId?: number
provider?: ethers.providers.JsonRpcProvider
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
signer?: ethers.Signer
}
}
Expand Down Expand Up @@ -363,8 +377,8 @@ export async function lock (
options?: {
provider?: ethers.providers.JsonRpcProvider
ethChainId?: number
etherCustodianAddress?: string
etherCustodianAbi?: string
etherCustodianProxyAddress?: string
etherCustodianProxyAbi?: string
signer?: ethers.Signer
}
): Promise<Transfer> {
Expand All @@ -382,8 +396,8 @@ export async function lock (
}

const ethTokenLocker = new ethers.Contract(
options.etherCustodianAddress ?? bridgeParams.etherCustodianAddress,
options.etherCustodianAbi ?? bridgeParams.etherCustodianAbi,
options.etherCustodianProxyAddress ?? bridgeParams.etherCustodianProxyAddress,
options.etherCustodianProxyAbi ?? bridgeParams.etherCustodianProxyAbi,
options.signer ?? provider.getSigner()
)

Expand Down

0 comments on commit 19bae80

Please sign in to comment.