For a recent test it's been requested me to generate a Smart Contract with Ethernum and use some functions provided through ABI json to extract some info.
I'm using https://ropsten.etherscan.io as suggested.
I studied Ethernum for the last 2 days and I tried with Solidity Remix to extract these info but I don't understand how to use the ABI functions with Solidity Remix.
All I have is an Address contract and an ABI contract.
Is there someone available to provide me some info?
Thanks
I would recommend you to programmatically do it using a library like web3js, web3js allows you to interact with the Ethereum network (accounts, smart contracts) through the RPC webservice.
In the following example, I deployed a contract called SimpleStorage on a local blockchain with Truffle and Ganache (tools and framework for ethereum).
pragma solidity ^0.4.2;
contract SimpleStorage {
uint public value;
function SimpleStorage() {
value = 1;
}
function setValue(uint val) {
value = val;
}
function getValue() returns(uint) {
return value;
}
}
Each contract deployed on the Ethereum Blockchain has a ABI (Application Binary Interface) sort of Swagger for your Smart Contract. Programs use the ABI to interact with the Smart Contract via RPC.
Each contract is deployed at a unique address like 0x3450226a2fccb0d3668e7c3a730c43ef50ec8a06
1. Initiate a nodeJS project and add web3js library
$ npm init
$ npm install web3#0.20.6 -s
2. Create a JavaScrit file index.js
Inject the dependency
const Web3 = require('web3');
Declare the rpc endpoint of your node. I'm using a local blockchain, but you could easily connect to a Ropsten public node with Infura for example (depends on which network you contract is deployed)
const RPC_ENDPOINT = "http://localhost:8545" //https://ropsten.infura.io
Connect to a Ethereum node
var web3 = new Web3(new Web3.providers.HttpProvider(RPC_ENDPOINT));
Set default account
web3.eth.defaultAccount = web3.eth.accounts[0]
Put your ABI here and the address where the smart contract is deployed
var abi = [...];
var address = "0x3450226a2fccb0d3668e7c3a730c43ef50ec8a06";
Load the contract schema from the abi
var SimpleStorageContract = web3.eth.contract(abi);
Instantiate the contract by address
var simpleStorageContractInstance = SimpleStorageContract.at(address);
Call one of the ABI function
var value = simpleStorageContractInstance.getValue.call();
console.log("value="+value);
Result:
When I invoke the function getValue of my SimpleStorage contract instance, the function returns 1.
value=1
Full code:
const Web3 = require('web3');
const RPC_ENDPOINT = "http://localhost:8545"
// Connection to a Ethereum node
var web3 = new Web3(new Web3.providers.HttpProvider(RPC_ENDPOINT));
// Set default account
web3.eth.defaultAccount = web3.eth.accounts[0]
// ABI describes a smart contract interface developped in Solidity
var abi = [
{
"constant": true,
"inputs": [],
"name": "value",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"constant": false,
"inputs": [
{
"name": "val",
"type": "uint256"
}
],
"name": "setValue",
"outputs": [],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [],
"name": "getValue",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
];
// Address where the smart contract is deployed
var address = "0x3450226a2fccb0d3668e7c3a730c43ef50ec8a06";
// Load the contract schema from the abi
var SimpleStorageContract = web3.eth.contract(abi);
// Instanciate by address
var simpleStorageContractInstance = SimpleStorageContract.at(address);
// Call one of the ABI function
var value = simpleStorageContractInstance.getValue.call();
console.log("value="+value);
GitHub of the project:
https://github.com/gjeanmart/stackexchange/tree/master/51809356-create-smart-contract-and-use-abi-functions
Ethereum StackExchange
There is a dedicated StackExchange community for Ethereum questions here
Related
My Project
package.json
{
"name": "azure-functions",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "func start",
"test": "echo \"No tests yet...\""
},
"dependencies": {
"durable-functions": "^2.0.2"
}
}
host.json
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[3.*, 4.0.0)"
}
}
DurableFunctionsHttpStart/function.json
{
"bindings": [
{
"authLevel": "anonymous",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"route": "orchestrators/{functionName}",
"methods": [
"post",
"get"
]
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"name": "starter",
"type": "orchestrationClient",
"direction": "in"
}
]
}
DurableFunctionsHttpStart/index.js
const df = require("durable-functions");
module.exports = async function (context, req) {
const client = df.getClient(context);
const instanceId = await client.startNew(req.params.functionName, undefined, req.body);
context.log(`Started orchestration with ID = '${instanceId}'.`);
return client.createCheckStatusResponse(context.bindingData.req, instanceId);
};
Hello/function.json
{
"bindings": [
{
"name": "name",
"type": "activityTrigger",
"direction": "in"
}
]
}
Hello/index.js
/*
* This function is not intended to be invoked directly. Instead it will be
* triggered by an orchestrator function.
*
* Before running this sample, please:
* - create a Durable orchestration function
* - create a Durable HTTP starter function
* - run 'npm install durable-functions' from the wwwroot folder of your
* function app in Kudu
*/
module.exports = async function (context) {
return `Hello ${context.bindings.name}!`;
};
HelloOrchestrator/function.json
{
"bindings": [
{
"name": "context",
"type": "orchestrationTrigger",
"direction": "in"
}
]
}
HelloOrchestrator/index.js
/*
* This function is not intended to be invoked directly. Instead it will be
* triggered by an HTTP starter function.
*
* Before running this sample, please:
* - create a Durable activity function (default name is "Hello")
* - create a Durable HTTP starter function
* - run 'npm install durable-functions' from the wwwroot folder of your
* function app in Kudu
*/
const df = require("durable-functions");
module.exports = df.orchestrator(function* (context) {
const outputs = [];
// Replace "Hello" with the name of your Durable Activity Function.
outputs.push(yield context.df.callActivity("Hello", "Tokyo"));
outputs.push(yield context.df.callActivity("Hello", "Seattle"));
outputs.push(yield context.df.callActivity("Hello", "London"));
// returns ["Hello Tokyo!", "Hello Seattle!", "Hello London!"]
return outputs;
});
Upon running npm start on the root of the page, i am getting the following error.
Azure Functions Core Tools
Core Tools Version: 4.0.4736 Commit hash: N/A (64-bit)
Function Runtime Version: 4.8.1.18957
[2022-09-05T11:52:51.483Z] A host error has occurred during startup operation '5dd1dd91-e64a-4866-......'.
[2022-09-05T11:52:51.483Z] Microsoft.Azure.WebJobs.Extensions.DurableTask: Unable to resolve the Azure Storage connection named 'Storage'.
Value cannot be null. (Parameter 'provider')
What could be the reason, i followed this tutorial https://learn.microsoft.com/en-us/azure/azure-functions/durable/quickstart-js-vscode
I didn’t get any prompt to select azure account as mentioned here https://learn.microsoft.com/en-us/azure/azure-functions/durable/quickstart-js-vscode#test-the-function-locally
That exception suggests that the runtime cannot find the value of AzureWebJobsStorage. You should have a local.settings.json file in your project that should look something like this:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=....",
"FUNCTIONS_WORKER_RUNTIME": "node"
}
}
The value of AzureWebJobsStorage should be set to a storage connection string that the Azure function runtime requires.
See: App settings reference for Azure Functions
I'm trying to run decentralized-model locally. I've managed to deploy:
Link contract
AggregatorProxy
FluxAggregator
Consumer contract
Oracle node (offchain)
External adapters (coingecko + coinapi)
I'm mainly struggling for the last piece which is creating a Job which uses the FluxMonitor initiator.
I've created the following job where "0x5379A65A620aEb405C5C5338bA1767AcB48d6750" is the address of FluxAggregator contract
{
"initiators": [
{
"type": "fluxmonitor",
"params": {
"address": "0x5379A65A620aEb405C5C5338bA1767AcB48d6750",
"requestData": {
"data": {
"from": "ETH",
"to": "USD"
}
},
"feeds": [
{
"bridge": "coinapi_cl_ea"
},
{
"bridge": "coingecko_cl_ea"
}
],
"threshold": 1,
"absoluteThreshold": 1,
"precision": 8,
"pollTimer": {
"period": "15m0s"
},
"idleTimer": {
"duration": "1h0m0s"
}
}
}
],
"tasks": [
{
"type": "NoOp"
}
]
}
Unfortunately, it doesn't work, it makes my local ganache fail with this error "Error: The nonce generation function failed, or the private key was invalid"
I've put my Ganache in debug mode in order to log requests to the blockchain. Noticed the following call
eth_call
{
"jsonrpc": "2.0",
"id": 28,
"method": "eth_call",
"params": [
{
"data": "0xfeaf968c",
"from": "0x0000000000000000000000000000000000000000",
"to": "0x5379a65a620aeb405c5c5338ba1767acb48d6750"
},
"latest"
]
}
the signature of the function is correct
"latestRoundData()": "feaf968c"
However , what seems weird is that the from address is "0x0" . Any idea why my Oracle node doesn't use its key to sign the transaction?
thanks a lot
Problem from Ganache. In fact , I wrote a truffle script which:
calls "latestRoundData()" populating the "FROM" with a valid address
calls "latestRoundData()" populating the "FROM" with a 0x0 address
Then I ran the script 2 times:
Connecting to Ganache-cli --> 1st call is successful while the 2nd call fails
Connecting to Kovan testnet --> both calls are successful
I've just opened an issue for ganache-cli team: https://github.com/trufflesuite/ganache-cli/issues/840
I am working on an old web service where I generate the rest endpoints documentation that comply with OAS standards using a custom tool. Using this OAS json file I can deploy the API to Azure API Managements services through the portal and it all works fine. However, I need to automate this process and hence need to use ARM templates to deploy all web services to Azure APIM. I have been looking into the examples provided https://learn.microsoft.com/en-us/azure/templates/microsoft.apimanagement/service/apis but just can't seem to wrap my head around how to use a local OAS.json file or a file in github.
{
"$schema": "http://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "Location for all resources."
}
}
},
"variables": {
"apiManagementServiceName": "price-capture"
},
"resources": [
{
"apiVersion": "2018-01-01",
"type": "Microsoft.ApiManagement/service/apis",
"name": "[variables('apiManagementServiceName')]",
"properties": {
"displayName": "Service display Name",
"apiRevision": "1",
"description": "API description",
//need help since it's not a swagger url
//wondering if there is a way to ref a local file like the option
//provided in the portal when we register api's manually.
"serviceUrl": "----",
"path": "----",
"protocols": [
"https"
],
"isCurrent": true,
"apiVersion": "v1",
"apiVersionDescription": "apiVersionDescription"
}
}
]
}
You can deploy and configure an entire API on API Management via ARM templates, but you cannot use a local file to provide the OpenApi/Swagger.
In your case the OpenApi/Swagger needs to be publicly accessible so the resource manager can read from it, so if the Github URL is freely accessible it should work.
I typically store the OpenApi/Swagger to a storage account and use the SAS token to access it from the ARM template.
You can check out this blog for details on automating API deployment in APIM:
https://blog.eldert.net/api-management-ci-cd-using-arm-templates-linked-template/
You can deploy the API using an Azure Resource Manager template of type Microsoft.ApiManagement/service/apis, and to use an Open API / swagger definition you need to specify the contentValue and and contentFormat parameters of the template
{
"name": "awesome-api-management/petstore",
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2018-06-01-preview",
"properties": {
"path": "petstore"
"contentValue": "petstore swagger file contents here", // or it's URL
"contentFormat": "swagger-json", // or swagger-link-json if externally available
}
}
I don't think it's possible to deploy the APIs configs via templates.
I've been trying to figure this out myself but I'm pretty sure you can't include the actual APIs you want in the service.
From what I can tell, you can't do that with the GIT repo either because that needs authentication that is manually created in the portal
I think the only thing you can automate with the ARM template is the actual API Management service and then you need to use the Azure API to add and configure the APIs on it.
However, I have yet to figure out how to do that myself.
I actually have a service ticket open to get help on that.
The API has changed slightly so this works:
The yaml file (calculatorApiFile) needs to be uploaded first to a blob storage, but this can be done as part of the deployment pipeline
{
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2019-01-01",
"name": "[concat(parameters('service_name'), '/b12b1d5ab8204cg6b695e3e861fdd709')]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('service_name'))]"
],
"properties": {
"displayName": "Calculator",
"apiRevision": "1",
"description": "A simple Calculator ",
"path": "calc",
"value": "[concat(parameters('containerUri'), parameters('calculatorApiFile'), parameters('containerSasToken'))]",
"format": "openapi-link",
"protocols": [
"https"
],
"isCurrent": true
}
}
I figured out the answer ..all I had to do was write an azure function that fetches the oas.yaml file from a private github repository.
"variables":{
"swagger_json":"[concat(parameters('url_of_azurefunctionwithaccesskey'),'&&githuburi='parameter('raw_url'),'&githubaccesstoken=',parameter('personalaccesstoken')]"
},
"resources": [
{
"type": "Microsoft.ApiManagement/service/apis",
"name": "[concat(parameters('apimName') ,'/' ,parameters('serviceName'))]",
"apiVersion": "2018-06-01-preview",
"properties": {
"apiRevision": "[parameters('apiRevision')]",
"path": "pricecapture",
"contentValue": "[variables('swagger_json')]",
"contentFormat": "openapi-link"
}
}]
The Azure function that I had to write was something like this:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.IO;
using System.Text;
public static async Task<HttpResponseMessage> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var gitHubUri = req.Query["githuburi"];
var gitHubAccessToken = req.Query["githubaccesstoken"];
var encoding = Encoding.ASCII;
if (string.IsNullOrEmpty(gitHubUri))
{
var errorcontent = new StringContent("please pass the raw file content URI (raw.githubusercontent.com) in the request URI string", Encoding.ASCII);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.BadRequest,
Content = errorcontent
};
}
else if (string.IsNullOrEmpty(gitHubAccessToken))
{
var errorcontent = new StringContent("please pass the GitHub personal access token in the request URI string", Encoding.ASCII);
return new HttpResponseMessage
{
StatusCode = HttpStatusCode.BadRequest,
Content = errorcontent
};
}
else
{
var strAuthHeader = "token " + gitHubAccessToken;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3.raw");
client.DefaultRequestHeaders.Add("Authorization", strAuthHeader);
var response = await client.GetAsync(gitHubUri);
return response;
}
}
If you load your YAML into a variable, that can be passed to the ARM template and be passed as the value:
deploy.bat:
SETLOCAL EnableDelayedExpansion
set API_DEPLOYMENT=<deployment name>
set API_GROUP=<deployment group>
set API=<api file path.yml>
set OPENAPI=
for /f "delims=" %%x in ('type %API%') do set "OPENAPI=!OPENAPI!%%x\n"
call az deployment group create -n %API_DEPLOYMENT% -g %API_GROUP% --mode Complete -f deploy.json -p openApi="!OPENAPI!"
ENDLOCAL
deploy.json (note the use of replace)
...
{
"type": "Microsoft.ApiManagement/service/apis",
"apiVersion": "2020-12-01",
"name": "[variables('apiName')]",
"properties": {
"path": "[variables('service')]",
"apiType": "http",
"displayName": "[variables('apiDisplayName')]",
"format": "openapi",
"value": "[replace(parameters('openApi'), '\\n', '\n')]"
},
...
},
...
I am using Google cloud datastore which is exposed by jersey rest, i have made authentication using oauth2 to access rest APIS.
Now I want to call restful API from my gmail addons to populate some lovs on gmail sidebar.
I have tried oauth2 authentication provided on https://github.com/googlesamples/apps-script-oauth2.
How do i show authorizationUrl on sidebar of gmail using gmail Addons?
CODEBASE
appscript.json
{
"timeZone": "America/Los_Angeles",
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "Gmail",
"serviceId": "gmail",
"version": "v1"
}],
"libraries": [{
"userSymbol": "OAuth2",
"libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF",
"version": "24",
"developmentMode": true
}]
},
"oauthScopes": ["https://www.googleapis.com/auth/gmail.addons.execute", "https://www.googleapis.com/auth/gmail.addons.current.message.metadata", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.storage"],
"gmail": {
"name": "Gmail Add-on Quickstart",
"logoUrl": "https://www.gstatic.com/images/icons/material/system/2x/bookmark_black_24dp.png",
"contextualTriggers": [{
"unconditional": {
},
"onTriggerFunction": "buildAddOn"
}],
"primaryColor": "#4285F4",
"secondaryColor": "#4285F4",
"openLinkUrlPrefixes": ["https://mail.google.com/"],
"version": "TRUSTED_TESTER_V2"
}
}
Code.gs
function buildAddOn(e) {
var driveService = createOauthService();
Logger.log('Access'+driveService.hasAccess()); // GETTING FALSE HERE
Logger.log('Auth URL'+driveService.getAuthorizationUrl()); // GETTING PROPER AUTH URL.
Logger.log('Token'+driveService.getAccessToken()); // NEED TOKEN TO BE USED ON REST CALL
}
function createOauthService() {
return OAuth2.createService('drive')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId('MY CLOUD CONSOLE CLIENT ID')
.setClientSecret('MY SECREAT')
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('https://www.googleapis.com/auth/drive')
.setParam('login_hint', Session.getActiveUser().getEmail())
.setParam('access_type', 'offline');
.setParam('approval_prompt', 'force');
}
Is this correct way or am i missing something ?
Please suggest.
One documented way to do this is to return a card from your buildAddOn() function which contains a button configured to launch the authorization sequence.
function buildAuthorizeCard() {
var authorizationUrl = getOAuthService().getAuthorizationUrl();
var card = CardService.newCardBuilder();
var section = CardService.newCardSection();
section.addWidget(CardService.newTextButton()
.setText("Authorize MyService")
.setAuthorizationAction(
CardService.newAuthorizationAction()
.setAuthorizationUrl(authorizationUrl)
));
card.addSection(section);
return card.build();
}
You can give that a try.
I'm writing a Restful api with node js and I'm facing a weird problem: I'm testing the API using a Chrome extension called postman and sending the json object below:
{
"items": [
{
"appid": 730,
"classid": "2222",
"id": 99,
"instanceid": "instanceID",
"market_name": "Market name"
},
{
"appid": 730,
"classid": "2222",
"id": 99,
"instanceid": "instanceID",
"market_name": "Market name"
}
],
"message": "Mensagem de teste",
"user": 76561197960275584
}
My problem is with the "user" property. When getting it from the server it returns me 76561197960275580 but the value sent was 76561197960275584. When I send it using string it works but when sending as number - which is like the consumer of the api sends data - it gives me this problem.
Here is some of my API code. It is using express 4.
var express = require('express');
var bodyParser = require('body-parser');
var api = express();
api.use(bodyParser.urlencoded({ extended: false }));
api.use(bodyParser.json());
api.post('/import', function importEndPoint(req, res) {
console.log('req.body.user=' + req.body.user);
});
Does anyone would have a tip for me to solve it?
Thanks in advance for any help.