Issue encoding array of addresses for Web3 - javascript

I'm trying to call the Uniswap Router contract like:
// dummy data
Function: swapExactETHForTokens(uint256 amountOutMin, address[] path, address to, uint256 deadline)
MethodID: 0x7ff36ab5
[0]: 000000000000000000000000000000000000000000000000000000dd0f593444
[1]: 0000000000000000000000000000000000000000000000000000000000000080
[2]: 00000000000000000000000047c0a182235478ca13d248d049eaa28d4ff7520f
[3]: 000000000000000000000000000000000000000000000000000000005f9a1e44
[4]: 0000000000000000000000000000000000000000000000000000000000000002
[5]: 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
[6]: 0000000000000000000000001a969239e12f07281f8876d11afcee081d872adf
In my TypeScript code I have:
const abi = web3.eth.abi.encodeFunctionCall(
{
type: 'function',
name: 'swapExactTokensForTokens',
inputs: [
{
name: 'amountIn',
type: 'uint256',
},
{
name: 'amountOutMin',
type: 'uint256',
},
{
name: 'path',
type: 'address[]',
},
{
name: 'to',
type: 'address',
},
{
name: 'deadline',
type: 'uint256',
},
],
},
[
fromWei,
toWei,
// the problem
web3.eth.abi.encodeParameter('address[]', [
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
'0x20fe562d797a42dcb3399062ae9546cd06f63280',
]),
getAddress(),
deadline,
]
)
From the error, it looks like encodeFunctionCall wasn't expecting an encoded array (at least, the way I did it). So how would I pass an array of addresses?
(node:21008) UnhandledPromiseRejectionWarning:
Error: expected array value
(argument="path", value="0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000020fe562d797a42dcb3399062ae9546cd06f63280", code=INVALID_ARGUMENT, version=abi/5.0.0-beta.153)
Full source: https://github.com/ZaneH/tradr/blob/56d670aeec09ed0e8c3e359c48ae8b36fdea7c30/packages/backend/src/modules/Trades.ts#L37

I believe that web3.eth.abi.encodeFunctionCall expects JSON type parameters, e.g. address[] is represented as an simple array of strings ["0x...", "0x..."]
// the problem
web3.eth.abi.encodeParameter('address[]', [
'0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
'0x20fe562d797a42dcb3399062ae9546cd06f63280',
]),
Instead of Please try:
[
"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
"0x20fe562d797a42dcb3399062ae9546cd06f63280"
],

Related

Storing data from JSON object received from Google People Api

So I have a server that receives data from Google People api regarding contacts and my received object has the following structure:
{ connections:
[ { resourceName: 'people/c3904925882068251400',
etag: '%EgYBAgkLNy4aDQECAwQFBgcICQoLDA0iDFZUOUE0NkRBZW0wPQ==',
names:
[ { metadata: { primary: true, source: [Object] },
displayName: 'Mihai Vrincut',
familyName: 'Vrincut',
givenName: 'Mihai',
displayNameLastFirst: 'Vrincut, Mihai' },
{ metadata: { source: [Object] },
displayName: 'Mihai Vrincut',
familyName: 'Vrincut',
givenName: 'Mihai',
displayNameLastFirst: 'Vrincut, Mihai' } ],
emailAddresses:
[ { metadata: { primary: true, source: [Object] },
value: 'mihai.vrincut#gmail.com' } ] },
{ resourceName: 'people/c3275206487406036814',
etag: '%EgYBAgkLNy4aDQECAwQFBgcICQoLDA0iDHBFVzBUMm8wWU5nPQ==',
names:
[ { metadata: { primary: true, source: [Object] },
displayName: 'aaaaaaaaa',
givenName: 'aaaaaaaaa',
displayNameLastFirst: 'aaaaaaaaa' } ] },
{ resourceName: 'people/c5777943907795350059',
etag: '%EgYBAgkLNy4aDQECAwQFBgcICQoLDA0iDGxOeGYwblg3bFUwPQ==',
names:
[ { metadata: { primary: true, source: [Object] },
displayName: 'costin',
givenName: 'costin',
phoneticFamilyName: 'cancius',
phoneticGivenName: 'costin',
displayNameLastFirst: 'costin' } ],
emailAddresses: [ { metadata: { primary: true, source: [Object] }, value: 'hj' } ],
phoneNumbers:
[ { metadata: { primary: true, source: [Object] },
value: '07543532512',
canonicalForm: '+40754353251' } ] } ], totalPeople: 3}totalItems: 3 }
In order to get this object I used the util.inspect() method. However, when I try to access the names for example, I get undefined:
var response=util.inspect(responses,{depth:5});
Console.log(response.connections[0].names);
What is wrong?
So, given the situation, and the information you've given over the comment sections.
I assume that responses is already an object, but util.inspect, makes it a string with a JSON kind of syntax but without the quotes (") before and after the names of the keys. That's why you get
{ connections: ^ SyntaxError: Unexpected token c in JSON at position 2
So, try going over the responses object.
console.log(responses)
And get the name of the keys. With them
console.log(responses.sth.sthElse.anotherSth.anotherSthElse.lastSth.connections)
And see if you get the expected result :)
You should convert the response to JSON Object.
try this:
console.log(JSON.parse(response).connections[0].names);
(I am assuming you are working in Javascript)
What I would do is validate if the answer is a String, you have a
console.log (typeof response)
if it is a string, convert it to JSON:
let responseObject = JSON.parse (response);
Finally, try if you can access the object:
console.log (responseObject.connections [0] .names);
You tell me your answer :)

Keys to Mongoose Object are different from property names

In order to troubleshoot an error I have been getting, I wrote the following snippet:
var myFunction = function(obj) {
var keys = Object.getOwnPropertyNames(obj);
console.log(obj);
console.log(keys);
}
When running my function within a mongoose query callback, the console logs this:
{_id: 5a8g123vjsdj83nf8afvn48,
username: 'Player1',
adv1: { name: 'a', type: '!' },
adv2: { name: 'a', type: '!' },
adv3: { name: 'a', type: '!' },
__v: 0,
invitations: [ 'PlayTest1', 'PlayTest2' ] }
[ '$__', 'isNew', 'errors', '_doc', '$init' ]
Now as far as I understand it, the last line in the console (separated for reading convenience) should read:
[ '_id', 'username', 'adv1', 'adv2', 'adv3', '__v', 'invitations ]
My question is why does the keys obj I create in myFunction not contain the properties names shown when I log the actual object?
Mongoose document fields are stored in obj._doc
console.log displays the document fields due to an .inspect function attached to the document object.
Use node --inspect if you want to debug something.

Storing Javascript Array of Objects in Mongo DB using Mongoose

I have an array of the form [{key: ..., type: ..., value: ...}] and want to store it in the fields field in the following schema:
var articleSchema = mongoose.Schema({
name: {
type: String,
unique: true,
required: true
},
updated: {
type: Date,
default: Date.now
},
pageviews: {
type: Number,
default: 0
},
fields: [{
key: String,
type: String,
value: String
}],
image: String
});
I am doing this as follows, my Javascript array referenced as keyValueObj
Article.findOneAndUpdate(
{ name: articleName },
{
fields: keyValueObj
},
{ upsert: true },
callback
);
However, all that is stored in the database in the fields field is an array of strings like this: ["[object Object]"]
How can I store my Javascript array so that it matches my mongoose schema correctly?
I was able to fix this using Molda's idea of using a separate schema.
The updated fields field in the articleSchema now looks like this:
fields: [{
type: Schema.Types.ObjectId,
ref: 'Field'
}]
I then converted the array to an array of schema objects, like this:
keyValueObj = keyValueObj.map(function(fieldObj){
return new Field({
key: fieldObj.key,
type: fieldObj.type,
value: fieldObj.value
});
});
I was then able to store keyValueObj the was doing it in the initial code.

Nested Javascript Object : recursion and "complex" transformation (with lodash)

I apologize in advance for the complex example here; I tried to trim it down as much as I could to illustrate what I try to achieve
I have a complex structure that I need to traverse and transform based on some conditions; Here's an (short) example of the structure that should cover most scenarios:
{ PROP1: {
metadata: Object, // somewhere deeper in metadata I have a `value` key
parent: { $ref: String },
employee: {
parent: { $ref: String },
id: String,
metadata: Object,
products: {
metadata: Object,
model: { $ref: String },
type: 'array',
value: ["String", "String" , "String"] ,
[...]
},
model: {
id: String,
email: {
metadata: Object,
value: 'a#b.com',
type: 'string',
validity: Object,
[...]
},
name: {
firstName: {
metadata: Object,
value: 'John',
type: String,
validity: Object,
[...]
},
lastName: {
metadata: Object,
value: 'Smith',
type: String,
validity: Object,
[...]
},
}
},
operations: {
id: String,
items: [
{ action: {value: "UPDATE", model: {$ref: String }, [...] },
{...}
],
metadata: Object,
[...]
}
}
},
PROP2: {
// similar as PROP1
},
[... and so on ...]
}
I basically need to clean that up before sending it to the backend;
Whenever a value contains $ref, I don't want the key/val pair (e.g.: PROP1.parent is of no use and can be omitted)
whenever a value contains value, I need to omit everything else and move the value of value as the value of key (e.g.: PROP1.employee.products should equal ['String', 'String', 'String'])
keys like id, metadata, validity (etc) can be completely omitted regardless of its content
So the end result should be along those lines:
{ PROP1: {
employee: {
products: ['item','item','item'],
model: {
email: 'a#b.com',
name: { firstName: 'John', lastName: 'Smith'},
},
operations: [
{action: 'UPDATE'}
]
}
},
PROP2: { ... }
}
I tried lots of different approaches using different lodash methods but couldn't wrap my head around this...
Any help will be greatly appreciated
Thanks
In pseudo code, try something like this. Implement the specifics and post more info when you run into trouble.
var ignoreKeyArray = ["id", ...] // keys to ignore and remove
var newJSON = "{}";
for (property in JSON) {
var newProp = parseJSON(key, property);
insert newProp in newJSON object
}
var parseJSON = function (key, jsonBlob) {
if (key in ignoreKeyArray || jsonBlob contains value "$ref")
return "";
var jsonOut = key + ": {}";
for (child in jsonBlob) {
add parseJSON(child) to jsonOut;
}
return jsonOut;
}
If you have any questions, comment so I can extend the answer and clarify.

MongoDB Malformed Geometry with geojson

Using MongoDB v2.6.5
When I attempt to save a geojson document into the db I receive the following error:
name: 'MongoError',
code: 16755,
err: 'insertDocument :: caused by :: 16755 Can\'t extract geo keys from object, malformed geometry?: { _id: ObjectId(\'55271b90d075728028d4c9e1\'), ..., location: [ { _id: ObjectId(\'55271b90d075728028d4c9e3\'), loc: { type: "Point", coordinates: [ -105.01621, 39.57422 ] } } ] } ], status: [ "lead" ], created: new Date(1428626320406), lastName: "Doe", firstName: "John", __v: 0 }' }
I'm attempting to insert a Point into the table with a 2dsphere index, all managed through MongooseJS as shown below.
var GeoAddressSchema = new Schema({
// Only holds points.
loc: {
type: { type: String },
coordinates: []
}
});
var Lead = new Schema({
// Other fields ...
location: [GeoAddressSchema],
// ...
});
LeadAddressSchema.index({ location: '2dsphere' });
The geojson that is being saved:
{ type: "Point", coordinates: [ -111.855211, 33.58513 ] }
The geojson is valid according to: http://geojsonlint.com/ if I wrap the fields in quotes, but I should not need to do that (and cannot for Mongo afaik).
Anyone have any idea why this would fail? It looks correct.
Reference links
MongoDB GeoJSON: http://docs.mongodb.org/manual/reference/geojson/
MongoDB 2dSphere: http://docs.mongodb.org/manual/core/2dsphere/
First observation: you need not introduce the loc path in the location structure.
Further, you need not even define a separate schema for your location field in the Lead schema.
Try this:
var Lead = new Schema({
// Other fields ...
location: {
type: {
type: 'String',
default: 'Point' // and optionally skip including `type: String` everywhere
},
coordinates: {
type: [Number]
}
},
// More fields ...
});
LeadAddressSchema.index({ location: '2dsphere' });
Another problem I faced was that the 2dsphere index gets messed up, when figuring and testing out solutions. So try dropping the index, or even better the collection after you make structural changes to the schema.
> db.lead.drop(); // on the mongo console`

Categories

Resources