Commit a7e8ba99 authored by smartcontracts's avatar smartcontracts Committed by GitHub

Merge pull request #2079 from ethereum-optimism/sc/sdk-resend-message

feat(sdk): implement resendMessage
parents 1c6d89be 6812d26e
...@@ -14,6 +14,7 @@ import { ...@@ -14,6 +14,7 @@ import {
NumberLike, NumberLike,
MessageDirection, MessageDirection,
} from './interfaces' } from './interfaces'
import { omit } from './utils'
export class CrossChainMessenger implements ICrossChainMessenger { export class CrossChainMessenger implements ICrossChainMessenger {
provider: ICrossChainProvider provider: ICrossChainProvider
...@@ -43,6 +44,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -43,6 +44,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides?: L1ToL2Overrides overrides?: L1ToL2Overrides
): Promise<TransactionResponse> { ): Promise<TransactionResponse> {
const tx = await this.populateTransaction.sendMessage(message, overrides) const tx = await this.populateTransaction.sendMessage(message, overrides)
if (message.direction === MessageDirection.L1_TO_L2) { if (message.direction === MessageDirection.L1_TO_L2) {
return this.l1Signer.sendTransaction(tx) return this.l1Signer.sendTransaction(tx)
} else { } else {
...@@ -55,7 +57,13 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -55,7 +57,13 @@ export class CrossChainMessenger implements ICrossChainMessenger {
messageGasLimit: NumberLike, messageGasLimit: NumberLike,
overrides?: Overrides overrides?: Overrides
): Promise<TransactionResponse> { ): Promise<TransactionResponse> {
throw new Error('Not implemented') const tx = await this.populateTransaction.resendMessage(
message,
messageGasLimit,
overrides
)
return this.l1Signer.sendTransaction(tx)
} }
public async finalizeMessage( public async finalizeMessage(
...@@ -91,7 +99,8 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -91,7 +99,8 @@ export class CrossChainMessenger implements ICrossChainMessenger {
message.target, message.target,
message.message, message.message,
overrides?.l2GasLimit || overrides?.l2GasLimit ||
(await this.provider.estimateL2MessageGasLimit(message)) (await this.provider.estimateL2MessageGasLimit(message)),
omit(overrides || {}, 'l2GasLimit')
) )
} else { } else {
return this.provider.contracts.l2.L2CrossDomainMessenger.connect( return this.provider.contracts.l2.L2CrossDomainMessenger.connect(
...@@ -99,7 +108,8 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -99,7 +108,8 @@ export class CrossChainMessenger implements ICrossChainMessenger {
).populateTransaction.sendMessage( ).populateTransaction.sendMessage(
message.target, message.target,
message.message, message.message,
0 // Gas limit goes unused when sending from L2 to L1 0, // Gas limit goes unused when sending from L2 to L1
omit(overrides || {}, 'l2GasLimit')
) )
} }
}, },
...@@ -109,7 +119,22 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -109,7 +119,22 @@ export class CrossChainMessenger implements ICrossChainMessenger {
messageGasLimit: NumberLike, messageGasLimit: NumberLike,
overrides?: Overrides overrides?: Overrides
): Promise<TransactionRequest> => { ): Promise<TransactionRequest> => {
throw new Error('Not implemented') const resolved = await this.provider.toCrossChainMessage(message)
if (resolved.direction === MessageDirection.L2_TO_L1) {
throw new Error(`cannot resend L2 to L1 message`)
}
return this.provider.contracts.l1.L1CrossDomainMessenger.connect(
this.l1Signer
).populateTransaction.replayMessage(
resolved.target,
resolved.sender,
resolved.message,
resolved.messageNonce,
resolved.gasLimit,
messageGasLimit,
overrides || {}
)
}, },
finalizeMessage: async ( finalizeMessage: async (
...@@ -140,6 +165,7 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -140,6 +165,7 @@ export class CrossChainMessenger implements ICrossChainMessenger {
overrides?: L1ToL2Overrides overrides?: L1ToL2Overrides
): Promise<BigNumber> => { ): Promise<BigNumber> => {
const tx = await this.populateTransaction.sendMessage(message, overrides) const tx = await this.populateTransaction.sendMessage(message, overrides)
if (message.direction === MessageDirection.L1_TO_L2) { if (message.direction === MessageDirection.L1_TO_L2) {
return this.provider.l1Provider.estimateGas(tx) return this.provider.l1Provider.estimateGas(tx)
} else { } else {
...@@ -152,7 +178,13 @@ export class CrossChainMessenger implements ICrossChainMessenger { ...@@ -152,7 +178,13 @@ export class CrossChainMessenger implements ICrossChainMessenger {
messageGasLimit: NumberLike, messageGasLimit: NumberLike,
overrides?: Overrides overrides?: Overrides
): Promise<BigNumber> => { ): Promise<BigNumber> => {
throw new Error('Not implemented') const tx = await this.populateTransaction.resendMessage(
message,
messageGasLimit,
overrides
)
return this.provider.l1Provider.estimateGas(tx)
}, },
finalizeMessage: async ( finalizeMessage: async (
......
...@@ -134,6 +134,7 @@ export class CrossChainProvider implements ICrossChainProvider { ...@@ -134,6 +134,7 @@ export class CrossChainProvider implements ICrossChainProvider {
sender: parsed.args.sender, sender: parsed.args.sender,
message: parsed.args.message, message: parsed.args.message,
messageNonce: parsed.args.messageNonce, messageNonce: parsed.args.messageNonce,
gasLimit: parsed.args.gasLimit,
logIndex: log.logIndex, logIndex: log.logIndex,
blockNumber: log.blockNumber, blockNumber: log.blockNumber,
transactionHash: log.transactionHash, transactionHash: log.transactionHash,
......
...@@ -161,6 +161,7 @@ export interface CoreCrossChainMessage { ...@@ -161,6 +161,7 @@ export interface CoreCrossChainMessage {
*/ */
export interface CrossChainMessage extends CoreCrossChainMessage { export interface CrossChainMessage extends CoreCrossChainMessage {
direction: MessageDirection direction: MessageDirection
gasLimit: number
logIndex: number logIndex: number
blockNumber: number blockNumber: number
transactionHash: string transactionHash: string
......
...@@ -25,6 +25,24 @@ contract MockMessenger is ICrossDomainMessenger { ...@@ -25,6 +25,24 @@ contract MockMessenger is ICrossDomainMessenger {
nonce++; nonce++;
} }
function replayMessage(
address _target,
address _sender,
bytes calldata _message,
uint256 _queueIndex,
uint32 _oldGasLimit,
uint32 _newGasLimit
) public {
emit SentMessage(
_target,
_sender,
_message,
nonce,
_newGasLimit
);
nonce++;
}
struct SentMessageEventParams { struct SentMessageEventParams {
address target; address target;
address sender; address sender;
......
...@@ -118,12 +118,77 @@ describe('CrossChainMessenger', () => { ...@@ -118,12 +118,77 @@ describe('CrossChainMessenger', () => {
}) })
describe('resendMessage', () => { describe('resendMessage', () => {
describe('when the message being resent exists', () => { let l1Messenger: Contract
it('should resend the message with the new gas limit') let l2Messenger: Contract
let provider: CrossChainProvider
let messenger: CrossChainMessenger
beforeEach(async () => {
l1Messenger = (await (
await ethers.getContractFactory('MockMessenger')
).deploy()) as any
l2Messenger = (await (
await ethers.getContractFactory('MockMessenger')
).deploy()) as any
provider = new CrossChainProvider({
l1Provider: ethers.provider,
l2Provider: ethers.provider,
l1ChainId: 31337,
contracts: {
l1: {
L1CrossDomainMessenger: l1Messenger.address,
},
l2: {
L2CrossDomainMessenger: l2Messenger.address,
},
},
})
messenger = new CrossChainMessenger({
provider,
l1Signer,
l2Signer,
})
}) })
describe('when the message being resent does not exist', () => { describe('when resending an L1 to L2 message', () => {
it('should throw an error') it('should resend the message with the new gas limit', async () => {
const message = {
direction: MessageDirection.L1_TO_L2,
target: '0x' + '11'.repeat(20),
message: '0x' + '22'.repeat(32),
}
const sent = await messenger.sendMessage(message, {
l2GasLimit: 1234,
})
await expect(messenger.resendMessage(sent, 10000))
.to.emit(l1Messenger, 'SentMessage')
.withArgs(
message.target,
await l1Signer.getAddress(),
message.message,
1, // nonce is now 1
10000
)
})
})
describe('when resending an L2 to L1 message', () => {
it('should throw an error', async () => {
const message = {
direction: MessageDirection.L2_TO_L1,
target: '0x' + '11'.repeat(20),
message: '0x' + '22'.repeat(32),
}
const sent = await messenger.sendMessage(message, {
l2GasLimit: 1234,
})
await expect(messenger.resendMessage(sent, 10000)).to.be.rejected
})
}) })
}) })
......
...@@ -270,6 +270,7 @@ describe('CrossChainProvider', () => { ...@@ -270,6 +270,7 @@ describe('CrossChainProvider', () => {
target: message.target, target: message.target,
message: message.message, message: message.message,
messageNonce: ethers.BigNumber.from(message.messageNonce), messageNonce: ethers.BigNumber.from(message.messageNonce),
gasLimit: ethers.BigNumber.from(message.gasLimit),
logIndex: i, logIndex: i,
blockNumber: tx.blockNumber, blockNumber: tx.blockNumber,
transactionHash: tx.hash, transactionHash: tx.hash,
...@@ -321,6 +322,7 @@ describe('CrossChainProvider', () => { ...@@ -321,6 +322,7 @@ describe('CrossChainProvider', () => {
target: message.target, target: message.target,
message: message.message, message: message.message,
messageNonce: ethers.BigNumber.from(message.messageNonce), messageNonce: ethers.BigNumber.from(message.messageNonce),
gasLimit: ethers.BigNumber.from(message.gasLimit),
logIndex: i, logIndex: i,
blockNumber: tx.blockNumber, blockNumber: tx.blockNumber,
transactionHash: tx.hash, transactionHash: tx.hash,
...@@ -685,6 +687,7 @@ describe('CrossChainProvider', () => { ...@@ -685,6 +687,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1006,6 +1009,7 @@ describe('CrossChainProvider', () => { ...@@ -1006,6 +1009,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1036,6 +1040,7 @@ describe('CrossChainProvider', () => { ...@@ -1036,6 +1040,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1066,6 +1071,7 @@ describe('CrossChainProvider', () => { ...@@ -1066,6 +1071,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1101,6 +1107,7 @@ describe('CrossChainProvider', () => { ...@@ -1101,6 +1107,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1145,6 +1152,7 @@ describe('CrossChainProvider', () => { ...@@ -1145,6 +1152,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1176,6 +1184,7 @@ describe('CrossChainProvider', () => { ...@@ -1176,6 +1184,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
...@@ -1208,6 +1217,7 @@ describe('CrossChainProvider', () => { ...@@ -1208,6 +1217,7 @@ describe('CrossChainProvider', () => {
sender: '0x' + '22'.repeat(20), sender: '0x' + '22'.repeat(20),
message: '0x' + '33'.repeat(64), message: '0x' + '33'.repeat(64),
messageNonce: 1234, messageNonce: 1234,
gasLimit: 0,
logIndex: 0, logIndex: 0,
blockNumber: 1234, blockNumber: 1234,
transactionHash: '0x' + '44'.repeat(32), transactionHash: '0x' + '44'.repeat(32),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment