$ npm install
$ cd node_modules/truffle
$ npm install [email protected]
$ cd -
$ ln -s node_modules/truffle/build/cli.bundled.js truffle
$ export PATH=`pwd`:$PATH
위와 같이 하시면 Truffle 환경은 구성이 끝나게 됩니다.
Truffle로 바로 BaoBob 이나 cypress server로 배포할 수 있지만, 우선 저희는 SmartContract를 Test하고 검증해야 하기 때문에 Ganache를 이용하여 로컬 환경에서 배포하도록 하겠습니다.
아래 링크에서 Ganache를 설치하고 실행합니다.
https://trufflesuite.com/ganache/
Ganache를 실행하면 아래와 같은 Network ID와 RPC Server 정보가 있습니다.
보시면 Network ID는 1337이고 RPC Server는 HTTP://127.0.0.1 Port는 7545 입니다.
혹시 위와 설정이 다르다면, 가장 오른쪽 톱니바퀴를 누르시고 아래 화면에서 변경해주세요.
위와 같이 설정 후에 truffle-config.js를 아래와 같이 변경해줍니다.
// truffle-config.js
module.exports = {
networks: {
klaytn: {
host: "127.0.0.1", // rpc 주소
port: 7545, // port name
//from: "0x75a59b94889a05c03c66c3c84e9d2f8308ca4abd", // 현재는 테스트이기 때문에 필요없지만 추후 배포시에는 account 주소 입력 필요
network_id: "1337", // 로컬 네트워크 id -> 추후에 메인넷으로 변경 후 배포
//gas: 20000000, // 트랜잭션 가스 한도
//gasPrice: 25000000000, // Baobab의 gasPrice는 25 Gpeb입니다
},
},
compilers: {
solc: {
version: "0.5.6", // 컴파일러 버전을 0.5.6로 지정
},
},
};
우선 배포하고자 하는 Smart Contract를 contracts 폴더 내에 작성합니다.
그 이후에 migrations/1_initial_migraion.js에서 아래와 같이 작성해줍니다.
const Migrations = artifacts.require("./Migrations.sol");
const KlaytnGreeter = artifacts.require("./KlaytnGreeter.sol"); // 작성한 smart contract
module.exports = function (deployer) {
deployer.deploy(Migrations);
deployer.deploy(KlaytnGreeter, "Hello, Klaytn"); // 이와 같이 작성해주자
};
위와 같이 하나의 migration js file에 넣어도 되고, 혹은 migrations 폴더 내에 prefix 숫자를 넣어서 2_klaytn_greeter.js 와 같이 폴더를 생성하여 별도로 배포 코드를 작성해도 됩니다.
배포 전의 Ganache를 살펴보면 아래와 같습니다.
총 10개의 지갑이 있고 각각 100이더씩 있는 것을 볼 수 있습니다.
위와 같이 블록도 0개이고 Transaction도 없습니다.
이제 terminal에 아래와 같이 명령어를 넣어봅시다.
truffle migrate --network klaytn// klaytn은 truffle-config.js에서 설정한 network name이다.
⚡ ⚙ root@gimdaun-ui-MacBook-Pro ~/klaytn main ● truffle migrate --network klaytn
Compiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'klaytn'
> Network id: 1337
> Block gas limit: 0x6691b7
1_initial_migration.js
======================
Replacing 'Migrations'
----------------------
> transaction hash: 0x06b66a084e478939099f01725186bb065e12e56415fe2f4a49d6df47506b199c
> Blocks: 0 Seconds: 0
> contract address: 0x6133DA5EB2d6Fb4CBb208D7788491212651BbBa6
> block number: 1
> block timestamp: 1644563019
> account: 0x111CF6AD702092D6D6103F8d18f41006A869A335
> balance: 99.99619978
> gas used: 190011
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00380022 ETH
Replacing 'KlaytnGreeter'
-------------------------
> transaction hash: 0xad84658fe1919822cac7b5c270bfefca8a5d376a8aa5f7941e7be070cd670f21
> Blocks: 0 Seconds: 0
> contract address: 0x4FB897FFe54D903ccBd2DE14765A948Bca5235Df
> block number: 2
> block timestamp: 1644563019
> account: 0x111CF6AD702092D6D6103F8d18f41006A869A335
> balance: 99.9917825
> gas used: 220864
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00441728 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.0082175 ETH
Summary
=======
> Total deployments: 2
> Final cost: 0.0082175 ETH
위와 같이 log가 나오면서 로컬 환경에 배포가 됨을 알 수 있습니다.
이제 Ganache에 가서 확인해보면
위와 같이 smart contract 배포로 인해 Gas가 사용되어 이더가 소모된 부분과 블록이 쌓인 부분, transaction이 발생한 부분을 모니터링 할 수 있습니다.
smart contract의 동작만을 검증하기 때문에 이더리움 로컬 네트워크 상에서 진행해도 문제 없을 것을 판단됩니다.
정상적으로 서버에 Smart Contract가 배포가 되었다면, truffle console을 이용하여 배포된 smart cotract내에 함수나 변수를 확인할 수 있습니다.
$ truffle console
배포가 정상적으로 된 상태에서 상기 명령어를 치면 아래처럼 terminal 창이 변경됩니다.
$ truffle console
truffle(ganache)>
이제 여기서 아래와 같이 입력하면
truffle(ganache)> NFTSimple.deployed().then(function(instance){it=instance})
undefined
undefined라는 msg가 나오게 되는데 it라는 변수에 NFTSimple smartcontract instance가 들어오게 됩니다.
이 때 Console창에 아래와 같이 입력하면
truffle(ganache)> it
TruffleContract {
constructor: [Function: TruffleContract] {
_constructorMethods: {
setProvider: [Function: setProvider],
new: [Function: new],
at: [AsyncFunction: at],
deployed: [AsyncFunction: deployed],
defaults: [Function: defaults],
hasNetwork: [Function: hasNetwork],
isDeployed: [Function: isDeployed],
detectNetwork: [AsyncFunction: detectNetwork],
setNetwork: [Function: setNetwork],
setNetworkType: [Function: setNetworkType],
setWallet: [Function: setWallet],
resetAddress: [Function: resetAddress],
link: [Function: link],
clone: [Function: clone],
addProp: [Function: addProp],
toJSON: [Function: toJSON],
decodeLogs: [Function: decodeLogs]
},
_properties: {
contract_name: [Object],
contractName: [Object],
gasMultiplier: [Object],
timeoutBlocks: [Object],
autoGas: [Object],
numberFormat: [Object],
abi: [Object],
metadata: [Function: metadata],
network: [Function: network],
networks: [Function: networks],
address: [Object],
transactionHash: [Object],
links: [Function: links],
events: [Function: events],
binary: [Function: binary],
deployedBinary: [Function: deployedBinary],
unlinked_binary: [Object],
bytecode: [Object],
deployedBytecode: [Object],
sourceMap: [Object],
deployedSourceMap: [Object],
source: [Object],
sourcePath: [Object],
legacyAST: [Object],
ast: [Object],
compiler: [Object],
schema_version: [Function: schema_version],
schemaVersion: [Function: schemaVersion],
updated_at: [Function: updated_at],
updatedAt: [Function: updatedAt],
userdoc: [Function: userdoc],
devdoc: [Function: devdoc]
},
_property_values: {},
_json: {
contractName: 'NFTSimple',
abi: [Array],
metadata: '{"compiler":{"version":"0.5.6+commit.b259423e"},"language":"Solidity","output":{"abi":[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tokenOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"to","type":"address"},{"name":"tokenId","type":"uint256"},{"name":"tokenURI","type":"string"}],"name":"mintWithTokenURI","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"id","type":"uint256"},{"name":"uri","type":"string"}],"name":"setTokenUri","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"tokenURIs","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"ownedTokens","outputs":[{"name":"","type":"uint256[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"tokenId","type":"uint256"},{"name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_addr","type":"address"}],"name":"balance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}],"devdoc":{"methods":{}},"userdoc":{"methods":{}}},"settings":{"compilationTarget":{"/Users/kimdawoon/klaytn/contracts/NFTSimple.sol":"NFTSimple"},"evmVersion":"petersburg","libraries":{},"optimizer":{"enabled":false,"runs":200},"remappings":[]},"sources":{"/Users/kimdawoon/klaytn/contracts/NFTSimple.sol":{"keccak256":"0xf0f74d9232e794b5b9043885d7543ad446f4659cc06cdff5ee1da3886e757d83","urls":["bzzr://ce577591ab3e9d25d63f467e272aff539b0b535cfc78e93ce807eb6d2518a57b"]}},"version":1}',
bytecode: '0x60806040526040518060400160405280600881526020017f4b6c61794c696f6e0000000000000000000000000000000000000000000000008152506000908051906020019062000051929190620000b4565b506040518060400160405280600281526020017f4b4c000000000000000000000000000000000000000000000000000000000000815250600190805190602001906200009f929190620000b4565b50348015620000ad57600080fd5b5062000163565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620000f757805160ff191683800117855562000128565b8280016001018555821562000128579182015b82811115620001275782518255916020019190600101906200010a565b5b5090506200013791906200013b565b5090565b6200016091905b808211156200015c57600081600090555060010162000142565b5090565b90565b6114b380620001736000396000f3fe608060405234801561001057600080fd5b506004361061009e5760003560e01c806370a082311161006657806370a08231146103fd57806395d89b4114610455578063b12ab40f146104d8578063b88d4fde14610571578063e3d670d7146106765761009e565b806306fdde03146100a35780631caaa4871461012657806350bb4e7f1461019457806357f7789e146102915780636c8b703f14610356575b600080fd5b6100ab6106ce565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100eb5780820151818401526020810190506100d0565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101526004803603602081101561013c57600080fd5b810190808035906020019092919050505061076c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610277600480360360608110156101aa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156101f157600080fd5b82018360208201111561020357600080fd5b8035906020019184600183028401116401000000008311171561022557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061079f565b604051808215151515815260200191505060405180910390f35b610354600480360360408110156102a757600080fd5b8101908080359060200190929190803590602001906401000000008111156102ce57600080fd5b8201836020820111156102e057600080fd5b8035906020019184600183028401116401000000008311171561030257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061088f565b005b6103826004803603602081101561036c57600080fd5b81019080803590602001909291905050506108bb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c25780820151818401526020810190506103a7565b50505050905090810190601f1680156103ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61043f6004803603602081101561041357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061096b565b6040518082815260200191505060405180910390f35b61045d610a3c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561049d578082015181840152602081019050610482565b50505050905090810190601f1680156104ca5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61051a600480360360208110156104ee57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ada565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561055d578082015181840152602081019050610542565b505050509050019250505060405180910390f35b6106746004803603608081101561058757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105ee57600080fd5b82018360208201111561060057600080fd5b8035906020019184600183028401116401000000008311171561062257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610b71565b005b6106b86004803603602081101561068c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610df5565b6040518082815260200191505060405180910390f35b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107645780601f1061073957610100808354040283529160200191610764565b820191906000526020600020905b81548152906001019060200180831161074757829003601f168201915b505050505081565b60026020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000836002600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160036000858152602001908152602001600020908051906020019061081a92919061133d565b50600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020839080600181540180825580915050906001820390600052602060002001600090919290919091505550600190509392505050565b806003600084815260200190815260200160002090805190602001906108b692919061133d565b505050565b60036020528060005260406000206000915090508054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109635780601f1061093857610100808354040283529160200191610963565b820191906000526020600020905b81548152906001019060200180831161094657829003601f168201915b505050505081565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156109f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061145f6029913960400191505060405180910390fd5b600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ad25780601f10610aa757610100808354040283529160200191610ad2565b820191906000526020600020905b815481529060010190602001808311610ab557829003601f168201915b505050505081565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015610b6557602002820191906000526020600020905b815481526020019060010190808311610b51575b50505050509050919050565b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610c12576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f66726f6d20212d206d73672e73656e646572000000000000000000000000000081525060200191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610cc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061143d6022913960400191505060405180910390fd5b610cd38483610e07565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050906001820390600052602060002001600090919290919091505550826002600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610d9a8484848461106e565b610def576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018061140f602e913960400191505060405180910390fd5b50505050565b6000610e008261096b565b9050919050565b60006001600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905003905060008090505b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905081101561101557600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208181548110610eeb57fe5b906000526020600020015483141561100857600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610f4757fe5b9060005260206000200154600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610f9c57fe5b906000526020600020018190555082600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208381548110610ff557fe5b9060005260206000200181905550611015565b8080600101915050610e57565b50600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548091906001900361106891906113bd565b50505050565b600080606061107c8661132a565b61108b57600192505050611322565b8573ffffffffffffffffffffffffffffffffffffffff16636745782b60e01b33898888604051602401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561115b578082015181840152602081019050611140565b50505050905090810190601f1680156111885780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b6020831061122057805182526020820191506020810190506020830392506111fd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611282576040519150601f19603f3d011682016040523d82523d6000602084013e611287565b606091505b508092508193505050600081511415801561130b5750636745782b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168180602001905160208110156112d957600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b1561131b57600192505050611322565b6000925050505b949350505050565b600080823b905060008111915050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061137e57805160ff19168380011785556113ac565b828001600101855582156113ac579182015b828111156113ab578251825591602001919060010190611390565b5b5090506113b991906113e9565b5090565b8154818355818111156113e4578183600052602060002091820191016113e391906113e9565b5b505050565b61140b91905b808211156114075760008160009055506001016113ef565b5090565b9056fe4b495031373a207472616e7366657220746f206e6f6e204b49503137526563656976657220696d706c656d656e74796f7520617265206e6f7420746865206f776e6572206f662074686520746f6b656e4b495031373a2062616c616e636520717565727920666f7220746865207a65726f2061646472657373a165627a7a7230582074631fbcf9d3afb7a18a7098f93ab03085fef6dcfc8608f48f7cc7585da581380029',
deployedBytecode: '0x608060405234801561001057600080fd5b506004361061009e5760003560e01c806370a082311161006657806370a08231146103fd57806395d89b4114610455578063b12ab40f146104d8578063b88d4fde14610571578063e3d670d7146106765761009e565b806306fdde03146100a35780631caaa4871461012657806350bb4e7f1461019457806357f7789e146102915780636c8b703f14610356575b600080fd5b6100ab6106ce565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100eb5780820151818401526020810190506100d0565b50505050905090810190601f1680156101185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101526004803603602081101561013c57600080fd5b810190808035906020019092919050505061076c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610277600480360360608110156101aa57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156101f157600080fd5b82018360208201111561020357600080fd5b8035906020019184600183028401116401000000008311171561022557600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061079f565b604051808215151515815260200191505060405180910390f35b610354600480360360408110156102a757600080fd5b8101908080359060200190929190803590602001906401000000008111156102ce57600080fd5b8201836020820111156102e057600080fd5b8035906020019184600183028401116401000000008311171561030257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050919291929050505061088f565b005b6103826004803603602081101561036c57600080fd5b81019080803590602001909291905050506108bb565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103c25780820151818401526020810190506103a7565b50505050905090810190601f1680156103ef5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61043f6004803603602081101561041357600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061096b565b6040518082815260200191505060405180910390f35b61045d610a3c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561049d578082015181840152602081019050610482565b50505050905090810190601f1680156104ca5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61051a600480360360208110156104ee57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610ada565b6040518080602001828103825283818151815260200191508051906020019060200280838360005b8381101561055d578082015181840152602081019050610542565b505050509050019250505060405180910390f35b6106746004803603608081101561058757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001906401000000008111156105ee57600080fd5b82018360208201111561060057600080fd5b8035906020019184600183028401116401000000008311171561062257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610b71565b005b6106b86004803603602081101561068c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610df5565b6040518082815260200191505060405180910390f35b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107645780601f1061073957610100808354040283529160200191610764565b820191906000526020600020905b81548152906001019060200180831161074757829003601f168201915b505050505081565b60026020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000836002600085815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508160036000858152602001908152602001600020908051906020019061081a92919061133d565b50600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020839080600181540180825580915050906001820390600052602060002001600090919290919091505550600190509392505050565b806003600084815260200190815260200160002090805190602001906108b692919061133d565b505050565b60036020528060005260406000206000915090508054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156109635780601f1061093857610100808354040283529160200191610963565b820191906000526020600020905b81548152906001019060200180831161094657829003601f168201915b505050505081565b60008073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156109f2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602981526020018061145f6029913960400191505060405180910390fd5b600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805490509050919050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610ad25780601f10610aa757610100808354040283529160200191610ad2565b820191906000526020600020905b815481529060010190602001808311610ab557829003601f168201915b505050505081565b6060600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020805480602002602001604051908101604052809291908181526020018280548015610b6557602002820191906000526020600020905b815481526020019060010190808311610b51575b50505050509050919050565b3373ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610c12576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260128152602001807f66726f6d20212d206d73672e73656e646572000000000000000000000000000081525060200191505060405180910390fd5b6002600083815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610cc9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061143d6022913960400191505060405180910390fd5b610cd38483610e07565b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020829080600181540180825580915050906001820390600052602060002001600090919290919091505550826002600084815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550610d9a8484848461106e565b610def576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018061140f602e913960400191505060405180910390fd5b50505050565b6000610e008261096b565b9050919050565b60006001600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905003905060008090505b600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208054905081101561101557600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208181548110610eeb57fe5b906000526020600020015483141561100857600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610f4757fe5b9060005260206000200154600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208281548110610f9c57fe5b906000526020600020018190555082600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208381548110610ff557fe5b9060005260206000200181905550611015565b8080600101915050610e57565b50600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002080548091906001900361106891906113bd565b50505050565b600080606061107c8661132a565b61108b57600192505050611322565b8573ffffffffffffffffffffffffffffffffffffffff16636745782b60e01b33898888604051602401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200183815260200180602001828103825283818151815260200191508051906020019080838360005b8381101561115b578082015181840152602081019050611140565b50505050905090810190601f1680156111885780820380516001836020036101000a031916815260200191505b5095505050505050604051602081830303815290604052907bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040518082805190602001908083835b6020831061122057805182526020820191506020810190506020830392506111fd565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114611282576040519150601f19603f3d011682016040523d82523d6000602084013e611287565b606091505b508092508193505050600081511415801561130b5750636745782b60e01b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19168180602001905160208110156112d957600080fd5b81019080805190602001909291905050507bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916145b1561131b57600192505050611322565b6000925050505b949350505050565b600080823b905060008111915050919050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061137e57805160ff19168380011785556113ac565b828001600101855582156113ac579182015b828111156113ab578251825591602001919060010190611390565b5b5090506113b991906113e9565b5090565b8154818355818111156113e4578183600052602060002091820191016113e391906113e9565b5b505050565b61140b91905b808211156114075760008160009055506001016113ef565b5090565b9056fe4b495031373a207472616e7366657220746f206e6f6e204b49503137526563656976657220696d706c656d656e74796f7520617265206e6f7420746865206f776e6572206f662074686520746f6b656e4b495031373a2062616c616e636520717565727920666f7220746865207a65726f2061646472657373a165627a7a7230582074631fbcf9d3afb7a18a7098f93ab03085fef6dcfc8608f48f7cc7585da581380029',
sourceMap: '85:4074:1:-;;;110:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;147:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;85:4074;8:9:-1;5:2;;;30:1;27;20:12;5:2;85:4074:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;',
deployedSourceMap: '85:4074:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;85:4074:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;110:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;110:31:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;192:45;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;192:45:1;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;659:375;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;659:375:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;8;5:28;2:2;;;46:1;43;36:12;2:2;659:375:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;659:375:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;659:375:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;659:375:1;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3984:173;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3984:173:1;;;;;;;;;;;;;;;;;;;21:11:-1;8;5:28;2:2;;;46:1;43;36:12;2:2;3984:173:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;3984:173:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;3984:173:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;3984:173:1;;;;;;;;;;;;;;;:::i;:::-;;266:43;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;266:43:1;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;266:43:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1040:207;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;1040:207:1;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;147:27;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;147:27:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3861:117;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3861:117:1;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;3861:117:1;;;;;;;;;;;;;;;;;1358:772;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;1358:772:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;21:11:-1;8;5:28;2:2;;;46:1;43;36:12;2:2;1358:772:1;;35:9:-1;28:4;12:14;8:25;5:40;2:2;;;58:1;55;48:12;2:2;1358:772:1;;;;;;100:9:-1;95:1;81:12;77:20;67:8;63:35;60:50;39:11;25:12;22:29;11:107;8:2;;;131:1;128;121:12;8:2;1358:772:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;30:3:-1;22:6;14;1:33;99:1;93:3;85:6;81:16;74:27;137:4;133:9;126:4;121:3;117:14;113:30;106:37;;169:3;161:6;157:16;147:26;;1358:772:1;;;;;;;;;;;;;;;:::i;:::-;;1250:102;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;1250:102:1;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;110:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;192:45::-;;;;;;;;;;;;;;;;;;;;;;:::o;659:375::-;753:4;890:2;868:10;:19;879:7;868:19;;;;;;;;;;;;:24;;;;;;;;;;;;;;;;;;923:8;902:9;:18;912:7;902:18;;;;;;;;;;;:29;;;;;;;;;;;;:::i;:::-;;975:12;:16;988:2;975:16;;;;;;;;;;;;;;;997:7;975:30;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;975:30:1;;;;;;;;;;;;;;;;;;;;;;1023:4;1016:11;;659:375;;;;;:::o;3984:173::-;4136:3;4120:9;:13;4130:2;4120:13;;;;;;;;;;;:19;;;;;;;;;;;;:::i;:::-;;3984:173;;:::o;266:43::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;1040:207::-;1095:7;1144:1;1127:19;;:5;:19;;;;1110:95;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1218:12;:19;1231:5;1218:19;;;;;;;;;;;;;;;:26;;;;1211:33;;1040:207;;;:::o;147:27::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;3861:117::-;3918:16;3952:12;:19;3965:5;3952:19;;;;;;;;;;;;;;;3945:26;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3861:117;;;:::o;1358:772::-;1479:10;1471:18;;:4;:18;;;1463:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1600:10;:19;1611:7;1600:19;;;;;;;;;;;;;;;;;;;;;1592:27;;:4;:27;;;1584:74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1739:35;1760:4;1766:7;1739:20;:35::i;:::-;1784:12;:16;1797:2;1784:16;;;;;;;;;;;;;;;1806:7;1784:30;;39:1:-1;33:3;27:10;23:18;57:10;52:3;45:23;79:10;72:17;;0:93;1784:30:1;;;;;;;;;;;;;;;;;;;;;;1857:2;1835:10;:19;1846:7;1835:19;;;;;;;;;;;;:24;;;;;;;;;;;;;;;;;;2006:47;2028:4;2034:2;2038:7;2047:5;2006:21;:47::i;:::-;1985:128;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1358:772;;;;:::o;1250:102::-;1303:4;1327:16;1337:5;1327:9;:16::i;:::-;1320:23;;1250:102;;;:::o;3216:639::-;3410:20;3461:1;3433:12;:18;3446:4;3433:18;;;;;;;;;;;;;;;:25;;;;:29;3410:52;;3476:9;3488:1;3476:13;;3472:340;3495:12;:18;3508:4;3495:18;;;;;;;;;;;;;;;:25;;;;3491:1;:29;3472:340;;;3554:12;:18;3567:4;3554:18;;;;;;;;;;;;;;;3573:1;3554:21;;;;;;;;;;;;;;;;3543:7;:32;3540:262;;;3673:12;:18;3686:4;3673:18;;;;;;;;;;;;;;;3692:12;3673:32;;;;;;;;;;;;;;;;3649:12;:18;3662:4;3649:18;;;;;;;;;;;;;;;3668:1;3649:21;;;;;;;;;;;;;;;:56;;;;3757:7;3722:12;:18;3735:4;3722:18;;;;;;;;;;;;;;;3741:12;3722:32;;;;;;;;;;;;;;;:42;;;;3782:5;;3540:262;3522:3;;;;;;;3472:340;;;;3821:12;:18;3834:4;3821:18;;;;;;;;;;;;;;;:27;;;;;;;;;;;;:::i;:::-;;3216:639;;;:::o;2182:856::-;2293:4;2308:12;2330:23;2368:14;2379:2;2368:10;:14::i;:::-;2364:94;;2443:4;2436:11;;;;;;2364:94;2492:2;:7;;512:10;2600:15;;2673:10;2701:4;2723:7;2748:5;2560:207;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;2560:207:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;49:4:-1;39:7;30;26:21;22:32;13:7;6:49;2560:207:1;;;;;;;38:4:-1;29:7;25:18;67:10;61:17;96:58;199:8;192:4;186;182:15;179:29;167:10;160:49;0:215;;;2560:207:1;2492:285;;;;;;;;;;;;;36:153:-1;66:2;61:3;58:11;36:153;;182:3;176:10;171:3;164:23;98:2;93:3;89:12;82:19;;123:2;118:3;114:12;107:19;;148:2;143:3;139:12;132:19;;36:153;;;274:1;267:3;263:2;259:12;254:3;250:22;246:30;315:4;311:9;305:3;299:10;295:26;356:4;350:3;344:10;340:21;389:7;380;377:20;372:3;365:33;3:399;;;2492:285:1;;;;;;;;;;;;;;;;;;;;;;;;14:1:-1;21;16:31;;;;75:4;69:11;64:16;;144:4;140:9;133:4;115:16;111:27;107:43;104:1;100:51;94:4;87:65;169:16;166:1;159:27;225:16;222:1;215:4;212:1;208:12;193:49;7:242;;16:31;36:4;31:9;;7:242;;2468:309:1;;;;;;;;2824:1;2803:10;:17;:22;;:160;;;;;512:10;2948:15;;2912:51;;;2923:10;2912:32;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2912:32:1;;;;;;;;;;;;;;;;:51;;;;2803:160;2787:223;;;2995:4;2988:11;;;;;;2787:223;3026:5;3019:12;;;;2182:856;;;;;;;:::o;3044:166::-;3103:4;3118:12;3170:7;3158:20;3150:28;;3202:1;3195:4;:8;3188:15;;;3044:166;;;:::o;85:4074::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o',
source: '//Klaytn IDE uses solidity 0.4.24 0.5.6 versions.\n' +
'pragma solidity >=0.4.24 <=0.5.6;\n' +
'\n' +
'contract NFTSimple {\n' +
' string public name = "KlayLion";\n' +
' string public symbol = "KL"; // 단위 \n' +
'\n' +
' mapping(uint256 => address) public tokenOwner; // token owner mapping\n' +
' mapping(uint256 => string) public tokenURIs; // key - value type declare\n' +
'\n' +
' // 소유한 토큰 리스트\n' +
' mapping(address => uint256[]) private _ownedTokens;\n' +
' // onKIP17Received bytes value\n' +
'\n' +
' bytes4 private constant _KIP17_RECEIVED = 0x6745782b;\n' +
'\n' +
' // mint(tokenId, uri, owner) : 발행\n' +
' // transferFrom(from, to, tokenId) : 전송 -> owner가 바뀌는 것 (from -> to)\n' +
'\n' +
' function mintWithTokenURI(address to, uint256 tokenId, string memory tokenURI) public returns(bool){\n' +
' // to에게 tokenId(일련번호)를 발행하겠다. \n' +
' // 적힐 글자는 tokenURI\n' +
' tokenOwner[tokenId] = to;\n' +
' tokenURIs[tokenId] = tokenURI;\n' +
'\n' +
' // add token to the list\n' +
' _ownedTokens[to].push(tokenId);\n' +
'\n' +
' return true;\n' +
' }\n' +
'\n' +
' function balanceOf(address owner) public view returns (uint256) {\n' +
' require(\n' +
' owner != address(0),\n' +
' "KIP17: balance query for the zero address"\n' +
' );\n' +
' return _ownedTokens[owner].length;\n' +
'}\n' +
'\n' +
' function balance (address _addr) public view returns(uint){\n' +
' return balanceOf(_addr);\n' +
' }\n' +
'\n' +
' function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory _data) public{\n' +
' require(from == msg.sender, "from !- msg.sender"); // 보내는 사람이 현재 이 함수를 실행한 주체 \n' +
' require(from == tokenOwner[tokenId], "you are not the owner of the token"); // 보내는 사람이 보내려고 하는 토큰의 주인\n' +
' //\n' +
' _removeTokenFromList(from, tokenId);\n' +
' _ownedTokens[to].push(tokenId);\n' +
' //\n' +
' tokenOwner[tokenId] = to;\n' +
'\n' +
' // 만약에 받는 쪽이 실행할 코드가 있는 스마트 컨트렉트이면 코드를 실행할 것\n' +
' require(\n' +
' _checkOnKIP17Received(from, to, tokenId, _data), "KIP17: transfer to non KIP17Receiver implement"\n' +
' );\n' +
'\n' +
' \n' +
' }\n' +
'\n' +
' //internal option : 외부 호춣 불가 \n' +
' function _checkOnKIP17Received(address from, address to, uint256 tokenId, bytes memory _data) internal returns(bool){\n' +
' bool success;\n' +
' bytes memory returndata;\n' +
'\n' +
' if(!isContract(to)){ // smart contract address인지 판별\n' +
' return true;\n' +
' }\n' +
'\n' +
' (success, returndata) = to.call( // 성공여부와 return 값을 받아와라 \n' +
' abi.encodeWithSelector(\n' +
' _KIP17_RECEIVED, //smart contract면 이걸 실행해라\n' +
' msg.sender,\n' +
' from,\n' +
' tokenId,\n' +
' _data\n' +
' )\n' +
' );\n' +
' if(\n' +
' returndata.length != 0 && //만약 return 값이 존재하며 그 값이 _KIP17_RECEIVED이면, \n' +
' abi.decode(returndata, (bytes4)) == _KIP17_RECEIVED\n' +
' ) {\n' +
' return true;\n' +
' }\n' +
' return false;\n' +
' }\n' +
'\n' +
' function isContract(address account) internal view returns(bool){\n' +
' uint256 size;\n' +
' assembly {size := extcodesize(account)}\n' +
' return size > 0;\n' +
' }\n' +
'\n' +
' function _removeTokenFromList(address from, uint256 tokenId) private{\n' +
' // [10, 15, 19, 20] -> 19번을 삭제하고 싶어요.\n' +
' // [10, 15, 20, 19]\n' +
' // [10, 15, 20]\n' +
' uint256 lastTokenIdx = _ownedTokens[from].length - 1;\n' +
' for(uint256 i = 0; i < _ownedTokens[from].length; i++){\n' +
' if(tokenId == _ownedTokens[from][i]){\n' +
' // swap last token with deleting token;\n' +
' _ownedTokens[from][i] = _ownedTokens[from][lastTokenIdx];\n' +
' _ownedTokens[from][lastTokenIdx] = tokenId;\n' +
' break;\n' +
' }\n' +
' }\n' +
' _ownedTokens[from].length--;\n' +
' }\n' +
'\n' +
' function ownedTokens(address owner) public view returns (uint256[] memory){\n' +
' return _ownedTokens[owner];\n' +
' }\n' +
'\n' +
' function setTokenUri(uint256 id, string memory uri) public { // memory는 좀 긴 타입의 데이터를 표시할 떄 쓴다. \n' +
' tokenURIs[id] = uri; // mapping\n' +
' }\n' +
'} \n' +
'\n' +
'\n' +
'contract NFTMarket {\n' +
' //token 보낸 사람을 기억 W\n' +
' mapping(uint256 => address) public seller;\n' +
'\n' +
' function buyNFT(uint256 tokenId, address NFTAddress) public payable returns (bool){ //payable이 있어야 KLAY를 보낼 수 있다. \n' +
' //NFTAddress에는 NFTSimple이 배포된 주소를 넣어준다. \n' +
'\n' +
' // 판매한 사람에게 0.01 KLAY 전송\n' +
' address payable receiver = address(uint160(seller[tokenId])); // 돈을 받을 사람은 seller이다. payable L 돈을 받을 수 있는~\n' +
'\n' +
' // Send 0.01 KAY to receiver\n' +
' // 10 ** 18 PEB = 1 KLAY\n' +
' // 10 ** 16 PEB = 0.01 KLAY\n' +
' receiver.transfer(10 ** 16); // buyNFT를 호출한 사람이 이것까지 낸다. \n' +
'\n' +
" NFTSimple(NFTAddress).safeTransferFrom(address(this), msg.sender, tokenId, '0x00'); // to 대신 msg.sender 무조건 이 함수 호출한 사람에게 보낸다. \n" +
' return true;\n' +
' }\n' +
'\n' +
' // Market이 토큰을 받았을 때 (판매대에 올라갔을 때), 판매자가 누구인지 기록해야 한다. \n' +
' function onKIP17Received(address operator, address from , uint256 tokenId, bytes memory data) public returns (bytes4) {\n' +
' seller[tokenId] = from;\n' +
'\n' +
' return bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"));\n' +
' // return이 의미하는 것은 현재 구현된 함수가 이 smart contract에 존재한다는 것을 알리는 용도\n' +
' }\n' +
'}',
sourcePath: '/Users/kimdawoon/klaytn/contracts/NFTSimple.sol',
ast: [Object],
legacyAST: [Object],
compiler: [Object],
networks: [Object],
schemaVersion: '3.0.14',
updatedAt: '2022-02-12T05:50:19.373Z',
devdoc: [Object],
userdoc: [Object]
},
setProvider: [Function: bound setProvider],
new: [Function: bound new] {
estimateGas: [Function: bound estimateDeployment]
},
at: [Function: bound at] AsyncFunction,
deployed: [Function: bound deployed] AsyncFunction,
defaults: [Function: bound defaults],
hasNetwork: [Function: bound hasNetwork],
isDeployed: [Function: bound isDeployed],
detectNetwork: [Function: bound detectNetwork] AsyncFunction,
setNetwork: [Function: bound setNetwork],
setNetworkType: [Function: bound setNetworkType],
setWallet: [Function: bound setWallet],
resetAddress: [Function: bound resetAddress],
link: [Function: bound link],
clone: [Function: bound clone],
addProp: [Function: bound addProp],
toJSON: [Function: bound toJSON],
decodeLogs: [Function: bound decodeLogs],
web3: Web3Shim {
currentProvider: [Getter/Setter],
_requestManager: [RequestManager],
givenProvider: null,
providers: [Object],
_provider: [HttpProvider],
setProvider: [Function (anonymous)],
BatchRequest: [Function: bound Batch],
extend: [Function],
version: '1.2.1',
utils: [Object],
eth: [Eth],
shh: [Shh],
bzz: [Bzz],
networkType: 'ethereum'
},
class_defaults: {
from: '0x2a467DA4a19ACac7D793381E0801b463d49a40D0',
gas: 6721975,
gasPrice: 20000000000
},
currentProvider: HttpProvider {
host: 'http://127.0.0.1:7545',
httpAgent: [Agent],
timeout: 0,
headers: undefined,
connected: true,
send: [Function (anonymous)],
_alreadyWrapped: true
},
network_id: '5777',
networkType: 'ethereum'
},
methods: {
'name()': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'tokenOwner(uint256)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'tokenURIs(uint256)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'symbol()': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'mintWithTokenURI(address,uint256,string)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'balanceOf(address)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'balance(address)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'safeTransferFrom(address,address,uint256,bytes)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'ownedTokens(address)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
'setTokenUri(uint256,string)': [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
}
},
abi: [
{
constant: true,
inputs: [],
name: 'name',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0x06fdde03'
},
{
constant: true,
inputs: [Array],
name: 'tokenOwner',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0x1caaa487'
},
{
constant: true,
inputs: [Array],
name: 'tokenURIs',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0x6c8b703f'
},
{
constant: true,
inputs: [],
name: 'symbol',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0x95d89b41'
},
{
constant: false,
inputs: [Array],
name: 'mintWithTokenURI',
outputs: [Array],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
signature: '0x50bb4e7f'
},
{
constant: true,
inputs: [Array],
name: 'balanceOf',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0x70a08231'
},
{
constant: true,
inputs: [Array],
name: 'balance',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0xe3d670d7'
},
{
constant: false,
inputs: [Array],
name: 'safeTransferFrom',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
signature: '0xb88d4fde'
},
{
constant: true,
inputs: [Array],
name: 'ownedTokens',
outputs: [Array],
payable: false,
stateMutability: 'view',
type: 'function',
signature: '0xb12ab40f'
},
{
constant: false,
inputs: [Array],
name: 'setTokenUri',
outputs: [],
payable: false,
stateMutability: 'nonpayable',
type: 'function',
signature: '0x57f7789e'
}
],
address: '0xC4D4a60745bDc14Dd92aD40909A5D162CE77b803',
transactionHash: undefined,
contract: Contract {
currentProvider: [Getter/Setter],
_requestManager: RequestManager {
provider: [HttpProvider],
providers: [Object],
subscriptions: {}
},
givenProvider: null,
providers: {
WebsocketProvider: [Function: WebsocketProvider],
HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider]
},
_provider: HttpProvider {
host: 'http://127.0.0.1:7545',
httpAgent: [Agent],
timeout: 0,
headers: undefined,
connected: true,
send: [Function (anonymous)],
_alreadyWrapped: true
},
setProvider: [Function (anonymous)],
BatchRequest: [Function: bound Batch],
extend: [Function: ex] {
formatters: [Object],
utils: [Object],
Method: [Function: Method]
},
clearSubscriptions: [Function (anonymous)],
options: { address: [Getter/Setter], jsonInterface: [Getter/Setter] },
defaultAccount: [Getter/Setter],
defaultBlock: [Getter/Setter],
methods: {
name: [Function: bound _createTxObject],
'0x06fdde03': [Function: bound _createTxObject],
'name()': [Function: bound _createTxObject],
tokenOwner: [Function: bound _createTxObject],
'0x1caaa487': [Function: bound _createTxObject],
'tokenOwner(uint256)': [Function: bound _createTxObject],
tokenURIs: [Function: bound _createTxObject],
'0x6c8b703f': [Function: bound _createTxObject],
'tokenURIs(uint256)': [Function: bound _createTxObject],
symbol: [Function: bound _createTxObject],
'0x95d89b41': [Function: bound _createTxObject],
'symbol()': [Function: bound _createTxObject],
mintWithTokenURI: [Function: bound _createTxObject],
'0x50bb4e7f': [Function: bound _createTxObject],
'mintWithTokenURI(address,uint256,string)': [Function: bound _createTxObject],
balanceOf: [Function: bound _createTxObject],
'0x70a08231': [Function: bound _createTxObject],
'balanceOf(address)': [Function: bound _createTxObject],
balance: [Function: bound _createTxObject],
'0xe3d670d7': [Function: bound _createTxObject],
'balance(address)': [Function: bound _createTxObject],
safeTransferFrom: [Function: bound _createTxObject],
'0xb88d4fde': [Function: bound _createTxObject],
'safeTransferFrom(address,address,uint256,bytes)': [Function: bound _createTxObject],
ownedTokens: [Function: bound _createTxObject],
'0xb12ab40f': [Function: bound _createTxObject],
'ownedTokens(address)': [Function: bound _createTxObject],
setTokenUri: [Function: bound _createTxObject],
'0x57f7789e': [Function: bound _createTxObject],
'setTokenUri(uint256,string)': [Function: bound _createTxObject]
},
events: { allEvents: [Function: bound ] },
_address: '0xC4D4a60745bDc14Dd92aD40909A5D162CE77b803',
_jsonInterface: [
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object],
[Object], [Object]
]
},
name: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
tokenOwner: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
tokenURIs: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
symbol: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
mintWithTokenURI: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
balanceOf: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
balance: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
safeTransferFrom: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
ownedTokens: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
setTokenUri: [Function (anonymous)] {
call: [Function (anonymous)],
sendTransaction: [Function (anonymous)],
estimateGas: [Function (anonymous)],
request: [Function (anonymous)]
},
sendTransaction: [Function (anonymous)],
send: [Function (anonymous)],
allEvents: [Function (anonymous)],
getPastEvents: [Function (anonymous)]
}
각종 smart contract 관련 정보들이 나오게 됩니다.
또한 console에 it. tap을 두번 치게 되면
truffle(ganache)> it.
it.__proto__ it.hasOwnProperty it.isPrototypeOf
it.propertyIsEnumerable it.toLocaleString it.toString
it.valueOf
it.abi it.address it.allEvents
it.balance it.balanceOf it.constructor
it.contract it.getPastEvents it.methods
it.mintWithTokenURI it.name it.ownedTokens
it.safeTransferFrom it.send it.sendTransaction
it.setTokenUri it.symbol it.tokenOwner
it.tokenURIs it.transactionHash
사용할 수 잇는 변수들을 확인할 수 있습니다.
이제 contract 내에 있는 함수를 테스트 해보면 아래와 같이 할 수 있습니다.
truffle(ganache)> it.mintWithTokenURI("0x2a467DA4a19ACac7D793381E0801b463d49a40D0",10,"happy")
{
tx: '0xb7aa585552c452b53cef4903ef2a4caa50fb563c4dbc1fed606b62f880f361d6',
receipt: {
transactionHash: '0xb7aa585552c452b53cef4903ef2a4caa50fb563c4dbc1fed606b62f880f361d6',
transactionIndex: 0,
blockHash: '0x53b59e086e003ac8ddfb30fe9af3cff768e6cf116f74b474cfd2e0f850acafe5',
blockNumber: 4,
from: '0x2a467da4a19acac7d793381e0801b463d49a40d0',
to: '0xc4d4a60745bdc14dd92ad40909a5d162ce77b803',
gasUsed: 105977,
cumulativeGasUsed: 105977,
contractAddress: null,
logs: [],
status: true,
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
rawLogs: []
},
logs: []
}
위와 같이 mintWithTokenURI function을 실행하여 보았습니다.
이제 제대로 생성됐는지 확인하기 위해 아래와 같이 명령을 입력해보면,
truffle(ganache)> it.balanceOf("0x2a467DA4a19ACac7D793381E0801b463d49a40D0")
BN { negative: 0, words: [ 1, <1 empty item> ], length: 1, red: null }
해당 주소의 balanceOf 명령에 응답으로 1이 나왔음을 알 수 있습니다.
다시 한 번 생성을 해보고 확인을 해보면
truffle(ganache)> it.mintWithTokenURI("0x2a467DA4a19ACac7D793381E0801b463d49a40D0",11,"happy")
{
tx: '0xd729179c6b15775bc9006efac56060c8b2ade22ced218b8c32c753e353ff6a40',
receipt: {
transactionHash: '0xd729179c6b15775bc9006efac56060c8b2ade22ced218b8c32c753e353ff6a40',
transactionIndex: 0,
blockHash: '0x2d23e7a9b2aef66a7863c361965412d27e0c254801abf7f97b686047fcda172c',
blockNumber: 5,
from: '0x2a467da4a19acac7d793381e0801b463d49a40d0',
to: '0xc4d4a60745bdc14dd92ad40909a5d162ce77b803',
gasUsed: 90977,
cumulativeGasUsed: 90977,
contractAddress: null,
logs: [],
status: true,
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
rawLogs: []
},
logs: []
}
truffle(ganache)> it.balanceOf("0x2a467DA4a19ACac7D793381E0801b463d49a40D0")
BN { negative: 0, words: [ 2, <1 empty item> ], length: 1, red: null }
정상적으로 tokenId 2가 생성되고 balanceOf로 확인 시 2개의 token이 할당 됨을 볼 수 있습니다.
./test/TestSimpleStorage.sol
상기 경로 내에 예제 Test Code를 작성했습니다.
기본적인 포멧은 해당 코드와 같습니다.
//Klaytn IDE uses solidity 0.4.24 0.5.6 versions.
pragma solidity >=0.4.24 <=0.5.6;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/NFTSimple.sol";
contract TestSimpleStorage{
function testSimpleStorage() public {
NFTSimple it = new NFTSimple();
it.mintWithTokenURI(address(this), 20, "happy");
uint256 ans = it.balanceOf(address(this));
Assert.equal(ans, 3, "value equal test");
}
}
새로 Contract Code를 작성해서 내부에 Test할 Contract의 instance를 생성하고, 원하는 함수를 호출 후 Truffle Assert 함수로 Check하는 식입니다.
현재 해당 코드를 작성 후 Truffle Console에서 Test 하 시에는 아래와 같이 입력합니다.
truffle(ganache)> test
Using network 'ganache'.
Compiling your contracts...
===========================
> Compiling ./test/TestSimpleStorage.sol
> compilation warnings encountered:
/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:40:2: Warning: Variable is shadowed in inline assembly by an instruction of the same name
function balance (address _addr) public view returns(uint){
^ (Relevant source part starts here and spans across multiple lines).
,/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:140:30: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
function onKIP17Received(address operator, address from , uint256 tokenId, bytes memory data) public returns (bytes4) {
^--------------^
,/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:140:80: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
function onKIP17Received(address operator, address from , uint256 tokenId, bytes memory data) public returns (bytes4) {
^---------------^
TypeError [ERR_INVALID_REPL_INPUT]: Listeners for `uncaughtException` cannot be used in the REPL
at new NodeError (internal/errors.js:322:7)
at process.<anonymous> (repl.js:349:15)
at process.emit (events.js:412:35)
at process.emit (/usr/local/lib/node_modules/truffle/build/webpack:/~/source-map-support/source-map-support.js:465:1)
at _addListener (events.js:443:14)
at process.addListener (events.js:497:10)
at Runner.run (/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/runner.js:868:11)
at Mocha.run (/usr/local/lib/node_modules/truffle/node_modules/mocha/lib/mocha.js:612:17)
at /usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-core/lib/test.js:116:1
at new Promise (<anonymous>)
at Object.run (/usr/local/lib/node_modules/truffle/build/webpack:/packages/truffle-core/lib/test.js:115:1)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
현재 TypeErr가 나서 정상적으로 결과가 나오지는 않았습니다.
해당 부분은 확인 후 수정 예정이므로 해당 과정만 참고 바랍니다.
truffle 버전을 truffle@nodeLTS로 변경해주시면 test가 정상적으로 수행됩니다.
npm un -g truffle
npm i -g truffle@nodeLTS
이전에 수행하려던 test를 다시 수행하면
//Klaytn IDE uses solidity 0.4.24 0.5.6 versions.
pragma solidity >=0.4.24 <=0.5.6;
import "truffle/Assert.sol";
import "truffle/DeployedAddresses.sol";
import "../contracts/NFTSimple.sol";
contract TestSimpleStorage{
function testSimpleStorage() public {
NFTSimple it = new NFTSimple();
it.mintWithTokenURI(address(this), 20, "happy");
uint256 ans = it.balanceOf(address(this));
Assert.equal(ans, 1, "value equal test");
}
}
코드에서 보다시피 배포한 주소에 1개의 토큰을 mint하고 다시 해당 주소에 대해 balanceOf를 호출한 값과 결과를 비교하게 됩니다.
예상하다시피 1이 나와야 합니다.
truffle(ganache)> test
Using network 'ganache'.
Compiling your contracts...
===========================
> Compiling ./test/TestSimpleStorage.sol
> Compilation warnings encountered:
/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:40:2: Warning: Variable is shadowed in inline assembly by an instruction of the same name
function balance (address _addr) public view returns(uint){
^ (Relevant source part starts here and spans across multiple lines).
,/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:140:30: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
function onKIP17Received(address operator, address from , uint256 tokenId, bytes memory data) public returns (bytes4) {
^--------------^
,/Users/kimdawoon/klaytn/contracts/NFTSimple.sol:140:80: Warning: Unused function parameter. Remove or comment out the variable name to silence this warning.
function onKIP17Received(address operator, address from , uint256 tokenId, bytes memory data) public returns (bytes4) {
^---------------^
> Artifacts written to /tmp/test-2022113-8636-1qrqaru.3vqu
> Compiled successfully using:
- solc: 0.5.6+commit.b259423e.Emscripten.clang
TestSimpleStorage
✓ testSimpleStorage (166ms)
1 passing (7s)
예상했다시피 test를 통과하고 passing된 결과가 나오게 됩니다.