소스 검색

Implement full bridge in Solidity (#5)

Hendrik Hofstadt 5 년 전
부모
커밋
20a67604fd
6개의 변경된 파일1131개의 추가작업 그리고 88개의 파일을 삭제
  1. 506 0
      ethereum/contracts/BytesLib.sol
  2. 135 0
      ethereum/contracts/SchnorrSECP256K1.sol
  3. 6 4
      ethereum/contracts/Wormhole.sol
  4. 33 0
      ethereum/contracts/WrappedAsset.sol
  5. 451 83
      ethereum/package-lock.json
  6. 0 1
      ethereum/package.json

+ 506 - 0
ethereum/contracts/BytesLib.sol

@@ -0,0 +1,506 @@
+// SPDX-License-Identifier: Unlicense
+/*
+ * @title Solidity Bytes Arrays Utils
+ * @author Gonçalo Sá <goncalo.sa@consensys.net>
+ *
+ * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
+ *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
+ */
+pragma solidity >=0.5.0 <0.7.0;
+
+
+library BytesLib {
+    function concat(
+        bytes memory _preBytes,
+        bytes memory _postBytes
+    )
+    internal
+    pure
+    returns (bytes memory)
+    {
+        bytes memory tempBytes;
+
+        assembly {
+        // Get a location of some free memory and store it in tempBytes as
+        // Solidity does for memory variables.
+            tempBytes := mload(0x40)
+
+        // Store the length of the first bytes array at the beginning of
+        // the memory for tempBytes.
+            let length := mload(_preBytes)
+            mstore(tempBytes, length)
+
+        // Maintain a memory counter for the current write location in the
+        // temp bytes array by adding the 32 bytes for the array length to
+        // the starting location.
+            let mc := add(tempBytes, 0x20)
+        // Stop copying when the memory counter reaches the length of the
+        // first bytes array.
+            let end := add(mc, length)
+
+            for {
+            // Initialize a copy counter to the start of the _preBytes data,
+            // 32 bytes into its memory.
+                let cc := add(_preBytes, 0x20)
+            } lt(mc, end) {
+            // Increase both counters by 32 bytes each iteration.
+                mc := add(mc, 0x20)
+                cc := add(cc, 0x20)
+            } {
+            // Write the _preBytes data into the tempBytes memory 32 bytes
+            // at a time.
+                mstore(mc, mload(cc))
+            }
+
+        // Add the length of _postBytes to the current length of tempBytes
+        // and store it as the new length in the first 32 bytes of the
+        // tempBytes memory.
+            length := mload(_postBytes)
+            mstore(tempBytes, add(length, mload(tempBytes)))
+
+        // Move the memory counter back from a multiple of 0x20 to the
+        // actual end of the _preBytes data.
+            mc := end
+        // Stop copying when the memory counter reaches the new combined
+        // length of the arrays.
+            end := add(mc, length)
+
+            for {
+                let cc := add(_postBytes, 0x20)
+            } lt(mc, end) {
+                mc := add(mc, 0x20)
+                cc := add(cc, 0x20)
+            } {
+                mstore(mc, mload(cc))
+            }
+
+        // Update the free-memory pointer by padding our last write location
+        // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
+        // next 32 byte block, then round down to the nearest multiple of
+        // 32. If the sum of the length of the two arrays is zero then add
+        // one before rounding down to leave a blank 32 bytes (the length block with 0).
+            mstore(0x40, and(
+            add(add(end, iszero(add(length, mload(_preBytes)))), 31),
+            not(31) // Round down to the nearest 32 bytes.
+            ))
+        }
+
+        return tempBytes;
+    }
+
+    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
+        assembly {
+        // Read the first 32 bytes of _preBytes storage, which is the length
+        // of the array. (We don't need to use the offset into the slot
+        // because arrays use the entire slot.)
+            let fslot := sload(_preBytes_slot)
+        // Arrays of 31 bytes or less have an even value in their slot,
+        // while longer arrays have an odd value. The actual length is
+        // the slot divided by two for odd values, and the lowest order
+        // byte divided by two for even values.
+        // If the slot is even, bitwise and the slot with 255 and divide by
+        // two to get the length. If the slot is odd, bitwise and the slot
+        // with -1 and divide by two.
+            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
+            let mlength := mload(_postBytes)
+            let newlength := add(slength, mlength)
+        // slength can contain both the length and contents of the array
+        // if length < 32 bytes so let's prepare for that
+        // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
+            switch add(lt(slength, 32), lt(newlength, 32))
+            case 2 {
+            // Since the new array still fits in the slot, we just need to
+            // update the contents of the slot.
+            // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
+                sstore(
+                _preBytes_slot,
+                // all the modifications to the slot are inside this
+                // next block
+                add(
+                // we can just add to the slot contents because the
+                // bytes we want to change are the LSBs
+                fslot,
+                add(
+                mul(
+                div(
+                // load the bytes from memory
+                mload(add(_postBytes, 0x20)),
+                // zero all bytes to the right
+                exp(0x100, sub(32, mlength))
+                ),
+                // and now shift left the number of bytes to
+                // leave space for the length in the slot
+                exp(0x100, sub(32, newlength))
+                ),
+                // increase length by the double of the memory
+                // bytes length
+                mul(mlength, 2)
+                )
+                )
+                )
+            }
+            case 1 {
+            // The stored value fits in the slot, but the combined value
+            // will exceed it.
+            // get the keccak hash to get the contents of the array
+                mstore(0x0, _preBytes_slot)
+                let sc := add(keccak256(0x0, 0x20), div(slength, 32))
+
+            // save new length
+                sstore(_preBytes_slot, add(mul(newlength, 2), 1))
+
+            // The contents of the _postBytes array start 32 bytes into
+            // the structure. Our first read should obtain the `submod`
+            // bytes that can fit into the unused space in the last word
+            // of the stored array. To get this, we read 32 bytes starting
+            // from `submod`, so the data we read overlaps with the array
+            // contents by `submod` bytes. Masking the lowest-order
+            // `submod` bytes allows us to add that value directly to the
+            // stored value.
+
+                let submod := sub(32, slength)
+                let mc := add(_postBytes, submod)
+                let end := add(_postBytes, mlength)
+                let mask := sub(exp(0x100, submod), 1)
+
+                sstore(
+                sc,
+                add(
+                and(
+                fslot,
+                0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00
+                ),
+                and(mload(mc), mask)
+                )
+                )
+
+                for {
+                    mc := add(mc, 0x20)
+                    sc := add(sc, 1)
+                } lt(mc, end) {
+                    sc := add(sc, 1)
+                    mc := add(mc, 0x20)
+                } {
+                    sstore(sc, mload(mc))
+                }
+
+                mask := exp(0x100, sub(mc, end))
+
+                sstore(sc, mul(div(mload(mc), mask), mask))
+            }
+            default {
+            // get the keccak hash to get the contents of the array
+                mstore(0x0, _preBytes_slot)
+            // Start copying to the last used word of the stored array.
+                let sc := add(keccak256(0x0, 0x20), div(slength, 32))
+
+            // save new length
+                sstore(_preBytes_slot, add(mul(newlength, 2), 1))
+
+            // Copy over the first `submod` bytes of the new data as in
+            // case 1 above.
+                let slengthmod := mod(slength, 32)
+                let mlengthmod := mod(mlength, 32)
+                let submod := sub(32, slengthmod)
+                let mc := add(_postBytes, submod)
+                let end := add(_postBytes, mlength)
+                let mask := sub(exp(0x100, submod), 1)
+
+                sstore(sc, add(sload(sc), and(mload(mc), mask)))
+
+                for {
+                    sc := add(sc, 1)
+                    mc := add(mc, 0x20)
+                } lt(mc, end) {
+                    sc := add(sc, 1)
+                    mc := add(mc, 0x20)
+                } {
+                    sstore(sc, mload(mc))
+                }
+
+                mask := exp(0x100, sub(mc, end))
+
+                sstore(sc, mul(div(mload(mc), mask), mask))
+            }
+        }
+    }
+
+    function slice(
+        bytes memory _bytes,
+        uint256 _start,
+        uint256 _length
+    )
+    internal
+    pure
+    returns (bytes memory)
+    {
+        require(_bytes.length >= (_start + _length), "Read out of bounds");
+
+        bytes memory tempBytes;
+
+        assembly {
+            switch iszero(_length)
+            case 0 {
+            // Get a location of some free memory and store it in tempBytes as
+            // Solidity does for memory variables.
+                tempBytes := mload(0x40)
+
+            // The first word of the slice result is potentially a partial
+            // word read from the original array. To read it, we calculate
+            // the length of that partial word and start copying that many
+            // bytes into the array. The first word we copy will start with
+            // data we don't care about, but the last `lengthmod` bytes will
+            // land at the beginning of the contents of the new array. When
+            // we're done copying, we overwrite the full first word with
+            // the actual length of the slice.
+                let lengthmod := and(_length, 31)
+
+            // The multiplication in the next line is necessary
+            // because when slicing multiples of 32 bytes (lengthmod == 0)
+            // the following copy loop was copying the origin's length
+            // and then ending prematurely not copying everything it should.
+                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
+                let end := add(mc, _length)
+
+                for {
+                // The multiplication in the next line has the same exact purpose
+                // as the one above.
+                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
+                } lt(mc, end) {
+                    mc := add(mc, 0x20)
+                    cc := add(cc, 0x20)
+                } {
+                    mstore(mc, mload(cc))
+                }
+
+                mstore(tempBytes, _length)
+
+            //update free-memory pointer
+            //allocating the array padded to 32 bytes like the compiler does now
+                mstore(0x40, and(add(mc, 31), not(31)))
+            }
+            //if we want a zero-length slice let's just return a zero-length array
+            default {
+                tempBytes := mload(0x40)
+
+                mstore(0x40, add(tempBytes, 0x20))
+            }
+        }
+
+        return tempBytes;
+    }
+
+    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
+        require(_bytes.length >= (_start + 20), "Read out of bounds");
+        address tempAddress;
+
+        assembly {
+            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
+        }
+
+        return tempAddress;
+    }
+
+    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
+        require(_bytes.length >= (_start + 1), "Read out of bounds");
+        uint8 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x1), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
+        require(_bytes.length >= (_start + 2), "Read out of bounds");
+        uint16 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x2), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
+        require(_bytes.length >= (_start + 4), "Read out of bounds");
+        uint32 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x4), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
+        require(_bytes.length >= (_start + 8), "Read out of bounds");
+        uint64 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x8), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
+        require(_bytes.length >= (_start + 12), "Read out of bounds");
+        uint96 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0xc), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
+        require(_bytes.length >= (_start + 16), "Read out of bounds");
+        uint128 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x10), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
+        require(_bytes.length >= (_start + 32), "Read out of bounds");
+        uint256 tempUint;
+
+        assembly {
+            tempUint := mload(add(add(_bytes, 0x20), _start))
+        }
+
+        return tempUint;
+    }
+
+    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
+        require(_bytes.length >= (_start + 32), "Read out of bounds");
+        bytes32 tempBytes32;
+
+        assembly {
+            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
+        }
+
+        return tempBytes32;
+    }
+
+    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
+        bool success = true;
+
+        assembly {
+            let length := mload(_preBytes)
+
+        // if lengths don't match the arrays are not equal
+            switch eq(length, mload(_postBytes))
+            case 1 {
+            // cb is a circuit breaker in the for loop since there's
+            //  no said feature for inline assembly loops
+            // cb = 1 - don't breaker
+            // cb = 0 - break
+                let cb := 1
+
+                let mc := add(_preBytes, 0x20)
+                let end := add(mc, length)
+
+                for {
+                    let cc := add(_postBytes, 0x20)
+                // the next line is the loop condition:
+                // while(uint256(mc < end) + cb == 2)
+                } eq(add(lt(mc, end), cb), 2) {
+                    mc := add(mc, 0x20)
+                    cc := add(cc, 0x20)
+                } {
+                // if any of these checks fails then arrays are not equal
+                    if iszero(eq(mload(mc), mload(cc))) {
+                    // unsuccess:
+                        success := 0
+                        cb := 0
+                    }
+                }
+            }
+            default {
+            // unsuccess:
+                success := 0
+            }
+        }
+
+        return success;
+    }
+
+    function equalStorage(
+        bytes storage _preBytes,
+        bytes memory _postBytes
+    )
+    internal
+    view
+    returns (bool)
+    {
+        bool success = true;
+
+        assembly {
+        // we know _preBytes_offset is 0
+            let fslot := sload(_preBytes_slot)
+        // Decode the length of the stored array like in concatStorage().
+            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
+            let mlength := mload(_postBytes)
+
+        // if lengths don't match the arrays are not equal
+            switch eq(slength, mlength)
+            case 1 {
+            // slength can contain both the length and contents of the array
+            // if length < 32 bytes so let's prepare for that
+            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
+                if iszero(iszero(slength)) {
+                    switch lt(slength, 32)
+                    case 1 {
+                    // blank the last byte which is the length
+                        fslot := mul(div(fslot, 0x100), 0x100)
+
+                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
+                        // unsuccess:
+                            success := 0
+                        }
+                    }
+                    default {
+                    // cb is a circuit breaker in the for loop since there's
+                    //  no said feature for inline assembly loops
+                    // cb = 1 - don't breaker
+                    // cb = 0 - break
+                        let cb := 1
+
+                    // get the keccak hash to get the contents of the array
+                        mstore(0x0, _preBytes_slot)
+                        let sc := keccak256(0x0, 0x20)
+
+                        let mc := add(_postBytes, 0x20)
+                        let end := add(mc, mlength)
+
+                    // the next line is the loop condition:
+                    // while(uint256(mc < end) + cb == 2)
+                        for {} eq(add(lt(mc, end), cb), 2) {
+                            sc := add(sc, 1)
+                            mc := add(mc, 0x20)
+                        } {
+                            if iszero(eq(sload(sc), mload(mc))) {
+                            // unsuccess:
+                                success := 0
+                                cb := 0
+                            }
+                        }
+                    }
+                }
+            }
+            default {
+            // unsuccess:
+                success := 0
+            }
+        }
+
+        return success;
+    }
+}

+ 135 - 0
ethereum/contracts/SchnorrSECP256K1.sol

@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: MIT
+// Taken from https://github.com/smartcontractkit/chainlink
+
+pragma solidity ^0.6.0;
+
+library Schnorr {
+    // See https://en.bitcoin.it/wiki/Secp256k1 for this constant.
+    uint256 constant public Q = // Group order of secp256k1
+    // solium-disable-next-line indentation
+    0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141;
+    // solium-disable-next-line zeppelin/no-arithmetic-operations
+    uint256 constant public HALF_Q = (Q >> 1) + 1;
+
+    /** **************************************************************************
+        @notice verifySignature returns true iff passed a valid Schnorr signature.
+        @dev See https://en.wikipedia.org/wiki/Schnorr_signature for reference.
+        @dev In what follows, let d be your secret key, PK be your public key,
+        PKx be the x ordinate of your public key, and PKyp be the parity bit for
+        the y ordinate (i.e., 0 if PKy is even, 1 if odd.)
+        **************************************************************************
+        @dev TO CREATE A VALID SIGNATURE FOR THIS METHOD
+        @dev First PKx must be less than HALF_Q. Then follow these instructions
+             (see evm/test/schnorr_test.js, for an example of carrying them out):
+        @dev 1. Hash the target message to a uint256, called msgHash here, using
+                keccak256
+        @dev 2. Pick k uniformly and cryptographically securely randomly from
+                {0,...,Q-1}. It is critical that k remains confidential, as your
+                private key can be reconstructed from k and the signature.
+        @dev 3. Compute k*g in the secp256k1 group, where g is the group
+                generator. (This is the same as computing the public key from the
+                secret key k. But it's OK if k*g's x ordinate is greater than
+                HALF_Q.)
+        @dev 4. Compute the ethereum address for k*g. This is the lower 160 bits
+                of the keccak hash of the concatenated affine coordinates of k*g,
+                as 32-byte big-endians. (For instance, you could pass k to
+                ethereumjs-utils's privateToAddress to compute this, though that
+                should be strictly a development convenience, not for handling
+                live secrets, unless you've locked your javascript environment
+                down very carefully.) Call this address
+                nonceTimesGeneratorAddress.
+        @dev 5. Compute e=uint256(keccak256(PKx as a 32-byte big-endian
+                                          ‖ PKyp as a single byte
+                                          ‖ msgHash
+                                          ‖ nonceTimesGeneratorAddress))
+                This value e is called "msgChallenge" in verifySignature's source
+                code below. Here "‖" means concatenation of the listed byte
+                arrays.
+        @dev 6. Let x be your secret key. Compute s = (k - d * e) % Q. Add Q to
+                it, if it's negative. This is your signature. (d is your secret
+                key.)
+        **************************************************************************
+        @dev TO VERIFY A SIGNATURE
+        @dev Given a signature (s, e) of msgHash, constructed as above, compute
+        S=e*PK+s*generator in the secp256k1 group law, and then the ethereum
+        address of S, as described in step 4. Call that
+        nonceTimesGeneratorAddress. Then call the verifySignature method as:
+        @dev    verifySignature(PKx, PKyp, s, msgHash,
+                                nonceTimesGeneratorAddress)
+        **************************************************************************
+        @dev This signging scheme deviates slightly from the classical Schnorr
+        signature, in that the address of k*g is used in place of k*g itself,
+        both when calculating e and when verifying sum S as described in the
+        verification paragraph above. This reduces the difficulty of
+        brute-forcing a signature by trying random secp256k1 points in place of
+        k*g in the signature verification process from 256 bits to 160 bits.
+        However, the difficulty of cracking the public key using "baby-step,
+        giant-step" is only 128 bits, so this weakening constitutes no compromise
+        in the security of the signatures or the key.
+        @dev The constraint signingPubKeyX < HALF_Q comes from Eq. (281), p. 24
+        of Yellow Paper version 78d7b9a. ecrecover only accepts "s" inputs less
+        than HALF_Q, to protect against a signature- malleability vulnerability in
+        ECDSA. Schnorr does not have this vulnerability, but we must account for
+        ecrecover's defense anyway. And since we are abusing ecrecover by putting
+        signingPubKeyX in ecrecover's "s" argument the constraint applies to
+        signingPubKeyX, even though it represents a value in the base field, and
+        has no natural relationship to the order of the curve's cyclic group.
+        **************************************************************************
+        @param signingPubKeyX is the x ordinate of the public key. This must be
+               less than HALF_Q.
+        @param pubKeyYParity is 0 if the y ordinate of the public key is even, 1
+               if it's odd.
+        @param signature is the actual signature, described as s in the above
+               instructions.
+        @param msgHash is a 256-bit hash of the message being signed.
+        @param nonceTimesGeneratorAddress is the ethereum address of k*g in the
+               above instructions
+        **************************************************************************
+        @return True if passed a valid signature, false otherwise. */
+    function verifySignature(
+        uint256 signingPubKeyX,
+        uint8 pubKeyYParity,
+        uint256 signature,
+        uint256 msgHash,
+        address nonceTimesGeneratorAddress) external pure returns (bool) {
+        require(signingPubKeyX < HALF_Q, "Public-key x >= HALF_Q");
+        // Avoid signature malleability from multiple representations for ℤ/Qℤ elts
+        require(signature < Q, "signature must be reduced modulo Q");
+
+        // Forbid trivial inputs, to avoid ecrecover edge cases. The main thing to
+        // avoid is something which causes ecrecover to return 0x0: then trivial
+        // signatures could be constructed with the nonceTimesGeneratorAddress input
+        // set to 0x0.
+        //
+        // solium-disable-next-line indentation
+        require(nonceTimesGeneratorAddress != address(0) && signingPubKeyX > 0 &&
+        signature > 0 && msgHash > 0, "no zero inputs allowed");
+
+        // solium-disable-next-line indentation
+        uint256 msgChallenge = // "e"
+        // solium-disable-next-line indentation
+        uint256(keccak256(abi.encodePacked(signingPubKeyX, pubKeyYParity,
+            msgHash, nonceTimesGeneratorAddress))
+        );
+
+        // Verify msgChallenge * signingPubKey + signature * generator ==
+        //        nonce * generator
+        //
+        // https://ethresear.ch/t/you-can-kinda-abuse-ecrecover-to-do-ecmul-in-secp256k1-today/2384/9
+        // The point corresponding to the address returned by
+        // ecrecover(-s*r,v,r,e*r) is (r⁻¹ mod Q)*(e*r*R-(-s)*r*g)=e*R+s*g, where R
+        // is the (v,r) point. See https://crypto.stackexchange.com/a/18106
+        //
+        // solium-disable-next-line indentation
+        address recoveredAddress = ecrecover(
+        // solium-disable-next-line zeppelin/no-arithmetic-operations
+            bytes32(Q - mulmod(signingPubKeyX, signature, Q)),
+        // https://ethereum.github.io/yellowpaper/paper.pdf p. 24, "The
+        // value 27 represents an even y value and 28 represents an odd
+        // y value."
+            (pubKeyYParity == 0) ? 27 : 28,
+            bytes32(signingPubKeyX),
+            bytes32(mulmod(msgChallenge, signingPubKeyX, Q)));
+        return nonceTimesGeneratorAddress == recoveredAddress;
+    }
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 6 - 4
ethereum/contracts/Wormhole.sol


+ 33 - 0
ethereum/contracts/WrappedAsset.sol

@@ -0,0 +1,33 @@
+// contracts/WrappedAsset.sol
+// SPDX-License-Identifier: Apache 2
+pragma solidity ^0.6.0;
+
+import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
+
+contract WrappedAsset is ERC20("Wormhole Wrapped Asset", "WASSET") {
+    uint8 public assetChain;
+    bytes32 public assetAddress;
+    bool public initialized;
+    address public bridge;
+
+    function initialize(uint8 _assetChain, bytes32 _assetAddress) public {
+        require(!initialized, "already initialized");
+        // Set local fields
+        assetChain = _assetChain;
+        assetAddress = _assetAddress;
+        bridge = msg.sender;
+        initialized = true;
+    }
+
+    function mint(address account, uint256 amount) external {
+        require(msg.sender == bridge, "mint can only be called by the bridge");
+
+        super._mint(account, amount);
+    }
+
+    function burn(address account, uint256 amount) external {
+        require(msg.sender == bridge, "burn can only be called by the bridge");
+
+        super._burn(account, amount);
+    }
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 451 - 83
ethereum/package-lock.json


+ 0 - 1
ethereum/package.json

@@ -3,7 +3,6 @@
   "version": "1.0.0",
   "description": "",
   "main": "networks.js",
-  "dependencies": {},
   "devDependencies": {
     "@openzeppelin/cli": "^2.8.2",
     "@openzeppelin/contracts": "^3.1.0"

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.