CSC School:CRC Interface #10

zeroxlive
Coinmonks
5 min readDec 29, 2022

--

We are familiar with CRC standards now.but how do we implement CRC standard with Solidity?

in this part we will look at CRC standard’s interface.

New to trading? Try crypto trading bots or copy trading on best crypto exchanges

CRC-20

Following is the basic interface of CRC20 that describes the function and event signature of CRC20 contracts, followed by the explanation of each given function:

contract CRC20 {
event Transfer(
address indexed from,
address indexed to,
uint256 value
);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
); function totalSupply() public view returns(uint256);
function balanceOf(address who) public view returns(uint256);
function transfer(address to, uint256 value) public returns(bool);
function allowance(address owner, address spender)
public view returns (uint256);
function transferFrom(address from, address to, uint256 value)
public returns (bool);
function approve(address spender, uint256 value)
public returns (bool);
}

Following are the features and components of the CRC-20 smart contract Interface.

totalsupply

The function totalSupply is public and thus accessible to all. It displays the total number of tokens that are currently in circulation. Since this totalSupply function is labeled with a view modifier, it doesn’t consume gas. Moreover, it updates the internal token value totalSupply_ whenever a new token is minted.

// its value is increased when new tokens are minted
uint256 totalSupply_;// access the value of totalSupply_
function totalSupply() public view returns (uint256) {
return totalSupply_;
}

balanceOf

balanceOf is another public with view modifier that makes it accessible to everyone, and it’s gas-free. It takes the CSC address and returns the tokens to the allocated address.

// Updated when tokens are minted or transferred
mapping(address => uint256) balances;// Returns tokens held by the address passed as _owner
function balanceOf(address _owner)
public view returns (uint256 balance) {
return balances[_owner];
}

transfer

Function transfer differs from the above two functions since it requires fas and thus results in significant changes in the CSC smart contracts. It transfers tokens from one address to another at the request of respective token holders.

function transfer(address _to, uint256 _value)
public returns (bool) { // Check for blank addresses
require(_to != address(0)); // Check to ensure valid transfer
require(_value <= balances[msg.sender]); // SafeMath.sub will throw if there is not enough balance.
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
// Event transfer defined in the CRC 20 interface above
Transfer(msg.sender, _to, _value); return true;
}

allowance, approve and transferFrom

The last functions allowance, approve, and transferFrom supports advanced functionalities such as authorizing some other Ethereum address to utilize token on behalf of the respective holder.

CRC-721

To understand how CRC-721 works, let’s have a look at its interface added here:

contract CRC721 {
event Transfer(
address indexed _from,
address indexed _to,
uint256 _tokenId
); event Approval(
address indexed _owner,
address indexed _approved,
uint256 _tokenId
); function balanceOf(address _owner)
public view returns (uint256 _balance); function ownerOf(uint256 _tokenId)public view returns (address _owner); function transfer(address _to, uint256 _tokenId) public; function approve(address _to, uint256 _tokenId) public; function takeOwnership(uint256 _tokenId) public;
}

balanceOf

In the below snippet, ownedTokens represents the complete list of token IDs of a particular address. Whereas,balanceOf function returns the number of tokens of that address.

mapping (address => uint256[]) private ownedTokens;function balanceOf(address _owner) public view returns (uint256) {
return ownedTokens[_owner].length;
}

OwnerOf

Mapping token owner takes tokened and outputs the owner of that ID. However, since its visibility is set private, by using the ownerOf function, you can set the value of this mapping as public. It also requires a check against zero addresses before it returns the value.

mapping (uint256 => address) private tokenOwner;function ownerOf(uint256 _tokenId) public view returns (address) {
address owner = tokenOwner[_tokenId];
require(owner != address(0));
return owner;
}

transfer

This transfer function takes in the new owner’s address as _to parameter and _tokenId of the token being transferred, also note that it can only be called by the owner of token. It must include the logic to check whether the transfer clears approval check, required for a transfer. Then comes the logic to remove token’s possession from current owner and add it to the list of tokens owned by new owner.

modifier onlyOwnerOf(uint256 _tokenId) {
require(ownerOf(_tokenId) == msg.sender);
_;
}function transfer(address _to, uint256 _tokenId)
public onlyOwnerOf(_tokenId) {
// Logic to clear approval for token transfer // Logic to remove token from current token owner // Logic to add Token to new token owner
}

approve

Approve is another function for another address to claim the ownership on a given token ID. It is restricted by a modifier only OwnerOf, which explains that only the token oners can access this function for a definite reason.

mapping (uint256 => address) private tokenApprovals;modifier onlyOwnerOf(uint256 _tokenId) {
require(ownerOf(_tokenId) == msg.sender);
_;
}function approvedFor(uint256 _tokenId)
public view returns (address) {
return tokenApprovals[_tokenId];
}function approve(address _to, uint256 _tokenId)
public onlyOwnerOf(_tokenId) {
address owner = ownerOf(_tokenId);
require(_to != owner); if (approvedFor(_tokenId) != 0 || _to != 0) {
tokenApprovals[_tokenId] = _to; // Event initialised in the interface above
Approval(owner, _to, _tokenId);
}
}

takeOwnership

Function takeOwnership takes _tokenId and applies the same check on the message sender. If he passes the check logic similar to the transfer function, he must claim the ownership of the following _tokenID .

function isApprovedFor(address _owner, uint256 _tokenId)
internal view returns (bool) {
return approvedFor(_tokenId) == _owner;
}function takeOwnership(uint256 _tokenId) public {
require(isApprovedFor(msg.sender, _tokenId)); // Logic to clear approval for token transfer // Logic to remove token from current token owner // Logic to add Token to new token owner
}

ERC-1155

Batch Transfers

The batch transfer is closely similar to regular CRC-20 transfers. Let’s look at CRC-20 transferFrom function:

// CRC-20
function transferFrom(address from, address to, uint256 value) external returns (bool);
// CRC-1155
function safeBatchTransferFrom(
address _from,
address _to,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external;

CRC-1155 differs in passing the token value as an array and an array of ids. The transfer results like this:

  • Transfer 200 tokens with id 5 from _from to _to.
  • Transfer 300 tokens with id 7 from _from to _to.
  • Transfer 3 tokens with id 15 from _from to _to.

Apart from utilizing the function of CRC-1155 as transferFrom, no transfer, you can utilize it as regular transfer by setting the form address to the address of calling the function.

Batch Balance

The respective CRC-20 balanceOf call likewise has its partner function with batch support. As a reminder, this is the CRC-20 version:

// CRC-20
function balanceOf(address owner) external view returns (uint256);
// CRC-1155
function balanceOfBatch(
address[] calldata _owners,
uint256[] calldata _ids
) external view returns (uint256[] memory);

Even simpler for the balance call, we can retrieve multiple balances in a single call. We pass the array of owners, followed by the array of token ids.
For example given _ids=[3, 6, 13] and _owners=[0xbeef…, 0x1337…, 0x1111…], the return value will be

[balanceOf(0xbeef...),balanceOf(0x1337...),balanceOf(0x1111...)]

Batch Approval

// CRC-1155
function setApprovalForAll(
address _operator,
bool _approved
) external;
function isApprovedForAll(
address _owner,
address _operator
) external view returns (bool);

The approvals here are slightly different than CRC-20. You need to set the operator to approved or not approved using setApprovalForAll rather than approving specific amounts.

Receive Hook

function onCRC1155BatchReceived(
address _operator,
address _from,
uint256[] calldata _ids,
uint256[] calldata _values,
bytes calldata _data
) external returns(bytes4);

CRC-1155 supports receive hooks only for smart contracts. The hook function must have to return a predefined magic bytes4 value which is as following:

bytes4(keccak256("onCRC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))

As soon as receiving contracts returns this value, we assume that the contract can now accept the transfer and it understand how to manage CRC-1155 tokens. That’s done!

Join Coinmonks Telegram Channel and Youtube Channel learn about crypto trading and investing

Also, Read

--

--