├── .gitignore ├── LICENSE ├── README.md ├── contracts ├── ExampleERC20.sol ├── MockContract.sol ├── NFT.sol └── Storage.sol ├── hardhat.config.ts ├── package.json ├── scripts ├── deploy.ts ├── erc20.ts ├── example.js ├── fund-cchain-addresses.js ├── nft.ts ├── sendAvaxJSONProvider.ts ├── sendAvaxWalletSigner.ts └── storage.ts ├── setup.js ├── test └── Coin.js ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | 3 | /.idea 4 | *.tsbuildinfo 5 | 6 | .DS_Store 7 | 8 | # Logs 9 | logs 10 | *.log 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | node_modules/ 16 | .env* 17 | !.env*.default 18 | .vscode/* 19 | !.vscode/settings.json.default 20 | 21 | cache/ 22 | artifacts/ 23 | 24 | .yalc 25 | yalc.lock 26 | 27 | # Logs 28 | logs 29 | *.log 30 | npm-debug.log* 31 | yarn-debug.log* 32 | yarn-error.log* 33 | lerna-debug.log* 34 | .pnpm-debug.log* 35 | 36 | # Diagnostic reports (https://nodejs.org/api/report.html) 37 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 38 | 39 | # Runtime data 40 | pids 41 | *.pid 42 | *.seed 43 | *.pid.lock 44 | 45 | # Directory for instrumented libs generated by jscoverage/JSCover 46 | lib-cov 47 | 48 | # Coverage directory used by tools like istanbul 49 | coverage 50 | *.lcov 51 | 52 | # nyc test coverage 53 | .nyc_output 54 | 55 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 56 | .grunt 57 | 58 | # Bower dependency directory (https://bower.io/) 59 | bower_components 60 | 61 | # node-waf configuration 62 | .lock-wscript 63 | 64 | # Compiled binary addons (https://nodejs.org/api/addons.html) 65 | build/Release 66 | 67 | # Dependency directories 68 | node_modules/ 69 | jspm_packages/ 70 | 71 | # Snowpack dependency directory (https://snowpack.dev/) 72 | web_modules/ 73 | 74 | # TypeScript cache 75 | *.tsbuildinfo 76 | 77 | # Optional npm cache directory 78 | .npm 79 | 80 | # Optional eslint cache 81 | .eslintcache 82 | 83 | # Microbundle cache 84 | .rpt2_cache/ 85 | .rts2_cache_cjs/ 86 | .rts2_cache_es/ 87 | .rts2_cache_umd/ 88 | 89 | # Optional REPL history 90 | .node_repl_history 91 | 92 | # Output of 'npm pack' 93 | *.tgz 94 | 95 | # Yarn Integrity file 96 | .yarn-integrity 97 | 98 | # dotenv environment variables file 99 | .env 100 | .env.test 101 | .env.production 102 | 103 | # parcel-bundler cache (https://parceljs.org/) 104 | .cache 105 | .parcel-cache 106 | 107 | # Next.js build output 108 | .next 109 | out 110 | 111 | # Nuxt.js build / generate output 112 | .nuxt 113 | dist 114 | 115 | # Gatsby files 116 | .cache/ 117 | # Comment in the public line in if your project uses Gatsby and not Next.js 118 | # https://nextjs.org/blog/next-9-1#public-directory-support 119 | # public 120 | 121 | # vuepress build output 122 | .vuepress/dist 123 | 124 | # Serverless directories 125 | .serverless/ 126 | 127 | # FuseBox cache 128 | .fusebox/ 129 | 130 | # DynamoDB Local files 131 | .dynamodb/ 132 | 133 | # TernJS port file 134 | .tern-port 135 | 136 | # Stores VSCode versions used for testing VSCode extensions 137 | .vscode-test 138 | 139 | # yarn v2 140 | .yarn/cache 141 | .yarn/unplugged 142 | .yarn/build-state.yml 143 | .yarn/install-state.gz 144 | .pnp.* 145 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Ava Labs, Inc. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Avalanche is an open-source platform for launching decentralized applications and enterprise blockchain deployments in one interoperable, highly scalable ecosystem. Avalanche gives you complete control on both the network and application layers—helping you build anything you can imagine. 4 | 5 | The Avalanche Network is composed of many blockchains. One of these blockchains is the C-Chain (Contract Chain), which is an Ethereum Virtual Machine instance. The C-Chain's API is almost identical to an Ethereum node's API. Avalanche offers the same interface as Ethereum but with higher speed, higher throughput, lower fees and lower transaction confirmation times. These properties considerably improve the performance of DApps and the user experience of smart contracts. 6 | 7 | The goal of this guide is to lay out best practices regarding writing, testing and deployment of smart contracts to Avalanche's C-Chain. We'll be building smart contracts with development environment [Hardhat](https://hardhat.org). 8 | 9 | ## Prerequisites 10 | 11 | ### NodeJS and Yarn 12 | 13 | First, install the LTS (long-term support) version of [nodejs](https://nodejs.org/en). This is `14.17.0` at the time of writing. NodeJS bundles `npm`. 14 | 15 | Next, install [yarn](https://yarnpkg.com): 16 | 17 | ```zsh 18 | npm install -g yarn 19 | ``` 20 | 21 | ### AvalancheGo and Avash 22 | 23 | [AvalancheGo](https://github.com/ava-labs/avalanchego) is an Avalanche node implementation written in Go. [Avash](https://docs.avax.network/build/tools/avash) is a tool to quickly deploy local test networks. Together, you can deploy local test networks and run tests on them. 24 | 25 | ### Solidity and Avalanche 26 | 27 | It is also helpful to have a basic understanding of [Solidity](https://docs.soliditylang.org) and [Avalanche](https://docs.avax.network). 28 | 29 | ## Dependencies 30 | 31 | Clone the [quickstart repository](https://github.com/ava-labs/avalanche-smart-contract-quickstart) and install the necessary packages via `yarn`. 32 | 33 | ```zsh 34 | $ git clone https://github.com/ava-labs/avalanche-smart-contract-quickstart.git 35 | $ cd avalanche-smart-contract-quickstart 36 | $ yarn 37 | ``` 38 | 39 | ## Write Contracts 40 | 41 | Edit the `Coin.sol` contract in `contracts/`. `Coin.sol` is an [Open Zeppelin](https://openzeppelin.com) [ERC20](https://eips.ethereum.org/EIPS/eip-20) contract. ERC20 is a popular smart contract interface. You can also add your own contracts. 42 | 43 | ## Hardhat Config 44 | 45 | Hardhat uses `hardhat.config.js` as the configuration file. You can define tasks, networks, compilers and more in that file. For more information see [here](https://hardhat.org/config/). 46 | 47 | In our repository we use a pre-configured file [hardhat.config.ts](https://github.com/ava-labs/avalanche-smart-contract-quickstart/blob/main/hardhat.config.ts). This file configures necessary network information to provide smooth interaction with Avalanche. There are also some pre-defined private keys for testing on a local test network. 48 | 49 | ## Hardhat Tasks 50 | 51 | You can define custom hardhat tasks in [hardhat.config.ts](https://github.com/ava-labs/avalanche-smart-contract-quickstart/blob/main/hardhat.config.ts). 52 | 53 | ## Documentation 54 | 55 | There is a documentation under the Avalanche's official documentation repository: 56 | [Using Hardhat with the Avalanche C-Chain](https://docs.avax.network/build/tutorials/smart-contracts/using-hardhat-with-the-avalanche-c-chain) -------------------------------------------------------------------------------- /contracts/ExampleERC20.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.2; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | import "@openzeppelin/contracts/access/Ownable.sol"; 6 | 7 | contract ExampleERC20 is ERC20, Ownable { 8 | string private TOKEN_NAME = "Example ERC20 Token"; 9 | string private TOKEN_SYMBOL = "XMPL"; 10 | 11 | uint256 private constant TOTAL_SUPPLY = 123456789; 12 | 13 | constructor()ERC20(TOKEN_NAME, TOKEN_SYMBOL) { 14 | _mint(msg.sender, TOTAL_SUPPLY); 15 | } 16 | 17 | function mint(address to, uint256 amount) public onlyOwner { 18 | _mint(to, amount); 19 | } 20 | 21 | function burn(address from, uint256 amount) public onlyOwner { 22 | _burn(from, amount); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /contracts/MockContract.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.4; 3 | 4 | /////////////////////////////////////////////// 5 | // This contract is taken from Gnosis and is 6 | // used to facilitate unit testing. It should 7 | // not be deployed in production. 8 | /////////////////////////////////////////////// 9 | 10 | interface MockInterface { 11 | /** 12 | * @dev After calling this method, the mock will return `response` when it is called 13 | * with any calldata that is not mocked more specifically below 14 | * (e.g. using givenMethodReturn). 15 | * @param response ABI encoded response that will be returned if method is invoked 16 | */ 17 | function givenAnyReturn(bytes calldata response) external; 18 | 19 | function givenAnyReturnBool(bool response) external; 20 | 21 | function givenAnyReturnUint(uint256 response) external; 22 | 23 | function givenAnyReturnAddress(address response) external; 24 | 25 | function givenAnyRevert() external; 26 | 27 | function givenAnyRevertWithMessage(string calldata message) external; 28 | 29 | function givenAnyRunOutOfGas() external; 30 | 31 | /** 32 | * @dev After calling this method, the mock will return `response` when the given 33 | * methodId is called regardless of arguments. If the methodId and arguments 34 | * are mocked more specifically (using `givenMethodAndArguments`) the latter 35 | * will take precedence. 36 | * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it 37 | * @param response ABI encoded response that will be returned if method is invoked 38 | */ 39 | function givenMethodReturn(bytes calldata method, bytes calldata response) 40 | external; 41 | 42 | function givenMethodReturnBool(bytes calldata method, bool response) external; 43 | 44 | function givenMethodReturnUint(bytes calldata method, uint256 response) 45 | external; 46 | 47 | function givenMethodReturnAddress(bytes calldata method, address response) 48 | external; 49 | 50 | function givenMethodRevert(bytes calldata method) external; 51 | 52 | function givenMethodRevertWithMessage( 53 | bytes calldata method, 54 | string calldata message 55 | ) external; 56 | 57 | function givenMethodRunOutOfGas(bytes calldata method) external; 58 | 59 | /** 60 | * @dev After calling this method, the mock will return `response` when the given 61 | * methodId is called with matching arguments. These exact calldataMocks will take 62 | * precedence over all other calldataMocks. 63 | * @param call ABI encoded calldata (methodId and arguments) 64 | * @param response ABI encoded response that will be returned if contract is invoked with calldata 65 | */ 66 | function givenCalldataReturn(bytes calldata call, bytes calldata response) 67 | external; 68 | 69 | function givenCalldataReturnBool(bytes calldata call, bool response) external; 70 | 71 | function givenCalldataReturnUint(bytes calldata call, uint256 response) 72 | external; 73 | 74 | function givenCalldataReturnAddress(bytes calldata call, address response) 75 | external; 76 | 77 | function givenCalldataRevert(bytes calldata call) external; 78 | 79 | function givenCalldataRevertWithMessage( 80 | bytes calldata call, 81 | string calldata message 82 | ) external; 83 | 84 | function givenCalldataRunOutOfGas(bytes calldata call) external; 85 | 86 | /** 87 | * @dev Returns the number of times anything has been called on this mock since last reset 88 | */ 89 | function invocationCount() external returns (uint256); 90 | 91 | /** 92 | * @dev Returns the number of times the given method has been called on this mock since last reset 93 | * @param method ABI encoded methodId. It is valid to pass full calldata (including arguments). The mock will extract the methodId from it 94 | */ 95 | function invocationCountForMethod(bytes calldata method) 96 | external 97 | returns (uint256); 98 | 99 | /** 100 | * @dev Returns the number of times this mock has been called with the exact calldata since last reset. 101 | * @param call ABI encoded calldata (methodId and arguments) 102 | */ 103 | function invocationCountForCalldata(bytes calldata call) 104 | external 105 | returns (uint256); 106 | 107 | /** 108 | * @dev Resets all mocked methods and invocation counts. 109 | */ 110 | function reset() external; 111 | } 112 | 113 | /** 114 | * Implementation of the MockInterface. 115 | */ 116 | contract MockContract is MockInterface { 117 | enum MockType { 118 | Return, 119 | Revert, 120 | OutOfGas 121 | } 122 | 123 | bytes32 public constant MOCKS_LIST_START = hex"01"; 124 | bytes public constant MOCKS_LIST_END = "0xff"; 125 | bytes32 public constant MOCKS_LIST_END_HASH = keccak256(MOCKS_LIST_END); 126 | bytes4 public constant SENTINEL_ANY_MOCKS = hex"01"; 127 | bytes public constant DEFAULT_FALLBACK_VALUE = abi.encode(false); 128 | 129 | // A linked list allows easy iteration and inclusion checks 130 | mapping(bytes32 => bytes) calldataMocks; 131 | mapping(bytes => MockType) calldataMockTypes; 132 | mapping(bytes => bytes) calldataExpectations; 133 | mapping(bytes => string) calldataRevertMessage; 134 | mapping(bytes32 => uint256) calldataInvocations; 135 | 136 | mapping(bytes4 => bytes4) methodIdMocks; 137 | mapping(bytes4 => MockType) methodIdMockTypes; 138 | mapping(bytes4 => bytes) methodIdExpectations; 139 | mapping(bytes4 => string) methodIdRevertMessages; 140 | mapping(bytes32 => uint256) methodIdInvocations; 141 | 142 | MockType fallbackMockType; 143 | bytes fallbackExpectation = DEFAULT_FALLBACK_VALUE; 144 | string fallbackRevertMessage; 145 | uint256 invocations; 146 | uint256 resetCount; 147 | 148 | constructor() public { 149 | calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; 150 | methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; 151 | } 152 | 153 | function trackCalldataMock(bytes memory call) private { 154 | bytes32 callHash = keccak256(call); 155 | if (calldataMocks[callHash].length == 0) { 156 | calldataMocks[callHash] = calldataMocks[MOCKS_LIST_START]; 157 | calldataMocks[MOCKS_LIST_START] = call; 158 | } 159 | } 160 | 161 | function trackMethodIdMock(bytes4 methodId) private { 162 | if (methodIdMocks[methodId] == 0x0) { 163 | methodIdMocks[methodId] = methodIdMocks[SENTINEL_ANY_MOCKS]; 164 | methodIdMocks[SENTINEL_ANY_MOCKS] = methodId; 165 | } 166 | } 167 | 168 | function _givenAnyReturn(bytes memory response) internal { 169 | fallbackMockType = MockType.Return; 170 | fallbackExpectation = response; 171 | } 172 | 173 | function givenAnyReturn(bytes calldata response) external override { 174 | _givenAnyReturn(response); 175 | } 176 | 177 | function givenAnyReturnBool(bool response) external override { 178 | uint256 flag = response ? 1 : 0; 179 | _givenAnyReturn(uintToBytes(flag)); 180 | } 181 | 182 | function givenAnyReturnUint(uint256 response) external override { 183 | _givenAnyReturn(uintToBytes(response)); 184 | } 185 | 186 | function givenAnyReturnAddress(address response) external override { 187 | _givenAnyReturn(uintToBytes(uint256(response))); 188 | } 189 | 190 | function givenAnyRevert() external override { 191 | fallbackMockType = MockType.Revert; 192 | fallbackRevertMessage = ""; 193 | } 194 | 195 | function givenAnyRevertWithMessage(string calldata message) 196 | external 197 | override 198 | { 199 | fallbackMockType = MockType.Revert; 200 | fallbackRevertMessage = message; 201 | } 202 | 203 | function givenAnyRunOutOfGas() external override { 204 | fallbackMockType = MockType.OutOfGas; 205 | } 206 | 207 | function _givenCalldataReturn(bytes memory call, bytes memory response) 208 | private 209 | { 210 | calldataMockTypes[call] = MockType.Return; 211 | calldataExpectations[call] = response; 212 | trackCalldataMock(call); 213 | } 214 | 215 | function givenCalldataReturn(bytes calldata call, bytes calldata response) 216 | external 217 | override 218 | { 219 | _givenCalldataReturn(call, response); 220 | } 221 | 222 | function givenCalldataReturnBool(bytes calldata call, bool response) 223 | external 224 | override 225 | { 226 | uint256 flag = response ? 1 : 0; 227 | _givenCalldataReturn(call, uintToBytes(flag)); 228 | } 229 | 230 | function givenCalldataReturnUint(bytes calldata call, uint256 response) 231 | external 232 | override 233 | { 234 | _givenCalldataReturn(call, uintToBytes(response)); 235 | } 236 | 237 | function givenCalldataReturnAddress(bytes calldata call, address response) 238 | external 239 | override 240 | { 241 | _givenCalldataReturn(call, uintToBytes(uint256(response))); 242 | } 243 | 244 | function _givenMethodReturn(bytes memory call, bytes memory response) 245 | private 246 | { 247 | bytes4 method = bytesToBytes4(call); 248 | methodIdMockTypes[method] = MockType.Return; 249 | methodIdExpectations[method] = response; 250 | trackMethodIdMock(method); 251 | } 252 | 253 | function givenMethodReturn(bytes calldata call, bytes calldata response) 254 | external 255 | override 256 | { 257 | _givenMethodReturn(call, response); 258 | } 259 | 260 | function givenMethodReturnBool(bytes calldata call, bool response) 261 | external 262 | override 263 | { 264 | uint256 flag = response ? 1 : 0; 265 | _givenMethodReturn(call, uintToBytes(flag)); 266 | } 267 | 268 | function givenMethodReturnUint(bytes calldata call, uint256 response) 269 | external 270 | override 271 | { 272 | _givenMethodReturn(call, uintToBytes(response)); 273 | } 274 | 275 | function givenMethodReturnAddress(bytes calldata call, address response) 276 | external 277 | override 278 | { 279 | _givenMethodReturn(call, uintToBytes(uint256(response))); 280 | } 281 | 282 | function givenCalldataRevert(bytes calldata call) external override { 283 | calldataMockTypes[call] = MockType.Revert; 284 | calldataRevertMessage[call] = ""; 285 | trackCalldataMock(call); 286 | } 287 | 288 | function givenMethodRevert(bytes calldata call) external override { 289 | bytes4 method = bytesToBytes4(call); 290 | methodIdMockTypes[method] = MockType.Revert; 291 | trackMethodIdMock(method); 292 | } 293 | 294 | function givenCalldataRevertWithMessage( 295 | bytes calldata call, 296 | string calldata message 297 | ) external override { 298 | calldataMockTypes[call] = MockType.Revert; 299 | calldataRevertMessage[call] = message; 300 | trackCalldataMock(call); 301 | } 302 | 303 | function givenMethodRevertWithMessage( 304 | bytes calldata call, 305 | string calldata message 306 | ) external override { 307 | bytes4 method = bytesToBytes4(call); 308 | methodIdMockTypes[method] = MockType.Revert; 309 | methodIdRevertMessages[method] = message; 310 | trackMethodIdMock(method); 311 | } 312 | 313 | function givenCalldataRunOutOfGas(bytes calldata call) external override { 314 | calldataMockTypes[call] = MockType.OutOfGas; 315 | trackCalldataMock(call); 316 | } 317 | 318 | function givenMethodRunOutOfGas(bytes calldata call) external override { 319 | bytes4 method = bytesToBytes4(call); 320 | methodIdMockTypes[method] = MockType.OutOfGas; 321 | trackMethodIdMock(method); 322 | } 323 | 324 | function invocationCount() external override returns (uint256) { 325 | return invocations; 326 | } 327 | 328 | function invocationCountForMethod(bytes calldata call) 329 | external 330 | override 331 | returns (uint256) 332 | { 333 | bytes4 method = bytesToBytes4(call); 334 | return methodIdInvocations[keccak256(abi.encodePacked(resetCount, method))]; 335 | } 336 | 337 | function invocationCountForCalldata(bytes calldata call) 338 | external 339 | override 340 | returns (uint256) 341 | { 342 | return calldataInvocations[keccak256(abi.encodePacked(resetCount, call))]; 343 | } 344 | 345 | function reset() external override { 346 | // Reset all exact calldataMocks 347 | bytes memory nextMock = calldataMocks[MOCKS_LIST_START]; 348 | bytes32 mockHash = keccak256(nextMock); 349 | // We cannot compary bytes 350 | while (mockHash != MOCKS_LIST_END_HASH) { 351 | // Reset all mock maps 352 | calldataMockTypes[nextMock] = MockType.Return; 353 | calldataExpectations[nextMock] = hex""; 354 | calldataRevertMessage[nextMock] = ""; 355 | // Set next mock to remove 356 | nextMock = calldataMocks[mockHash]; 357 | // Remove from linked list 358 | calldataMocks[mockHash] = ""; 359 | // Update mock hash 360 | mockHash = keccak256(nextMock); 361 | } 362 | // Clear list 363 | calldataMocks[MOCKS_LIST_START] = MOCKS_LIST_END; 364 | 365 | // Reset all any calldataMocks 366 | bytes4 nextAnyMock = methodIdMocks[SENTINEL_ANY_MOCKS]; 367 | while (nextAnyMock != SENTINEL_ANY_MOCKS) { 368 | bytes4 currentAnyMock = nextAnyMock; 369 | methodIdMockTypes[currentAnyMock] = MockType.Return; 370 | methodIdExpectations[currentAnyMock] = hex""; 371 | methodIdRevertMessages[currentAnyMock] = ""; 372 | nextAnyMock = methodIdMocks[currentAnyMock]; 373 | // Remove from linked list 374 | methodIdMocks[currentAnyMock] = 0x0; 375 | } 376 | // Clear list 377 | methodIdMocks[SENTINEL_ANY_MOCKS] = SENTINEL_ANY_MOCKS; 378 | 379 | fallbackExpectation = DEFAULT_FALLBACK_VALUE; 380 | fallbackMockType = MockType.Return; 381 | invocations = 0; 382 | resetCount += 1; 383 | } 384 | 385 | function useAllGas() private { 386 | while (true) { 387 | bool s; 388 | assembly { 389 | //expensive call to EC multiply contract 390 | s := call(sub(gas(), 2000), 6, 0, 0x0, 0xc0, 0x0, 0x60) 391 | } 392 | } 393 | } 394 | 395 | function bytesToBytes4(bytes memory b) private pure returns (bytes4) { 396 | bytes4 out; 397 | for (uint256 i = 0; i < 4; i++) { 398 | out |= bytes4(b[i] & 0xFF) >> (i * 8); 399 | } 400 | return out; 401 | } 402 | 403 | function uintToBytes(uint256 x) private pure returns (bytes memory b) { 404 | b = new bytes(32); 405 | assembly { 406 | mstore(add(b, 32), x) 407 | } 408 | } 409 | 410 | function updateInvocationCount(bytes4 methodId, bytes memory originalMsgData) 411 | public 412 | { 413 | require( 414 | msg.sender == address(this), 415 | "Can only be called from the contract itself" 416 | ); 417 | invocations += 1; 418 | methodIdInvocations[keccak256(abi.encodePacked(resetCount, methodId))] += 1; 419 | calldataInvocations[ 420 | keccak256(abi.encodePacked(resetCount, originalMsgData)) 421 | ] += 1; 422 | } 423 | 424 | fallback() external payable { 425 | bytes4 methodId; 426 | assembly { 427 | methodId := calldataload(0) 428 | } 429 | 430 | // First, check exact matching overrides 431 | if (calldataMockTypes[msg.data] == MockType.Revert) { 432 | revert(calldataRevertMessage[msg.data]); 433 | } 434 | if (calldataMockTypes[msg.data] == MockType.OutOfGas) { 435 | useAllGas(); 436 | } 437 | bytes memory result = calldataExpectations[msg.data]; 438 | 439 | // Then check method Id overrides 440 | if (result.length == 0) { 441 | if (methodIdMockTypes[methodId] == MockType.Revert) { 442 | revert(methodIdRevertMessages[methodId]); 443 | } 444 | if (methodIdMockTypes[methodId] == MockType.OutOfGas) { 445 | useAllGas(); 446 | } 447 | result = methodIdExpectations[methodId]; 448 | } 449 | 450 | // Last, use the fallback override 451 | if (result.length == 0) { 452 | if (fallbackMockType == MockType.Revert) { 453 | revert(fallbackRevertMessage); 454 | } 455 | if (fallbackMockType == MockType.OutOfGas) { 456 | useAllGas(); 457 | } 458 | result = fallbackExpectation; 459 | } 460 | 461 | // Record invocation as separate call so we don't rollback in case we are called with STATICCALL 462 | (, bytes memory r) = address(this).call{ gas: 100000 }( 463 | abi.encodeWithSignature( 464 | "updateInvocationCount(bytes4,bytes)", 465 | methodId, 466 | msg.data 467 | ) 468 | ); 469 | assert(r.length == 0); 470 | 471 | assembly { 472 | return(add(0x20, result), mload(result)) 473 | } 474 | } 475 | } 476 | -------------------------------------------------------------------------------- /contracts/NFT.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | // contracts/ERC721.sol 3 | 4 | pragma solidity >=0.6.2; 5 | 6 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 7 | import "@openzeppelin/contracts/utils/Counters.sol"; 8 | 9 | contract NFT is ERC721 { 10 | using Counters for Counters.Counter; 11 | Counters.Counter private _tokenIds; 12 | 13 | constructor() ERC721("GameItem", "ITM") {} 14 | 15 | // commented out unused variable 16 | // function awardItem(address player, string memory tokenURI) 17 | function awardItem(address player) 18 | public 19 | returns (uint256) 20 | { 21 | _tokenIds.increment(); 22 | 23 | uint256 newItemId = _tokenIds.current(); 24 | _mint(player, newItemId); 25 | // _setTokenURI(newItemId, tokenURI); 26 | 27 | return newItemId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /contracts/Storage.sol: -------------------------------------------------------------------------------- 1 | //SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0 <0.8.0; 3 | 4 | contract Storage { 5 | uint256 number; 6 | 7 | function store(uint256 num) public { 8 | number = num; 9 | } 10 | 11 | function retrieve() public view returns (uint256) { 12 | return number; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { task } from "hardhat/config" 2 | import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers" 3 | import { BigNumber } from "ethers" 4 | import "@nomiclabs/hardhat-waffle" 5 | 6 | // When using the hardhat network, you may choose to fork Fuji or Avalanche Mainnet 7 | // This will allow you to debug contracts using the hardhat network while keeping the current network state 8 | // To enable forking, turn one of these booleans on, and then run your tasks/scripts using ``--network hardhat`` 9 | // For more information go to the hardhat guide 10 | // https://hardhat.org/hardhat-network/ 11 | // https://hardhat.org/guides/mainnet-forking.html 12 | const FORK_FUJI = false 13 | const FORK_MAINNET = false 14 | const forkingData = FORK_FUJI ? { 15 | url: 'https://api.avax-test.network/ext/bc/C/rpc', 16 | } : FORK_MAINNET ? { 17 | url: 'https://api.avax.network/ext/bc/C/rpc' 18 | } : undefined 19 | 20 | task("accounts", "Prints the list of accounts", async (args, hre): Promise => { 21 | const accounts: SignerWithAddress[] = await hre.ethers.getSigners() 22 | accounts.forEach((account: SignerWithAddress): void => { 23 | console.log(account.address) 24 | }) 25 | }) 26 | 27 | task("balances", "Prints the list of AVAX account balances", async (args, hre): Promise => { 28 | const accounts: SignerWithAddress[] = await hre.ethers.getSigners() 29 | for(const account of accounts){ 30 | const balance: BigNumber = await hre.ethers.provider.getBalance( 31 | account.address 32 | ); 33 | console.log(`${account.address} has balance ${balance.toString()}`); 34 | } 35 | }) 36 | 37 | export default { 38 | solidity: { 39 | compilers: [ 40 | { 41 | version: "0.5.16" 42 | }, 43 | { 44 | version: "0.6.2" 45 | }, 46 | { 47 | version: "0.6.4" 48 | }, 49 | { 50 | version: "0.7.0" 51 | }, 52 | { 53 | version: "0.8.0" 54 | } 55 | ] 56 | }, 57 | networks: { 58 | hardhat: { 59 | gasPrice: 225000000000, 60 | chainId: !forkingData ? 43112 : undefined, //Only specify a chainId if we are not forking 61 | forking: forkingData 62 | }, 63 | local: { 64 | url: 'http://localhost:9650/ext/bc/C/rpc', 65 | gasPrice: 225000000000, 66 | chainId: 43112, 67 | accounts: [ 68 | "0x56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027", 69 | "0x7b4198529994b0dc604278c99d153cfd069d594753d471171a1d102a10438e07", 70 | "0x15614556be13730e9e8d6eacc1603143e7b96987429df8726384c2ec4502ef6e", 71 | "0x31b571bf6894a248831ff937bb49f7754509fe93bbd2517c9c73c4144c0e97dc", 72 | "0x6934bef917e01692b789da754a0eae31a8536eb465e7bff752ea291dad88c675", 73 | "0xe700bdbdbc279b808b1ec45f8c2370e4616d3a02c336e68d85d4668e08f53cff", 74 | "0xbbc2865b76ba28016bc2255c7504d000e046ae01934b04c694592a6276988630", 75 | "0xcdbfd34f687ced8c6968854f8a99ae47712c4f4183b78dcc4a903d1bfe8cbf60", 76 | "0x86f78c5416151fe3546dece84fda4b4b1e36089f2dbc48496faf3a950f16157c", 77 | "0x750839e9dbbd2a0910efe40f50b2f3b2f2f59f5580bb4b83bd8c1201cf9a010a" 78 | ] 79 | }, 80 | fuji: { 81 | url: 'https://api.avax-test.network/ext/bc/C/rpc', 82 | gasPrice: 225000000000, 83 | chainId: 43113, 84 | accounts: [] 85 | }, 86 | mainnet: { 87 | url: 'https://api.avax.network/ext/bc/C/rpc', 88 | gasPrice: 225000000000, 89 | chainId: 43114, 90 | accounts: [] 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "avalanche-smart-contract-quickstart", 3 | "devDependencies": { 4 | "@nomiclabs/hardhat-ethers": "^2.0.2", 5 | "@nomiclabs/hardhat-waffle": "^2.0.1", 6 | "@openzeppelin/contracts": "^4.3.0", 7 | "@types/chai": "^4.2.21", 8 | "@types/mocha": "^9.0.0", 9 | "@types/node": "^16.7.1", 10 | "avalanche": "3.8.5", 11 | "chai": "^4.3.4", 12 | "ethereum-waffle": "^3.4.0", 13 | "ethereumjs-tx": "^2.1.2", 14 | "ethers": "^5.4.5", 15 | "hardhat": "2.6.1", 16 | "ts-node": "^10.2.1", 17 | "web3": "^1.5.2" 18 | }, 19 | "version": "1.0.0", 20 | "description": "", 21 | "main": "index.js", 22 | "repository": "https://github.com/ava-labs/avalanche-smart-contract-quickstart", 23 | "author": "Connor Daly ", 24 | "contributors": [ 25 | "Gabriel Cardona " 26 | ], 27 | "license": "BSD-3-Clause", 28 | "scripts": { 29 | "precompile": "rimraf ./build/", 30 | "compile": "npx hardhat compile", 31 | "console": "npx hardhat console", 32 | "pretest": "yarn compile", 33 | "test": "npx hardhat test", 34 | "deploy": "npx hardhat run scripts/deploy.ts", 35 | "erc20": "npx hardhat run scripts/erc20.ts", 36 | "nft": "npx hardhat run scripts/nft.ts --network mainnet", 37 | "storage": "npx hardhat run scripts/storage.ts", 38 | "send-avax-wallet-signer": "npx hardhat run scripts/sendAvaxWalletSigner.ts", 39 | "send-avax-json-provider": "npx hardhat run scripts/sendAvaxJSONProvider.ts", 40 | "lint": "prettier ./test/**/*.ts --check", 41 | "prepublishOnly": "yarn test", 42 | "hardhat": "npx hardhat", 43 | "accounts": "npx hardhat accounts", 44 | "balances": "npx hardhat balances", 45 | "fund-cchain-addresses": "npx hardhat run scripts/fund-cchain-addresses.js" 46 | }, 47 | "dependencies": { 48 | "typescript": "^4.5.4" 49 | }, 50 | "engines": { 51 | "node": ">=14.17.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /scripts/deploy.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Contract, 3 | ContractFactory 4 | } from "ethers" 5 | import { ethers } from "hardhat" 6 | 7 | const main = async(): Promise => { 8 | const Coin: ContractFactory = await ethers.getContractFactory("ExampleERC20") 9 | const coin: Contract = await Coin.deploy() 10 | 11 | await coin.deployed() 12 | console.log(`Coin deployed to: ${coin.address}`) 13 | } 14 | 15 | main() 16 | .then(() => process.exit(0)) 17 | .catch(error => { 18 | console.error(error) 19 | process.exit(1) 20 | }) 21 | -------------------------------------------------------------------------------- /scripts/erc20.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BigNumber, 3 | Contract 4 | } from "ethers" 5 | import { ethers } from "hardhat" 6 | 7 | const coinName: string = "" 8 | const coinAddr: string = "" 9 | const walletAddress: string = "" 10 | 11 | const main = async (): Promise => { 12 | const contract: Contract = await ethers.getContractAt(coinName, coinAddr) 13 | const contractAddress: string = contract.address 14 | console.log(`Address: ${contractAddress}`) 15 | 16 | const name: string = await contract.name() 17 | console.log(`Name: ${name}`) 18 | 19 | const symbol: string = await contract.symbol() 20 | console.log(`Symbol: ${symbol}`) 21 | 22 | const decimals: string = await contract.decimals() 23 | console.log(`Decimals: ${decimals}`) 24 | 25 | const balance: BigNumber = await contract.balanceOf(walletAddress) 26 | console.log(`Balance of ${walletAddress}: ${balance.toString()}`) 27 | 28 | let totalSupply: BigNumber = await contract.totalSupply() 29 | console.log(`Total supply: ${totalSupply.toString()}`) 30 | 31 | console.log(`-----MINTING-----`) 32 | await contract.mint(walletAddress, totalSupply) 33 | 34 | totalSupply = await contract.totalSupply() 35 | console.log(`Total supply: ${totalSupply.toString()}`) 36 | 37 | console.log(`-----BURNING-----`) 38 | await contract.burn(walletAddress, totalSupply) 39 | 40 | totalSupply = await contract.totalSupply() 41 | console.log(`Total supply: ${totalSupply.toString()}`) 42 | 43 | const tx = await contract.transfer(walletAddress, balance) 44 | console.log("--TX--") 45 | console.log(tx) 46 | 47 | const txReceipt = await tx.wait() 48 | console.log("--TX RECEIPT--") 49 | console.log(txReceipt) 50 | } 51 | 52 | main() 53 | .then(() => process.exit(0)) 54 | .catch(error => { 55 | console.error(error) 56 | process.exit(1) 57 | }) -------------------------------------------------------------------------------- /scripts/example.js: -------------------------------------------------------------------------------- 1 | const { Contract } = require("ethers"); 2 | const hre = require("hardhat"); 3 | 4 | // TODO: Enter your deployed contract address 5 | const COIN_ADDR = "0x0000000000000000000000000000000000000000"; 6 | 7 | /** 8 | * Empty. Try calling some functions here. 9 | */ 10 | async function main() { 11 | 12 | } 13 | 14 | /** 15 | * Takes a transaction response and calculates the amount of gas used and converts 16 | * it to AVAX. Prints results to console. 17 | * 18 | * @param {TransactionResponse} tx transactionn to extract gas info from 19 | * @param {string} methodName Name of method to print 20 | */ 21 | async function calculateGasFee(tx, methodName) { 22 | const gasPrice = 470000000000; 23 | const weiPerAvax = Number('1000000000000000000'); 24 | 25 | const txReceipt = await tx.wait(); 26 | const gasUsed = txReceipt.gasUsed.toString() 27 | const avax = gasUsed * gasPrice / weiPerAvax; 28 | console.log(methodName, "gas used:", gasUsed); 29 | console.log(methodName, "AVAX cost:", avax); 30 | } 31 | 32 | /** 33 | * Calls transfer on the provided contract. Transfers the ERC20 from the from signer 34 | * to the to signer for the amount of amount. 35 | * 36 | * @param {Signer} from signer to send from 37 | * @param {Signer} to signer to send to 38 | * @param {number} amount amount to send 39 | * @param {Contract} coinContract ERC20 contract to call 40 | */ 41 | async function sendERC20(from, to, amount, coinContract) { 42 | const coin = coinContract.connect(from); 43 | tx = await coin.transfer(to.getAddress(), amount); 44 | 45 | await calculateGasFee(tx, "Transfer"); 46 | 47 | } 48 | 49 | // We recommend this pattern to be able to use async/await everywhere 50 | // and properly handle errors. 51 | main() 52 | .then(() => process.exit(0)) 53 | .catch(error => { 54 | console.error(error); 55 | process.exit(1); 56 | }); -------------------------------------------------------------------------------- /scripts/fund-cchain-addresses.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | Object.defineProperty(exports, '__esModule', { value: true }); 3 | const avalanche_1 = require('avalanche'); 4 | const avm_1 = require('avalanche/dist/apis/avm'); 5 | const evm_1 = require('avalanche/dist/apis/evm'); 6 | const utils_1 = require('avalanche/dist/utils'); 7 | const sleep = (ms) => { 8 | return new Promise((resolve) => setTimeout(resolve, ms)); 9 | }; 10 | const ip = 'localhost'; 11 | const port = 9650; 12 | const protocol = 'http'; 13 | const networkID = 12345; 14 | const avalanche = new avalanche_1.Avalanche(ip, port, protocol, networkID); 15 | const mstimeout = 3000; 16 | const xchain = avalanche.XChain(); 17 | const cchain = avalanche.CChain(); 18 | const bintools = avalanche_1.BinTools.getInstance(); 19 | const xKeychain = xchain.keyChain(); 20 | const cKeychain = cchain.keyChain(); 21 | const privKeys = [ 22 | 'PrivateKey-ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN', 23 | 'PrivateKey-wHR4zmr9am94KVYnV2aRR4QXt78cuGebt1GpYNwJYEbfAGonj', 24 | 'PrivateKey-AR874kuHtHpDk7ntffuEQ9cwiQLL2dz1DmJankW1EyXnz5fc7', 25 | 'PrivateKey-Ntk8vV7zaWzAot2wuDXK4e9ZGFUnU49AYTDew5XUyYaNz2u9d', 26 | 'PrivateKey-oLM8XbXxXmBHVbdKm2tRYQ1WdMj3b2NggftQpvDUXWSMtdY4i', 27 | 'PrivateKey-2kjfDc9RVUQJnu3HQDGiVdxvhM9BmR3UTx7Aq8AJ82G2MspATy', 28 | 'PrivateKey-2Rh5Gtu28ca7PS6rLfN6uou9ext8Y5xhoAJDdWPU7GESBLHtv6', 29 | 'PrivateKey-2ZcbEPKkXjswsNRBGViGzruReAtTAxW9hsGeMc2GgppnJnDgne', 30 | 'PrivateKey-22SYvqaRgFtPJfiZmswrCyE57UcssLVnNPDJ48PYAiCjKVAGy7', 31 | 'PrivateKey-tYRsRPijLo6KD2azMLzkcB2ZUndU3a2dJ8kEqBtqesa85pWhB' 32 | ]; 33 | privKeys.forEach((privKey) => { 34 | xKeychain.importKey(privKey); 35 | cKeychain.importKey(privKey); 36 | }); 37 | const xAddresses = xchain.keyChain().getAddresses(); 38 | const xAddressStrings = xchain.keyChain().getAddressStrings(); 39 | const cAddressStrings = cchain.keyChain().getAddressStrings(); 40 | const cAddresses = cchain.keyChain().getAddresses(); 41 | const cHexAddresses = [ 42 | '0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC', 43 | '0x9632a79656af553f58738b0fb750320158495942', 44 | '0x55ee05df718f1a5c1441e76190eb1a19ee2c9430', 45 | '0x4cf2ed3665f6bfa95ce6a11cfdb7a2ef5fc1c7e4', 46 | '0x0b891db1901d4875056896f28b6665083935c7a8', 47 | '0x01f253be2ebf0bd64649fa468bf7b95ca933bde2', 48 | '0x78A23300E04FB5d5D2820E23cc679738982e1fd5', 49 | '0x3c7dae394bbf8e9ee1359ad14c1c47003bd06293', 50 | '0x61e0b3cd93f36847abbd5d40d6f00a8ec6f3cffb', 51 | '0x0fa8ea536be85f32724d57a37758761b86416123' 52 | ]; 53 | const cChainBlockchainID = utils_1.Defaults.network['12345'].C.blockchainID; 54 | const cChainBlockchainIdBuf = bintools.cb58Decode(cChainBlockchainID); 55 | const xChainBlockchainID = utils_1.Defaults.network['12345'].X.blockchainID; 56 | const xChainBlockchainIdBuf = bintools.cb58Decode(xChainBlockchainID); 57 | const exportedOuts = []; 58 | const outputs = []; 59 | const inputs = []; 60 | const importedIns = []; 61 | const evmOutputs = []; 62 | const fee = xchain.getDefaultTxFee(); 63 | const locktime = new avalanche_1.BN(0); 64 | const threshold = 1; 65 | const memo = bintools.stringToBuffer( 66 | 'AVM utility method buildExportTx to export AVAX to the C-Chain from the X-Chain' 67 | ); 68 | 69 | const waitForUtxo = async () => { 70 | const u = await cchain.getUTXOs(cAddressStrings[0], 'X'); 71 | 72 | if (u.utxos.getAllUTXOs().length) { 73 | return u.utxos.getAllUTXOs(); 74 | } else { 75 | await sleep(mstimeout); 76 | return waitForUtxo(); 77 | } 78 | }; 79 | 80 | const main = async () => { 81 | const avaxAssetID = await xchain.getAVAXAssetID(); 82 | const getBalanceResponse = await xchain.getBalance( 83 | xAddressStrings[0], 84 | bintools.cb58Encode(avaxAssetID) 85 | ); 86 | const balance = new avalanche_1.BN(getBalanceResponse.balance); 87 | const avmUTXOResponse = await xchain.getUTXOs(xAddressStrings); 88 | const avmUTXOSet = avmUTXOResponse.utxos; 89 | const avmUTXOs = avmUTXOSet.getAllUTXOs(); 90 | // 1,000 AVAX 91 | const amount = new avalanche_1.BN(1000000000000); 92 | console.log('Exporting 1000 AVAX to each address on the C-Chain...'); 93 | let secpTransferOutput = new avm_1.SECPTransferOutput( 94 | amount.mul(new avalanche_1.BN(10)), 95 | [cAddresses[0]], 96 | locktime, 97 | threshold 98 | ); 99 | let transferableOutput = new avm_1.TransferableOutput( 100 | avaxAssetID, 101 | secpTransferOutput 102 | ); 103 | exportedOuts.push(transferableOutput); 104 | secpTransferOutput = new avm_1.SECPTransferOutput( 105 | balance.sub(amount.mul(new avalanche_1.BN(10))).sub(fee), 106 | xAddresses, 107 | locktime, 108 | threshold 109 | ); 110 | transferableOutput = new avm_1.TransferableOutput( 111 | avaxAssetID, 112 | secpTransferOutput 113 | ); 114 | outputs.push(transferableOutput); 115 | avmUTXOs.forEach((utxo) => { 116 | const amountOutput = utxo.getOutput(); 117 | const amt = amountOutput.getAmount().clone(); 118 | const txid = utxo.getTxID(); 119 | const outputidx = utxo.getOutputIdx(); 120 | const secpTransferInput = new avm_1.SECPTransferInput(amt); 121 | secpTransferInput.addSignatureIdx(0, xAddresses[0]); 122 | const input = new avm_1.TransferableInput( 123 | txid, 124 | outputidx, 125 | avaxAssetID, 126 | secpTransferInput 127 | ); 128 | inputs.push(input); 129 | }); 130 | 131 | const exportTx = new avm_1.ExportTx( 132 | networkID, 133 | bintools.cb58Decode(xChainBlockchainID), 134 | outputs, 135 | inputs, 136 | memo, 137 | bintools.cb58Decode(cChainBlockchainID), 138 | exportedOuts 139 | ); 140 | const avmUnsignedTx = new avm_1.UnsignedTx(exportTx); 141 | const avmTx = avmUnsignedTx.sign(xKeychain); 142 | const avmTXID = await xchain.issueTx(avmTx); 143 | console.log(avmTXID); 144 | await sleep(mstimeout); 145 | console.log('Importing AVAX to the C-Chain...'); 146 | console.log('Please wait'); 147 | const utxos = await waitForUtxo(); 148 | 149 | utxos.forEach((utxo, index) => { 150 | const assetID = utxo.getAssetID(); 151 | const txid = utxo.getTxID(); 152 | const outputidx = utxo.getOutputIdx(); 153 | const output = utxo.getOutput(); 154 | const amt = output.getAmount().clone(); 155 | const input = new evm_1.SECPTransferInput(amt); 156 | input.addSignatureIdx(0, cAddresses[0]); 157 | const xferin = new evm_1.TransferableInput(txid, outputidx, assetID, input); 158 | importedIns.push(xferin); 159 | 160 | cHexAddresses.forEach((cHexAddress) => { 161 | const evmOutput = new evm_1.EVMOutput( 162 | cHexAddress, 163 | new avalanche_1.BN(1000000000), 164 | assetID 165 | ); 166 | evmOutputs.push(evmOutput); 167 | }); 168 | }); 169 | 170 | const importTx = new evm_1.ImportTx( 171 | networkID, 172 | cChainBlockchainIdBuf, 173 | xChainBlockchainIdBuf, 174 | importedIns, 175 | evmOutputs 176 | ); 177 | const evmUnsignedTx = new evm_1.UnsignedTx(importTx); 178 | 179 | const evmTx = evmUnsignedTx.sign(cKeychain); 180 | const evmTXID = await cchain.issueTx(evmTx); 181 | console.log(evmTXID); 182 | }; 183 | main(); 184 | -------------------------------------------------------------------------------- /scripts/nft.ts: -------------------------------------------------------------------------------- 1 | import { Contract } from "ethers" 2 | import { ethers } from "hardhat" 3 | import { abi } from "../artifacts/contracts/NFT.sol/NFT.json" 4 | 5 | const coinAddr: string = "0xe304EDd5C4e590e2b8ce08b9625597FF38192D71" 6 | const main = async (): Promise => { 7 | const contract: Contract = new Contract(coinAddr, abi, ethers.provider) 8 | const tokenID: number = 395 9 | const tokenURI = await contract.tokenURI(tokenID) 10 | console.log(tokenURI) 11 | } 12 | 13 | main() 14 | .then(() => process.exit(0)) 15 | .catch(error => { 16 | console.error(error) 17 | process.exit(1) 18 | }) -------------------------------------------------------------------------------- /scripts/sendAvaxJSONProvider.ts: -------------------------------------------------------------------------------- 1 | import { utils } from "ethers" 2 | import { ethers } from "hardhat" 3 | interface Param { 4 | from: string 5 | to: string 6 | value: string 7 | } 8 | 9 | const main = async(): Promise => { 10 | const from: string = "0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC" 11 | const to: string = "0xDd1749831fbF70d88AB7bB07ef7CD9c53D054a57" 12 | const amount: string = "0.01" 13 | const params: Param[] = [{ 14 | from: from, 15 | to: to, 16 | value: utils.parseUnits(amount, "ether").toHexString() 17 | }] 18 | const tx: any = await ethers.provider.send("eth_sendTransaction", params) 19 | console.log(tx) 20 | } 21 | 22 | main() 23 | .then(() => process.exit(0)) 24 | .catch(error => { 25 | console.error(error) 26 | process.exit(1) 27 | }) -------------------------------------------------------------------------------- /scripts/sendAvaxWalletSigner.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BigNumber, 3 | providers, 4 | utils, 5 | Wallet 6 | } from "ethers" 7 | 8 | const walletAddress: string = "0xDd1749831fbF70d88AB7bB07ef7CD9c53D054a57" 9 | const pk: string = "0x56289e99c94b6912bfc12adc093c9b51124f0dc54ac7a766b2bc5ccf558d8027" 10 | const protocol: string = "http" 11 | const host: string = "localhost" 12 | const port: number = 9650 13 | 14 | const main = async(): Promise => { 15 | const provider: providers.JsonRpcProvider = new providers.JsonRpcProvider(`${protocol}://${host}:${port}/ext/bc/C/rpc`) 16 | const num: number = await provider.getBlockNumber() 17 | console.log(num) 18 | 19 | const balance: BigNumber = await provider.getBalance(walletAddress) 20 | console.log(balance) 21 | 22 | const formatted: string = utils.formatEther(balance) 23 | console.log(formatted) 24 | 25 | const parsed: BigNumber = utils.parseEther("1.0") 26 | console.log(parsed) 27 | 28 | const wallet: Wallet = new Wallet(pk, provider) 29 | const tx: providers.TransactionResponse = await wallet.sendTransaction({ 30 | to: walletAddress, 31 | value: parsed 32 | }); 33 | console.log(tx) 34 | } 35 | 36 | main() 37 | .then(() => process.exit(0)) 38 | .catch(error => { 39 | console.error(error) 40 | process.exit(1) 41 | }) -------------------------------------------------------------------------------- /scripts/storage.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BigNumber, 3 | Contract 4 | } from "ethers" 5 | import { ethers } from "hardhat" 6 | 7 | const contractName: string = "Storage" 8 | const contractAddress: string = "0xE3573540ab8A1C4c754Fd958Dc1db39BBE81b208" 9 | 10 | const main = async(): Promise => { 11 | const contract: Contract = await ethers.getContractAt(contractName, contractAddress) 12 | const num: BigNumber = await contract.retrieve() 13 | console.log(`Number: ${num.toString()}`) 14 | const tx = await contract.store(507) 15 | console.log(tx) 16 | } 17 | 18 | main() -------------------------------------------------------------------------------- /setup.js: -------------------------------------------------------------------------------- 1 | const hardhat = require("hardhat") 2 | const Web3 = require("web3") 3 | -------------------------------------------------------------------------------- /test/Coin.js: -------------------------------------------------------------------------------- 1 | // test/Airdrop.js 2 | // Load dependencies 3 | const { expect } = require('chai'); 4 | const { BigNumber } = require('ethers'); 5 | const { ethers } = require('hardhat'); 6 | const Web3 = require('web3'); 7 | 8 | const OWNER_ADDRESS = ethers.utils.getAddress("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); 9 | 10 | const DECIMALS = 2; 11 | 12 | const AMT = 150 13 | 14 | /////////////////////////////////////////////////////////// 15 | // SEE https://hardhat.org/tutorial/testing-contracts.html 16 | // FOR HELP WRITING TESTS 17 | // USE https://github.com/gnosis/mock-contract FOR HELP 18 | // WITH MOCK CONTRACT 19 | /////////////////////////////////////////////////////////// 20 | 21 | // Start test block 22 | describe('Coin', function () { 23 | before(async function () { 24 | this.Coin = await ethers.getContractFactory("ExampleERC20"); 25 | this.MockContract = await ethers.getContractFactory("contracts/MockContract.sol:MockContract"); 26 | }); 27 | 28 | beforeEach(async function () { 29 | this.coin = await this.Coin.deploy() 30 | await this.coin.deployed() 31 | this.mock = await this.MockContract.deploy() 32 | await this.mock.deployed() 33 | }); 34 | 35 | // Test cases 36 | 37 | ////////////////////////////// 38 | // Constructor 39 | ////////////////////////////// 40 | describe("Constructor", function () { 41 | it('mock test', async function () { 42 | // If another contract calls balanceOf on the mock contract, return AMT 43 | const balanceOf = Web3.utils.sha3('balanceOf(address)').slice(0,10); 44 | await this.mock.givenMethodReturnUint(balanceOf, AMT); 45 | }); 46 | }); 47 | 48 | ////////////////////////////// 49 | // setRemainderDestination 50 | ////////////////////////////// 51 | describe("otherMethod", function () { 52 | 53 | }); 54 | }); -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "resolveJsonModule": true 4 | } 5 | } --------------------------------------------------------------------------------