Skip to content

Commit

Permalink
refactor(transformation)!: drop extra wrapper around bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
davidyuk committed Oct 13, 2021
1 parent fa38b40 commit 9b70f8e
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 46 deletions.
6 changes: 2 additions & 4 deletions src/contract/aci/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ export const prepareArgsForEncode = async (aci, params) => {
validateArguments(aci, params)
const bindings = aci.bindings
// Cast argument from JS to Sophia type
return Promise.all(aci.arguments.map(async ({ type }, i) => transform(type, params[i], {
bindings
})))
return Promise.all(aci.arguments.map(async ({ type }, i) => transform(type, params[i], bindings)))
}

export const decodeEvents = (events, fnACI) => {
Expand All @@ -133,7 +131,7 @@ export const decodeCallResult = async (result, fnACI, opt) => {
decodedResult: await transformDecodedData(
fnACI.returns,
await result.decode(),
{ ...opt, bindings: fnACI.bindings }
fnACI.bindings
),
decodedEvents: decodeEvents(result.result.log, fnACI)
}
Expand Down
70 changes: 31 additions & 39 deletions src/contract/aci/transformation.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ const isRemoteAddress = (t) => {
/**
* Parse sophia type
* @param type
* @param returnType
* @param bindings
* @return {Object}
*/
export function readType (type, { bindings } = {}) {
export function readType (type, bindings) {
let [t] = Array.isArray(type) ? type : [type]

// If remote address
Expand All @@ -175,24 +175,20 @@ export function readType (type, { bindings } = {}) {
* @param bindings
* @return {string}
*/
export function transform (type, value, { bindings } = {}) {
const { t, generic } = readType(type, { bindings })
export function transform (type, value, bindings) {
const { t, generic } = readType(type, bindings)

switch (t) {
case SOPHIA_TYPES.ChainTtl:
return `${value}`
case SOPHIA_TYPES.string:
return `"${value}"`
case SOPHIA_TYPES.list:
return `[${value.map(el => transform(generic, el, { bindings }))}]`
return `[${value.map(el => transform(generic, el, bindings))}]`
case SOPHIA_TYPES.tuple:
return `(${value.map((el, i) => transform(generic[i], el, {
bindings
}))})`
return `(${value.map((el, i) => transform(generic[i], el, bindings))})`
case SOPHIA_TYPES.option: {
return value === undefined ? 'None' : `Some(${transform(generic, value, {
bindings
})})`
return value === undefined ? 'None' : `Some(${transform(generic, value, bindings)})`
}
case SOPHIA_TYPES.hash:
case SOPHIA_TYPES.bytes:
Expand All @@ -205,34 +201,30 @@ export function transform (type, value, { bindings } = {}) {
case SOPHIA_TYPES.record:
return `{${generic.reduce(
(acc, { name, type }, i) => {
acc += `${i !== 0 ? ',' : ''}${name} = ${transform(type, value[name], {
bindings
})}`
acc += `${i !== 0 ? ',' : ''}${name} = ${transform(type, value[name], bindings)}`
return acc
},
''
)}}`
case SOPHIA_TYPES.map:
return transformMap(value, generic, { bindings })
return transformMap(value, generic, bindings)
case SOPHIA_TYPES.variant:
return transformVariant(value, generic, { bindings })
return transformVariant(value, generic, bindings)
}

return `${value}`
}

function transformVariant (value, generic, { bindings }) {
function transformVariant (value, generic, bindings) {
const [[variant, variantArgs]] = typeof value === 'string' ? [[value, []]] : Object.entries(value)
const [[v, type]] = Object.entries(generic.find(o => Object.keys(o)[0].toLowerCase() === variant.toLowerCase()))
return `${v}${!type.length
? ''
: `(${variantArgs.slice(0, type.length).map((el, i) => transform(type[i], el, {
bindings
}))})`
: `(${variantArgs.slice(0, type.length).map((el, i) => transform(type[i], el, bindings))})`
}`
}

function transformMap (value, generic, { bindings }) {
function transformMap (value, generic, bindings) {
if (!Array.isArray(value)) {
if (value.entries) value = Array.from(value.entries())
else if (value instanceof Object) value = Object.entries(value)
Expand All @@ -242,8 +234,8 @@ function transformMap (value, generic, { bindings }) {
'{',
value
.map(([key, value]) => [
`[${transform(generic[0], key, { bindings })}]`,
transform(generic[1], value, { bindings })
`[${transform(generic[0], key, bindings)}]`,
transform(generic[1], value, bindings)
].join(' = '))
.join(),
'}'
Expand All @@ -256,11 +248,11 @@ function transformMap (value, generic, { bindings }) {
* Transform decoded data to JS type
* @param aci
* @param result
* @param transformDecodedData
* @param bindings
* @return {*}
*/
export function transformDecodedData (aci, result, { bindings } = {}) {
const { t, generic } = readType(aci, { bindings })
export function transformDecodedData (aci, result, bindings) {
const { t, generic } = readType(aci, bindings)

switch (t) {
case SOPHIA_TYPES.bool:
Expand All @@ -278,8 +270,8 @@ export function transformDecodedData (aci, result, { bindings } = {}) {
return result
.reduce(
(acc, [key, val]) => {
key = transformDecodedData(keyT, key, { bindings })
val = transformDecodedData(valueT, val, { bindings })
key = transformDecodedData(keyT, key, bindings)
val = transformDecodedData(valueT, val, bindings)
acc.push([key, val])
return acc
},
Expand All @@ -289,19 +281,19 @@ export function transformDecodedData (aci, result, { bindings } = {}) {
case SOPHIA_TYPES.option: {
if (result === 'None') return undefined
const [[variantType, [value]]] = Object.entries(result)
return variantType === 'Some' ? transformDecodedData(generic, value, { bindings }) : undefined
return variantType === 'Some' ? transformDecodedData(generic, value, bindings) : undefined
}
case SOPHIA_TYPES.list:
return result.map((value) => transformDecodedData(generic, value, { bindings }))
return result.map((value) => transformDecodedData(generic, value, bindings))
case SOPHIA_TYPES.tuple:
return result.map((value, i) => { return transformDecodedData(generic[i], value, { bindings }) })
return result.map((value, i) => { return transformDecodedData(generic[i], value, bindings) })
case SOPHIA_TYPES.record: {
const genericMap = generic.reduce((acc, val) => ({ ...acc, [val.name]: { type: val.type } }), {})
return Object.entries(result).reduce(
(acc, [name, value]) =>
({
...acc,
[name]: transformDecodedData(genericMap[name].type, value, { bindings })
[name]: transformDecodedData(genericMap[name].type, value, bindings)
}),
{}
)
Expand All @@ -318,8 +310,8 @@ export function transformDecodedData (aci, result, { bindings } = {}) {
* @param bindings
* @return {Object} JoiSchema
*/
function prepareSchema (type, { bindings } = {}) {
const { t, generic } = readType(type, { bindings })
function prepareSchema (type, bindings) {
const { t, generic } = readType(type, bindings)

switch (t) {
case SOPHIA_TYPES.int:
Expand Down Expand Up @@ -351,12 +343,12 @@ function prepareSchema (type, { bindings } = {}) {
case SOPHIA_TYPES.bool:
return Joi.boolean().error(getJoiErrorMsg)
case SOPHIA_TYPES.list:
return Joi.array().items(prepareSchema(generic, { bindings })).error(getJoiErrorMsg)
return Joi.array().items(prepareSchema(generic, bindings)).error(getJoiErrorMsg)
case SOPHIA_TYPES.tuple:
return Joi.array().ordered(generic.map(type => prepareSchema(type, { bindings }).required())).label('Tuple argument').error(getJoiErrorMsg)
return Joi.array().ordered(generic.map(type => prepareSchema(type, bindings).required())).label('Tuple argument').error(getJoiErrorMsg)
case SOPHIA_TYPES.record:
return Joi.object(
generic.reduce((acc, { name, type }) => ({ ...acc, [name]: prepareSchema(type, { bindings }) }), {})
generic.reduce((acc, { name, type }) => ({ ...acc, [name]: prepareSchema(type, bindings) }), {})
).error(getJoiErrorMsg)
case SOPHIA_TYPES.hash:
return JoiBinary.binary().bufferCheck(32).error(getJoiErrorMsg)
Expand All @@ -365,7 +357,7 @@ function prepareSchema (type, { bindings } = {}) {
case SOPHIA_TYPES.signature:
return JoiBinary.binary().bufferCheck(64).error(getJoiErrorMsg)
case SOPHIA_TYPES.option:
return prepareSchema(generic, { bindings }).optional().error(getJoiErrorMsg)
return prepareSchema(generic, bindings).optional().error(getJoiErrorMsg)
// @Todo Need to transform Map to Array of arrays before validating it
// case SOPHIA_TYPES.map:
// return Joi.array().items(Joi.array().ordered(generic.map(type => prepareSchema(type))))
Expand Down Expand Up @@ -454,7 +446,7 @@ const JoiBinary = Joi.extend((joi) => ({
export function validateArguments (aci, params) {
const validationSchema = Joi.array().ordered(
aci.arguments
.map(({ type }, i) => prepareSchema(type, { bindings: aci.bindings }).label(`[${params[i]}]`))
.map(({ type }, i) => prepareSchema(type, aci.bindings).label(`[${params[i]}]`))
).sparse(true).label('Argument')
const { error } = Joi.validate(params, validationSchema, { abortEarly: false })
if (error) {
Expand Down
6 changes: 3 additions & 3 deletions test/integration/contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -1077,11 +1077,11 @@ describe('Contract', function () {
})
it('Resolve remote contract type', async () => {
const fnACI = getFunctionACI(cInstance.aci, 'remoteContract', { external: cInstance.externalAci })
readType('Voting', { bindings: fnACI.bindings }).t.should.be.equal('address')
readType('Voting', fnACI.bindings).t.should.be.equal('address')
})
it('Resolve external contract type', async () => {
const fnACI = getFunctionACI(cInstance.aci, 'remoteArgs', { external: cInstance.externalAci })
readType(fnACI.arguments[0].type, { bindings: fnACI.bindings }).should.eql({
readType(fnACI.arguments[0].type, fnACI.bindings).should.eql({
t: 'record',
generic: [{
name: 'value',
Expand All @@ -1093,7 +1093,7 @@ describe('Contract', function () {
}
}]
})
readType(fnACI.returns, { bindings: fnACI.bindings }).t.should.be.equal('int')
readType(fnACI.returns, fnACI.bindings).t.should.be.equal('int')
})
})
})
Expand Down

0 comments on commit 9b70f8e

Please sign in to comment.