Skip to content

Instantly share code, notes, and snippets.

@wadro
Last active June 23, 2021 06:23
Show Gist options
  • Save wadro/390ee44e607ea4d4119383cd7d42d924 to your computer and use it in GitHub Desktop.
Save wadro/390ee44e607ea4d4119383cd7d42d924 to your computer and use it in GitHub Desktop.
멋쟁이사자처럼 Klaytn NFT Class 2주차 과제
/*
### 과제 제출 리스트
- [1주차(https://gist.github.com/wadro/26fee8648d9c2aae9431bb2ee8805835)](https://gist.github.com/wadro/26fee8648d9c2aae9431bb2ee8805835)
- [2주차(https://gist.github.com/wadro/390ee44e607ea4d4119383cd7d42d924)](https://gist.github.com/wadro/390ee44e607ea4d4119383cd7d42d924)
- [3주차(https://gist.github.com/wadro/e48b7665df98a81759e929742bb62cdb)](https://gist.github.com/wadro/e48b7665df98a81759e929742bb62cdb)
- [해커톤(https://gist.github.com/wadro/6fac56024ba4e2ebda34ec354ce0dbf6)](https://gist.github.com/wadro/6fac56024ba4e2ebda34ec354ce0dbf6)
---
*/
// 배포한 주소(account):
// BAOBAB_CONTRACT_ADDRESS : 0xC837e882Cb30aabF294534344b9ED77f6F456E19
// CYPRESS_CONTRACT_ADDRESS : 0xa559b3575fa5538c9f1b5bE43B19C0E00fA1419a
// 수정된 부분:
// 1. 컨트랙트 이름
// - NFTSimple -> MyTrademark [line 19]
// - NFTMarket -> TrademarkMarket [line 181]
// 2. 추가한 함수
// - logTrademark: [line 63]
// - tokenId 로 구분
// - logs 매핑(tokenId => 사용기록[배열]) 과 timestamps 매핑 (tokenId => 시간[배열]) ( 현재시간은 now 로 호출 )
/**
* 오후 12:16 2021-06-23 변경사항
* 1. tokenUri -> tokenInfo struct 로 변경
* - tokenUri 관련 함수 전부 변경
*
*/
// Klaytn IDE uses solidity 0.4.24, 0.5.6 versions.
pragma solidity >=0.4.24 <=0.5.6;
contract MyTrademark {
string public name = "LogTrademark";
string public symbol = "KL";
struct tokenInfo {
string title;
string tokenUri;
string description;
uint256 category;
uint256 sector;
}
mapping(uint256 => address) public tokenOwner;
mapping(uint256 => tokenInfo) public tokenInfoMap;
mapping(uint256 => uint256[]) private _timestamps;
mapping(uint256 => string[]) private _logs;
uint256[] private _enrolledTokens;
mapping(address => uint256[]) private _ownedTokens;
bytes4 private constant _KIP17_RECEIVED = 0x6745782b;
function registerMarkInfo(
address to, uint256 tokenId, string memory title,
string memory tokenUri, string memory description,
uint256 category, uint256 sector
) public returns (bool) {
require(to == msg.sender, "from != msg.sender");
require(
tokenOwner[tokenId] == 0x0000000000000000000000000000000000000000,
"enrolled ID!"
);
tokenOwner[tokenId] = to;
tokenInfo storage newToken = tokenInfoMap[tokenId];
newToken.title = title;
newToken.tokenUri = tokenUri;
newToken.description = description;
newToken.category = category;
newToken.sector = sector;
_enrolledTokens.push(tokenId);
// add token to the list
_ownedTokens[to].push(tokenId);
uint256 _tempNow = now;
_timestamps[tokenId].push(_tempNow); // 0: uint256: 1621905998
_logs[tokenId].push("Trace your first use log!");
return true;
}
function getMarkInfo(
uint256 tokenId
) public view returns (string memory, string memory, string memory,uint256,uint256){
tokenInfo storage s = tokenInfoMap[tokenId];
return (s.title,s.tokenUri,s.description,s.category,s.sector);
}
function setMarkInfo(
address from, uint256 tokenId, string memory title,
string memory tokenUri, string memory description,
uint256 category, uint256 sector
) public returns (bool) {
require(from == msg.sender, "from != msg.sender");
require(
from == tokenOwner[tokenId],
"you are not the owner of the token"
);
tokenInfo storage s = tokenInfoMap[tokenId];
s.title = title;
s.tokenUri = tokenUri;
s.description = description;
s.category = category;
s.sector = sector;
return true;
}
function logTrademark(
address from,
uint256 tokenId,
string memory logData
) public {
bytes memory _tempLog = bytes(_logs[tokenId][0]); // Uses memory
require(from == msg.sender, "from != msg.sender");
require(
from == tokenOwner[tokenId],
"you are not the owner of the token"
);
require(
// _tempLog.length == 25,
_tempLog.length != 0,
// firstlog != 0,
"first log error!"
);
_logs[tokenId].push(logData);
_timestamps[tokenId].push(now);
}
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public {
require(from == msg.sender, "from != msg.sender");
require(
from == tokenOwner[tokenId],
"you are not the owner of the token"
);
_removeTokenFromList(from, tokenId);
_ownedTokens[to].push(tokenId);
tokenOwner[tokenId] = to;
require(
_checkOnKIP17Received(from, to, tokenId, _data),
"KIP17: transfer to non KIP17Receiver implementer"
);
}
function _removeTokenFromList(address from, uint256 tokenId) private {
uint256 lastTokenIndex = _ownedTokens[from].length - 1;
for (uint256 i = 0; i < _ownedTokens[from].length; i++) {
if (tokenId == _ownedTokens[from][i]) {
// Swap last token with deleting token;
_ownedTokens[from][i] = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][lastTokenIndex] = tokenId;
break;
}
}
_ownedTokens[from].length--;
}
function ownedTokens(address owner) public view returns (uint256[] memory) {
return _ownedTokens[owner];
}
function enrolledTokens() public view returns (uint256[] memory) {
return _enrolledTokens;
}
function getLogTimes(uint256 tokenId) public view returns (uint256[] memory) {
return _timestamps[tokenId];
}
function getLog(uint256 tokenId, uint256 index) public view returns (string memory) {
return _logs[tokenId][index];
}
function _checkOnKIP17Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) internal returns (bool) {
bool success;
bytes memory returndata;
if (!isContract(to)) {
return true;
}
(success, returndata) = to.call(
abi.encodeWithSelector(
_KIP17_RECEIVED,
msg.sender,
from,
tokenId,
_data
)
);
if (
returndata.length != 0 &&
abi.decode(returndata, (bytes4)) == _KIP17_RECEIVED
) {
return true;
}
return false;
}
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly {
size := extcodesize(account)
}
return size > 0;
}
}
contract TrademarkDeal {
mapping(uint256 => address[]) public seller;
function buyNFT(uint256 tokenId, address NFT)
public
payable
returns (bool)
{
uint256 _lastSellerIndex = seller[tokenId].length - 1;
address payable receiver = address(uint160(seller[tokenId][_lastSellerIndex]));
// Send 0.01 klay to Seller
receiver.transfer(10**16);
// Send NFT if properly send klay
MyTrademark(NFT).safeTransferFrom(
address(this),
msg.sender,
tokenId,
"0x00"
);
return true;
}
// Called when SafeTransferFrom called from NFT Contract
function onKIP17Received(
address operator,
address from,
uint256 tokenId,
bytes memory data
) public returns (bytes4) {
// Set token seller, who was a token owner
seller[tokenId].push(from);
// return signature which means this contract implemented interface for ERC721
return
bytes4(keccak256("onKIP17Received(address,address,uint256,bytes)"));
}
}
@wadro
Copy link
Author

wadro commented May 25, 2021

수정된 부분:
1. 컨트랙트 이름
- NFTSimple -> MyTrademark [line 19]
- NFTMarket -> TrademarkMarket [line 181]
2. 추가한 함수
- logTrademark: [line 63]
- tokenId 로 구분
- logs 매핑(tokenId => 사용기록[배열]) 과 timestamps 매핑 (tokenId => 시간[배열]) ( 현재시간은 now 로 호출 )

@BbChip0103
Copy link

BbChip0103 commented May 25, 2021

반갑습니다.
1주차 아이디어부터 지금 코드까지 쭉 읽어보았는데요.
비슷한 상표끼리 비교하고 분쟁이 일어나는 것을 떠나서, 간단하게 '누가 먼저 상표를 썼는지에 대한 증거'로서는 충분히 유용하게 쓸 수 있을 듯 합니다.

제가 상표라는 것에 대해서는 잘 몰라서 구글링해보니, 대표적으로는 회사의 로고가 상표로서 여겨지는 듯 합니다.
대외적인 활동보다는 내부적인 활동에 대해서 적용하기 좋을 듯 한데, 예시를 들어보면.
"어떤 회사가 자회사의 로고를 붙인 상품을 TV에 광고를 했다." 이런 정보는 굳이 NFT로 기록하지 않더라도 충분히 시간과 활동을 증명할 수 있을 듯 합니다.
하지만, 내부적인 상표 기록들, "ㅇㅇ년 ㅇㅇ월 ㅇㅇ일. ㅁㅁ한 컨셉으로 ㅁㅁ한 형태의 상표 프로토타입 제작."과 당시 프로토타입 로고 이미지(지금 string으로 기록하시는데, 이미지도 raw data 그대로 string으로 기록하면 될 듯 합니다)같은 건 블록체인이 아니라면 그 시기에 그 활동을 했다는 것을 증명하기가 참 까다롭지요. 파일의 만든 날짜 같은건 헤더 조금만 바꾸면 쉽게 조작할 수 있으니까요.

얼마 전에 골목식당 덮죽집 상표를 안타깝게 도난당한 사건이 있었습니다.
상표와 상품을 베낀 사측 입장에서는, 자신들도 원래 생각했던 아이템과 이름이라 억울한 입장이라고 주장하였습니다.
누가 봐도 거짓말이라는 것이 티가 나지만, 사실 증명하기가 굉장히 까다롭습니다.
원래 덮죽집 식당 측에서는 방송 기록을 통해 증명할 수 있었지만, 만약 방송이 아니었다면 조금 암울한 상황이 될 뻔 했습니다.
또한 방송을 보면 덮죽집 사장님께서 공책에다가 자필로 개발일지를 쓰셨습니다만, 그러한 증거는 모방한 회사측에서도 충분히 비슷한 것을 만들어서 우길 수도 있었구요.
이런 최근의 사례를 따져봤을 때, 자잘한 활동 기록을 증명할 수 있는 것이, 위 변조 진위여부를 판단할 때 굉장히 중요한 증거로 사용될 수 있을 듯 합니다.

@wadro
Copy link
Author

wadro commented May 25, 2021

@BbChip0103

훌륭한 코멘트 감사합니다.
앞으로도 복습하는 의미로 조금씩 다듬어 가보려고 합니다.

미국에서 쓰이고 있는 보조등록부 라는 개념을 가져온 것으로
말씀하신것처럼 사용한 내역을 증명 할수 있도록 공용장부를 만드는 느낌이죠.
사용자의 참여도를 올리고, 증명에만 거의 포커스를 맞출수 있도록 기존 특허 출원 절차보다 간소화시키려고 생각중입니다.

아이디어에 대한 코멘트부터 코드에 대한 코멘트까지 정성어린 조언에 감사드리고 좋게 봐주셔서 다행입니다.
흔히들 무관심보단 악플이 낫다고 하죠 ㅎㅎ 얼마든지 태클을 걸어도 괜찮습니다.
아이디어의 입장에서는 더 성장할수 있고, 사회 전체적으로 이익이 된다면 결국 긍정적인 영향이 저에게도 돌아오니까요.
(그렇다고 사회를 위해 희생한다는 말은 아니고 어디까지나 밸런스를 맞춘다는 가정입니다.)

예전에는 이런 활동을 할때 남들에게 비판받고 공격받는 것이 두려울때가 있었지만, 때로는 정말 악담에 진정성이 담길때가 있죠.
그리고 이 코멘트에는 꼭 답장 안하셔도 됩니다. 가끔 헛소리를 합니다.

@anxiubin
Copy link

안녕하세요 고민해서 코드를 작성하신 점이 눈에 띄네요:)
저는 그냥 연습용으로만 올려놨는데.. ㅎㅎ

73번째줄

이 부분은 왜 주석처리 하셨는지 알 수 있을까요?
logTrademark 함수를 실행하기 전에 최초 1회 로그가 등록되어있는지 확인이 필요할 것 같다고 생각이 들어요.

require(!logs[tokenId][0], "You should mint Token first");        

문구와 함께 이렇게 넣어주는 건 어떨까요?

@wadro
Copy link
Author

wadro commented May 26, 2021

@anxiubin

안녕하세요 고민해서 코드를 작성하신 점이 눈에 띄네요:)
저는 그냥 연습용으로만 올려놨는데.. ㅎㅎ

73번째줄

이 부분은 왜 주석처리 하셨는지 알 수 있을까요?
logTrademark 함수를 실행하기 전에 최초 1회 로그가 등록되어있는지 확인이 필요할 것 같다고 생각이 들어요.

require(!logs[tokenId][0], "You should mint Token first");        

문구와 함께 이렇게 넣어주는 건 어떨까요?

저 부분이 아마 에러가 나서 주석처리 했던 걸로 기억해요.
다음 수업을 듣고 다시 수정해보려구요.
조언해주신 코드로 해보겠습니다. 😄

@juliana-kim
Copy link

반복적으로 사용되는 require문(예를들어 "you are not the owner of the token)과 같은 경우는 modifier로 별도 구현해도 좋을거 같습니다.

@wadro
Copy link
Author

wadro commented Jun 23, 2021

반복적으로 사용되는 require문(예를들어 "you are not the owner of the token)과 같은 경우는 modifier로 별도 구현해도 좋을거 같습니다.

코멘트 감사합니다! 수정해보겠습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment