Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/revoke sbt #156

Merged
merged 13 commits into from
Oct 10, 2023
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);
}

}
Loading