Web3j - How to read the contract without credentials? - java

I'm using Web3j to interact with my deployed smart contract.
I've deployed my contract onto the testnet and can interact with it, however using the generated wrapper code, it requires my wallet.
Web3j web3 = Web3j.build(new HttpService("https://testnet-endpoint-rpc.com"));
Credentials credentials = WalletUtils.loadCredentials(
"coolpassword1", "src\\main\\resources\\path-to-key-store.keystore"
);
FastRawTransactionManager txMananger = new FastRawTransactionManager(web3, credentials, 365);
MySmartContract contract = MySmartContract.load(
"0x73292b80f99ffdc4e9a908865ce1d35fde7b736f", //Address for smartcontract
web3,
txMananger,
new DefaultGasProvider()
);
//Reading from the contract
String contractName = contract.contractName(BigInteger.valueOf(0)).send();
How can I read from the contract without credentials?

I believe you can use the encodedFunctions to read without credentials but for write, you need the credentials.
Ex: balances is one of the methods in the contract with a single input of an address
Function function =
new Function("balances",
Arrays.asList(new org.web3j.abi.datatypes.Address(walletAddress)),
new ArrayList());
String encodedFunction = FunctionEncoder.encode(function);
org.web3j.protocol.core.methods.response.EthCall response = this.web3.ethCall(
Transaction.createEthCallTransaction(walletAddress, ContractAddress, encodedFunction),
DefaultBlockParameterName.LATEST)
.sendAsync().get();

Related

Getting ERC1155 Wallet Balance Using Java Web3J

Since Web3J doesn't currently support ERC1155, is there a way to get the balance for a wallet? My guess is to use a function for this, but I can't seem to figure out how to get it to work.
Function function = new Function(
"balancedOf",
Arrays.asList(new Address(ethAddress), new Uint256(1)),
Arrays.asList(new org.web3j.abi.TypeReference<Bool>() {}));
String data = FunctionEncoder.encode(function);
Do I then create a transaction? Or do I use ethSendRawTransaction? balanceOf only has 2 input so I would expect to have to invoke it from a smartcontract, but I don't see a way to do it.
From reading the web3j docs, It seems that you can do the following:
Function function = new Function<>(
"functionName",
Arrays.asList(new Type(value)), // Solidity Types in smart contract functions
Arrays.asList(new TypeReference<Type>() {}, ...));
String encodedFunction = FunctionEncoder.encode(function)
org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall(
Transaction.createEthCallTransaction(<from>, contractAddress, encodedFunction),
DefaultBlockParameterName.LATEST)
.sendAsync().get();
List<Type> someTypes = FunctionReturnDecoder.decode(
response.getValue(), function.getOutputParameters());
The response object, from org.web3j.protocol.core.methods.response.EthCall does the JSON-RPC call "eth_call" which only retrieves data form the blockchain.
I believe this is the equivalent of doing in web3js the following:
let contract = new web3.eth.Contract(<ABI>, <Contract Address>);
const res = await contract.functionName(<params>);

Milo OPC UA Server with Historical Data Access

Hy,
I’m new to milo (and OPC-UA) and try to implement an OPC-UA server with Historical Data Access. I reused the current milo server example and create a history node. On this node I can query (with the Prosys OPC UA Client) the empty history. I know that I have to implement the persistency of the history nodes by myself.
So far so good – but I could not found any information about to handle the history read request and how to return the response. More precisely how to add the HistoryData to an HistoryReadResult
#Override
public void historyRead(HistoryReadContext context, HistoryReadDetails readDetails, TimestampsToReturn timestamps,
List<HistoryReadValueId> readValueIds)
{
List<HistoryReadResult> results = Lists.newArrayListWithCapacity(readValueIds.size());
for (HistoryReadValueId readValueId : readValueIds){
//return 3 historical entries
DataValue v1 = new DataValue(new Variant(new Double(1)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(1, ChronoUnit.MINUTES))));
DataValue v2 = new DataValue(new Variant(new Double(2)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(2, ChronoUnit.MINUTES))));
DataValue v3 = new DataValue(new Variant(new Double(3)), StatusCode.GOOD, new DateTime(Date.from(Instant.now().minus(3, ChronoUnit.MINUTES))));
HistoryData data = new HistoryData(new DataValue[] {v1,v2,v3});
//???
HistoryReadResult result = new HistoryReadResult(StatusCode.GOOD, ByteString.NULL_VALUE, ??? );
results.add(result);
}
context.complete(results);
}
You're going to need access to the spec to successfully implement historical access services. Part 4 and Part 11.
The last parameter in the HistoryReadResult constructor is supposed to be a HistoryData structure. ExtensionObject is basically the container that structures are encoded and transferred in.
To create that ExtensionObject you would first create a HistoryData (or HistoryModifiedData, depends... see the spec) and then do something like ExtensionObject.encode(historyData) to get the object you need to finish building the HistoryReadResult.
Overrides historyRead is the correct way to do.
HistoryReadResult result = new HistoryReadResult(StatusCode.GOOD, ByteString.NULL_VALUE,ExtensionObject.encode(data) );
However method was not called by generic client such as UA-Expert before defining my variableNode with specific AccessLevel and Historizing mode like this :
Set<AccessLevel> acclevels = new LinkedHashSet<>();
acclevels.add(AccessLevel.CurrentRead);
acclevels.add(AccessLevel.CurrentWrite);
acclevels.add(AccessLevel.HistoryRead);
UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(server.getNodeMap())
.setNodeId(new NodeId(namespaceIndex, "HelloWorld/Test/" + name))
.setAccessLevel(ubyte(AccessLevel.getMask(acclevels)))
.setUserAccessLevel(ubyte(AccessLevel.getMask(acclevels)))
.setBrowseName(new QualifiedName(namespaceIndex, name))
.setDisplayName(LocalizedText.english(name))
.setDataType(typeId)
.setTypeDefinition(Identifiers.BaseDataVariableType)
.setHistorizing(true)
.build();

How to create bulkconnection with accesstoken in salesforce

I need to create BulkConnection for bulk API into salesforce.
We can able to create BulkConnection using ConnectorConfig with basic SOAP authentication.
Code is below,
ConnectorConfig config = new ConnectorConfig();
config.setUsername("USERNAME");
config.setPassword("PASSWORD+TOKEN");
config.setCompression(true);
config.setTraceFile("traceLogs.txt");
config.setTraceMessage(true);
config.setPrettyPrintXml(true);
config.setAuthEndpoint("https://login.salesforce.com/services/Soap/u/39.0");
PartnerConnection connection = new PartnerConnection(config);
String soapEndpoint = config.getServiceEndpoint();
String apiVersion = "39.0";
String restEndpoint = soapEndpoint.substring(0, soapEndpoint.indexOf("Soap/")) + "async/" + apiVersion;
config.setRestEndpoint(restEndpoint);
bulkConnection = new BulkConnection(config);
Above code is working fine.
But in my case, I can't able to collect username & password for each of the customer's salesforce account.
Is this possible to create BulkConnection using accestoken?..
Please give me your suggestion.
Thanks,
Harish

AWS cognito does not generate tokens when run from a serverlet

I am trying to get amazon cognito to work. If I run the code to generate a login token from a standalone java program it works.
public class cognito extends HttpServlet
{
public static void main(String[] args) throws Exception {
AWSCredentials credentials = new BasicAWSCredentials("*******", "********");
AmazonCognitoIdentityClient client =
new AmazonCognitoIdentityClient(credentials);
client.setRegion(Region.getRegion(Regions.EU_WEST_1));
GetOpenIdTokenForDeveloperIdentityRequest tokenRequest =
new GetOpenIdTokenForDeveloperIdentityRequest();
tokenRequest.setIdentityPoolId("*************");
HashMap<String, String> map = new HashMap<String, String>();
//Key -> Developer Provider Name used when creating the identity pool
//Value -> Unique identifier of the user in your <u>backend</u>
map.put("test", "AmazonCognitoIdentity");
//Duration of the generated OpenID Connect Token
tokenRequest.setLogins(map);
tokenRequest.setTokenDuration(1000l);
GetOpenIdTokenForDeveloperIdentityResult result = client
.getOpenIdTokenForDeveloperIdentity(tokenRequest);
String identityId = result.getIdentityId();
String token = result.getToken();
System.out.println("id = " + identityId + " token = " + token);
}
}
However when I run this code from a servlet on a redhat linux server, it always times out.
Any suggestion would be helpful
map.put("test", "AmazonCognitoIdentity");
are you sure your developer provider name is "test"?
you can see it in your cognito identity pool edit page.
And "AmazonCognitoIdentity" should be your own unique user-id.
Without the actual exception, it is hard to tell what is the exact issue. It could be that something else running in your servlet engine is setting a much more aggressive socket timeout than the default when it runs from the command line. You might want to explicitly set the connection and socket timeouts using methods using this class http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/ClientConfiguration.html and pass it in to the identity client constructor.

insert a domain name into servlet authentication token

I am using Waffle for an SSO solution in my web-app.
Everything works fine but I would like to modify some functionality slightly:
Currently, if a user is not connected to the domain the SSO fails and opens a little authorization dialog:
The windows authorization requires the user name formatted like Domain\Username but most of my users will not know to add the domain in front of their username. So I would like to provide a default domain name if one is not specified.
I found a waffle function that I can override which will give me access to the decoded authentication token, I added a println to the waffle function and it shows the username in plain text (either with or without the domain depending on what is typed in the dialog):
public IWindowsSecurityContext acceptSecurityToken(String connectionId, byte[] token, String securityPackage) {
// I can see the passed username in the logs with this
System.out.println(new String(token));
// I don't understand any of the JNA stuff below this comment:
IWindowsCredentialsHandle serverCredential = new WindowsCredentialsHandleImpl(
null, Sspi.SECPKG_CRED_INBOUND, securityPackage);
serverCredential.initialize();
SecBufferDesc pbServerToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, Sspi.MAX_TOKEN_SIZE);
SecBufferDesc pbClientToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, token);
NativeLongByReference pfClientContextAttr = new NativeLongByReference();
CtxtHandle continueContext = _continueContexts.get(connectionId);
CtxtHandle phNewServerContext = new CtxtHandle();
int rc = Secur32.INSTANCE.AcceptSecurityContext(serverCredential.getHandle(),
continueContext, pbClientToken, new NativeLong(Sspi.ISC_REQ_CONNECTION),
new NativeLong(Sspi.SECURITY_NATIVE_DREP), phNewServerContext,
pbServerToken, pfClientContextAttr, null);
WindowsSecurityContextImpl sc = new WindowsSecurityContextImpl();
sc.setCredentialsHandle(serverCredential.getHandle());
sc.setSecurityPackage(securityPackage);
sc.setSecurityContext(phNewServerContext);
switch (rc)
{
case W32Errors.SEC_E_OK:
// the security context received from the client was accepted
_continueContexts.remove(connectionId);
// if an output token was generated by the function, it must be sent to the client process
if (pbServerToken != null
&& pbServerToken.pBuffers != null
&& pbServerToken.cBuffers.intValue() == 1
&& pbServerToken.pBuffers[0].cbBuffer.intValue() > 0) {
sc.setToken(pbServerToken.getBytes());
}
sc.setContinue(false);
break;
case W32Errors.SEC_I_CONTINUE_NEEDED:
// the server must send the output token to the client and wait for a returned token
_continueContexts.put(connectionId, phNewServerContext);
sc.setToken(pbServerToken.getBytes());
sc.setContinue(true);
break;
default:
sc.dispose();
WindowsSecurityContextImpl.dispose(continueContext);
_continueContexts.remove(connectionId);
throw new Win32Exception(rc);
}
return sc;
}
That whole function is from the Waffle API I only added the println at the beginning.
The passed username prints in plain text inside this token between a bunch of random byte chars (ÉsR=ÍtÍö?æ¸+Û-).
I am admittedly in very far over my head with JNA and java in general but I thought that because I can see the username here there must be a way to prepend the domain name to the username part of this token? I could be wrong.
My other idea was to add the domain to the pbClientToken that is created from the raw byte[] token this method is passed.
The pbClientToken is a JNA Structure object derivative. It has the Stucture method writeField which looked promising but I can't seem to figure out what field I should write. The Structure.getFields method doesn't seem to be available from pbClientToken.
I was hoping that this was a simple problem for someone more familiar with byte[] processing or JNA.
You cannot do this. What happens behind this dialog is a call to LogonUser on the user's machine, which gives you a ticket, which is then sent to the server. Unfortunately the server is not in the same domain, so even if you manage to extract the username it's completely useless.

Categories