Web3 client can't write to contract in Flutter app using WalletConnect for credendtial - flutter

I used web3dart with flutter with Ganache and Truffle to run my Solidity contract, the contract is being read fine by my Flutter app but when I run functions that write to the contract it doesn't work (can't write to the contract from the app). I saw on the web3dart package it says you should use .sendTransaction() instead of .call() when running a function that writes to the contract
for the credential, I used WalletConnect I used the WalletConnectEthereumCredentials class that was written in the package example source code here
The transaction is successful from MetaMask wallet Address to the contract address(traceable with EtherScan), but still, contract data remains unchanged.
Solidity Code:
function update(string memory newMessage) public {
message = newMessage;
}
Flutter Code:
final cred = WalletConnectEthereumCredentials(provider: provider);
try {
var transactionId = await _web3client.sendTransaction(
cred,
Transaction.callContract(
contract: _deployedContract,
function: _updateFunction,
parameters: ["NEW_MESSAGE"],
from: EthereumAddress.fromHex(
cred.provider.connector.session.accounts[0]),
),
chainId: 4);
You can see what's on WalletConnectEthereumCredentials and WalletConnectEthereumCredentials on the walletConnect repository

Solved!
Just deploy the contract instead of running it locally on your machine.
I was basically trying to make a transaction to a contract that is running locally on Ganache. So I deployed the contract on truffle, this solved the issue and I can fully interact with the contract using my app.

Related

Is there yet an idiomatic way to make native calls to AWS Lambda or API Gateway from a Flutter application?

Goal: Make a signed request (SigV4) to AWS Lambda or API Gateway from a Flutter application (iOS, for the sake of this question).
For context, AWS introduced support for "native calls to AWS backends in [...] Flutter or Dart applications" back in May of 2022. There is an example of how to sign a request to Cognito to gather information about a User Pool, but I have not seen any application of this concept for Lambda or API Gateway calls, yet.
I'm wondering if anyone else has had success using AWS's official Dart packages to send signed requests or knows of another way to securely call AWS from a Flutter application.
EDIT:
I was able to accomplish the goal. Here's how I did it:
The code (all-caps denotes placeholders for your own values):
import 'dart:convert';
import 'package:aws_common/aws_common.dart';
import 'package:aws_signature_v4/aws_signature_v4.dart';
const signer = AWSSigV4Signer(
credentialsProvider: AWSCredentialsProvider.dartEnvironment(),
);
const region = 'REGION';
Future<void> yourFunction() async {
final scope = AWSCredentialScope(
region: region,
service: AWSService.apiGatewayV2,
dateTime: AWSDateTime(DateTime.now()),
);
final request = AWSHttpRequest(
method: AWSHttpMethod.post,
uri: Uri.https('HOST.execute-api.REGION.amazonaws.com','/STAGE_NAME'),
headers: const {
AWSHeaders.contentType: 'application/x-amz-json-1.1',
},
body: json.encode({
'EVENT_KEY':'EVENT_VALUE',
}).codeUnits,
);
final signedRequest = await signer.sign(
request,
credentialScope: scope,
);
final resp = await signedRequest.send();
final respBody = await resp.decodeBody();
print('\n\n${signedRequest.headers}\n\n${respBody}\n\n${resp.statusCode}\n\n');
}
Within a single AWS region (except where n/a):
create IAM user with execute-api:Invoke permission and programmatic access; store keys securely for later use.
create a Lambda function (can be the default, for testing).
create API in API Gateway:
REST (not private)
Regional endpoint
Add method (for me, POST)
IAM authorization type
Integration type is Lambda
select the target Lambda function, but
do not use Lambda proxy
deploy the newly created API to a new stage (give it a name)
Edit your dart file to include the new resources, including the stage name.
Test your API within API Gateway (I was getting 502 until I unchecked "Lambda proxy integration").
Run the following in your terminal after a successful API test; be sure to insert the keys for the IAM user you created.
flutter run --dart-define=AWS_ACCESS_KEY_ID=... --dart-define=AWS_SECRET_ACCESS_KEY=...
Summary:
In my case, I have a button that executes this function. If you keep the print statement in the above dart code, you should hopefully see {"statusCode": 200, "body": "\"Hello from Lambda!\""} as the response body.
Hope this helps others. Cannot make any guarantees that my approach will work in another environment. I also may have forgotten to include something relevant in the steps above. Still open to questions and suggestions.
Thank you.

How do I call a callable v2 Cloud Function in Flutter?

I have a Flutter app that uses cloud functions. I upgraded one function to a v2 function and it no longer works. The function cannot be found. The function logs do not show that it is being called. It is in the us-central1 region, as is the rest of the project.
final result = await FirebaseFunctions.instance.httpsCallable('addMessage').call();
Instead of addMessage I have tried the full function URL found in the firebase console, but that does not work either.
Function declaration:
exports.addMessage = onCall(async (request) => {
//Run function
});
How do I call a v2 cloud function in flutter?
Conclusion: as of now you cannot call a v2 cloud function using the flutter cloud_functions package. You must use a regular http request to the full function URL (the cloud_functions package does not support using full URLs). You can use the dart http package to do this, handling the request and response manually.

How to send signed manifest to the PTE to interact with a published package

I managed to publish a package to the PTE via resim publish.
Now I am stuck as I have the following problem:
How to send a signed manifest to the PTE (from my account as I need a badge that will be returned)?
In order to create a Manifest, and sign it, you must back an element which upon activation constructs a Manifest, sends it to the PTE Extension to be signed, and receives the results.
Here is some sample code, this is the Typescript part:
document.getElementById('instantiateMainComponent')!.onclick = async function () {
// Construct manifest
const manifest = new ManifestBuilder()
// Instantiates component
.callFunction(Package_Address, 'ComponentName', 'instantiate', [])
// Deposits returned resources to account
.callMethodWithAllResources(Account_Address, 'deposit_batch')
.build()
.toString();
// Send manifest to extension for signing
const receipt = await signTransaction(manifest);
// Add results here
}
And here is my associated HTML:
<h2>3. Instantiate Main Component</h2>
<p><button id="instantiateMainComponent">Instantiate</button></p>
This was one of the things I needed to do not too long ago. To clarify, for the public test environment (only the PTE, nothing else) not all transactions require signatures. Matter of fact, only transactions which withdraw funds from an account require a signature, nothing else requires one. This means the following:
For all transactions which do not withdraw funds from an account, you can continue using the PTE API to send your transactions and not sign them.
If signing transactions is necessary, then my recommendation is to construct and sign your transactions using Rust since it already has an SBOR implementation and you can very easily sign all of your transactions with Rust + the existing Scrypto libraries.
Regarding the Rust implementation, here is an example code I wrote in Rust which signs transactions and submits them to the PTE (PTE01 but you can change it to PTE02): https://github.com/0xOmarA/PTE-programmatic-interactions/blob/main/src/main.rs
Here is an example of this code being used in action: https://github.com/0xOmarA/RaDEX/tree/main/bootstrap

Issue with getOrCreateAssociatedAccountInfo on Quicknode

I just switched to Quicknode (testnet) as the public Solana node has IP limits. I notice that when I call token.getOrCreateAssociatedAccountInfo I encounter an issue which never happened on the main public node:
{"name":"Error","message":"Failed to find account","stack":"Error: Failed to find account\n at Token.getAccountInfo (/var/www/node_modules/#solana/spl-token/lib/index.cjs.js:493:13)\n at process.processTicksAndRejections (node:internal/process/task_queues:95:5)\n at async Token.getOrCreateAssociatedAccountInfo (/var/www/node_modules/#solana/spl-token/lib/index.cjs.js:338:16)\n at async SolanaBlockchainAPI.reward (/var/www/src/datasources/solanaBlockchain.js:266:35)
Is there some sort of compatibility issue ?
my code...
const token = new Token(
connection,
new web3.PublicKey(token_type.token_address),
TOKEN_PROGRAM_ID,
this.appTreasPair
);
const recipientTokenAddress = await token.getOrCreateAssociatedAccountInfo(
new web3.PublicKey(solana_public_address)
);
From the error it looks like there's some trouble locating the account that you're plugging into the getOrCreateAssociatedAccountInfo call.
There's not a lot of info to work with here, but my initial guess is you were working on the public solana devnet, and plugged into a testnet QuickNode URL, which would explain why the account isn't available for you.
Solution here would be to make sure you're on devnet instead of testnet when creating your QuickNode endpoint. Testnet really isn't used very much outside of people testing infrastructure. You're usually either working on production stuff (mainnet) or want to test out different functionalities on the developer testing net (devnet).

How to include another Contract as dependency?

A function in a contract that is spawning a new contract executes fine from Remix but fails when called from my custom app, without giving any details except "transaction failed". I'm pretty sure the reason for this is that both contracts are written in the same file in Remix so it knows exactly how to define the child contract whereas my app only takes in the abi of the source/parent.
The simplified distributed code is something like this:
pragma solidity ^0.6.0;
contract Parent{
address[] public children;
function createChild (uint256[] memory distro)external payable{
children.push(address(new Child(msg.sender,distro)));
}
}
contract Child{
address payable owner;
uint256[] distribution;
constructor(address payable admin,uint256[] memory distro)public payable{
owner=admin;
distribution=distro;
}
}
in my Flutter app, I'm defining the Parent contract using a list of strings like so:
List<String> source = [
"function createChild(int256[]) payable",
]
And then proceed to get the user's wallet credentials and push the transaction like so:
String address = "0xbAF01C91b2d53cC9eeb0ED1A300783Cb74563010"; //address of deployed Parent
var contract = Contract(address, source, web3user);
contract.connect(web3user.getSigner()); // uses the connected wallet as signer
var ponse = await promiseToFuture(callMethod(contract, "createChild", [
[
[30, 70], //the array of int256 it takes as parameters
TxParams(
value: "1000000000000",
gasLimit: "1000000",
)
]));
How do I let my app know about the Child contract? I'm thinking it should be somehow included in the source list of functions, so that the EVM knows what to compile and deploy, but it's unclear how to specify that.
Whenever you want to interact with a contract on-chain, you need 4 things:
The ABI
The Address
The Blockchain
A wallet with funds to pay for the gas
And when you create your contract, yes, your application needs to know what the ABI of the child contract is. So when you create your child contract, you'll need to pass in the ABI.