When it goes to transfer, it shows the wrong token in the metamask
(async ()=>{
const contract = new web3.eth.Contract(ABI, contractAddress);
const transfer = await contract.methods.transfer(reciever, 1);
const data = await transfer.encodeABI();
if(window.ethereum.chainId == '0x61'){
ethereum
.request({
method: 'eth_sendTransaction',
params: [
{
from: ethereum.selectedAddress,
to: reciever,
gasPrice: '1000000',
gas: '',
data: data,
},
],
})
.then((txHash) => console.log(txHash))
.catch((error) => console.error);
} else {
ethereum.request({ method: 'wallet_switchEthereumChain', params:[{chainId: '0x61'}]})
}
})()
It should show the token, but it shows differently,
When transferring tokens, the transaction needs to be processed by the contract address (not by the token receiver). Note that the contract receiver is passed as the first argument of the transfer() function.
Solution: Replace to: reciever with to: contractAddress in the params section of your snippet.
Related
As the title suggests, I am trying to implement Stripe into my flutter app using the stripe extension for Firebase and using Javascript Firebase Cloud Functions for the server side. I believe the issue is on the server side when I try to create a customer and create a payment intent.
The server side code is here:
const functions = require("firebase-functions");
const stripe = require("stripe")("my test secret key"); // this works fine for the other stripe functions I am calling
exports.stripePaymentIntentRequest = functions.https.onRequest(
async (req, res) => {
const {email, amount} = req.body;
try {
let customerId;
// Gets the customer who's email id matches the one sent by the client
const customerList = await stripe.customers.list({
email: email,
limit: 1,
});
// Checks the if the customer exists, if not creates a new customer
if (customerList.data.length !== 0) {
customerId = customerList.data[0].id;
} else {
const customer = await stripe.customers.create({
email: email,
});
customerId = customer.data.id;
}
// Creates a temporary secret key linked with the customer
const ephemeralKey = await stripe.ephemeralKeys.create(
{customer: customerId},
{apiVersion: "2022-11-15"},
);
// Creates a new payment intent with amount passed in from the client
const paymentIntent = await stripe.paymentIntents.create({
amount: parseInt(amount),
currency: "gbp",
customer: customerId,
});
res.status(200).send({
paymentIntent: paymentIntent.client_secret,
ephemeralKey: ephemeralKey.secret,
customer: customerId,
success: true,
});
} catch (error) {
res.status(404).send({success: false, error: error.message});
}
},
);
Then my client-side code is:
try {
// 1. create payment intent on the server
final response = await http.post(
Uri.parse(
'https://us-central1-clublink-1.cloudfunctions.net/stripePaymentIntentRequest'),
headers: {"Content-Type": "application/json"},
body: json.encode({
'email': email,
'amount': amount.toString(),
}),
);
final jsonResponse = json.decode(response.body);
if (jsonResponse['error'] != null) {
throw Exception(jsonResponse['error']);
}
log(jsonResponse.toString());
//2. initialize the payment sheet
await Stripe.instance.initPaymentSheet(
paymentSheetParameters: SetupPaymentSheetParameters(
paymentIntentClientSecret: jsonResponse['paymentIntent'],
merchantDisplayName: 'Clublink UK',
customerId: jsonResponse['customer'],
customerEphemeralKeySecret: jsonResponse['ephemeralKey'],
style: ThemeMode.dark,
),
);
await Stripe.instance.presentPaymentSheet();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Payment completed!')),
);
} catch (e) {
if (e is StripeException) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Error from Stripe: ${e.error.localizedMessage}'),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
}
I basically copied the flutter_stripe documentation to create the payment sheet with the necessary changes. Any help would be greatly appreciated!
Ok so I found what worked! I was being given a 403 status error with reason "forbidden". This meant I had to go to the google cloud console and update the permissions in the cloud functions tab.
After a long discussion with ChatGPT, I managed to write code that redirects the user to the Stripe payment page and then captures an event when the transaction is successfully completed.
The problem is that my fetch request has already received a response from the /checkout endpoint and is not waiting for a response from /webhook. And I would like my API to return a properly generated response after successfully finalizing the transaction. What am I doing wrong?
First, I send a request to the /checkout endpoint, which takes care of generating the payment link and sending it back:
fetch('http://localhost:3001/checkout', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
items: [
{
id: 0,
},
],
}),
})
.then((res) => {
if (res.ok) return res.json();
return res.json().then((e) => console.error(e));
})
.then(({url}) => {
console.log(url);
window.location = url;
})
.catch((e) => {
console.log(e);
});
This code when I press the button redirects me to the Stripe payment page.
Endpoint /checkout:
app.post('/checkout', async (req, res) => {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line_items: req.body.items.map(({id}) => {
const storeItem = storeItems.get(id);
return {
price_data: {
currency: 'pln',
product_data: {
name: storeItem.name,
},
unit_amount: storeItem.priceInCents,
},
quantity: 1,
};
}),
mode: 'payment',
success_url: `${process.env.CLIENT_URL}/success.html`,
cancel_url: `${process.env.CLIENT_URL}/cancel.html`,
});
console.log(session.url);
res.json({url: session.url});
} catch (e) {
// If there is an error send it to the client
console.log(e.message);
res.status(500).json({error: e.message});
}
});
I connected StripeCLI to my server using stripe listen --forward-to localhost:3001/webhook. Now I can capture the successful transaction event using the /webhook endpoint, but I have no way to return The transaction was successful to the client:
app.post('/webhook', (req, res) => {
const event = req.body;
if (event.type === 'checkout.session.completed') {
res.send('The transaction was successful');
}
});
After the suceesful payment the customer should be redirected back to your website. Where you can create success page.
success_url: `${process.env.CLIENT_URL}/success.html`,
If you want to get some data back from the Strapi after the paymant is successful page you can add this
success_url: `${process.env.CLIENT_URL}/success.html?&session_id={CHECKOUT_SESSION_ID}`
At the succes page you just deconstruct the data. And do whatever you want with them :)
If you deconstruct the object for example like this: (Next.js)
const stripe = require("stripe")(`${process.env.STRIPE_SECRET_KEY}`);
export async function getServerSideProps(params) {
const order = await stripe.checkout.sessions.retrieve(
params.query.session_id,
{
expand: ["line_items"],
},
);
const shippingRate = await stripe.shippingRates.retrieve(
"shr_1MJv",
);
return { props: { order, shippingRate } };
}
export default function Success({ order, shippingRate }) {
const route = useRouter();
Yo can log out the whole object to see whats inside
console.log(order);
If the payment was sucessfull you should get in prop variable: payment_status: "paid"
Stripe will automatically redirect the client to the success_url that you specified when you created a Stripe session.
You can use the webhook for saving the order in the database for example, but not to redirect the client.
I want to add custom expires time for fitbit implicit auth flow the default expires time is a day you can customize it I want to make it for a year. If you are using the web version you can change it by directly changing the expires_in params in the url.
As shown in this below url.
https://www.fitbit.com/oauth2/authorize?response_type=token&client_id=randomid&redirect_uri=https%3A%2F%2Fauth.expo.io%2F%40albert%2Fyourapp&scope=activity%20heartrate%20location%20nutrition%20profile%20settings%20sleep%20social%20weight%20oxygen_saturation%20respiratory_rate%20temperature&expires_in=31536000
WebBrowser.maybeCompleteAuthSession();
const useProxy = Platform.select({ web: false, default: true });
// Endpoint
const discovery = {
authorizationEndpoint: 'https://www.fitbit.com/oauth2/authorize',
tokenEndpoint: 'https://api.fitbit.com/oauth2/token',
revocationEndpoint: 'https://api.fitbit.com/oauth2/revoke',
};
const [request, response, promptAsync] = useAuthRequest(
{
responseType: ResponseType.Token,
clientId: 'randomid',
scopes: ['activity', 'profile'],
redirectUri: makeRedirectUri({
useProxy,
scheme: 'nudge://',
}),
},
discovery
);
const loginFitbit = async (token) => {
if (token) {
try {
await signInFitbit(token, dispatch);
await storeFitbitToken(token);
setLoggedIn(true);
} catch (e) {
setLoggedIn(false);
addError('Could not login Fitbit. Please try agian later.');
}
}
};
React.useEffect(() => {
if (response?.type === 'success') {
const { access_token } = response.params;
console.log("res",response)
loginFitbit(access_token);
} else {
console.log('error', response);
}
}, [response]);
React.useEffect(() => {
const fetchData = async () => {
let token;
try {
token = await getFitbitToken();
setLoggedIn(true);
} catch (e) {
setLoggedIn(false);
console.error(e);
}
dispatch({ type: 'RESTORE_FITBIT_TOKEN', token: token });
};
fetchData();
}, [dispatch])
If your application type is currently set to using the Authorization Code Grant Flow, access tokens have a default expiration of 8 hours (28800 seconds). This cannot be changed.
However, if you'd like your users to be able to select how long your application can access their data, you will need to change your application settings to the Implicit Grant Flow. This authorization flow allows users to select how long they give consent to your application (1 day, 1 week, 30 days, or 1 year).
https://community.fitbit.com/t5/Web-API-Development/Query-parameter-expires-in-not-working/td-p/3522818
If you want to add extra query params for your auth request you need to add extraParams object with your custom fields.
https://docs.expo.dev/versions/latest/sdk/auth-session/#authrequestconfig
const [request, response, promptAsync] = useAuthRequest(
{
responseType: ResponseType.Token,
clientId: "randomid",
scopes: ["activity", "profile"],
redirectUri: makeRedirectUri({
useProxy,
scheme: "nudge://",
}),
extraParams: {
expires_in: 3600, // <--- new value
},
},
discovery
);
I am attempting to create a button on my dapp to send Ethereum. I would like to log a bit of the data in my own database after the transaction is successful. I don't want to log the data in my db until AFTER I know the transaction was successful. Is there a way to do this in Javascript?
Here is my code:
sendEthButton.addEventListener('click', () => {
let userETH = document.getElementById("inputId").value;
var wei_val = userETH*10e17;
var hexString = wei_val.toString(16);
ethereum
.request({
method: 'eth_sendTransaction',
params: [
{
from: accounts[0],
to: my_address,
//value: '0x6f05b59d3b20000',
value: hexString,
gasPrice: '',
gas: '',
},
],
})
.then((txHash) => console.log(txHash))
.catch((error) => console.error);
});
I know that I can test for the txHash, but that doesn't indicate whether or not the transaction was successful, just whether or not it was successfully initiated.
How can I test for a successful transaction through JS?
I want to test a a cloud function that creates users.
In normal cases, inside the browser i generate an idToken and i send it to server via headers: Authorization : Bearer etcIdToken
But I want to test this function without the browser. In my mocha tests i have:
before(done => {
firebase = require firebase.. -- this is suppose to be like the browser lib.
admin = require admin..
idToken = null;
uid = "AY8HrgYIeuQswolbLl53pjdJw8b2";
admin.auth()
.createCustomToken(uid) -- admin creates a customToken
.then(customToken => {
return firebase.auth() -- this is like browser code. customToken get's passed to the browser.
.signInWithCustomToken(customToken) -- browser signs in.
.then(signedInUser => firebase.auth() -- now i want to get an idToken. But this gives me an error.
.currentUser.getIdToken())
})
.then(idToken_ => {
idToken = idToken_
done();
})
.catch(err => done(err));
})
The error i'm getting is:
firebase.auth(...).currentUser.getIdToken is not a function - getting the idToken like this works on client - and is documented here.
I tried directly with signedInUser.getIdToken(). Same problem:
signedInUser.getIdToken is not a function - not documented. just a test.
I think this is because firebase object is not intended for node.js use like i'm doing here. When signing in - stuff get's saved in browser local storage - and maybe this is why.
But the question still remains. How can i get an idToken inside node.js in order to be able to test:
return chai.request(myFunctions.manageUsers)
.post("/create")
.set("Authorization", "Bearer " + idToken) --- i need the idToken here - like would be if i'm getting it from the browser.
.send({
displayName: "jony",
email: "jony#gmail.com",
password: "123456"
})
am I approaching this wrong? I know that if i can get the idToken it will work. Do i rely need the browser for this? Thanks :)
From Exchange custom token for an ID and refresh token, you can transform a custom token to an id token with the api. Hence, you just have to generate a custom token first from the uid, then transform it in a custom token. Here is my sample:
const admin = require('firebase-admin');
const config = require('config');
const rp = require('request-promise');
module.exports.getIdToken = async uid => {
const customToken = await admin.auth().createCustomToken(uid)
const res = await rp({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${config.get('firebase.apiKey')}`,
method: 'POST',
body: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.idToken;
};
L. Meyer's Answer Worked for me.
But, the rp npm package is deprecated and is no longer used.
Here is the modified working code using axios.
const axios = require('axios').default;
const admin = require('firebase-admin');
const FIREBASE_API_KEY = 'YOUR_API_KEY_FROM_FIREBASE_CONSOLE';
const createIdTokenfromCustomToken = async uid => {
try {
const customToken = await admin.auth().createCustomToken(uid);
const res = await axios({
url: `https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=${FIREBASE_API_KEY}`,
method: 'post',
data: {
token: customToken,
returnSecureToken: true
},
json: true,
});
return res.data.idToken;
} catch (e) {
console.log(e);
}
}
curl 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<FIREBASE_KEY>' -H 'Content-Type: application/json'--data-binary '{"email": "test#test.com","password":"test","returnSecureToken":true}'
If this curl doesn't run, try running the same thing on Postman. It works!