Skip to content

Commit a8c4cc7

Browse files
committed
add contract package
1 parent 130c328 commit a8c4cc7

19 files changed

+5847
-2448
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"lerna": "4.0.0",
7070
"lint-staged": "^10.2.11",
7171
"prettier": "^2.0.5",
72+
"ts-node": "^10.2.1",
7273
"typescript": "~3.9.5"
7374
},
7475
"private": true

packages/contracts/.gitignore

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
9+
# Diagnostic reports (https://nodejs.org/api/report.html)
10+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
11+
12+
# Runtime data
13+
pids
14+
*.pid
15+
*.seed
16+
*.pid.lock
17+
18+
# Directory for instrumented libs generated by jscoverage/JSCover
19+
lib-cov
20+
21+
# Coverage directory used by tools like istanbul
22+
coverage
23+
*.lcov
24+
25+
# nyc test coverage
26+
.nyc_output
27+
28+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
29+
.grunt
30+
31+
# Bower dependency directory (https://bower.io/)
32+
bower_components
33+
34+
# node-waf configuration
35+
.lock-wscript
36+
37+
# Compiled binary addons (https://nodejs.org/api/addons.html)
38+
build/Release
39+
40+
# Dependency directories
41+
node_modules/
42+
jspm_packages/
43+
44+
# TypeScript v1 declaration files
45+
typings/
46+
47+
# TypeScript cache
48+
*.tsbuildinfo
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Microbundle cache
57+
.rpt2_cache/
58+
.rts2_cache_cjs/
59+
.rts2_cache_es/
60+
.rts2_cache_umd/
61+
62+
# Optional REPL history
63+
.node_repl_history
64+
65+
# Output of 'npm pack'
66+
*.tgz
67+
68+
# Yarn Integrity file
69+
.yarn-integrity
70+
71+
# dotenv environment variables file
72+
.env
73+
.env.test
74+
75+
# parcel-bundler cache (https://parceljs.org/)
76+
.cache
77+
78+
# Next.js build output
79+
.next
80+
81+
# Nuxt.js build / generate output
82+
.nuxt
83+
dist
84+
85+
# Gatsby files
86+
.cache/
87+
# Comment in the public line in if your project uses Gatsby and *not* Next.js
88+
# https://nextjs.org/blog/next-9-1#public-directory-support
89+
# public
90+
91+
# vuepress build output
92+
.vuepress/dist
93+
94+
# Serverless directories
95+
.serverless/
96+
97+
# FuseBox cache
98+
.fusebox/
99+
100+
# DynamoDB Local files
101+
.dynamodb/
102+
103+
# TernJS port file
104+
.tern-port
105+
106+
artifacts/
107+
cache/

packages/contracts/.prettierrc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"printWidth": 120,
3+
"singleQuote": true,
4+
"trailingComma": "all",
5+
"bracketSpacing": true,
6+
"arrowParens": "avoid",
7+
"semi": true,
8+
"useTabs": false,
9+
"tabWidth": 2
10+
}

packages/contracts/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 AMIS
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/contracts/README.md

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.13;
3+
4+
import '@openzeppelin/contracts/interfaces/IERC165.sol';
5+
6+
interface INativeMetaTransactionV1 is IERC165 {
7+
function executeMetaTransaction(
8+
address authorizer,
9+
bytes memory callData,
10+
uint8 v,
11+
bytes32 r,
12+
bytes32 s
13+
) external payable returns (bytes memory);
14+
15+
function getNonce(address authorizer) external view returns (uint256);
16+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.13;
3+
4+
import '@openzeppelin/contracts/interfaces/IERC165.sol';
5+
6+
interface INativeMetaTransactionV2 is IERC165 {
7+
function executeMetaTransaction(
8+
address relayer,
9+
address authorizer,
10+
bytes32 nonce,
11+
bytes memory callData,
12+
uint256 deadline,
13+
uint8 v,
14+
bytes32 r,
15+
bytes32 s
16+
) external payable returns (bytes memory);
17+
18+
function authorizationState(address authorizer, bytes32 nonce) external view returns (bool);
19+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.13;
3+
4+
import '@openzeppelin/contracts/interfaces/IERC165.sol';
5+
6+
interface INativeMetaTransactionV3 is IERC165 {
7+
function executeMetaTransaction(
8+
address relayer,
9+
address authorizer,
10+
bytes32 nonce,
11+
bytes memory callData,
12+
uint256 validAfter,
13+
uint256 validBefore,
14+
uint8 v,
15+
bytes32 r,
16+
bytes32 s
17+
) external payable returns (bytes memory);
18+
19+
function authorizationState(address authorizer, bytes32 nonce) external view returns (bool);
20+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.13;
3+
4+
import '@openzeppelin/contracts/utils/Context.sol';
5+
6+
import '../utils/EIP712.sol';
7+
import '../utils/EIP712Domain.sol';
8+
9+
abstract contract NativeMetaTransaction is Context, EIP712Domain {
10+
constructor(string memory name, string memory version) {
11+
domainData = DomainData(name, version, block.chainid, address(this));
12+
DOMAIN_SEPARATOR = EIP712.makeDomainSeparator(name, version);
13+
}
14+
15+
/**
16+
* @notice Check that function call is valid
17+
* @param callData The authorized function call
18+
*/
19+
function _requireValidFuntionCall(bytes memory callData) internal pure {
20+
if (callData.length == 0) {
21+
return;
22+
}
23+
24+
bytes4 sigHash;
25+
assembly {
26+
sigHash := mload(add(callData, 32))
27+
}
28+
29+
require(sigHash != msg.sig, 'NativeMetaTransaction: calling executeMetaTransaction is forbidden');
30+
}
31+
32+
function _msgSender() internal view virtual override returns (address sender) {
33+
if (msg.sender == address(this)) {
34+
bytes memory array = msg.data;
35+
uint256 index = msg.data.length;
36+
assembly {
37+
// Load the 32 bytes word from memory with the address on the lower 20 bytes, and mask those.
38+
sender := and(mload(add(array, index)), 0xffffffffffffffffffffffffffffffffffffffff)
39+
}
40+
} else {
41+
sender = msg.sender;
42+
}
43+
return sender;
44+
}
45+
46+
function _msgData() internal view virtual override returns (bytes calldata) {
47+
if (msg.sender == address(this)) {
48+
return msg.data[:msg.data.length - 20];
49+
} else {
50+
return msg.data;
51+
}
52+
}
53+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//SPDX-License-Identifier: MIT
2+
pragma solidity 0.8.13;
3+
4+
import '@openzeppelin/contracts/utils/math/SafeMath.sol';
5+
6+
import './NativeMetaTransaction.sol';
7+
import './INativeMetaTransactionV1.sol';
8+
9+
// Example typed data
10+
//
11+
// {
12+
// types: {
13+
// EIP712Domain: [
14+
// { name: "name", type: "string" },
15+
// { name: "version", type: "string" },
16+
// { name: "chainId", type: "uint256" },
17+
// { name: "verifyingContract", type: "address" },
18+
// ],
19+
// MetaTransaction: [
20+
// { name: "authorizer", type: "address" },
21+
// { name: "nonce", type: "uint256" },
22+
// { name: "callData", type: "bytes" },
23+
// ],
24+
// },
25+
// domain: {
26+
// name: "MetaTransaction",
27+
// version: "1",
28+
// chainId: 1,
29+
// verifyingContract: "0x1111111111111111111111111111111111111111",
30+
// },
31+
// primaryType: "MetaTransaction",
32+
// message: {
33+
// authorizer: authorizer.address,
34+
// nonce: 1
35+
// callData: "0x....",
36+
// },
37+
// }
38+
//
39+
contract NativeMetaTransactionV1 is NativeMetaTransaction, INativeMetaTransactionV1 {
40+
using SafeMath for uint256;
41+
42+
bytes32 private constant META_TRANSACTION_TYPEHASH =
43+
keccak256(bytes('MetaTransaction(address authorizer,uint256 nonce,bytes callData)'));
44+
45+
event MetaTransactionExecuted(address authorizer, address relayer, bytes callData);
46+
mapping(address => uint256) private nonces;
47+
48+
constructor(string memory name, string memory version) NativeMetaTransaction(name, version) {}
49+
50+
function executeMetaTransaction(
51+
address authorizer,
52+
bytes memory callData,
53+
uint8 v,
54+
bytes32 r,
55+
bytes32 s
56+
) public payable returns (bytes memory) {
57+
_requireValidAuthorization(authorizer, callData, v, r, s);
58+
59+
nonces[authorizer] = nonces[authorizer].add(1);
60+
61+
// Append authorizer at the end to extract it from calling context
62+
(bool success, bytes memory returnData) = address(this).call(abi.encodePacked(callData, authorizer));
63+
64+
require(success, 'NativeMetaTransaction: function call not successful');
65+
emit MetaTransactionExecuted(authorizer, msg.sender, callData);
66+
67+
return returnData;
68+
}
69+
70+
function getNonce(address authorizer) external view returns (uint256 nonce) {
71+
nonce = nonces[authorizer];
72+
}
73+
74+
/**
75+
* @notice Check that authorization is valid
76+
* @param authorizer User's address
77+
* @param callData The authorized function call
78+
* @param v v of the signature
79+
* @param r r of the signature
80+
* @param s s of the signature
81+
*/
82+
function _requireValidAuthorization(
83+
address authorizer,
84+
bytes memory callData,
85+
uint8 v,
86+
bytes32 r,
87+
bytes32 s
88+
) internal view {
89+
_requireValidFuntionCall(callData);
90+
91+
bytes memory data = abi.encode(META_TRANSACTION_TYPEHASH, authorizer, nonces[authorizer], keccak256(callData));
92+
93+
require(EIP712.recover(DOMAIN_SEPARATOR, v, r, s, data) == authorizer, 'NativeMetaTransaction: invalid signature');
94+
}
95+
96+
function supportsInterface(bytes4 interfaceId) external view virtual returns (bool) {
97+
return interfaceId == type(INativeMetaTransactionV1).interfaceId;
98+
}
99+
}

0 commit comments

Comments
 (0)