Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
N
nebula
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
exchain
nebula
Commits
b6f89fad
Unverified
Commit
b6f89fad
authored
Dec 07, 2021
by
Kelvin Fichter
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: add sdk utils and corresponding tests
parent
dc9d738a
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
337 additions
and
2 deletions
+337
-2
clever-bananas-look.md
.changeset/clever-bananas-look.md
+5
-0
Dockerfile.monorepo
ops/docker/Dockerfile.monorepo
+1
-0
TestLib_CrossDomainUtils.sol
...tracts/test-libraries/bridge/TestLib_CrossDomainUtils.sol
+20
-0
hardhat.config.ts
packages/sdk/hardhat.config.ts
+15
-0
package.json
packages/sdk/package.json
+3
-1
index.ts
packages/sdk/src/index.ts
+1
-0
types.ts
packages/sdk/src/interfaces/types.ts
+9
-1
utils.ts
packages/sdk/src/utils.ts
+86
-0
AbsolutelyNothing.sol
packages/sdk/test/contracts/AbsolutelyNothing.sol
+7
-0
MessageEncodingHelper.sol
packages/sdk/test/contracts/MessageEncodingHelper.sol
+42
-0
utils.spec.ts
packages/sdk/test/utils.spec.ts
+148
-0
No files found.
.changeset/clever-bananas-look.md
0 → 100644
View file @
b6f89fad
---
'
@eth-optimism/contracts'
:
patch
---
Adds a new TestLib_CrossDomainUtils so we can properly test cross chain encoding functions
ops/docker/Dockerfile.monorepo
View file @
b6f89fad
...
...
@@ -24,6 +24,7 @@ FROM node as builder
WORKDIR /optimism
COPY .git ./.git
COPY *.json yarn.lock ./
COPY packages/sdk/package.json ./packages/sdk/package.json
COPY packages/core-utils/package.json ./packages/core-utils/package.json
COPY packages/common-ts/package.json ./packages/common-ts/package.json
COPY packages/contracts/package.json ./packages/contracts/package.json
...
...
packages/contracts/contracts/test-libraries/bridge/TestLib_CrossDomainUtils.sol
0 → 100644
View file @
b6f89fad
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;
/* Library Imports */
import { Lib_CrossDomainUtils } from "../../libraries/bridge/Lib_CrossDomainUtils.sol";
/**
* @title TestLib_CrossDomainUtils
*/
library TestLib_CrossDomainUtils {
function encodeXDomainCalldata(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
) public pure returns (bytes memory) {
return
Lib_CrossDomainUtils.encodeXDomainCalldata(_target, _sender, _message, _messageNonce);
}
}
packages/sdk/hardhat.config.ts
0 → 100644
View file @
b6f89fad
import
{
HardhatUserConfig
}
from
'
hardhat/types
'
import
'
@nomiclabs/hardhat-ethers
'
import
'
@nomiclabs/hardhat-waffle
'
const
config
:
HardhatUserConfig
=
{
solidity
:
{
version
:
'
0.8.9
'
,
},
paths
:
{
sources
:
'
./test/contracts
'
,
},
}
export
default
config
packages/sdk/package.json
View file @
b6f89fad
...
...
@@ -14,7 +14,9 @@
"lint"
:
"yarn lint:fix && yarn lint:check"
,
"lint:check"
:
"eslint ."
,
"lint:fix"
:
"yarn lint:check --fix"
,
"pre-commit"
:
"lint-staged"
"pre-commit"
:
"lint-staged"
,
"test"
:
"hardhat test"
,
"test:coverage"
:
"nyc hardhat test && nyc merge .nyc_output coverage.json"
},
"keywords"
:
[
"optimism"
,
...
...
packages/sdk/src/index.ts
View file @
b6f89fad
export
*
from
'
./interfaces
'
export
*
from
'
./utils
'
packages/sdk/src/interfaces/types.ts
View file @
b6f89fad
...
...
@@ -106,6 +106,14 @@ export interface CrossChainMessage {
messageNonce
:
number
}
/**
* Convenience type for when you don't care which direction the message is going in.
*/
export
type
DirectionlessCrossChainMessage
=
Omit
<
CrossChainMessage
,
'
direction
'
>
/**
* Describes a token withdrawal or deposit, along with the underlying raw cross chain message
* behind the deposit or withdrawal.
...
...
@@ -188,7 +196,7 @@ export type MessageLike =
/**
* Stuff that can be coerced into a provider.
*/
export
type
ProviderLike
=
string
|
Provider
export
type
ProviderLike
=
string
|
Provider
|
any
/**
* Stuff that can be coerced into a signer.
...
...
packages/sdk/src/utils.ts
0 → 100644
View file @
b6f89fad
import
assert
from
'
assert
'
import
{
Provider
,
TransactionReceipt
,
TransactionResponse
,
}
from
'
@ethersproject/abstract-provider
'
import
{
getContractInterface
}
from
'
@eth-optimism/contracts
'
import
{
ethers
}
from
'
ethers
'
import
{
ProviderLike
,
TransactionLike
,
DirectionlessCrossChainMessage
,
}
from
'
./interfaces
'
/**
* Returns the canonical encoding of a cross chain message. This encoding is used in various
* locations within the Optimistic Ethereum smart contracts.
*
* @param message Cross chain message to encode.
* @returns Canonical encoding of the message.
*/
export
const
encodeCrossChainMessage
=
(
message
:
DirectionlessCrossChainMessage
):
string
=>
{
return
getContractInterface
(
'
L2CrossDomainMessenger
'
).
encodeFunctionData
(
'
relayMessage
'
,
[
message
.
target
,
message
.
sender
,
message
.
message
,
message
.
messageNonce
]
)
}
/**
* Returns the canonical hash of a cross chain message. This hash is used in various locations
* within the Optimistic Ethereum smart contracts and is the keccak256 hash of the result of
* encodeCrossChainMessage.
*
* @param message Cross chain message to hash.
* @returns Canonical hash of the message.
*/
export
const
hashCrossChainMessage
=
(
message
:
DirectionlessCrossChainMessage
):
string
=>
{
return
ethers
.
utils
.
solidityKeccak256
(
[
'
bytes
'
],
[
encodeCrossChainMessage
(
message
)]
)
}
/**
* Converts a ProviderLike into a provider. Assumes that if the ProviderLike is a string then
* it is a JSON-RPC url.
*
* @param provider ProviderLike to turn into a provider.
* @returns ProviderLike as a provider.
*/
export
const
toProvider
=
(
provider
:
ProviderLike
):
Provider
=>
{
if
(
typeof
provider
===
'
string
'
)
{
return
new
ethers
.
providers
.
JsonRpcProvider
(
provider
)
}
else
if
(
Provider
.
isProvider
(
provider
))
{
return
provider
}
else
{
throw
new
Error
(
'
Invalid provider
'
)
}
}
/**
* Pulls a transaction hash out of a TransactionLike object.
*
* @param transaction TransactionLike to convert into a transaction hash.
* @returns Transaction hash corresponding to the TransactionLike input.
*/
export
const
toTransactionHash
=
(
transaction
:
TransactionLike
):
string
=>
{
if
(
typeof
transaction
===
'
string
'
)
{
assert
(
ethers
.
utils
.
isHexString
(
transaction
,
32
),
'
Invalid transaction hash
'
)
return
transaction
}
else
if
((
transaction
as
TransactionReceipt
).
transactionHash
)
{
return
(
transaction
as
TransactionReceipt
).
transactionHash
}
else
if
((
transaction
as
TransactionResponse
).
hash
)
{
return
(
transaction
as
TransactionResponse
).
hash
}
else
{
throw
new
Error
(
'
Invalid transaction
'
)
}
}
packages/sdk/test/contracts/AbsolutelyNothing.sol
0 → 100644
View file @
b6f89fad
pragma solidity ^0.8.9;
contract AbsolutelyNothing {
function doAbsolutelyNothing() public {
return;
}
}
packages/sdk/test/contracts/MessageEncodingHelper.sol
0 → 100644
View file @
b6f89fad
pragma solidity ^0.8.9;
contract MessageEncodingHelper {
// This function is copy/pasted from the Lib_CrossDomainUtils library. We have to do this
// because the Lib_CrossDomainUtils library does not provide a function for hashing. Instead,
// I'm duplicating the functionality of the library here and exposing an additional method that
// does the required hashing. This is fragile and will break if we ever update the way that our
// contracts hash the encoded data, but at least it works for now.
// TODO: Next time we're planning to upgrade the contracts, make sure that the library also
// contains a function for hashing.
function encodeXDomainCalldata(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
) public pure returns (bytes memory) {
return
abi.encodeWithSignature(
"relayMessage(address,address,bytes,uint256)",
_target,
_sender,
_message,
_messageNonce
);
}
function hashXDomainCalldata(
address _target,
address _sender,
bytes memory _message,
uint256 _messageNonce
) public pure returns (bytes32) {
return keccak256(
encodeXDomainCalldata(
_target,
_sender,
_message,
_messageNonce
)
);
}
}
packages/sdk/test/utils.spec.ts
0 → 100644
View file @
b6f89fad
import
{
expect
}
from
'
./setup
'
import
{
Provider
}
from
'
@ethersproject/abstract-provider
'
import
{
Contract
,
Signer
}
from
'
ethers
'
import
{
ethers
}
from
'
hardhat
'
import
{
getContractFactory
}
from
'
@eth-optimism/contracts
'
import
{
toProvider
,
toTransactionHash
,
CrossChainMessage
,
MessageDirection
,
encodeCrossChainMessage
,
hashCrossChainMessage
,
}
from
'
../src
'
describe
(
'
utils
'
,
()
=>
{
let
signers
:
Signer
[]
before
(
async
()
=>
{
signers
=
(
await
ethers
.
getSigners
())
as
any
})
describe
(
'
encodeCrossChainMessage
'
,
()
=>
{
let
Lib_CrossDomainUtils
:
Contract
before
(
async
()
=>
{
Lib_CrossDomainUtils
=
(
await
getContractFactory
(
'
TestLib_CrossDomainUtils
'
,
signers
[
0
]
).
deploy
())
as
any
})
it
(
'
should properly encode a message
'
,
async
()
=>
{
const
message
:
CrossChainMessage
=
{
direction
:
MessageDirection
.
L1_TO_L2
,
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
1234
'
.
repeat
(
32
),
messageNonce
:
1234
,
}
const
actual
=
encodeCrossChainMessage
(
message
)
const
expected
=
await
Lib_CrossDomainUtils
.
encodeXDomainCalldata
(
message
.
target
,
message
.
sender
,
message
.
message
,
message
.
messageNonce
)
expect
(
actual
).
to
.
equal
(
expected
)
})
})
describe
(
'
hashCrossChainMessage
'
,
()
=>
{
let
MessageEncodingHelper
:
Contract
before
(
async
()
=>
{
MessageEncodingHelper
=
(
await
(
await
ethers
.
getContractFactory
(
'
MessageEncodingHelper
'
)
).
deploy
())
as
any
})
it
(
'
should properly hash a message
'
,
async
()
=>
{
const
message
:
CrossChainMessage
=
{
direction
:
MessageDirection
.
L1_TO_L2
,
target
:
'
0x
'
+
'
11
'
.
repeat
(
20
),
sender
:
'
0x
'
+
'
22
'
.
repeat
(
20
),
message
:
'
0x
'
+
'
1234
'
.
repeat
(
32
),
messageNonce
:
1234
,
}
const
actual
=
hashCrossChainMessage
(
message
)
const
expected
=
await
MessageEncodingHelper
.
hashXDomainCalldata
(
message
.
target
,
message
.
sender
,
message
.
message
,
message
.
messageNonce
)
expect
(
actual
).
to
.
equal
(
expected
)
})
})
describe
(
'
toProvider
'
,
()
=>
{
it
(
'
should convert a string to a JsonRpcProvider
'
,
()
=>
{
const
provider
=
toProvider
(
'
http://localhost:8545
'
)
expect
(
Provider
.
isProvider
(
provider
)).
to
.
be
.
true
})
it
(
'
should not do anything with a provider
'
,
()
=>
{
const
provider
=
toProvider
(
ethers
.
provider
)
expect
(
provider
).
to
.
deep
.
equal
(
ethers
.
provider
)
})
})
describe
(
'
toTransactionHash
'
,
()
=>
{
describe
(
'
string inputs
'
,
()
=>
{
it
(
'
should return the input if the input is a valid transaction hash
'
,
()
=>
{
const
input
=
'
0x
'
+
'
11
'
.
repeat
(
32
)
expect
(
toTransactionHash
(
input
)).
to
.
equal
(
input
)
})
it
(
'
should throw an error if the input is a hex string but not a transaction hash
'
,
()
=>
{
const
input
=
'
0x
'
+
'
11
'
.
repeat
(
31
)
expect
(()
=>
toTransactionHash
(
input
)).
to
.
throw
(
'
Invalid transaction hash
'
)
})
it
(
'
should throw an error if the input is not a hex string
'
,
()
=>
{
const
input
=
'
hi mom look at me go
'
expect
(()
=>
toTransactionHash
(
input
)).
to
.
throw
(
'
Invalid transaction hash
'
)
})
})
describe
(
'
transaction inputs
'
,
()
=>
{
let
AbsolutelyNothing
:
Contract
before
(
async
()
=>
{
AbsolutelyNothing
=
(
await
(
await
ethers
.
getContractFactory
(
'
AbsolutelyNothing
'
)
).
deploy
())
as
any
})
it
(
'
should return the transaction hash if the input is a transaction response
'
,
async
()
=>
{
const
tx
=
await
AbsolutelyNothing
.
doAbsolutelyNothing
()
expect
(
toTransactionHash
(
tx
)).
to
.
equal
(
tx
.
hash
)
})
it
(
'
should return the transaction hash if the input is a transaction receipt
'
,
async
()
=>
{
const
tx
=
await
AbsolutelyNothing
.
doAbsolutelyNothing
()
const
receipt
=
await
tx
.
wait
()
expect
(
toTransactionHash
(
receipt
)).
to
.
equal
(
receipt
.
transactionHash
)
})
})
describe
(
'
other types
'
,
()
=>
{
it
(
'
should throw if given a number as an input
'
,
()
=>
{
expect
(()
=>
toTransactionHash
(
1234
as
any
)).
to
.
throw
(
'
Invalid transaction
'
)
})
it
(
'
should throw if given a function as an input
'
,
()
=>
{
expect
(()
=>
toTransactionHash
((()
=>
{
return
1234
})
as
any
)
).
to
.
throw
(
'
Invalid transaction
'
)
})
})
})
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment