Before building our dApp; first, let’s understand the smart contract on which we’ll build our dApp.
pragma solidity ^0.5.2;
contract URLShortner {
struct URLStruct {
address owner;
string url;
bool exists;
bool paid;
}
mapping (bytes => URLStruct) lookupTable;
mapping (address => bytes[]) public shortenedURLs;
address[] accts;
address payable owner;
event URLShortened(string url, bytes slug, address owner);
constructor() public { owner = msg.sender; }
function shortenURLWithSlug(string memory _url, bytes memory _short, bool paid) public payable {
bool paidDefault = false;
if (!lookupTable[_short].exists){
lookupTable[_short] = URLStruct(msg.sender, _url, true, paid||paidDefault);
shortenedURLs[msg.sender].push(_short);
if(shortenedURLs[msg.sender].length < 1) {
accts.push(msg.sender);
}
emit URLShortened(_url, _short, msg.sender);
}
}
function shortenURL(string memory url, bool paid) public payable {
bool paidDefault = false;
bytes memory shortHash = getShortSlug(url);
return shortenURLWithSlug(url, shortHash, paid||paidDefault);
}
function listAccts() public view returns (address[] memory){
return accts;
}
function getURL(bytes memory _short) public view returns (string memory) {
URLStruct storage result = lookupTable[_short];
if(result.exists){
return result.url;
}
return "FAIL";
}
function kill() public {
if (msg.sender == owner) selfdestruct(owner);
}
// privates
function getShortSlug(string memory str) internal pure returns (bytes memory) {
bytes32 hash = sha256(abi.encodePacked(str));
uint main_shift = 15;
bytes32 mask = 0xffffff0000000000000000000000000000000000000000000000000000000000;
return abi.encodePacked(bytes3(hash<<(main_shift*6)&mask));
}
}
Explanation of the code above:
Line 1: Declaring the solidity version
Line 3-9: Declaring our smart contract as URLShortner, then creating a struct URLStruct to store/group to store the relevant details of a shortened URL; owner of type address which stores the address of the person shortening the URL, url of type string to store the URL to be shortened, exists of type boolean type will store if the URL is present, paid of type boolean to check if the transaction to shorten the URL is paid.
Line 10: Create a mapping to map the short version of the URL to URLStruct.
Line 11: Create a mapping where a particular owner’s address (a person shortening the URL) will be mapped to an array of shortened URLs that person has shortened. So, every individual shortening URLs will have an array of shortened URLs mapped to their address.
Line 12: Creating an array named accts of type address which will store the addresses of accounts who have interacted with the smart contract by shortening the URL.
Line 13: Declaring owner of type address payable which will allow that owner to access primitives useful to manage ethers.
Line 14: Creating an event URLShortened which will be emitted via the RPC on ethereum nodes worldwide - any front end can listen for this event.
Line 16: Creating a constructor and specifying the address of the creator of the smart contract - this address has special privileges.
Line 18-28:
- Creating a function shortenURLWithSlug which will allow a person/individual to specify the shortened version of the URL, the function is of state public which means it can be accessed outside scopes of this function and by other contracts.
- Setting paidDefault as false.
- An if condition to check if the short version of the given URL exists or not and if it does not exist it will be added to the lookupTable using a URLStruct.
- Adding the short URL (slug) to the person shortening the URL in the shortenedURLs.
- A condition to check if the number of URLs shortened by the person/individual is less than one and if the person/individual is shortening the URL for the first time then it will be added to the accts array which we saw on line 12.
- Emitting the event URLShortened.
Line 30-34: Creating a function shortenURL, this function is the same as the previous one except the person/individual doesn't get to specify the short version, they paste the URL and it will be shortened using the getShortSlug method which we’ll see later.
Line 36-38: Creating a function listAccts which will facilitate a getter method to get the accounts from the accts array as the accts isn’t public.
Line 40-46: Creating a function getURL, to check if the short URL exists in the lookupTable and if it does it will return the shortened URL and if it doesn’t it will return the word FAIL.
Line 48-50: Creating a function kill and an if condition in it which will check if the owner (the person from line 14) is connected to the contract, if yes then it’ll stop the connection/association.
Line 53-58: Creating a function getShortSlug which is a private method by which we generate the short URL.
To save time and ETH, we've already deployed this smart contract and it's address is embedded in our helper libraries and the code below.