Skip to content

Commit

Permalink
Merge pull request #156 from walt-id/feat/revoke_sbt
Browse files Browse the repository at this point in the history
Feat/revoke sbt
  • Loading branch information
SuperBatata authored Oct 10, 2023
2 parents d3f3466 + 943550c commit 6f636b1
Show file tree
Hide file tree
Showing 9 changed files with 605 additions and 36 deletions.
30 changes: 15 additions & 15 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,18 @@ publishing {
}
}

graphql {
client {
endpoint = "https://scan-api.opal.uniquenetwork.dev/v1/graphql/"
packageName = "id.walt.nftkit"
customScalars = listOf(
com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar(
"_Any",
"kotlinx.serialization.json.JsonObject",
"com.expediagroup.graphql.examples.client.gradle.AnyScalarConverter"
),
)
serializer = com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer.KOTLINX
}
}

//graphql {
// client {
// endpoint = "https://scan-api.opal.uniquenetwork.dev/v1/graphql/"
// packageName = "id.walt.nftkit"
// customScalars = listOf(
// com.expediagroup.graphql.plugin.gradle.config.GraphQLScalar(
// "_Any",
// "kotlinx.serialization.json.JsonObject",
// "com.expediagroup.graphql.examples.client.gradle.AnyScalarConverter"
// ),
// )
// serializer = com.expediagroup.graphql.plugin.gradle.config.GraphQLSerializer.KOTLINX
// }
//}
//
479 changes: 479 additions & 0 deletions src/main/java/smart_contract_wrapper/WaltidSoulBound.java

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/main/kotlin/id/walt/nftkit/Values.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ object Values {
const val ETHEREUM_TESTNET_SEPOLIA_BLOCK_EXPLORER_URL = "https://sepolia.etherscan.io/"
const val POLYGON_MAINNET_BLOCK_EXPLORER_URL = "https://polygonscan.com"
const val POLYGON_TESTNET_MUMBAI_BLOCK_EXPLORER_URL = "https://mumbai.polygonscan.com"
const val SHIMMEREVM_TESTNET_BLOCK_EXPLORER_URL = "https://explorer.evm.testnet.shimmer.network"
const val SHIMMEREVM_TESTNET_BLOCK_EXPLORER_URL = "https://explorer.evm.testnet.shimmer.network/"

const val ETHEREUM_MAINNET_ALCHEMY_URL = "https://eth-mainnet.alchemyapi.io/v2/"
const val ETHEREUM_TESTNET_GOERLI_ALCHEMY_URL = "https://eth-goerli.g.alchemy.com/v2/"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@ interface ISoulBoundTokenStandard {

fun supportsInterface(chain: EVMChain, contractAddress: String): Boolean

fun revoke(chain: EVMChain, contractAddress: String, tokenId: Uint256, signedAccount: String?): TransactionReceipt

fun unequip(chain: EVMChain, contractAddress: String, tokenId: Uint256, signedAccount: String?): TransactionReceipt
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import org.web3j.tx.RawTransactionManager
import org.web3j.tx.TransactionManager
import org.web3j.tx.gas.ContractGasProvider
import org.web3j.utils.Numeric
import smart_contract_wrapper.SoulBoundTest
import smart_contract_wrapper.WaltidSoulBound
import java.math.BigInteger

object SoulBoundTokenStandard : ISoulBoundTokenStandard {
Expand All @@ -24,7 +24,7 @@ object SoulBoundTokenStandard : ISoulBoundTokenStandard {



private fun loadContract(chain: EVMChain, address: String, signedAccount: String? ="") : SoulBoundTest {
private fun loadContract(chain: EVMChain, address: String, signedAccount: String? ="") : WaltidSoulBound {
val web3j = ProviderFactory.getProvider(chain)?.getWeb3j()

val privateKey: String = if(signedAccount == null || "" == (signedAccount)){
Expand All @@ -50,7 +50,7 @@ object SoulBoundTokenStandard : ISoulBoundTokenStandard {
val transactionManager: TransactionManager = RawTransactionManager(
web3j, credentials, chainId
)
return SoulBoundTest.load(address, web3j,transactionManager,gasProvider)
return WaltidSoulBound.load(address, web3j,transactionManager,gasProvider)

}

Expand Down Expand Up @@ -107,11 +107,11 @@ object SoulBoundTokenStandard : ISoulBoundTokenStandard {
val web3j = ProviderFactory.getProvider(chain)?.getWeb3j()
val credentials: Credentials = Credentials.create(WaltIdServices.loadChainConfig().privateKey)
val gasProvider: ContractGasProvider = WaltIdGasProvider
val remotCall: RemoteCall<SoulBoundTest>
val remotCall: RemoteCall<WaltidSoulBound>
val transactionManager: TransactionManager = RawTransactionManager(
web3j, credentials, chainId
)
remotCall = SoulBoundTest.deploy(web3j, transactionManager, gasProvider)
remotCall = WaltidSoulBound.deploy(web3j, transactionManager, gasProvider)

val contract = remotCall.send()

Expand All @@ -130,4 +130,23 @@ object SoulBoundTokenStandard : ISoulBoundTokenStandard {
val interfaceId = Bytes4(data)
return erc721URIStorageWrapper.supportsInterface(interfaceId).send().value
}


override fun revoke(
chain: EVMChain,
contractAddress: String,
tokenId: Uint256,
signedAccount: String?
): TransactionReceipt {
return loadContract(chain, contractAddress, signedAccount).revoke(tokenId).send()
}

override fun unequip(
chain: EVMChain,
contractAddress: String,
tokenId: Uint256,
signedAccount: String?
): TransactionReceipt {
return loadContract(chain, contractAddress, signedAccount).unequip(tokenId).send()
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/id/walt/nftkit/rest/NftController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,49 @@ object NftController {
it.description("")
}.json<MintingResponse>("200") { it.description("Transaction ID and token ID") }

fun revoke(ctx: Context) {
val chain = ctx.pathParam("chain")
val contractAddress = ctx.pathParam("contractAddress")
val tokenId = ctx.pathParam("tokenId")
val signedAccount = ctx.queryParam("signedAccount")
val result =
NftService.revokeToken(Common.getEVMChain(chain.uppercase()), contractAddress, BigInteger.valueOf(tokenId.toLong()), signedAccount)
ctx.json(
result
)
}

fun revokeDocs() = document().operation {
it.summary("NFT revoking")
.operationId("revokeNft").addTagsItem(TAG1)
}.pathParam<String>("chain") {
it.schema<EVMChain> { }
}.pathParam<String>("contractAddress") {
}.pathParam<String>("tokenId") {
}.queryParam<String>("signedAccount") {
}.json<TransactionResponse>("200") { it.description("Transaction ID") }

fun unequip(ctx: Context){
val chain = ctx.pathParam("chain")
val contractAddress = ctx.pathParam("contractAddress")
val tokenId = ctx.pathParam("tokenId")
val signedAccount = ctx.queryParam("signedAccount")
val result =
NftService.unequipToken(Common.getEVMChain(chain.uppercase()), contractAddress, BigInteger.valueOf(tokenId.toLong()), signedAccount)
ctx.json(
result
)
}

fun unequipDocs() = document().operation {
it.summary("NFT unequipping")
.operationId("unequipNft").addTagsItem(TAG1)
}.pathParam<String>("chain") {
it.schema<EVMChain> { }
}.pathParam<String>("contractAddress") {
}.pathParam<String>("tokenId") {
}.queryParam<String>("signedAccount") {
}.json<TransactionResponse>("200") { it.description("Transaction ID") }

fun getNftMetadatUri(ctx: Context) {
val chain = ctx.pathParam("chain")
Expand Down
8 changes: 8 additions & 0 deletions src/main/kotlin/id/walt/nftkit/rest/NftKitApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ object NftKitApi {
"chain/{chain}/owner/{ownerAddress}",
documented(NftController.getAccountNFTsDocs(), NftController::getAccountNFTs)
)
post(
"chain/{chain}/contract/{contractAddress}/token/{tokenId}/revokeToken",
documented(NftController.revokeDocs(), NftController::revoke)
)
post(
"chain/{chain}/contract/{contractAddress}/token/{tokenId}/unequipToken",
documented(NftController.unequipDocs(), NftController::unequip)
)
post(
"chain/{chain}/contract/{contractAddress}/token/{tokenId}/metadata",
documented(NftController.updateMetadataDocs(), NftController::updateMetadata)
Expand Down
10 changes: 10 additions & 0 deletions src/main/kotlin/id/walt/nftkit/services/NftService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -627,6 +627,16 @@ object NftService {
}


fun revokeToken(chain: EVMChain, contractAddress: String, tokenId: BigInteger, signedAccount: String?): TransactionResponse {
val transactionReceipt = SoulBoundTokenStandard.revoke(chain, contractAddress, Uint256(tokenId), signedAccount)
return Common.getTransactionResponse(chain, transactionReceipt)

}

fun unequipToken(chain: EVMChain , contractAddress: String, tokenId: BigInteger, signedAccount: String?): TransactionResponse {
val transactionReceipt = SoulBoundTokenStandard.unequip(chain, contractAddress, Uint256(tokenId), signedAccount)
return Common.getTransactionResponse(chain, transactionReceipt)
}

private fun getMetadatUri(chain: EVMChain, contractAddress: String, tokenId: BigInteger): String {
if (isErc721Standard(chain, contractAddress) == true) {
Expand Down
37 changes: 22 additions & 15 deletions src/main/solidity/soulbound.sol
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";

contract SoulBoundTest is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;
contract waltidSoulBound is ERC721,ERC721URIStorage , Ownable{

using Counters for Counters.Counter;
Counters.Counter private _tokenIdCounter;

constructor() ERC721("SoulBoundTest", "SBT") {}
constructor() ERC721("WaltidSBT","SBT") {}

function safeMint(address to , string memory uri) public onlyOwner {

function safeMint(address to, string memory uri) public onlyOwner {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
_safeMint(to, tokenId);
_setTokenURI(tokenId, uri);
}

function _beforeTokenTransfer(
address from,
address to,
uint256 tokenId
) internal override virtual {
require(from == address(0), "Err: token transfer is BLOCKED");
super._beforeTokenTransfer(from, to, tokenId);
}

// The following functions are overrides required by Solidity.

function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}

function unequip(uint256 tokenId) external {
require(ownerOf(tokenId) == msg.sender , "You are not the owner of this NFT");
_burn(tokenId);
}

function revoke(uint256 tokenId) external onlyOwner{
_burn(tokenId);
}

function tokenURI(uint256 tokenId)
public
view
Expand All @@ -43,4 +44,10 @@ contract SoulBoundTest is ERC721, ERC721URIStorage, Ownable {
{
return super.tokenURI(tokenId);
}

function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal override virtual {
require(from == address(0) || to == address(0), "Err: token transfer is BLOCKED");
super._beforeTokenTransfer(from, to, tokenId);
}

}

0 comments on commit 6f636b1

Please sign in to comment.